Skip to content

Commit 610a335

Browse files
committed
Show category for not installed assistants apps in selector
1 parent f50f074 commit 610a335

7 files changed

Lines changed: 83 additions & 7 deletions

File tree

app/src/main/AndroidManifest.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77

88
<uses-permission android:name="android.permission.VIBRATE" />
99

10+
<!--used to check if an assistant app is currently installed or not in (AssistantSelectorViewModel.kt)-->
11+
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
12+
tools:ignore="QueryAllPackagesPermission" />
13+
1014
<application
1115
android:name=".activity.AppActivity"
1216
android:allowBackup="false"

app/src/main/java/com/wstxda/switchai/data/AssistantItem.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ data class AssistantItem(
55
val name: String,
66
val iconResId: Int,
77
val isPinned: Boolean,
8+
var isInstalled: Boolean,
89
val lastUsedTimestamp: Long,
910
)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.wstxda.switchai.logic
2+
3+
import android.content.Context
4+
import android.content.pm.PackageManager
5+
6+
fun isPackageInstalled(context: Context, packageName: String): Boolean {
7+
return try {
8+
context.packageManager.getPackageInfo(packageName, 0)
9+
true
10+
} catch (_: PackageManager.NameNotFoundException) {
11+
false
12+
}
13+
}

app/src/main/java/com/wstxda/switchai/ui/viewholder/AssistantSelectorItemViewHolder.kt

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.wstxda.switchai.ui.viewholder
22

33
import android.content.Intent
4+
import android.view.View
45
import android.widget.Toast
56
import androidx.recyclerview.widget.RecyclerView
67
import com.wstxda.switchai.R
@@ -27,10 +28,16 @@ class AssistantSelectorItemViewHolder(
2728
if (item.isPinned) R.drawable.ic_pin_filled else R.drawable.ic_pin_outline
2829
)
2930

30-
binding.pinButton.setOnClickListener {
31-
onPinClicked(item.key)
32-
it.context.buttonVibration()
31+
if (item.isInstalled) {
32+
binding.pinButton.visibility = View.VISIBLE
33+
binding.pinButton.setOnClickListener {
34+
onPinClicked(item.key)
35+
it.context.buttonVibration()
36+
}
37+
} else {
38+
binding.pinButton.visibility = View.GONE
3339
}
40+
3441
itemView.setOnClickListener {
3542
val context = it.context
3643
DigitalAssistantMap.assistantsMap[item.key]?.let { cls ->

app/src/main/java/com/wstxda/switchai/utils/DigitalAssistantMap.kt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,32 @@ object DigitalAssistantMap {
3232
"zapia_assistant" to ZapiaAssistant::class.java,
3333
)
3434

35+
internal val assistantsPackages = mapOf(
36+
"alexa_assistant" to "com.amazon.dee.app",
37+
"alice_assistant" to "com.yandex.aliceapp",
38+
"chatgpt_assistant" to "com.openai.chatgpt",
39+
"claude_assistant" to "com.anthropic.claude",
40+
"copilot_assistant" to "com.microsoft.copilot",
41+
"deepseek_assistant" to "com.deepseek.chat",
42+
"doubao_assistant" to "com.larus.nova",
43+
"gemini_assistant" to "com.google.android.apps.bard",
44+
"grok_assistant" to "ai.x.grok",
45+
"home_assistant" to "io.homeassistant.companion.android",
46+
"kimi_assistant" to "com.moonshot.kimichat",
47+
"le_chat_assistant" to "ai.mistral.chat",
48+
"manus_assistant" to "tech.butterfly.app",
49+
"marusya_assistant" to "ru.mail.search.electroscope",
50+
"meta_assistant" to "com.facebook.stella",
51+
"minimax_assistant" to "com.minimax.ai",
52+
"perplexity_assistant" to "ai.perplexity.app.android",
53+
"qingyan_assistant" to "com.zhipuai.qingyan",
54+
"qwen_assistant" to "ai.qwenlm.chat.android",
55+
"ultimate_alexa_assistant" to "com.customsolutions.android.alexa",
56+
"wenxin_yiyan_assistant" to "com.baidu.newapp",
57+
"yuanbao_assistant" to "com.tencent.hunyuan.app.chat",
58+
"zapia_assistant" to "com.brainlogic.zapia",
59+
)
60+
3561
fun launchSelectedAssistant(context: Context) {
3662
val preferenceHelper = PreferenceHelper(context)
3763
val selectedShortcut =

app/src/main/java/com/wstxda/switchai/viewmodel/AssistantSelectorViewModel.kt

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import com.wstxda.switchai.utils.Constants.CAT_RECENTLY_USED_ASSISTANTS_KEY
2020
import com.wstxda.switchai.utils.Constants.CAT_MAX_RECENTLY_USED
2121
import com.wstxda.switchai.utils.Constants.PREFS_NAME
2222
import com.wstxda.switchai.ui.utils.AssistantResourcesManager
23+
import com.wstxda.switchai.logic.isPackageInstalled
2324

2425
class AssistantSelectorViewModel(application: Application) : AndroidViewModel(application),
2526
SharedPreferences.OnSharedPreferenceChangeListener {
@@ -123,6 +124,7 @@ class AssistantSelectorViewModel(application: Application) : AndroidViewModel(ap
123124
val resources = context.resources
124125

125126
val assistantsMap = DigitalAssistantMap.assistantsMap
127+
val assistantPackages = DigitalAssistantMap.assistantsPackages
126128

127129
val defaultVisibleAssistants =
128130
resources.getStringArray(R.array.assistant_visibility_values).toSet()
@@ -134,16 +136,25 @@ class AssistantSelectorViewModel(application: Application) : AndroidViewModel(ap
134136
assistantsMap.filterKeys { it in visibleAssistantKeys }.map { (key, _) ->
135137
val name = assistantResourcesManager.getAssistantName(key)
136138
val finalIconResId = assistantResourcesManager.getAssistantIcon(key)
139+
val packageName = assistantPackages[key] ?: ""
140+
val isInstalled = isPackageInstalled(context, packageName)
137141

138142
AssistantItem(
139-
key, name, finalIconResId, isPinned = false, lastUsedTimestamp = 0L
143+
key,
144+
name,
145+
finalIconResId,
146+
isInstalled = isInstalled,
147+
isPinned = false,
148+
lastUsedTimestamp = 0L
140149
)
141150
}
142151

152+
val (installedAssistants, notInstalledAssistants) = allVisibleAssistantDetails.partition { it.isInstalled }
153+
143154
val finalRecyclerViewItems = mutableListOf<AssistantSelectorRecyclerView>()
144155

145156
val pinnedItems = mutableListOf<AssistantSelectorRecyclerView.AssistantSelector>()
146-
allVisibleAssistantDetails.filter { it.key in pinnedAssistantKeys }.forEach { item ->
157+
installedAssistants.filter { it.key in pinnedAssistantKeys }.forEach { item ->
147158
pinnedItems.add(AssistantSelectorRecyclerView.AssistantSelector(item.copy(isPinned = true)))
148159
}
149160
if (pinnedItems.isNotEmpty()) {
@@ -160,7 +171,7 @@ class AssistantSelectorViewModel(application: Application) : AndroidViewModel(ap
160171
val recentItems = mutableListOf<AssistantSelectorRecyclerView.AssistantSelector>()
161172
recentlyUsedAssistants.forEach { (key, timestamp) ->
162173
if (visibleAssistantKeys.contains(key) && !pinnedAssistantKeys.contains(key)) {
163-
allVisibleAssistantDetails.find { it.key == key }?.let { item ->
174+
installedAssistants.find { it.key == key }?.let { item ->
164175
recentItems.add(
165176
AssistantSelectorRecyclerView.AssistantSelector(
166177
item.copy(
@@ -183,7 +194,7 @@ class AssistantSelectorViewModel(application: Application) : AndroidViewModel(ap
183194
}
184195

185196
val otherItems = mutableListOf<AssistantSelectorRecyclerView.AssistantSelector>()
186-
allVisibleAssistantDetails.forEach { item ->
197+
installedAssistants.forEach { item ->
187198
val isPinned = pinnedAssistantKeys.contains(item.key)
188199
val isRecent = recentlyUsedAssistants.any { it.first == item.key }
189200
if (!isPinned && !isRecent) {
@@ -202,6 +213,19 @@ class AssistantSelectorViewModel(application: Application) : AndroidViewModel(ap
202213
finalRecyclerViewItems.addAll(otherItems)
203214
}
204215

216+
if (notInstalledAssistants.isNotEmpty()) {
217+
finalRecyclerViewItems.add(
218+
AssistantSelectorRecyclerView.CategoryHeader(
219+
context.getString(
220+
R.string.assistant_category_not_installed
221+
)
222+
)
223+
)
224+
finalRecyclerViewItems.addAll(notInstalledAssistants.map {
225+
AssistantSelectorRecyclerView.AssistantSelector(it)
226+
})
227+
}
228+
205229
_assistantItems.value = finalRecyclerViewItems
206230
}
207231

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
<string name="assistant_category_pin">Pinned</string>
101101
<string name="assistant_category_recent">Recently used</string>
102102
<string name="assistant_category_all">Assistants</string>
103+
<string name="assistant_category_not_installed">Not installed</string>
103104
<!--open assistant messages-->
104105
<string name="assistant_open">Open assistant</string>
105106
<string name="assistant_open_error">Error open assistant</string>

0 commit comments

Comments
 (0)