Skip to content

Commit

Permalink
Issue #95: filter results in CatalogExamScheduleFragment.kt
Browse files Browse the repository at this point in the history
  • Loading branch information
Jtoliveira committed May 18, 2021
1 parent 55758ab commit 6c3f3d6
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import android.content.Context
import android.content.pm.ActivityInfo
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.view.View
Expand Down Expand Up @@ -107,18 +108,30 @@ class CatalogMainActivity : ExceptionHandlingActivity() {
return true
}

/**
* Instantiates the menu XML file @menu/top_bar_menu.xml into a Menu object.
* Configures the search view by enabling assisted search and adding a search
* submit button
*
* This method is called by the framework after OnCreate but before it finishes
*/
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.catalog_top_bar, menu)

val noConnectivity = menu.findItem(R.id.no_connection_action)

this.searchViewItem = menu.findItem(R.id.catalog_action_search)

val searchView = searchViewItem?.actionView as? SearchView

searchView?.apply {
isSubmitButtonEnabled = true

setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
return true
}

override fun onQueryTextChange(newText: String?): Boolean {
sharedViewModel.setSearchText(newText ?: "")
return true
}
})
}

noConnectivity.setOnMenuItemClickListener {
AlertDialog.Builder(this).setMessage(R.string.catalog_info_warning)
.setPositiveButton("Ok", null).show()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package org.ionproject.android.offline

import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModel
import org.ionproject.android.offline.models.CatalogCalendar
import org.ionproject.android.offline.models.CatalogProgramme
Expand All @@ -8,6 +11,27 @@ import org.ionproject.android.offline.models.Timetable

class CatalogSharedViewModel : ViewModel() {

/**
* Search text used to pass data from search bar to Exam Fragment
*/
private val searchTextLiveData = MutableLiveData<String>()

/**
* Updates SearchTextLiveData
*/
fun setSearchText(query: String) {
searchTextLiveData.postValue(query)
}

/**
* Observes the live data and calls onUpdate when a change occurs
*/
fun observeSearchText(lifecycleOwner: LifecycleOwner, onUpdate: (String) -> Unit) {
searchTextLiveData.observe(lifecycleOwner, Observer {
onUpdate(it)
})
}

/**
* The programme that the user chose from the list in the ProgrammesFragment (curso)
*/
Expand All @@ -19,10 +43,4 @@ class CatalogSharedViewModel : ViewModel() {
var selectedCatalogProgrammeTerm: String = ""

var selectedYear: String = ""

var parsedExamSchedule: ExamSchedule? = null

var parsedTimeTable: Timetable? = null

var parsedCalendar: CatalogCalendar? = null
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package org.ionproject.android.offline.catalogExamSchedule

import android.os.Bundle
import android.util.Log
import android.view.*
import androidx.appcompat.widget.SearchView
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.DividerItemDecoration
Expand All @@ -19,17 +19,23 @@ import org.ionproject.android.ExceptionHandlingFragment
import org.ionproject.android.R
import org.ionproject.android.common.startLoading
import org.ionproject.android.common.stopLoading
import org.ionproject.android.offline.CatalogMainActivity
import org.ionproject.android.offline.CatalogSharedViewModel
import org.ionproject.android.offline.CatalogSharedViewModelProvider
import org.ionproject.android.offline.catalogProgrammeDetails.CatalogProgrammeDetailsViewModel
import org.ionproject.android.offline.catalogProgrammeDetails.CatalogProgrammeDetailsViewModelProvider
import org.ionproject.android.offline.catalogProgrammes.CatalogProgrammesListAdapter
import org.ionproject.android.offline.catalogProgrammes.CatalogProgrammesViewModel
import org.ionproject.android.offline.catalogProgrammes.CatalogProgrammesViewModelProvider
import org.ionproject.android.offline.models.ExamDetails
import java.util.*

class CatalogExamScheduleFragment : ExceptionHandlingFragment() {

private val examsList = mutableListOf<ExamDetails>()

var adapter = CatalogExamsListAdapter(examsList)

/**
* This view model is shared between fragments and the MainActivity
*/
Expand All @@ -55,6 +61,16 @@ class CatalogExamScheduleFragment : ExceptionHandlingFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

/**
* Observes the live data in the shared view model;
*
* When the live data has a value, it means a query was input in the
* search action and we have to filter the exams
*/
sharedViewModel.observeSearchText(viewLifecycleOwner) {
adapter.filter.filter(it)
}

// Hide view, show progress bar
val viewGroup = catalog_exam_schedule_recyclerView.parent as ViewGroup
viewGroup.startLoading()
Expand All @@ -70,7 +86,9 @@ class CatalogExamScheduleFragment : ExceptionHandlingFragment() {
if (programme != null) {
examViewModel.getCatalogExamSchedule(programme, term){

val adapter = CatalogExamsListAdapter(it.exams)
examsList.addAll(it.exams)

adapter = CatalogExamsListAdapter(examsList)

catalog_exam_schedule_recyclerView.adapter = adapter
catalog_exam_schedule_recyclerView.layoutManager = LinearLayoutManager(context)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,71 @@
package org.ionproject.android.offline.catalogExamSchedule

import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Filter
import android.widget.Filterable
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.catalog_exam_schedule_item.view.*
import kotlinx.android.synthetic.main.list_item_exams.view.*
import org.ionproject.android.R
import org.ionproject.android.offline.models.ExamDetails
import java.util.*
import kotlin.collections.ArrayList

class CatalogExamsListAdapter(
private val exams: List<ExamDetails>
) : RecyclerView.Adapter<CatalogExamsListAdapter.CatalogExamViewHolder>() {
examsParameter: MutableList<ExamDetails>
) : RecyclerView.Adapter<CatalogExamsListAdapter.CatalogExamViewHolder>(), Filterable{

private val examsInside = examsParameter
private val examsFull = ArrayList(examsParameter)

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CatalogExamViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.catalog_exam_schedule_item, parent, false)

return CatalogExamViewHolder(view)
}

override fun getItemCount(): Int = exams.size
override fun getItemCount(): Int = examsInside.size

override fun onBindViewHolder(holder: CatalogExamViewHolder, position: Int) {
holder.bindTo(exams[position])
holder.bindTo(examsInside[position])
}

override fun getFilter(): Filter {
return examFilter
}

private val examFilter: Filter = object : Filter() {

override fun performFiltering(constraint: CharSequence): FilterResults {

Log.d("Catalog", "filtering with query [$constraint] and examinside size :${examsInside.size} exam full size: ${examsFull.size}")

val filteredList: MutableList<ExamDetails> = mutableListOf()

if (constraint.isEmpty()) {
filteredList.addAll(examsFull)
} else {
val filterPattern = constraint.toString().toLowerCase(Locale.ROOT).trim { it <= ' ' }
for (item in examsFull) {
if (item.name.toLowerCase(Locale.ROOT).contains(filterPattern)) {
filteredList.add(item)
}
}
}
val results = FilterResults()
results.values = filteredList
return results
}

override fun publishResults(constraint: CharSequence, results: FilterResults) {
examsInside.clear()
examsInside.addAll(results.values as MutableList<ExamDetails>)
notifyDataSetChanged()
}
}

class CatalogExamViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
Expand Down
7 changes: 7 additions & 0 deletions Project/app/src/main/res/menu/catalog_top_bar.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">

<item
android:id="@+id/catalog_action_search"
android:icon="@drawable/ic_search_white_24dp"
android:title="@string/title_search"
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="ifRoom|collapseActionView" />

<item
android:id="@+id/no_connection_action"
android:icon="@drawable/ic_no_connectivity_white_s4dp"
Expand Down

0 comments on commit 6c3f3d6

Please sign in to comment.