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

Verified Commit 231c0ff0 authored by Fahim M. Choudhury's avatar Fahim M. Choudhury
Browse files

feat: implement pagination for CleanAPK search results

parent 9789864e
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -214,6 +214,7 @@ dependencies {
    implementation(libs.navigation.fragment.ktx)
    implementation(libs.navigation.ui.ktx)
    implementation(libs.activity.ktx)
    implementation(libs.paging.runtime.ktx)

    // Material Design
    implementation(libs.material)
@@ -304,6 +305,7 @@ dependencies {
    implementation libs.activity.compose
    implementation libs.lifecycle.viewmodel.compose
    implementation libs.runtime.livedata
    implementation libs.paging.compose

    // Android Studio Preview support for Compose
    implementation libs.compose.ui.tooling.preview
+24 −24
Original line number Diff line number Diff line
@@ -66,7 +66,7 @@ interface CleanApkRetrofit {
        @Query("keyword") keyword: String,
        @Query("source") source: String = APP_SOURCE_FOSS,
        @Query("type") type: String = APP_TYPE_ANY,
        @Query("nres") nres: Int = 20,
        @Query("nres") pageSize: Int = 20,
        @Query("page") page: Int = 1,
        @Query("by") by: String? = null,
        @Query("architectures") architectures: List<String>? = null,
+37 −5
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
package foundation.e.apps.data.cleanapk

import foundation.e.apps.data.application.data.Application
import foundation.e.apps.data.cleanapk.data.search.Search
import foundation.e.apps.data.cleanapk.repositories.NUMBER_OF_ITEMS
import foundation.e.apps.data.cleanapk.repositories.NUMBER_OF_PAGES
import foundation.e.apps.data.enums.Source
@@ -36,16 +37,47 @@ class CleanApkSearchHelper @Inject constructor(
        appType: String
    ): List<Application> {
        return withContext(Dispatchers.IO) {
            val searchResult = cleanApkRetrofit.searchApps(
            getSearchResultPage(
                keyword = keyword,
                appSource = appSource,
                appType = appType,
                page = NUMBER_OF_PAGES,
                pageSize = NUMBER_OF_ITEMS,
            ).apps
        }
    }

    suspend fun getSearchResultPage(
        keyword: String,
        appSource: String,
        appType: String,
        page: Int,
        pageSize: Int,
    ): Search {
        return withContext(Dispatchers.IO) {
            val response = cleanApkRetrofit.searchApps(
                keyword = keyword,
                source = appSource,
                type = appType,
                nres = NUMBER_OF_ITEMS,
                page = NUMBER_OF_PAGES,
                pageSize = pageSize,
                page = page,
                architectures = SystemInfoProvider.getSupportedArchitectureList(),
            )
            searchResult.body()?.apps.orEmpty()
                .map { it.apply { source = mapSource(it) } }

            check(response.isSuccessful) {
                "CleanAPK search failed: HTTP ${response.code()}"
            }

            val body = checkNotNull(response.body()) {
                "CleanAPK search failed: empty body"
            }

            check(body.success) {
                "CleanAPK search failed: success=false"
            }

            body.apps.forEach { app -> app.source = mapSource(app) }
            body
        }
    }

+4 −2
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-2026 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,14 +13,17 @@
 *
 * 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.cleanapk.data.search

import com.google.gson.annotations.SerializedName
import foundation.e.apps.data.application.data.Application

data class Search(
    val apps: List<Application> = emptyList(),
    val numberOfResults: Int = -1,
    @SerializedName(value = "pages") val numberOfPages: Int = 0,
    val success: Boolean = false
)
+48 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2026 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
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * 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.search

import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import foundation.e.apps.data.application.data.Application
import foundation.e.apps.data.cleanapk.CleanApkSearchHelper
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject

class CleanApkSearchPagingRepository @Inject constructor(
    private val cleanApkSearchHelper: CleanApkSearchHelper,
) : SearchPagingRepository {

    override fun cleanApkSearch(params: CleanApkSearchParams): Flow<PagingData<Application>> {
        return Pager(
            config = PagingConfig(
                pageSize = params.pageSize,
                enablePlaceholders = false,
                prefetchDistance = 2
            ),
            pagingSourceFactory = {
                CleanApkSearchPagingSource(
                    cleanApkSearchHelper = cleanApkSearchHelper,
                    params = params
                )
            }
        ).flow
    }
}
Loading