Filter hidden items in UI layer
This commit is contained in:
parent
aa0cd9a062
commit
5ae0ec42b7
@ -120,7 +120,6 @@ dependencies {
|
|||||||
implementation(project(":favorites"))
|
implementation(project(":favorites"))
|
||||||
implementation(project(":files"))
|
implementation(project(":files"))
|
||||||
implementation(project(":g-services"))
|
implementation(project(":g-services"))
|
||||||
implementation(project(":hiddenitems"))
|
|
||||||
implementation(project(":i18n"))
|
implementation(project(":i18n"))
|
||||||
implementation(project(":icons"))
|
implementation(project(":icons"))
|
||||||
implementation(project(":ktx"))
|
implementation(project(":ktx"))
|
||||||
|
|||||||
@ -15,7 +15,6 @@ import de.mm20.launcher2.contacts.contactsModule
|
|||||||
import de.mm20.launcher2.debug.Debug
|
import de.mm20.launcher2.debug.Debug
|
||||||
import de.mm20.launcher2.favorites.favoritesModule
|
import de.mm20.launcher2.favorites.favoritesModule
|
||||||
import de.mm20.launcher2.files.filesModule
|
import de.mm20.launcher2.files.filesModule
|
||||||
import de.mm20.launcher2.hiddenitems.hiddenItemsModule
|
|
||||||
import de.mm20.launcher2.icons.iconsModule
|
import de.mm20.launcher2.icons.iconsModule
|
||||||
import de.mm20.launcher2.music.musicModule
|
import de.mm20.launcher2.music.musicModule
|
||||||
import de.mm20.launcher2.search.searchModule
|
import de.mm20.launcher2.search.searchModule
|
||||||
@ -61,7 +60,6 @@ class LauncherApplication : Application(), CoroutineScope, ImageLoaderFactory {
|
|||||||
databaseModule,
|
databaseModule,
|
||||||
favoritesModule,
|
favoritesModule,
|
||||||
filesModule,
|
filesModule,
|
||||||
hiddenItemsModule,
|
|
||||||
iconsModule,
|
iconsModule,
|
||||||
musicModule,
|
musicModule,
|
||||||
notificationsModule,
|
notificationsModule,
|
||||||
|
|||||||
@ -51,7 +51,6 @@ dependencies {
|
|||||||
implementation(project(":base"))
|
implementation(project(":base"))
|
||||||
implementation(project(":preferences"))
|
implementation(project(":preferences"))
|
||||||
implementation(project(":ktx"))
|
implementation(project(":ktx"))
|
||||||
implementation(project(":hiddenitems"))
|
|
||||||
implementation(project(":compat"))
|
implementation(project(":compat"))
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -11,7 +11,6 @@ import android.os.Process
|
|||||||
import android.os.UserHandle
|
import android.os.UserHandle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.github.promeg.pinyinhelper.Pinyin
|
import com.github.promeg.pinyinhelper.Pinyin
|
||||||
import de.mm20.launcher2.hiddenitems.HiddenItemsRepository
|
|
||||||
import de.mm20.launcher2.search.data.AppInstallation
|
import de.mm20.launcher2.search.data.AppInstallation
|
||||||
import de.mm20.launcher2.search.data.Application
|
import de.mm20.launcher2.search.data.Application
|
||||||
import de.mm20.launcher2.search.data.LauncherApp
|
import de.mm20.launcher2.search.data.LauncherApp
|
||||||
@ -23,13 +22,12 @@ import java.util.*
|
|||||||
|
|
||||||
interface AppRepository {
|
interface AppRepository {
|
||||||
fun search(query: String): Flow<List<Application>>
|
fun search(query: String): Flow<List<Application>>
|
||||||
fun getAllInstalledApps(includeHidden: Boolean = false): Flow<List<Application>>
|
fun getAllInstalledApps(): Flow<List<Application>>
|
||||||
fun getSuspendedPackages(): Flow<List<String>>
|
fun getSuspendedPackages(): Flow<List<String>>
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class AppRepositoryImpl(
|
internal class AppRepositoryImpl(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
hiddenItemsRepository: HiddenItemsRepository,
|
|
||||||
) : AppRepository {
|
) : AppRepository {
|
||||||
|
|
||||||
private val launcherApps =
|
private val launcherApps =
|
||||||
@ -37,7 +35,6 @@ internal class AppRepositoryImpl(
|
|||||||
|
|
||||||
private val installedApps = MutableStateFlow<List<LauncherApp>>(emptyList())
|
private val installedApps = MutableStateFlow<List<LauncherApp>>(emptyList())
|
||||||
private val installations = MutableStateFlow<MutableList<AppInstallation>>(mutableListOf())
|
private val installations = MutableStateFlow<MutableList<AppInstallation>>(mutableListOf())
|
||||||
private val hiddenItems = hiddenItemsRepository.hiddenItemsKeys
|
|
||||||
private val suspendedPackages = MutableStateFlow<List<String>>(emptyList())
|
private val suspendedPackages = MutableStateFlow<List<String>>(emptyList())
|
||||||
|
|
||||||
|
|
||||||
@ -191,7 +188,7 @@ internal class AppRepositoryImpl(
|
|||||||
|
|
||||||
override fun search(query: String): Flow<List<Application>> = channelFlow {
|
override fun search(query: String): Flow<List<Application>> = channelFlow {
|
||||||
|
|
||||||
merge(installedApps, hiddenItems, installations).collectLatest {
|
merge(installedApps, installations).collectLatest {
|
||||||
withContext(Dispatchers.Default) {
|
withContext(Dispatchers.Default) {
|
||||||
val appResults = mutableListOf<Application>()
|
val appResults = mutableListOf<Application>()
|
||||||
if (query.isEmpty()) {
|
if (query.isEmpty()) {
|
||||||
@ -204,13 +201,11 @@ internal class AppRepositoryImpl(
|
|||||||
appResults.addAll(installations.value.filter {
|
appResults.addAll(installations.value.filter {
|
||||||
matches(it.label, query)
|
matches(it.label, query)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
val componentName = ComponentName.unflattenFromString(query)
|
||||||
|
getActivityByComponentName(componentName)?.let { appResults.add(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
val componentName = ComponentName.unflattenFromString(query)
|
|
||||||
getActivityByComponentName(componentName)?.let { appResults.add(it) }
|
|
||||||
|
|
||||||
appResults.removeAll { hiddenItems.value.contains(it.key) }
|
|
||||||
|
|
||||||
appResults.sort()
|
appResults.sort()
|
||||||
|
|
||||||
send(appResults)
|
send(appResults)
|
||||||
@ -218,18 +213,8 @@ internal class AppRepositoryImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getAllInstalledApps(includeHidden: Boolean): Flow<List<Application>> {
|
override fun getAllInstalledApps(): Flow<List<Application>> {
|
||||||
return if (!includeHidden) {
|
return installedApps
|
||||||
channelFlow {
|
|
||||||
hiddenItems.collectLatest { hidden ->
|
|
||||||
installedApps.collectLatest { apps ->
|
|
||||||
send(apps.filter { !hidden.contains(it.key) })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
installedApps
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun matches(label: String, query: String): Boolean {
|
private fun matches(label: String, query: String): Boolean {
|
||||||
|
|||||||
@ -5,5 +5,5 @@ import org.koin.androidx.viewmodel.dsl.viewModel
|
|||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
|
||||||
val applicationsModule = module {
|
val applicationsModule = module {
|
||||||
single<AppRepository> { AppRepositoryImpl(androidContext(), get()) }
|
single<AppRepository> { AppRepositoryImpl(androidContext()) }
|
||||||
}
|
}
|
||||||
@ -46,7 +46,6 @@ dependencies {
|
|||||||
|
|
||||||
implementation(project(":search"))
|
implementation(project(":search"))
|
||||||
implementation(project(":permissions"))
|
implementation(project(":permissions"))
|
||||||
implementation(project(":hiddenitems"))
|
|
||||||
implementation(project(":base"))
|
implementation(project(":base"))
|
||||||
implementation(project(":preferences"))
|
implementation(project(":preferences"))
|
||||||
implementation(project(":ktx"))
|
implementation(project(":ktx"))
|
||||||
|
|||||||
@ -7,7 +7,6 @@ import android.content.pm.PackageManager
|
|||||||
import android.os.Process
|
import android.os.Process
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import com.github.promeg.pinyinhelper.Pinyin
|
import com.github.promeg.pinyinhelper.Pinyin
|
||||||
import de.mm20.launcher2.hiddenitems.HiddenItemsRepository
|
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||||
@ -33,7 +32,6 @@ interface AppShortcutRepository {
|
|||||||
internal class AppShortcutRepositoryImpl(
|
internal class AppShortcutRepositoryImpl(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val permissionsManager: PermissionsManager,
|
private val permissionsManager: PermissionsManager,
|
||||||
private val hiddenItemsRepository: HiddenItemsRepository,
|
|
||||||
private val dataStore: LauncherDataStore,
|
private val dataStore: LauncherDataStore,
|
||||||
) : AppShortcutRepository {
|
) : AppShortcutRepository {
|
||||||
|
|
||||||
@ -110,22 +108,20 @@ internal class AppShortcutRepositoryImpl(
|
|||||||
val pm = context.packageManager
|
val pm = context.packageManager
|
||||||
|
|
||||||
|
|
||||||
hiddenItemsRepository.hiddenItemsKeys.collectLatest { hidden ->
|
send(
|
||||||
send(
|
shortcuts.mapNotNull {
|
||||||
shortcuts.mapNotNull {
|
val label = try {
|
||||||
val label = try {
|
pm.getApplicationInfo(it.`package`, 0).loadLabel(pm).toString()
|
||||||
pm.getApplicationInfo(it.`package`, 0).loadLabel(pm).toString()
|
} catch (e: PackageManager.NameNotFoundException) {
|
||||||
} catch (e: PackageManager.NameNotFoundException) {
|
""
|
||||||
""
|
}
|
||||||
}
|
AppShortcut(
|
||||||
AppShortcut(
|
context,
|
||||||
context,
|
it,
|
||||||
it,
|
label
|
||||||
label
|
)
|
||||||
).takeIf { !hidden.contains(it.key) }
|
}.sorted()
|
||||||
}.sorted()
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,5 +4,5 @@ import org.koin.android.ext.koin.androidContext
|
|||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
|
||||||
val appShortcutsModule = module {
|
val appShortcutsModule = module {
|
||||||
single<AppShortcutRepository> { AppShortcutRepositoryImpl(androidContext(), get(), get(), get()) }
|
single<AppShortcutRepository> { AppShortcutRepositoryImpl(androidContext(), get(), get()) }
|
||||||
}
|
}
|
||||||
@ -46,7 +46,6 @@ dependencies {
|
|||||||
implementation(project(":preferences"))
|
implementation(project(":preferences"))
|
||||||
implementation(project(":ktx"))
|
implementation(project(":ktx"))
|
||||||
implementation(project(":base"))
|
implementation(project(":base"))
|
||||||
implementation(project(":hiddenitems"))
|
|
||||||
implementation(project(":permissions"))
|
implementation(project(":permissions"))
|
||||||
implementation(project(":material-color-utilities"))
|
implementation(project(":material-color-utilities"))
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,9 @@
|
|||||||
package de.mm20.launcher2.calendar
|
package de.mm20.launcher2.calendar
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
import android.content.ContentUris
|
import android.content.ContentUris
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.provider.CalendarContract
|
import android.provider.CalendarContract
|
||||||
import androidx.core.database.getStringOrNull
|
import androidx.core.database.getStringOrNull
|
||||||
import de.mm20.launcher2.hiddenitems.HiddenItemsRepository
|
|
||||||
import de.mm20.launcher2.ktx.checkPermission
|
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||||
@ -29,23 +26,21 @@ interface CalendarRepository {
|
|||||||
|
|
||||||
internal class CalendarRepositoryImpl(
|
internal class CalendarRepositoryImpl(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
hiddenItemsRepository: HiddenItemsRepository
|
|
||||||
) : CalendarRepository, KoinComponent {
|
) : CalendarRepository, KoinComponent {
|
||||||
|
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val dataStore: LauncherDataStore by inject()
|
||||||
private val permissionsManager: PermissionsManager by inject()
|
private val permissionsManager: PermissionsManager by inject()
|
||||||
|
|
||||||
private val hiddenItems = hiddenItemsRepository.hiddenItemsKeys
|
override fun search(query: String): Flow<List<CalendarEvent>> {
|
||||||
|
|
||||||
override fun search(query: String): Flow<List<CalendarEvent>> = channelFlow {
|
|
||||||
if (query.isBlank() || query.length < 3) {
|
if (query.isBlank() || query.length < 3) {
|
||||||
send(emptyList())
|
return flow {
|
||||||
return@channelFlow
|
emit(emptyList())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val hasPermission = permissionsManager.hasPermission(PermissionGroup.Calendar)
|
val hasPermission = permissionsManager.hasPermission(PermissionGroup.Calendar)
|
||||||
val searchCalendar = dataStore.data.map { it.calendarSearch.enabled }
|
val searchCalendar = dataStore.data.map { it.calendarSearch.enabled }
|
||||||
combine(hasPermission, searchCalendar) { permission, search ->
|
return combine(hasPermission, searchCalendar) { permission, search ->
|
||||||
permission && search
|
permission && search
|
||||||
}.map {
|
}.map {
|
||||||
if (it) {
|
if (it) {
|
||||||
@ -58,12 +53,6 @@ internal class CalendarRepositoryImpl(
|
|||||||
} else {
|
} else {
|
||||||
emptyList()
|
emptyList()
|
||||||
}
|
}
|
||||||
}.flatMapLatest { events ->
|
|
||||||
hiddenItems.map { hidden ->
|
|
||||||
events.filter { !hidden.contains(it.key) }
|
|
||||||
}
|
|
||||||
}.collectLatest {
|
|
||||||
send(it)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -160,23 +149,19 @@ internal class CalendarRepositoryImpl(
|
|||||||
hasPermission.collectLatest {
|
hasPermission.collectLatest {
|
||||||
if (it) {
|
if (it) {
|
||||||
dataStore.data.map { it.calendarWidget }.collectLatest { settings ->
|
dataStore.data.map { it.calendarWidget }.collectLatest { settings ->
|
||||||
hiddenItems.collectLatest { hidden ->
|
val now = System.currentTimeMillis()
|
||||||
val now = System.currentTimeMillis()
|
val end = now + 14 * 24 * 60 * 60 * 1000L
|
||||||
val end = now + 14 * 24 * 60 * 60 * 1000L
|
val events = withContext(Dispatchers.IO) {
|
||||||
val events = withContext(Dispatchers.IO) {
|
queryCalendarEvents(
|
||||||
queryCalendarEvents(
|
query = "",
|
||||||
query = "",
|
intervalStart = now,
|
||||||
intervalStart = now,
|
intervalEnd = end,
|
||||||
intervalEnd = end,
|
limit = 700,
|
||||||
limit = 700,
|
excludeAllDayEvents = settings.hideAlldayEvents,
|
||||||
excludeAllDayEvents = settings.hideAlldayEvents,
|
excludeCalendars = settings.excludeCalendarsList
|
||||||
excludeCalendars = settings.excludeCalendarsList
|
)
|
||||||
).filter {
|
|
||||||
!hiddenItems.value.contains(it.key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
send(events)
|
|
||||||
}
|
}
|
||||||
|
send(events)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
send(emptyList())
|
send(emptyList())
|
||||||
|
|||||||
@ -5,5 +5,5 @@ import org.koin.androidx.viewmodel.dsl.viewModel
|
|||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
|
||||||
val calendarModule = module {
|
val calendarModule = module {
|
||||||
single<CalendarRepository> { CalendarRepositoryImpl(androidContext(), get()) }
|
single<CalendarRepository> { CalendarRepositoryImpl(androidContext()) }
|
||||||
}
|
}
|
||||||
@ -46,7 +46,6 @@ dependencies {
|
|||||||
implementation(project(":preferences"))
|
implementation(project(":preferences"))
|
||||||
implementation(project(":ktx"))
|
implementation(project(":ktx"))
|
||||||
implementation(project(":base"))
|
implementation(project(":base"))
|
||||||
implementation(project(":hiddenitems"))
|
|
||||||
implementation(project(":permissions"))
|
implementation(project(":permissions"))
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -2,7 +2,6 @@ package de.mm20.launcher2.contacts
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.provider.ContactsContract
|
import android.provider.ContactsContract
|
||||||
import de.mm20.launcher2.hiddenitems.HiddenItemsRepository
|
|
||||||
import de.mm20.launcher2.permissions.PermissionGroup
|
import de.mm20.launcher2.permissions.PermissionGroup
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||||
@ -19,23 +18,22 @@ interface ContactRepository {
|
|||||||
|
|
||||||
internal class ContactRepositoryImpl(
|
internal class ContactRepositoryImpl(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
hiddenItemsRepository: HiddenItemsRepository
|
|
||||||
) : ContactRepository, KoinComponent {
|
) : ContactRepository, KoinComponent {
|
||||||
|
|
||||||
private val permissionsManager: PermissionsManager by inject()
|
private val permissionsManager: PermissionsManager by inject()
|
||||||
private val dataStore: LauncherDataStore by inject()
|
private val dataStore: LauncherDataStore by inject()
|
||||||
private val hiddenItems = hiddenItemsRepository.hiddenItemsKeys
|
|
||||||
|
|
||||||
override fun search(query: String): Flow<List<Contact>> = channelFlow {
|
override fun search(query: String): Flow<List<Contact>> {
|
||||||
val searchContacts = dataStore.data.map { it.contactsSearch.enabled }
|
val searchContacts = dataStore.data.map { it.contactsSearch.enabled }
|
||||||
val hasPermission = permissionsManager.hasPermission(PermissionGroup.Contacts)
|
val hasPermission = permissionsManager.hasPermission(PermissionGroup.Contacts)
|
||||||
|
|
||||||
if (query.length < 3) {
|
if (query.length < 3) {
|
||||||
send(emptyList())
|
return flow {
|
||||||
return@channelFlow
|
emit(emptyList())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
combine(searchContacts, hasPermission) { search, permission ->
|
return combine(searchContacts, hasPermission) { search, permission ->
|
||||||
search && permission
|
search && permission
|
||||||
}.map {
|
}.map {
|
||||||
if (it) {
|
if (it) {
|
||||||
@ -43,12 +41,6 @@ internal class ContactRepositoryImpl(
|
|||||||
} else {
|
} else {
|
||||||
emptyList()
|
emptyList()
|
||||||
}
|
}
|
||||||
}.flatMapLatest { contacts ->
|
|
||||||
hiddenItems.map { hidden ->
|
|
||||||
contacts.filter { !hidden.contains(it.key) }
|
|
||||||
}
|
|
||||||
}.collectLatest {
|
|
||||||
send(it)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,5 +5,5 @@ import org.koin.androidx.viewmodel.dsl.viewModel
|
|||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
|
||||||
val contactsModule = module {
|
val contactsModule = module {
|
||||||
single<ContactRepository> { ContactRepositoryImpl(androidContext(), get()) }
|
single<ContactRepository> { ContactRepositoryImpl(androidContext()) }
|
||||||
}
|
}
|
||||||
@ -24,6 +24,9 @@ interface SearchDao {
|
|||||||
@Query("SELECT * FROM Searchable WHERE pinned > 0 AND `key` LIKE 'calendar://%' ORDER BY pinned DESC, launchCount DESC")
|
@Query("SELECT * FROM Searchable WHERE pinned > 0 AND `key` LIKE 'calendar://%' ORDER BY pinned DESC, launchCount DESC")
|
||||||
fun getPinnedCalendarEvents(): Flow<List<FavoritesItemEntity>>
|
fun getPinnedCalendarEvents(): Flow<List<FavoritesItemEntity>>
|
||||||
|
|
||||||
|
@Query("SELECT `key` FROM Searchable WHERE hidden = 1 AND `key` LIKE 'calendar://%'")
|
||||||
|
fun getHiddenCalendarEventKeys(): Flow<List<String>>
|
||||||
|
|
||||||
|
|
||||||
@Query("SELECT COUNT(key) as count FROM Searchable WHERE pinned = 1;")
|
@Query("SELECT COUNT(key) as count FROM Searchable WHERE pinned = 1;")
|
||||||
fun getPinCount(): Int
|
fun getPinCount(): Int
|
||||||
|
|||||||
@ -27,6 +27,7 @@ interface FavoritesRepository {
|
|||||||
): Flow<List<Searchable>>
|
): Flow<List<Searchable>>
|
||||||
|
|
||||||
fun getPinnedCalendarEvents(): Flow<List<Searchable>>
|
fun getPinnedCalendarEvents(): Flow<List<Searchable>>
|
||||||
|
fun getHiddenCalendarEventKeys(): Flow<List<String>>
|
||||||
fun isPinned(searchable: Searchable): Flow<Boolean>
|
fun isPinned(searchable: Searchable): Flow<Boolean>
|
||||||
fun pinItem(searchable: Searchable)
|
fun pinItem(searchable: Searchable)
|
||||||
fun unpinItem(searchable: Searchable)
|
fun unpinItem(searchable: Searchable)
|
||||||
@ -37,6 +38,7 @@ interface FavoritesRepository {
|
|||||||
suspend fun getAllFavoriteItems(): List<FavoritesItem>
|
suspend fun getAllFavoriteItems(): List<FavoritesItem>
|
||||||
fun saveFavorites(favorites: List<FavoritesItem>)
|
fun saveFavorites(favorites: List<FavoritesItem>)
|
||||||
fun getHiddenItems(): Flow<List<Searchable>>
|
fun getHiddenItems(): Flow<List<Searchable>>
|
||||||
|
fun getHiddenItemKeys(): Flow<List<String>>
|
||||||
|
|
||||||
suspend fun export(toDir: File)
|
suspend fun export(toDir: File)
|
||||||
suspend fun import(fromDir: File)
|
suspend fun import(fromDir: File)
|
||||||
@ -91,6 +93,10 @@ internal class FavoritesRepositoryImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getHiddenCalendarEventKeys(): Flow<List<String>> {
|
||||||
|
return database.searchDao().getHiddenCalendarEventKeys()
|
||||||
|
}
|
||||||
|
|
||||||
override fun isPinned(searchable: Searchable): Flow<Boolean> {
|
override fun isPinned(searchable: Searchable): Flow<Boolean> {
|
||||||
return AppDatabase.getInstance(context).searchDao().isPinned(searchable.key)
|
return AppDatabase.getInstance(context).searchDao().isPinned(searchable.key)
|
||||||
}
|
}
|
||||||
@ -184,6 +190,10 @@ internal class FavoritesRepositoryImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getHiddenItemKeys(): Flow<List<String>> {
|
||||||
|
return database.searchDao().getHiddenItemKeys()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun fromDatabaseEntity(entity: FavoritesItemEntity): FavoritesItem {
|
private fun fromDatabaseEntity(entity: FavoritesItemEntity): FavoritesItem {
|
||||||
val deserializer: SearchableDeserializer =
|
val deserializer: SearchableDeserializer =
|
||||||
|
|||||||
@ -45,7 +45,6 @@ dependencies {
|
|||||||
implementation(libs.koin.android)
|
implementation(libs.koin.android)
|
||||||
|
|
||||||
implementation(project(":search"))
|
implementation(project(":search"))
|
||||||
implementation(project(":hiddenitems"))
|
|
||||||
implementation(project(":preferences"))
|
implementation(project(":preferences"))
|
||||||
implementation(project(":base"))
|
implementation(project(":base"))
|
||||||
implementation(project(":ktx"))
|
implementation(project(":ktx"))
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
package de.mm20.launcher2.files
|
package de.mm20.launcher2.files
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Log
|
|
||||||
import de.mm20.launcher2.files.providers.*
|
import de.mm20.launcher2.files.providers.*
|
||||||
import de.mm20.launcher2.hiddenitems.HiddenItemsRepository
|
|
||||||
import de.mm20.launcher2.nextcloud.NextcloudApiHelper
|
import de.mm20.launcher2.nextcloud.NextcloudApiHelper
|
||||||
import de.mm20.launcher2.owncloud.OwncloudClient
|
import de.mm20.launcher2.owncloud.OwncloudClient
|
||||||
import de.mm20.launcher2.permissions.PermissionsManager
|
import de.mm20.launcher2.permissions.PermissionsManager
|
||||||
@ -22,14 +20,12 @@ interface FileRepository {
|
|||||||
|
|
||||||
internal class FileRepositoryImpl(
|
internal class FileRepositoryImpl(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
hiddenItemsRepository: HiddenItemsRepository,
|
|
||||||
private val dataStore: LauncherDataStore,
|
private val dataStore: LauncherDataStore,
|
||||||
private val permissionsManager: PermissionsManager,
|
private val permissionsManager: PermissionsManager,
|
||||||
) : FileRepository {
|
) : FileRepository {
|
||||||
|
|
||||||
private val scope = CoroutineScope(Job() + Dispatchers.Default)
|
private val scope = CoroutineScope(Job() + Dispatchers.Default)
|
||||||
|
|
||||||
private val hiddenItems = hiddenItemsRepository.hiddenItemsKeys
|
|
||||||
|
|
||||||
private val providers = MutableStateFlow<List<FileProvider>>(emptyList())
|
private val providers = MutableStateFlow<List<FileProvider>>(emptyList())
|
||||||
|
|
||||||
@ -75,12 +71,10 @@ internal class FileRepositoryImpl(
|
|||||||
send(emptyList())
|
send(emptyList())
|
||||||
return@collectLatest
|
return@collectLatest
|
||||||
}
|
}
|
||||||
hiddenItems.collectLatest { hiddenItems ->
|
val results = mutableListOf<File>()
|
||||||
val results = mutableListOf<File>()
|
for (provider in providers) {
|
||||||
for (provider in providers) {
|
results.addAll(provider.search(query))
|
||||||
results.addAll(provider.search(query))
|
send(results.toList())
|
||||||
send(results.toList())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,5 +5,5 @@ import org.koin.androidx.viewmodel.dsl.viewModel
|
|||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
|
||||||
val filesModule = module {
|
val filesModule = module {
|
||||||
single<FileRepository> { FileRepositoryImpl(androidContext(), get(), get(), get()) }
|
single<FileRepository> { FileRepositoryImpl(androidContext(), get(), get()) }
|
||||||
}
|
}
|
||||||
1
hiddenitems/.gitignore
vendored
1
hiddenitems/.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
/build
|
|
||||||
@ -1,46 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id("com.android.library")
|
|
||||||
id("kotlin-android")
|
|
||||||
}
|
|
||||||
|
|
||||||
android {
|
|
||||||
compileSdk = sdk.versions.compileSdk.get().toInt()
|
|
||||||
|
|
||||||
defaultConfig {
|
|
||||||
minSdk = sdk.versions.minSdk.get().toInt()
|
|
||||||
targetSdk = sdk.versions.targetSdk.get().toInt()
|
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
|
||||||
consumerProguardFiles("consumer-rules.pro")
|
|
||||||
}
|
|
||||||
|
|
||||||
buildTypes {
|
|
||||||
release {
|
|
||||||
proguardFiles(
|
|
||||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
|
||||||
"proguard-rules.pro"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
|
||||||
targetCompatibility = JavaVersion.VERSION_1_8
|
|
||||||
}
|
|
||||||
|
|
||||||
kotlinOptions {
|
|
||||||
jvmTarget = "1.8"
|
|
||||||
}
|
|
||||||
namespace = "de.mm20.launcher2.hiddenitems"
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation(libs.bundles.kotlin)
|
|
||||||
implementation(libs.androidx.core)
|
|
||||||
implementation(libs.androidx.appcompat)
|
|
||||||
|
|
||||||
implementation(libs.koin.android)
|
|
||||||
|
|
||||||
implementation(project(":database"))
|
|
||||||
implementation(project(":search"))
|
|
||||||
}
|
|
||||||
21
hiddenitems/proguard-rules.pro
vendored
21
hiddenitems/proguard-rules.pro
vendored
@ -1,21 +0,0 @@
|
|||||||
# Add project specific ProGuard rules here.
|
|
||||||
# You can control the set of applied configuration files using the
|
|
||||||
# proguardFiles setting in build.gradle.kts.kts.kts.
|
|
||||||
#
|
|
||||||
# For more details, see
|
|
||||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
|
||||||
|
|
||||||
# If your project uses WebView with JS, uncomment the following
|
|
||||||
# and specify the fully qualified class name to the JavaScript interface
|
|
||||||
# class:
|
|
||||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
|
||||||
# public *;
|
|
||||||
#}
|
|
||||||
|
|
||||||
# Uncomment this to preserve the line number information for
|
|
||||||
# debugging stack traces.
|
|
||||||
#-keepattributes SourceFile,LineNumberTable
|
|
||||||
|
|
||||||
# If you keep the line number information, uncomment this to
|
|
||||||
# hide the original source file name.
|
|
||||||
#-renamesourcefileattribute SourceFile
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
|
|
||||||
/
|
|
||||||
</manifest>
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
package de.mm20.launcher2.hiddenitems
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import androidx.lifecycle.LiveData
|
|
||||||
import androidx.lifecycle.MediatorLiveData
|
|
||||||
import de.mm20.launcher2.database.AppDatabase
|
|
||||||
import de.mm20.launcher2.search.data.Searchable
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
|
||||||
import kotlinx.coroutines.flow.stateIn
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A low level repository for hidden items. This can only be used to retrieve keys and to check
|
|
||||||
* whether an item is hidden. To retrieve actual Searchable objects, use FavoritesRepository.
|
|
||||||
*/
|
|
||||||
class HiddenItemsRepository(val context: Context, database: AppDatabase) {
|
|
||||||
|
|
||||||
val scope = CoroutineScope(Job() + Dispatchers.Default)
|
|
||||||
val hiddenItemsKeys = MutableStateFlow<List<String>>(emptyList())
|
|
||||||
|
|
||||||
init {
|
|
||||||
scope.launch {
|
|
||||||
AppDatabase.getInstance(context).searchDao().getHiddenItemKeys().collectLatest {
|
|
||||||
hiddenItemsKeys.value = it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun isHidden(item: Searchable): Flow<Boolean> {
|
|
||||||
return AppDatabase.getInstance(context).searchDao().isHidden(item.key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
package de.mm20.launcher2.hiddenitems
|
|
||||||
|
|
||||||
import org.koin.android.ext.koin.androidContext
|
|
||||||
import org.koin.androidx.viewmodel.dsl.viewModel
|
|
||||||
import org.koin.dsl.module
|
|
||||||
|
|
||||||
val hiddenItemsModule = module {
|
|
||||||
single { HiddenItemsRepository(androidContext(), get()) }
|
|
||||||
}
|
|
||||||
@ -11,7 +11,6 @@ include(":contacts")
|
|||||||
include(":g-services")
|
include(":g-services")
|
||||||
include(":files")
|
include(":files")
|
||||||
include(":calculator")
|
include(":calculator")
|
||||||
include(":hiddenitems")
|
|
||||||
include(":badges")
|
include(":badges")
|
||||||
include(":applications")
|
include(":applications")
|
||||||
include(":ms-services")
|
include(":ms-services")
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package de.mm20.launcher2.ui.launcher.search
|
package de.mm20.launcher2.ui.launcher.search
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
@ -21,10 +22,7 @@ import de.mm20.launcher2.websites.WebsiteRepository
|
|||||||
import de.mm20.launcher2.widgets.WidgetRepository
|
import de.mm20.launcher2.widgets.WidgetRepository
|
||||||
import de.mm20.launcher2.wikipedia.WikipediaRepository
|
import de.mm20.launcher2.wikipedia.WikipediaRepository
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.*
|
||||||
import kotlinx.coroutines.flow.combine
|
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
|
|
||||||
@ -65,6 +63,10 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
|
|
||||||
val hideFavorites = MutableLiveData(false)
|
val hideFavorites = MutableLiveData(false)
|
||||||
|
|
||||||
|
private val hiddenItemKeys = favoritesRepository
|
||||||
|
.getHiddenItemKeys()
|
||||||
|
.shareIn(viewModelScope, SharingStarted.WhileSubscribed(), replay = 1)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
search("")
|
search("")
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
@ -100,18 +102,24 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
isSearching.postValue(true)
|
isSearching.postValue(true)
|
||||||
val jobs = mutableListOf<Deferred<Any>>()
|
val jobs = mutableListOf<Deferred<Any>>()
|
||||||
jobs += async {
|
jobs += async {
|
||||||
appRepository.search(query).collectLatest {
|
appRepository.search(query).collectLatest { apps ->
|
||||||
appResults.postValue(it)
|
hiddenItemKeys.collectLatest { hidden ->
|
||||||
|
appResults.postValue(apps.filter { !hidden.contains(it.key) })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jobs += async {
|
jobs += async {
|
||||||
contactRepository.search(query).collectLatest {
|
contactRepository.search(query).collectLatest { contacts ->
|
||||||
contactResults.postValue(it)
|
hiddenItemKeys.collectLatest { hidden ->
|
||||||
|
contactResults.postValue(contacts.filter { !hidden.contains(it.key) })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jobs += async {
|
jobs += async {
|
||||||
calendarRepository.search(query).collectLatest {
|
calendarRepository.search(query).collectLatest { events ->
|
||||||
calendarResults.postValue(it)
|
hiddenItemKeys.collectLatest { hidden ->
|
||||||
|
calendarResults.postValue(events.filter { !hidden.contains(it.key) })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jobs += async {
|
jobs += async {
|
||||||
@ -135,8 +143,10 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
jobs += async {
|
jobs += async {
|
||||||
fileRepository.search(query).collectLatest {
|
fileRepository.search(query).collectLatest { files ->
|
||||||
fileResults.postValue(it)
|
hiddenItemKeys.collectLatest { hidden ->
|
||||||
|
fileResults.postValue(files.filter { !hidden.contains(it.key) })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jobs += async {
|
jobs += async {
|
||||||
@ -145,8 +155,10 @@ class SearchVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
jobs += async {
|
jobs += async {
|
||||||
appShortcutRepository.search(query).collectLatest {
|
appShortcutRepository.search(query).collectLatest { shortcuts ->
|
||||||
appShortcutResults.postValue(it)
|
hiddenItemKeys.collectLatest { hidden ->
|
||||||
|
appShortcutResults.postValue(shortcuts.filter { !hidden.contains(it.key) })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jobs.map { it.await() }
|
jobs.map { it.await() }
|
||||||
|
|||||||
@ -143,8 +143,10 @@ class CalendarWidgetVM : ViewModel(), KoinComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
suspend fun onActive() {
|
suspend fun onActive() {
|
||||||
calendarRepository.getUpcomingEvents().collectLatest {
|
calendarRepository.getUpcomingEvents().collectLatest { events ->
|
||||||
upcomingEvents = it
|
favoritesRepository.getHiddenCalendarEventKeys().collectLatest { hidden ->
|
||||||
|
upcomingEvents = events.filter { !hidden.contains(it.key) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -34,7 +34,7 @@ class HiddenItemsSettingsScreenVM : ViewModel(), KoinComponent {
|
|||||||
private val favoritesRepository: FavoritesRepository by inject()
|
private val favoritesRepository: FavoritesRepository by inject()
|
||||||
private val iconRepository: IconRepository by inject()
|
private val iconRepository: IconRepository by inject()
|
||||||
|
|
||||||
val allApps = appRepository.getAllInstalledApps(true).map {
|
val allApps = appRepository.getAllInstalledApps().map {
|
||||||
withContext(Dispatchers.Default) { it.sorted() }
|
withContext(Dispatchers.Default) { it.sorted() }
|
||||||
}.asLiveData()
|
}.asLiveData()
|
||||||
val hiddenItems: LiveData<List<Searchable>> = liveData {
|
val hiddenItems: LiveData<List<Searchable>> = liveData {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user