Sort by various criteria

main
Clément FRÉVILLE 2 years ago
parent e64bd7a387
commit c12c46bdd5

@ -11,6 +11,7 @@ import androidx.navigation.fragment.NavHostFragment
import fr.uca.iut.clfreville2.teaiswarm.fragment.RepositoryListFragment import fr.uca.iut.clfreville2.teaiswarm.fragment.RepositoryListFragment
import fr.uca.iut.clfreville2.teaiswarm.fragment.SetupConfigFragment import fr.uca.iut.clfreville2.teaiswarm.fragment.SetupConfigFragment
import fr.uca.iut.clfreville2.teaiswarm.model.Repository import fr.uca.iut.clfreville2.teaiswarm.model.Repository
import fr.uca.iut.clfreville2.teaiswarm.model.search.SearchSettings
const val REPOSITORY_OWNER = "repository_owner" const val REPOSITORY_OWNER = "repository_owner"
const val REPOSITORY_NAME = "repository_name" const val REPOSITORY_NAME = "repository_name"
@ -47,10 +48,7 @@ class MainActivity : AppCompatActivity() {
override fun instantiate(classLoader: ClassLoader, className: String): Fragment = override fun instantiate(classLoader: ClassLoader, className: String): Fragment =
when (className) { when (className) {
RepositoryListFragment::class.java.name -> RepositoryListFragment( RepositoryListFragment::class.java.name -> RepositoryListFragment(
preferences.getString( SearchSettings(), onClick
USERNAME,
null
)!!, onClick
) )
SetupConfigFragment::class.java.name -> SetupConfigFragment(preferences) SetupConfigFragment::class.java.name -> SetupConfigFragment(preferences)
else -> super.instantiate(classLoader, className) else -> super.instantiate(classLoader, className)

@ -15,13 +15,17 @@ import fr.uca.iut.clfreville2.teaiswarm.R
import fr.uca.iut.clfreville2.teaiswarm.TeaIsWarm import fr.uca.iut.clfreville2.teaiswarm.TeaIsWarm
import fr.uca.iut.clfreville2.teaiswarm.adapter.RepositoryListAdapter import fr.uca.iut.clfreville2.teaiswarm.adapter.RepositoryListAdapter
import fr.uca.iut.clfreville2.teaiswarm.model.Repository import fr.uca.iut.clfreville2.teaiswarm.model.Repository
import fr.uca.iut.clfreville2.teaiswarm.model.search.SearchSettings
import fr.uca.iut.clfreville2.teaiswarm.network.RepositoryService import fr.uca.iut.clfreville2.teaiswarm.network.RepositoryService
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import retrofit2.HttpException import retrofit2.HttpException
import java.io.IOException import java.io.IOException
class RepositoryListFragment(private val username: String, private val onClick: (Repository) -> Unit) : Fragment(R.layout.repository_list) { class RepositoryListFragment(
private val search: SearchSettings,
private val onClick: (Repository) -> Unit
) : Fragment(R.layout.repository_list) {
private val service = TeaIsWarm.service private val service = TeaIsWarm.service
@ -35,7 +39,7 @@ class RepositoryListFragment(private val username: String, private val onClick:
factoryProducer = { factoryProducer = {
RepositoryViewModelFactory( RepositoryViewModelFactory(
service, service,
username search
) )
} }
) )
@ -53,13 +57,13 @@ class RepositoryListFragment(private val username: String, private val onClick:
class RepositorySource( class RepositorySource(
private val service: RepositoryService, private val service: RepositoryService,
private val username: String private val search: SearchSettings
) : PagingSource<Int, Repository>() { ) : PagingSource<Int, Repository>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Repository> = override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Repository> =
try { try {
val nextPageNumber = params.key ?: 1 val nextPageNumber = params.key ?: 1
val response = service.listActiveRepositories(username, nextPageNumber) val response = service.searchRepositories(search.copy(page = nextPageNumber))
LoadResult.Page( LoadResult.Page(
data = response, data = response,
prevKey = nextPageNumber - 1, prevKey = nextPageNumber - 1,
@ -80,23 +84,23 @@ class RepositoryListFragment(private val username: String, private val onClick:
class RepositoryViewModel( class RepositoryViewModel(
private val service: RepositoryService, private val service: RepositoryService,
private val username: String private val search: SearchSettings
) : ViewModel() { ) : ViewModel() {
val flow = Pager( val flow = Pager(
PagingConfig(pageSize = 10, enablePlaceholders = true) PagingConfig(pageSize = 10, enablePlaceholders = true)
) { ) {
RepositorySource(service, username) RepositorySource(service, search)
}.flow.cachedIn(viewModelScope) }.flow.cachedIn(viewModelScope)
} }
class RepositoryViewModelFactory( class RepositoryViewModelFactory(
private val service: RepositoryService, private val service: RepositoryService,
private val username: String private val search: SearchSettings
) : ViewModelProvider.Factory { ) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T { override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(RepositoryViewModel::class.java)) { if (modelClass.isAssignableFrom(RepositoryViewModel::class.java)) {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
return RepositoryViewModel(service, username) as T return RepositoryViewModel(service, search) as T
} }
throw IllegalArgumentException("Unknown ViewModel class") throw IllegalArgumentException("Unknown ViewModel class")
} }

@ -0,0 +1,14 @@
package fr.uca.iut.clfreville2.teaiswarm.model
import com.squareup.moshi.Json
enum class RepositoryMode {
@Json(name = "fork")
FORK,
@Json(name = "source")
SOURCE,
@Json(name = "mirror")
MIRROR,
@Json(name = "collaborative")
COLLABORATIVE,
}

@ -0,0 +1,3 @@
package fr.uca.iut.clfreville2.teaiswarm.model.search
data class SearchResults<T>(val data: List<T>)

@ -0,0 +1,15 @@
package fr.uca.iut.clfreville2.teaiswarm.model.search
import fr.uca.iut.clfreville2.teaiswarm.model.RepositoryMode
data class SearchSettings(
val query: String = "",
val userId: Int? = null,
val teamId: Int? = null,
val starredBy: Int? = null,
val mode: RepositoryMode? = null,
val sort: SortCriteria = SortCriteria.ALPHA,
val order: SortOrder = SortOrder.ASC,
val page: Int = 1,
val limit: Int = 10
)

@ -0,0 +1,16 @@
package fr.uca.iut.clfreville2.teaiswarm.model.search
import com.squareup.moshi.Json
enum class SortCriteria {
@Json(name = "alpha")
ALPHA,
@Json(name = "created")
CREATED,
@Json(name = "updated")
UPDATED,
@Json(name = "size")
SIZE,
@Json(name = "id")
ID
}

@ -0,0 +1,10 @@
package fr.uca.iut.clfreville2.teaiswarm.model.search
import com.squareup.moshi.Json
enum class SortOrder {
@Json(name = "asc")
ASC,
@Json(name = "desc")
DESC
}

@ -4,6 +4,8 @@ import com.squareup.moshi.Moshi
import com.squareup.moshi.adapters.Rfc3339DateJsonAdapter import com.squareup.moshi.adapters.Rfc3339DateJsonAdapter
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import fr.uca.iut.clfreville2.teaiswarm.model.* import fr.uca.iut.clfreville2.teaiswarm.model.*
import fr.uca.iut.clfreville2.teaiswarm.model.search.SearchResults
import fr.uca.iut.clfreville2.teaiswarm.model.search.SearchSettings
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@ -16,7 +18,7 @@ import retrofit2.http.Path
import retrofit2.http.Query import retrofit2.http.Query
import java.util.* import java.util.*
const val HTTP_NOT_FOUND = 404; const val HTTP_NOT_FOUND = 404
interface GiteaApiService { interface GiteaApiService {
@ -34,6 +36,19 @@ interface GiteaApiService {
@GET("users/{owner}") @GET("users/{owner}")
suspend fun searchOwner(@Path("owner") owner: String): Owner? suspend fun searchOwner(@Path("owner") owner: String): Owner?
@GET("repos/search")
suspend fun searchRepositories(
@Query("q") query: String,
@Query("uid") uid: Int?,
@Query("team_id") teamId: Int?,
@Query("starred_by") starredBy: Int?,
@Query("mode") mode: String?,
@Query("sort") sort: String,
@Query("order") order: String,
@Query("page") page: Int,
@Query("limit") limit: Int
): SearchResults<Repository>
} }
class GiteaService(private val handle: GiteaApiService) : RepositoryService { class GiteaService(private val handle: GiteaApiService) : RepositoryService {
@ -80,6 +95,19 @@ class GiteaService(private val handle: GiteaApiService) : RepositoryService {
throw ex throw ex
} }
} }
override suspend fun searchRepositories(settings: SearchSettings): List<Repository> =
handle.searchRepositories(
settings.query,
settings.userId,
settings.teamId,
settings.starredBy,
settings.mode?.toString()?.lowercase(),
settings.sort.toString().lowercase(),
settings.order.toString().lowercase(),
settings.page,
settings.limit
).data
} }
private const val CODEFIRST_API_BASE = "https://codefirst.iut.uca.fr/git/api/v1/" private const val CODEFIRST_API_BASE = "https://codefirst.iut.uca.fr/git/api/v1/"

@ -1,6 +1,7 @@
package fr.uca.iut.clfreville2.teaiswarm.network package fr.uca.iut.clfreville2.teaiswarm.network
import fr.uca.iut.clfreville2.teaiswarm.model.* import fr.uca.iut.clfreville2.teaiswarm.model.*
import fr.uca.iut.clfreville2.teaiswarm.model.search.SearchSettings
interface RepositoryService { interface RepositoryService {
@ -13,4 +14,6 @@ interface RepositoryService {
suspend fun retrieveFileContents(repository: RepositoryIdentifiable, filePath: String): FileContent suspend fun retrieveFileContents(repository: RepositoryIdentifiable, filePath: String): FileContent
suspend fun searchOwner(owner: String): Owner? suspend fun searchOwner(owner: String): Owner?
suspend fun searchRepositories(settings: SearchSettings): List<Repository>
} }

@ -1,6 +1,7 @@
package fr.uca.iut.clfreville2.teaiswarm.network package fr.uca.iut.clfreville2.teaiswarm.network
import fr.uca.iut.clfreville2.teaiswarm.model.* import fr.uca.iut.clfreville2.teaiswarm.model.*
import fr.uca.iut.clfreville2.teaiswarm.model.search.SearchSettings
import java.util.Date import java.util.Date
import kotlin.random.Random import kotlin.random.Random
@ -69,6 +70,9 @@ class StubRepositoryService : RepositoryService {
override suspend fun searchOwner(owner: String): Owner = override suspend fun searchOwner(owner: String): Owner =
Owner(1, owner) Owner(1, owner)
override suspend fun searchRepositories(settings: SearchSettings): List<Repository> =
listActiveRepositories(settings.query, settings.page)
} }
val CHAR_POOL = "abcdefghijklmnopqrstuvwxyz0123456789".toCharArray(); val CHAR_POOL = "abcdefghijklmnopqrstuvwxyz0123456789".toCharArray();

Loading…
Cancel
Save