11package com.wstxda.switchai.viewmodel
22
33import android.app.Application
4+ import android.content.BroadcastReceiver
5+ import android.content.Context
6+ import android.content.Intent
7+ import android.content.IntentFilter
48import android.content.SharedPreferences
59import androidx.core.content.edit
610import androidx.lifecycle.AndroidViewModel
@@ -36,6 +40,9 @@ class AssistantSelectorViewModel(application: Application) : AndroidViewModel(ap
3640 private val _isLoading = MutableLiveData <Boolean >()
3741 val isLoading: LiveData <Boolean > = _isLoading
3842
43+ private val _isDynamicModeEnabled = MutableLiveData <Boolean >()
44+ val isDynamicModeEnabled: LiveData <Boolean > = _isDynamicModeEnabled
45+
3946 private val pinnedAssistantKeys = mutableListOf<String >()
4047 private val recentlyUsedAssistants = mutableListOf<Pair <String , Long >>()
4148
@@ -56,8 +63,30 @@ class AssistantSelectorViewModel(application: Application) : AndroidViewModel(ap
5663
5764 private val packageChecker: PackageChecker = PackageChecker (application.applicationContext)
5865
66+ private val packageChangeReceiver = object : BroadcastReceiver () {
67+ override fun onReceive (context : Context ? , intent : Intent ? ) {
68+ if (isDynamicMode) {
69+ loadAssistants()
70+ }
71+ }
72+ }
73+
74+ private val isDynamicMode: Boolean
75+ get() = defaultSharedPreferences.getBoolean(
76+ Constants .ASSISTANT_MANAGER_DYNAMIC_PREF_KEY , false
77+ )
78+
5979 init {
6080 defaultSharedPreferences.registerOnSharedPreferenceChangeListener(this )
81+ _isDynamicModeEnabled .value = isDynamicMode
82+
83+ val intentFilter = IntentFilter ().apply {
84+ addAction(Intent .ACTION_PACKAGE_ADDED )
85+ addAction(Intent .ACTION_PACKAGE_REMOVED )
86+ addDataScheme(" package" )
87+ }
88+ getApplication<Application >().registerReceiver(packageChangeReceiver, intentFilter)
89+
6190 loadAssistants()
6291 }
6392
@@ -83,7 +112,8 @@ class AssistantSelectorViewModel(application: Application) : AndroidViewModel(ap
83112 return
84113 }
85114
86- val filteredList = allAssistantItems.filterIsInstance<AssistantSelectorRecyclerView .AssistantSelector >()
115+ val filteredList =
116+ allAssistantItems.filterIsInstance<AssistantSelectorRecyclerView .AssistantSelector >()
87117 .filter { assistant ->
88118 assistant.assistantItem.name.contains(query, ignoreCase = true )
89119 }
@@ -189,28 +219,35 @@ class AssistantSelectorViewModel(application: Application) : AndroidViewModel(ap
189219
190220 private fun getVisibleAssistantDetails (installedKeys : Set <String >): List <AssistantItem > {
191221 val context = getApplication<Application >().applicationContext
192- val defaultVisibleAssistants =
193- context.resources.getStringArray(R .array.assistant_values).toSet()
194- val visibleAssistantKeys = preferenceHelper.getStringSet(
195- Constants .ASSISTANT_MANAGER_DIALOG_PREF_KEY , defaultVisibleAssistants
196- )
197222
198- return AssistantsMap .assistantActivity.filterKeys { it in visibleAssistantKeys }
199- .map { (key, _) ->
200- AssistantItem (
201- key = key,
202- name = assistantResourcesManager.getAssistantName(key),
203- iconRes = assistantResourcesManager.getAssistantIcon(key),
204- isInstalled = key in installedKeys,
205- isPinned = key in pinnedAssistantKeys,
206- lastUsedTime = recentlyUsedAssistants.find { it.first == key }?.second ? : 0L
207- )
208- }
223+ val keysToShow: Set <String > = if (isDynamicMode) {
224+ installedKeys
225+ } else {
226+ val defaultVisibleAssistants =
227+ context.resources.getStringArray(R .array.assistant_values).toSet()
228+ preferenceHelper.getStringSet(
229+ Constants .ASSISTANT_MANAGER_MANUAL_PREF_KEY , defaultVisibleAssistants
230+ )
231+ }
232+
233+ return AssistantsMap .assistantActivity.filterKeys { it in keysToShow }.map { (key, _) ->
234+ AssistantItem (
235+ key = key,
236+ name = assistantResourcesManager.getAssistantName(key),
237+ iconRes = assistantResourcesManager.getAssistantIcon(key),
238+ isInstalled = key in installedKeys,
239+ isPinned = key in pinnedAssistantKeys,
240+ lastUsedTime = recentlyUsedAssistants.find { it.first == key }?.second ? : 0L
241+ )
242+ }
209243 }
210244
211245 private fun buildCategorizedList (assistants : List <AssistantItem >): List <AssistantSelectorRecyclerView > {
212246 val context = getApplication<Application >().applicationContext
213247 val (installedAssistants, notInstalledAssistants) = assistants.partition { it.isInstalled }
248+ val nameComparator =
249+ compareBy(String .CASE_INSENSITIVE_ORDER ) { it: AssistantItem -> it.name }
250+
214251 return buildList {
215252 val pinnedAssistants = installedAssistants.filter { it.isPinned }
216253 val unpinnedItems = installedAssistants.filterNot { it.isPinned }
@@ -223,7 +260,12 @@ class AssistantSelectorViewModel(application: Application) : AndroidViewModel(ap
223260 val (recentItems, otherItems) = unpinnedItems.partition { it.key in recentKeys }
224261
225262 if (pinnedItems.isNotEmpty()) {
226- add(AssistantSelectorRecyclerView .CategoryHeader (context.getString(R .string.assistant_category_pin)))
263+ add(
264+ AssistantSelectorRecyclerView .CategoryHeader (
265+ title = context.getString(R .string.assistant_category_pin),
266+ count = pinnedItems.size
267+ )
268+ )
227269 val tipDismissed = assistantStatePreferences.getBoolean(
228270 Constants .REORDER_TIP_DISMISSED_KEY , false
229271 )
@@ -233,20 +275,35 @@ class AssistantSelectorViewModel(application: Application) : AndroidViewModel(ap
233275 addAll(pinnedItems)
234276 }
235277 if (recentItems.isNotEmpty()) {
236- add(AssistantSelectorRecyclerView .CategoryHeader (context.getString(R .string.assistant_category_recent)))
278+ add(
279+ AssistantSelectorRecyclerView .CategoryHeader (
280+ title = context.getString(R .string.assistant_category_recent),
281+ count = recentItems.size
282+ )
283+ )
237284 val sortedRecent = recentItems.sortedByDescending { it.lastUsedTime }
238285 .map { AssistantSelectorRecyclerView .AssistantSelector (it) }
239286 addAll(sortedRecent)
240287 }
241288 if (otherItems.isNotEmpty()) {
242- add(AssistantSelectorRecyclerView .CategoryHeader (context.getString(R .string.assistant_category_all)))
243- val sortedOthers = otherItems.sortedBy { it.name }
289+ add(
290+ AssistantSelectorRecyclerView .CategoryHeader (
291+ title = context.getString(R .string.assistant_category_all),
292+ count = otherItems.size
293+ )
294+ )
295+ val sortedOthers = otherItems.sortedWith(nameComparator)
244296 .map { AssistantSelectorRecyclerView .AssistantSelector (it) }
245297 addAll(sortedOthers)
246298 }
247299 if (notInstalledAssistants.isNotEmpty()) {
248- add(AssistantSelectorRecyclerView .CategoryHeader (context.getString(R .string.assistant_category_not_installed)))
249- val sortedNotInstalled = notInstalledAssistants.sortedBy { it.name }
300+ add(
301+ AssistantSelectorRecyclerView .CategoryHeader (
302+ title = context.getString(R .string.assistant_category_not_installed),
303+ count = notInstalledAssistants.size
304+ )
305+ )
306+ val sortedNotInstalled = notInstalledAssistants.sortedWith(nameComparator)
250307 .map { AssistantSelectorRecyclerView .AssistantSelector (it) }
251308 addAll(sortedNotInstalled)
252309 }
@@ -277,14 +334,19 @@ class AssistantSelectorViewModel(application: Application) : AndroidViewModel(ap
277334 }
278335
279336 override fun onSharedPreferenceChanged (sharedPreferences : SharedPreferences ? , key : String? ) {
280- if (key == Constants .ASSISTANT_MANAGER_DIALOG_PREF_KEY ) {
281- loadAssistants()
337+ when (key) {
338+ Constants .ASSISTANT_MANAGER_MANUAL_PREF_KEY -> loadAssistants()
339+ Constants .ASSISTANT_MANAGER_DYNAMIC_PREF_KEY -> {
340+ _isDynamicModeEnabled .value = isDynamicMode
341+ loadAssistants()
342+ }
282343 }
283344 }
284345
285346 override fun onCleared () {
286347 super .onCleared()
287348 defaultSharedPreferences.unregisterOnSharedPreferenceChangeListener(this )
349+ getApplication<Application >().unregisterReceiver(packageChangeReceiver)
288350 }
289351
290352 fun dismissReorderTip () {
0 commit comments