Add a spinner for the sort criteria

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

@ -2,6 +2,9 @@ package fr.uca.iut.clfreville2.teaiswarm.fragment
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Spinner
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
@ -16,36 +19,50 @@ 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.model.search.SearchSettings
import fr.uca.iut.clfreville2.teaiswarm.model.search.SortCriteria
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
import kotlin.properties.Delegates
class RepositoryListFragment( class RepositoryListFragment(
private val search: SearchSettings, private val initialSearch: SearchSettings,
private val onClick: (Repository) -> Unit private val onClick: (Repository) -> Unit
) : Fragment(R.layout.repository_list) { ) : Fragment(R.layout.repository_list) {
private val service = TeaIsWarm.service private val service = TeaIsWarm.service
private var search: SearchSettings by Delegates.observable(SearchSettings()) { _, _, _ ->
updateRepositories()
}
private lateinit var recyclerView: RecyclerView
private lateinit var pagingAdapter: RepositoryListAdapter
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
updateRepositories() recyclerView = view.findViewById(R.id.repositories_view)
} val spinner: Spinner = view.findViewById(R.id.sort_by_spinner)
ArrayAdapter.createFromResource(
requireContext(),
R.array.sort_criteria,
android.R.layout.simple_spinner_item
).also { adapter ->
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spinner.adapter = adapter
}
spinner.onItemSelectedListener = SortListener()
private fun updateRepositories() {
val viewModel by viewModels<RepositoryViewModel>( val viewModel by viewModels<RepositoryViewModel>(
factoryProducer = { factoryProducer = {
RepositoryViewModelFactory( RepositoryViewModelFactory(
service, service
search ) { search }
)
} }
) )
val pagingAdapter = pagingAdapter =
RepositoryListAdapter(RepositoryListAdapter.RepositoryComparator, onClick) RepositoryListAdapter(RepositoryListAdapter.RepositoryComparator, onClick)
val recyclerView = requireView().findViewById<RecyclerView>(R.id.repositories_view)
recyclerView.adapter = pagingAdapter recyclerView.adapter = pagingAdapter
recyclerView.layoutManager = LinearLayoutManager(requireContext()) recyclerView.layoutManager = LinearLayoutManager(requireContext())
viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.lifecycleScope.launch {
@ -53,6 +70,12 @@ class RepositoryListFragment(
pagingAdapter.submitData(pagingData) pagingAdapter.submitData(pagingData)
} }
} }
search = initialSearch
}
private fun updateRepositories() {
pagingAdapter.refresh()
} }
class RepositorySource( class RepositorySource(
@ -84,18 +107,18 @@ class RepositoryListFragment(
class RepositoryViewModel( class RepositoryViewModel(
private val service: RepositoryService, private val service: RepositoryService,
private val search: SearchSettings private val search: () -> SearchSettings
) : ViewModel() { ) : ViewModel() {
val flow = Pager( val flow = Pager(
PagingConfig(pageSize = 10, enablePlaceholders = true) PagingConfig(pageSize = 10, enablePlaceholders = true)
) { ) {
RepositorySource(service, search) RepositorySource(service, search())
}.flow.cachedIn(viewModelScope) }.flow.cachedIn(viewModelScope)
} }
class RepositoryViewModelFactory( class RepositoryViewModelFactory(
private val service: RepositoryService, private val service: RepositoryService,
private val search: SearchSettings 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)) {
@ -105,4 +128,14 @@ class RepositoryListFragment(
throw IllegalArgumentException("Unknown ViewModel class") throw IllegalArgumentException("Unknown ViewModel class")
} }
} }
inner class SortListener : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
search = search.copy(sort = SortCriteria.values()[position])
}
override fun onNothingSelected(parent: AdapterView<*>?) {
search = search.copy(sort = SortCriteria.ALPHA)
}
}
} }

@ -86,28 +86,35 @@ class GiteaService(private val handle: GiteaApiService) : RepositoryService {
handle.retrieveFileContents(repository.identifier.owner, repository.identifier.name, filePath) handle.retrieveFileContents(repository.identifier.owner, repository.identifier.name, filePath)
} }
override suspend fun searchOwner(owner: String): Owner? = try { override suspend fun searchOwner(owner: String): Owner? = withContext(Dispatchers.IO) {
handle.searchOwner(owner) try {
} catch (ex: HttpException) { handle.searchOwner(owner)
if (ex.code() == HTTP_NOT_FOUND) { } catch (ex: HttpException) {
null if (ex.code() == HTTP_NOT_FOUND) {
} else { null
throw ex } else {
throw ex
}
} }
} }
override suspend fun searchRepositories(settings: SearchSettings): List<Repository> = override suspend fun searchRepositories(settings: SearchSettings): List<Repository> = withContext(Dispatchers.IO) {
handle.searchRepositories( if (settings.page < 1) {
settings.query, emptyList()
settings.userId, } else {
settings.teamId, handle.searchRepositories(
settings.starredBy, settings.query,
settings.mode?.toString()?.lowercase(), settings.userId,
settings.sort.toString().lowercase(), settings.teamId,
settings.order.toString().lowercase(), settings.starredBy,
settings.page, settings.mode?.toString()?.lowercase(),
settings.limit settings.sort.toString().lowercase(),
).data 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,9 +1,16 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:orientation="vertical">
<Spinner
android:id="@+id/sort_by_spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/repositories_view" android:id="@+id/repositories_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout> </LinearLayout>

@ -15,4 +15,12 @@
<string name="configure">Configure</string> <string name="configure">Configure</string>
<string name="activity">Activity</string> <string name="activity">Activity</string>
<string name="owner_not_found">User not found</string> <string name="owner_not_found">User not found</string>
<string name="desc_sort">Desc</string>
<string-array name="sort_criteria">
<item>alpha</item>
<item>created</item>
<item>updated</item>
<item>size</item>
<item>id</item>
</string-array>
</resources> </resources>
Loading…
Cancel
Save