Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1b362512 authored by Fahim M. Choudhury's avatar Fahim M. Choudhury
Browse files

Merge branch '3503-refactor-search' into 'main'

refactor: improve data layer for Search feature

See merge request !570
parents a6b5a3f0 2aeee215
Loading
Loading
Loading
Loading
Loading
+0 −7
Original line number Diff line number Diff line
@@ -110,7 +110,6 @@
    <ID>ProtectedMemberInFinalClass:ApplicationListFragment.kt$ApplicationListFragment$// protected to avoid SyntheticAccessor protected val args: ApplicationListFragmentArgs by navArgs()</ID>
    <ID>ProtectedMemberInFinalClass:ApplicationListFragment.kt$ApplicationListFragment$// protected to avoid SyntheticAccessor protected val viewModel: ApplicationListViewModel by viewModels()</ID>
    <ID>ProtectedMemberInFinalClass:GoogleSignInFragment.kt$GoogleSignInFragment$// protected to avoid SyntheticAccessor protected val viewModel: LoginViewModel by lazy { ViewModelProvider(requireActivity())[LoginViewModel::class.java] }</ID>
    <ID>ProtectedMemberInFinalClass:SearchFragment.kt$SearchFragment$protected val searchViewModel: SearchViewModel by viewModels()</ID>
    <ID>ReturnCount:ApkSignatureManager.kt$ApkSignatureManager$private fun verifyAPKSignature( apkInputStream: BufferedInputStream, apkSignatureInputStream: InputStream, publicKeyInputStream: InputStream, packageName: String ): Boolean</ID>
    <ID>ReturnCount:AppInstallProcessor.kt$AppInstallProcessor$private suspend fun updateDownloadUrls(appInstall: AppInstall): Boolean</ID>
    <ID>ReturnCount:AppInstallProcessor.kt$AppInstallProcessor$suspend fun enqueueFusedDownload( appInstall: AppInstall, isAnUpdate: Boolean = false, isSystemApp: Boolean = false )</ID>
@@ -125,7 +124,6 @@
    <ID>ReturnCount:PlayStoreAuthenticator.kt$PlayStoreAuthenticator$override suspend fun validateAuthData(): ResultSupreme&lt;AuthData?&gt;</ID>
    <ID>ReturnCount:PlayStoreAuthenticator.kt$PlayStoreAuthenticator$private suspend fun getAuthDataWithGoogleAccount(): ResultSupreme&lt;AuthData?&gt;</ID>
    <ID>ReturnCount:PrivacyInfoViewModel.kt$PrivacyInfoViewModel$fun shouldRequestExodusReport(application: Application?): Boolean</ID>
    <ID>ReturnCount:SearchApiImpl.kt$SearchApiImpl$private suspend fun replaceWithFDroid(gPlayApps: List&lt;Application&gt;): List&lt;Application&gt;</ID>
    <ID>ReturnCount:StorageNotificationManager.kt$StorageNotificationManager$private fun getSpaceMissing(appInstall: AppInstall, downloadId: Long? = null): Long</ID>
    <ID>ReturnCount:SystemAppsUpdatesRepository.kt$SystemAppsUpdatesRepository$private suspend fun getApplication( packageName: String, releaseType: OsReleaseType, sdkLevel: Int, device: String, ): Application?</ID>
    <ID>ReturnCount:SystemAppsUpdatesRepository.kt$SystemAppsUpdatesRepository$private suspend fun getReleaseDetailsUrl( systemAppProject: SystemAppProject, releaseType: OsReleaseType, ): String?</ID>
@@ -173,7 +171,6 @@
    <ID>TooGenericExceptionCaught:PlayStoreRepository.kt$PlayStoreRepository$exception: Exception</ID>
    <ID>TooGenericExceptionCaught:PwaManager.kt$PwaManager$e: Exception</ID>
    <ID>TooGenericExceptionCaught:PwaPlayerStatusReceiver.kt$PwaPlayerStatusReceiver$e: Exception</ID>
    <ID>TooGenericExceptionCaught:SearchApiImpl.kt$SearchApiImpl$e: Exception</ID>
    <ID>TooGenericExceptionCaught:SystemInfoProvider.kt$SystemInfoProvider$e: Exception</ID>
    <ID>TooGenericExceptionCaught:UpdatesManagerImpl.kt$UpdatesManagerImpl$e: Exception</ID>
    <ID>TooGenericExceptionCaught:UpdatesWorker.kt$UpdatesWorker$e: Throwable</ID>
@@ -188,19 +185,15 @@
    <ID>TooManyFunctions:ApplicationRepository.kt$ApplicationRepository</ID>
    <ID>TooManyFunctions:HomeFragment.kt$HomeFragment : TimeoutFragmentApplicationInstaller</ID>
    <ID>TooManyFunctions:MainActivityViewModel.kt$MainActivityViewModel : ViewModel</ID>
    <ID>TooManyFunctions:SearchFragment.kt$SearchFragment : TimeoutFragmentOnQueryTextListenerOnSuggestionListenerApplicationInstaller</ID>
    <ID>TooManyFunctions:TimeoutFragment.kt$TimeoutFragment : Fragment</ID>
    <ID>TooManyFunctions:UpdatesFragment.kt$UpdatesFragment : TimeoutFragmentApplicationInstaller</ID>
    <ID>UnusedParameter:PrivacyInfoViewModel.kt$PrivacyInfoViewModel$forced: Boolean = false</ID>
    <ID>UnusedParameter:SearchViewModel.kt$SearchViewModel$gPlayAuth: AuthObject.GPlayAuth</ID>
    <ID>UnusedPrivateProperty:SearchViewModel.kt$SearchViewModel.Companion$private const val DATA_LOAD_ERROR = "Data load error"</ID>
    <ID>UseCheckOrError:AppsApiImpl.kt$AppsApiImpl$throw IllegalStateException("Could not get store")</ID>
    <ID>UseCheckOrError:CleanApkAppsRepository.kt$CleanApkAppsRepository$throw IllegalStateException("No home data found")</ID>
    <ID>UseCheckOrError:CleanApkPwaRepository.kt$CleanApkPwaRepository$throw IllegalStateException("No home data found")</ID>
    <ID>UseCheckOrError:HomeApiImpl.kt$HomeApiImpl$throw IllegalStateException("Could not find store for $source")</ID>
    <ID>UseCheckOrError:PlayStoreRepository.kt$PlayStoreRepository$throw IllegalStateException("App version code cannot be 0")</ID>
    <ID>UseCheckOrError:PlayStoreRepository.kt$PlayStoreRepository$throw IllegalStateException("Could not get download details for $idOrPackageName")</ID>
    <ID>UseCheckOrError:SearchApiImpl.kt$SearchApiImpl$throw IllegalStateException("Could not get store")</ID>
    <ID>UseCheckOrError:Stores.kt$Stores$throw IllegalStateException("store not found")</ID>
    <ID>WildcardImport:SystemAppsUpdatesRepository.kt$import foundation.e.apps.data.gitlab.UpdatableSystemAppsApi.*</ID>
  </CurrentIssues>
+2 −0
Original line number Diff line number Diff line
@@ -20,9 +20,11 @@ package foundation.e.apps.data

import foundation.e.apps.data.application.data.Application
import foundation.e.apps.data.application.data.Home
import foundation.e.apps.data.application.search.SearchSuggestion

interface StoreRepository {
    suspend fun getHomeScreenData(list: MutableList<Home>): List<Home>
    suspend fun getAppDetails(packageName: String): Application
    suspend fun getSearchResults(pattern: String): List<Application>
    suspend fun getSearchSuggestions(pattern: String): List<SearchSuggestion>
}
+21 −30
Original line number Diff line number Diff line
/*
 * Apps  Quickly and easily install Android apps onto your device!
 * Copyright (C) 2021  E FOUNDATION
 * Copyright (C) 2021-2025 e Foundation
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
@@ -14,49 +13,57 @@
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 */

package foundation.e.apps.data.application

import androidx.lifecycle.LiveData
import com.aurora.gplayapi.SearchSuggestEntry
import com.aurora.gplayapi.data.models.AuthData
import com.aurora.gplayapi.data.models.SearchBundle
import foundation.e.apps.data.ResultSupreme
import foundation.e.apps.data.Stores
import foundation.e.apps.data.application.apps.AppsApi
import foundation.e.apps.data.application.category.CategoryApi
import foundation.e.apps.data.enums.FilterLevel
import foundation.e.apps.data.enums.ResultStatus
import foundation.e.apps.data.enums.Source
import foundation.e.apps.data.enums.Status
import foundation.e.apps.data.application.data.Application
import foundation.e.apps.data.application.data.Category
import foundation.e.apps.data.application.data.Home
import foundation.e.apps.data.application.downloadInfo.DownloadInfoApi
import foundation.e.apps.data.application.home.HomeApi
import foundation.e.apps.data.application.search.GplaySearchResult
import foundation.e.apps.data.application.search.SearchApi
import foundation.e.apps.data.application.utils.CategoryType
import foundation.e.apps.data.enums.FilterLevel
import foundation.e.apps.data.enums.ResultStatus
import foundation.e.apps.data.enums.Source
import foundation.e.apps.data.enums.Status
import foundation.e.apps.data.install.models.AppInstall
import foundation.e.apps.data.application.search.SearchResult
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class ApplicationRepository @Inject constructor(
    private val searchAPIImpl: SearchApi,
    private val homeApi: HomeApi,
    private val categoryApi: CategoryApi,
    private val appsApi: AppsApi,
    private val downloadInfoApi: DownloadInfoApi
    private val downloadInfoApi: DownloadInfoApi,
    private val stores: Stores
) {
    companion object {
        const val APP_TYPE_ANY = "any"
        const val APP_TYPE_OPEN = "open"
        const val APP_TYPE_PWA = "pwa"
    }


    suspend fun getHomeScreenData(): LiveData<ResultSupreme<List<Home>>> {
        return homeApi.fetchHomeScreenData()
    }

    fun getSelectedAppTypes(): List<String> {
        return searchAPIImpl.getSelectedAppTypes()
        val selectedAppTypes = mutableListOf<String>()
        if (stores.isStoreEnabled(Source.PLAY_STORE)) selectedAppTypes.add(APP_TYPE_ANY)
        if (stores.isStoreEnabled(Source.OPEN_SOURCE)) selectedAppTypes.add(APP_TYPE_OPEN)
        if (stores.isStoreEnabled(Source.PWA)) selectedAppTypes.add(APP_TYPE_PWA)

        return selectedAppTypes
    }

    suspend fun getApplicationDetails(
@@ -106,22 +113,6 @@ class ApplicationRepository @Inject constructor(
        return categoryApi.getCategoriesList(type)
    }

    suspend fun getSearchSuggestions(query: String): List<SearchSuggestEntry> {
        return searchAPIImpl.getSearchSuggestions(query)
    }

    suspend fun getCleanApkSearchResults(
        query: String
    ): SearchResult {
        return searchAPIImpl.getCleanApkSearchResults(query)
    }

    suspend fun getGplaySearchResults(
        query: String
    ): SearchResult {
        return searchAPIImpl.getGplaySearchResult(query)
    }

    suspend fun getAppsListBasedOnCategory(
        authData: AuthData,
        category: String,
+4 −3
Original line number Diff line number Diff line
@@ -22,8 +22,9 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.liveData
import foundation.e.apps.data.ResultSupreme
import foundation.e.apps.data.Stores
import foundation.e.apps.data.application.ApplicationRepository
import foundation.e.apps.data.application.data.Home
import foundation.e.apps.data.application.search.SearchApi
import foundation.e.apps.data.application.search.SearchRepository
import foundation.e.apps.data.enums.ResultStatus
import foundation.e.apps.data.enums.Source
import foundation.e.apps.data.handleNetworkResult
@@ -78,8 +79,8 @@ class HomeApiImpl @Inject constructor(
        setHomeErrorMessage(result.getResultStatus(), source)
        priorList.sortBy {
            when (it.source) {
                SearchApi.APP_TYPE_OPEN -> AppSourceWeight.OPEN_SOURCE.ordinal
                SearchApi.APP_TYPE_PWA -> AppSourceWeight.PWA.ordinal
                ApplicationRepository.APP_TYPE_OPEN -> AppSourceWeight.OPEN_SOURCE.ordinal
                ApplicationRepository.APP_TYPE_PWA -> AppSourceWeight.PWA.ordinal
                else -> AppSourceWeight.GPLAY.ordinal
            }
        }
+10 −25
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 e Foundation
 * Copyright MURENA SAS 2023
 * Apps  Quickly and easily install Android apps onto your device!
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
@@ -14,42 +14,27 @@
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 */

package foundation.e.apps.data.application.search

import com.aurora.gplayapi.SearchSuggestEntry
import com.aurora.gplayapi.data.models.AuthData
import com.aurora.gplayapi.data.models.SearchBundle
import foundation.e.apps.data.ResultSupreme
import foundation.e.apps.data.application.data.Application

typealias GplaySearchResult = ResultSupreme<Pair<List<Application>, Set<SearchBundle.SubBundle>>>

typealias SearchResult = ResultSupreme<Pair<List<Application>, Boolean>>

interface SearchApi {
    companion object {
        const val APP_TYPE_ANY = "any"
        const val APP_TYPE_OPEN = "open"
        const val APP_TYPE_PWA = "pwa"
    }

    fun getSelectedAppTypes(): List<String>
interface SearchRepository {

    /**
     * Fetches search results from cleanAPK and GPlay servers and returns them
     * @param query Query
     * @return ResultSupreme which contains a Pair<List<FusedApp>, Boolean> where List<FusedApp>
     *     is the app list and [Boolean] indicates more data to load or not.
     * Fetches search results from CleanAPK.
     *
     * @return ResultSupreme containing a Pair<List<Application>, Boolean>,
     * where List<Application> contains search results and [Boolean] indicates more data to load or not.
     */
    suspend fun getCleanApkSearchResults(
        query: String
    ): SearchResult
    suspend fun getOpenSourceSearchResults(query: String): SearchResult

    suspend fun getGplaySearchResult(
        query: String,
    ): SearchResult
    suspend fun getPlayStoreSearchResults(query: String): SearchResult

    suspend fun getSearchSuggestions(query: String): List<SearchSuggestEntry>
    suspend fun getSearchSuggestions(query: String): List<SearchSuggestion>
}
Loading