diff --git a/gn_mobile_core b/gn_mobile_core index f6d57616..3b91fd02 160000 --- a/gn_mobile_core +++ b/gn_mobile_core @@ -1 +1 @@ -Subproject commit f6d576163c6e779182b7f3d831e04c67f245580d +Subproject commit 3b91fd02c0959eb332a1a3267964c027a024b340 diff --git a/occtax/build.gradle b/occtax/build.gradle index 42b0e304..b8116e40 100644 --- a/occtax/build.gradle +++ b/occtax/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' -version = "0.3.4" +version = "0.3.5" android { compileSdkVersion 29 diff --git a/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/Filter.kt b/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/Filter.kt index 63479380..fe5c1cdf 100644 --- a/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/Filter.kt +++ b/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/Filter.kt @@ -58,6 +58,7 @@ open class Filter( * @author [S. Grimault](mailto:sebastien.grimault@gmail.com) */ enum class FilterType { + NAME, AREA_OBSERVATION, TAXONOMY } diff --git a/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/FilterName.kt b/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/FilterName.kt new file mode 100644 index 00000000..f3c6de0a --- /dev/null +++ b/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/FilterName.kt @@ -0,0 +1,52 @@ +package fr.geonature.occtax.ui.input.taxa + +import android.os.Parcel +import android.os.Parcelable + +/** + * Name filter. + * + * @author [S. Grimault](mailto:sebastien.grimault@gmail.com) + */ +class FilterName(value: Name) : Filter( + FilterType.NAME, + value +) { + class Name(val type: NameType) : + Parcelable { + + private constructor(source: Parcel) : this( + NameType.valueOf(source.readString() ?: NameType.SCIENTIFIC.name) + ) + + override fun describeContents(): Int { + return 0 + } + + override fun writeToParcel(dest: Parcel?, flags: Int) { + dest?.also { + it.writeString(type.name) + } + } + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): Name { + return Name(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } + } + + /** + * Taxon name types. + * + * @author [S. Grimault](mailto:sebastien.grimault@gmail.com) + */ + enum class NameType { + SCIENTIFIC, + COMMON + } +} \ No newline at end of file diff --git a/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/FilterNameRecyclerViewAdapter.kt b/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/FilterNameRecyclerViewAdapter.kt new file mode 100644 index 00000000..d0a1e837 --- /dev/null +++ b/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/FilterNameRecyclerViewAdapter.kt @@ -0,0 +1,65 @@ +package fr.geonature.occtax.ui.input.taxa + +import android.view.View +import android.widget.Switch +import fr.geonature.commons.ui.adapter.AbstractListItemRecyclerViewAdapter +import fr.geonature.occtax.R + +/** + * Default RecyclerView Adapter for [FilterName]. + * + * @author [S. Grimault](mailto:sebastien.grimault@gmail.com) + */ +class FilterNameRecyclerViewAdapter(val listener: FilterRecyclerViewAdapterListener) : + AbstractListItemRecyclerViewAdapter() { + + init { + setItems(listOf(FilterName(FilterName.Name(FilterName.NameType.SCIENTIFIC)))) + } + + override fun getViewHolder(view: View, viewType: Int): AbstractViewHolder { + return ViewHolder(view) + } + + override fun getLayoutResourceId(position: Int, item: FilterName): Int { + return R.layout.list_item_filter_name + } + + override fun areItemsTheSame( + oldItems: List, + newItems: List, + oldItemPosition: Int, + newItemPosition: Int + ): Boolean { + return oldItems[oldItemPosition] == newItems[newItemPosition] + } + + override fun areContentsTheSame( + oldItems: List, + newItems: List, + oldItemPosition: Int, + newItemPosition: Int + ): Boolean { + return oldItems[oldItemPosition] == newItems[newItemPosition] + } + + fun setSelectedFilter(filter: FilterName) { + this.setItems(listOf(filter)) + + notifyDataSetChanged() + } + + inner class ViewHolder(itemView: View) : + AbstractListItemRecyclerViewAdapter.AbstractViewHolder(itemView) { + + private val switch: Switch = itemView.findViewById(R.id.switch_name) + + override fun onBind(item: FilterName) { + switch.setOnClickListener { + listener.onSelectedFilters(if (switch.isChecked) FilterName(FilterName.Name(FilterName.NameType.COMMON)) else FilterName(FilterName.Name(FilterName.NameType.SCIENTIFIC))) + } + + switch.isChecked = item.value.type == FilterName.NameType.COMMON + } + } +} \ No newline at end of file diff --git a/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/FilterRecyclerViewAdapter.kt b/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/FilterRecyclerViewAdapter.kt index c06f522c..72a43742 100644 --- a/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/FilterRecyclerViewAdapter.kt +++ b/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/FilterRecyclerViewAdapter.kt @@ -13,10 +13,12 @@ import fr.geonature.commons.ui.adapter.StickyHeaderItemDecorator import fr.geonature.occtax.R /** - * Default RecyclerView Adapter used by [TaxaFilterFragment], combining [FilterAreaObservationRecyclerViewAdapter] and [FilterTaxonomyRecyclerViewAdapter] + * Default RecyclerView Adapter used by [TaxaFilterFragment], combining [FilterNameRecyclerViewAdapter], + * [FilterAreaObservationRecyclerViewAdapter] and [FilterTaxonomyRecyclerViewAdapter]. * * @author [S. Grimault](mailto:sebastien.grimault@gmail.com) * + * @see FilterNameRecyclerViewAdapter * @see FilterAreaObservationRecyclerViewAdapter * @see FilterTaxonomyRecyclerViewAdapter */ @@ -24,6 +26,16 @@ class FilterRecyclerViewAdapter(val listener: FilterRecyclerViewAdapterListener< RecyclerView.Adapter(), IStickyRecyclerViewAdapter { + private val filterNameRecyclerViewAdapter: FilterNameRecyclerViewAdapter = + FilterNameRecyclerViewAdapter(object : FilterRecyclerViewAdapterListener { + override fun onSelectedFilters(vararg filter: FilterName) { + val existingFilters = + selectedFilters.filter { it.type != Filter.FilterType.NAME } + selectedFilters.clear() + selectedFilters.addAll(existingFilters + filter) + listener.onSelectedFilters(*selectedFilters.toTypedArray()) + } + }) private val filterTitleAreaObservationRecyclerViewAdapter = FilterTitleRecyclerViewAdapter() private val filterAreaObservationRecyclerViewAdapter: FilterAreaObservationRecyclerViewAdapter = FilterAreaObservationRecyclerViewAdapter(object : @@ -49,6 +61,7 @@ class FilterRecyclerViewAdapter(val listener: FilterRecyclerViewAdapterListener< } }) private val mergeAdapter = MergeAdapter( + filterNameRecyclerViewAdapter, filterTitleAreaObservationRecyclerViewAdapter, filterAreaObservationRecyclerViewAdapter, filterTitleTaxonomyRecyclerViewAdapter, @@ -167,28 +180,30 @@ class FilterRecyclerViewAdapter(val listener: FilterRecyclerViewAdapterListener< } override fun getHeaderPositionForItem(itemPosition: Int): Int { - if (itemPosition == 0) { - return 0 + // the first adapter has no header + if (itemPosition < filterNameRecyclerViewAdapter.itemCount) { + + return -1 } - // if first adapter have some items - if (filterAreaObservationRecyclerViewAdapter.itemCount > 0 && itemPosition < (filterAreaObservationRecyclerViewAdapter.itemCount + filterTitleAreaObservationRecyclerViewAdapter.itemCount)) { - return 0 + // if filter area observation have some items + if (filterAreaObservationRecyclerViewAdapter.itemCount > 0 && itemPosition < (filterNameRecyclerViewAdapter.itemCount + filterAreaObservationRecyclerViewAdapter.itemCount + filterTitleAreaObservationRecyclerViewAdapter.itemCount)) { + return filterNameRecyclerViewAdapter.itemCount } - if (itemPosition == filterAreaObservationRecyclerViewAdapter.itemCount + filterTitleAreaObservationRecyclerViewAdapter.itemCount + filterTitleTaxonomyRecyclerViewAdapter.itemCount - 1) { + if (itemPosition == filterNameRecyclerViewAdapter.itemCount + filterAreaObservationRecyclerViewAdapter.itemCount + filterTitleAreaObservationRecyclerViewAdapter.itemCount + filterTitleTaxonomyRecyclerViewAdapter.itemCount - 1) { return itemPosition } val currentFilterTaxonomy = - filterTaxonomyRecyclerViewAdapter.items.getOrNull(itemPosition - (filterAreaObservationRecyclerViewAdapter.itemCount + filterTitleAreaObservationRecyclerViewAdapter.itemCount + filterTitleTaxonomyRecyclerViewAdapter.itemCount)) - ?: return filterAreaObservationRecyclerViewAdapter.itemCount + filterTitleAreaObservationRecyclerViewAdapter.itemCount + filterTitleTaxonomyRecyclerViewAdapter.itemCount + filterTaxonomyRecyclerViewAdapter.items.getOrNull(itemPosition - (filterNameRecyclerViewAdapter.itemCount + filterAreaObservationRecyclerViewAdapter.itemCount + filterTitleAreaObservationRecyclerViewAdapter.itemCount + filterTitleTaxonomyRecyclerViewAdapter.itemCount)) + ?: return filterNameRecyclerViewAdapter.itemCount + filterAreaObservationRecyclerViewAdapter.itemCount + filterTitleAreaObservationRecyclerViewAdapter.itemCount + filterTitleTaxonomyRecyclerViewAdapter.itemCount return filterTaxonomyRecyclerViewAdapter.items.indexOfFirst { it.value.kingdom == currentFilterTaxonomy.value.kingdom && it.value.group == Taxonomy.ANY }.takeIf { it >= 0 } - ?.plus(filterAreaObservationRecyclerViewAdapter.itemCount + filterTitleAreaObservationRecyclerViewAdapter.itemCount + filterTitleTaxonomyRecyclerViewAdapter.itemCount) - ?: filterAreaObservationRecyclerViewAdapter.itemCount + filterTitleAreaObservationRecyclerViewAdapter.itemCount + filterTitleTaxonomyRecyclerViewAdapter.itemCount - 1 + ?.plus(filterNameRecyclerViewAdapter.itemCount + filterAreaObservationRecyclerViewAdapter.itemCount + filterTitleAreaObservationRecyclerViewAdapter.itemCount + filterTitleTaxonomyRecyclerViewAdapter.itemCount) + ?: filterNameRecyclerViewAdapter.itemCount + filterAreaObservationRecyclerViewAdapter.itemCount + filterTitleAreaObservationRecyclerViewAdapter.itemCount + filterTitleTaxonomyRecyclerViewAdapter.itemCount - 1 } override fun onBindHeaderViewHolder(holder: HeaderViewHolder, headerPosition: Int) { @@ -216,6 +231,10 @@ class FilterRecyclerViewAdapter(val listener: FilterRecyclerViewAdapterListener< this.selectedFilters.clear() this.selectedFilters.addAll(filter) + (filter.find { it.type == Filter.FilterType.NAME } as FilterName?)?.also { + this.filterNameRecyclerViewAdapter.setSelectedFilter(it) + } + this.filterAreaObservationRecyclerViewAdapter.setSelectedFilters(*filter.filter { it.type == Filter.FilterType.AREA_OBSERVATION } .map { FilterAreaObservation(it.value as FilterAreaObservation.AreaObservation) } .toTypedArray()) @@ -247,24 +266,18 @@ class FilterRecyclerViewAdapter(val listener: FilterRecyclerViewAdapterListener< Typeface.BOLD ) - if (position == 0) { - label.text = filterTitleAreaObservationRecyclerViewAdapter.items.getOrNull(0) - ?: filterTitleTaxonomyRecyclerViewAdapter.items.getOrNull(0) - return - } - - if (filterAreaObservationRecyclerViewAdapter.itemCount > 0 && position < (filterAreaObservationRecyclerViewAdapter.itemCount + filterTitleAreaObservationRecyclerViewAdapter.itemCount)) { + if (filterAreaObservationRecyclerViewAdapter.itemCount > 0 && position < (filterNameRecyclerViewAdapter.itemCount + filterAreaObservationRecyclerViewAdapter.itemCount + filterTitleAreaObservationRecyclerViewAdapter.itemCount)) { label.text = filterTitleAreaObservationRecyclerViewAdapter.items.getOrNull(0) return } - if (position == filterAreaObservationRecyclerViewAdapter.itemCount + filterTitleAreaObservationRecyclerViewAdapter.itemCount + filterTitleTaxonomyRecyclerViewAdapter.itemCount - 1) { + if (position == filterNameRecyclerViewAdapter.itemCount + filterAreaObservationRecyclerViewAdapter.itemCount + filterTitleAreaObservationRecyclerViewAdapter.itemCount + filterTitleTaxonomyRecyclerViewAdapter.itemCount - 1) { label.text = filterTitleTaxonomyRecyclerViewAdapter.items.getOrNull(0) return } val taxonomyAsHeader = - filterTaxonomyRecyclerViewAdapter.items.getOrNull(position - (filterAreaObservationRecyclerViewAdapter.itemCount + filterTitleAreaObservationRecyclerViewAdapter.itemCount + filterTitleTaxonomyRecyclerViewAdapter.itemCount)) + filterTaxonomyRecyclerViewAdapter.items.getOrNull(position - (filterNameRecyclerViewAdapter.itemCount + filterAreaObservationRecyclerViewAdapter.itemCount + filterTitleAreaObservationRecyclerViewAdapter.itemCount + filterTitleTaxonomyRecyclerViewAdapter.itemCount)) if (taxonomyAsHeader == null) { label.text = filterTitleTaxonomyRecyclerViewAdapter.items.getOrNull(0) diff --git a/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/TaxaFragment.kt b/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/TaxaFragment.kt index 9147f60e..8b86b29e 100644 --- a/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/TaxaFragment.kt +++ b/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/TaxaFragment.kt @@ -13,6 +13,7 @@ import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.view.animation.AnimationUtils +import android.widget.ProgressBar import androidx.appcompat.widget.SearchView import androidx.core.view.get import androidx.fragment.app.Fragment @@ -52,6 +53,7 @@ class TaxaFragment : Fragment(), private var input: Input? = null private var adapter: TaxaRecyclerViewAdapter? = null private lateinit var savedState: Bundle + private var progressBar: ProgressBar? = null private var emptyTextView: View? = null private var filterChipGroup: ChipGroup? = null @@ -77,9 +79,11 @@ class TaxaFragment : Fragment(), "load taxa with selected feature ID: $selectedFeatureId" ) + adapter?.toggleCommonName((selectedFilters.find { it.type == Filter.FilterType.NAME }?.value as FilterName.Name?)?.type == FilterName.NameType.COMMON) + val taxonFilter = TaxonWithArea.Filter() - .byNameOrDescription(args?.getString(KEY_FILTER_BY_NAME)) + .byNameOrDescriptionOrRank(args?.getString(KEY_FILTER_BY_NAME)) .also { val filterByAreaObservation = selectedFilters.asSequence() @@ -113,7 +117,9 @@ class TaxaFragment : Fragment(), null, taxonFilter.first, taxonFilter.second.map { it.toString() }.toTypedArray(), - null + (if ((selectedFilters.find { it.type == Filter.FilterType.NAME }?.value as FilterName.Name?)?.type == FilterName.NameType.COMMON) TaxonWithArea.OrderBy() + .byCommonName() else TaxonWithArea.OrderBy() + .by(AbstractTaxon.COLUMN_NAME)).build() ) } LOADER_TAXON -> { @@ -197,6 +203,7 @@ class TaxaFragment : Fragment(), false ) val recyclerView = view.findViewById(android.R.id.list) + progressBar = view.findViewById(android.R.id.progress) emptyTextView = view.findViewById(R.id.emptyTextView) filterChipGroup = view.findViewById(R.id.chip_group_filter) @@ -227,6 +234,8 @@ class TaxaFragment : Fragment(), val emptyTextView = emptyTextView ?: return val context = context ?: return + progressBar?.visibility = View.GONE + if (emptyTextView.visibility == View.VISIBLE == show) { return } @@ -252,6 +261,7 @@ class TaxaFragment : Fragment(), }) with(recyclerView) { + setHasFixedSize(true) layoutManager = LinearLayoutManager(context) adapter = this@TaxaFragment.adapter } @@ -370,6 +380,10 @@ class TaxaFragment : Fragment(), } override fun getSubtitle(): CharSequence? { + if (progressBar?.visibility == View.VISIBLE && adapter?.itemCount == 0) { + return null + } + val taxaFound = adapter?.itemCount ?: return null return resources.getQuantityString( @@ -421,6 +435,8 @@ class TaxaFragment : Fragment(), } private fun loadTaxa() { + progressBar?.visibility = View.VISIBLE + LoaderManager.getInstance(this) .restartLoader( LOADER_TAXA, @@ -435,18 +451,68 @@ class TaxaFragment : Fragment(), filter ) + val filterName = + filter.find { it.type == Filter.FilterType.NAME }?.value as FilterName.Name? val selectedAreaObservation = filter.filter { it.type == Filter.FilterType.AREA_OBSERVATION } .map { it.value as FilterAreaObservation.AreaObservation } val selectedTaxonomy = filter.find { it.type == Filter.FilterType.TAXONOMY }?.value as Taxonomy? + filterByName(filterName) filterByAreaObservation(*selectedAreaObservation.toTypedArray()) filterByTaxonomy(selectedTaxonomy) loadTaxa() } + private fun filterByName(filterName: FilterName.Name?) { + val filterChipGroup = filterChipGroup ?: return + val context = context ?: return + + val nameChipsToDelete = arrayListOf() + + for (i in 0 until filterChipGroup.childCount) { + with(filterChipGroup[i]) { + if (this is Chip && tag is FilterName.Name) { + nameChipsToDelete.add(this) + } + } + } + + nameChipsToDelete.forEach { + filterChipGroup.removeView(it) + } + + filterChipGroup.visibility = if (filterChipGroup.childCount > 0) View.VISIBLE else View.GONE + + if (filterName != null && filterName.type == FilterName.NameType.COMMON) { + filterChipGroup.visibility = View.VISIBLE + + // build name filter chip + with( + LayoutInflater.from(context).inflate( + R.layout.chip, + filterChipGroup, + false + ) as Chip + ) { + tag = filterName + text = context.getText(R.string.taxa_filter_name_short) + setOnClickListener { + applyFilters(*getSelectedFilters().filter { it.type != Filter.FilterType.NAME } + .toTypedArray()) + } + setOnCloseIconClickListener { + applyFilters(*getSelectedFilters().filter { it.type != Filter.FilterType.NAME } + .toTypedArray()) + } + + filterChipGroup.addView(this) + } + } + } + private fun filterByAreaObservation(vararg areaObservation: FilterAreaObservation.AreaObservation) { val filterChipGroup = filterChipGroup ?: return val context = context ?: return @@ -559,11 +625,11 @@ class TaxaFragment : Fragment(), tag = Taxonomy(selectedTaxonomy.kingdom) text = selectedTaxonomy.kingdom setOnClickListener { - applyFilters(*getSelectedFilters().filter { it.type == Filter.FilterType.AREA_OBSERVATION } + applyFilters(*getSelectedFilters().filter { it.type != Filter.FilterType.TAXONOMY } .toTypedArray()) } setOnCloseIconClickListener { - applyFilters(*getSelectedFilters().filter { it.type == Filter.FilterType.AREA_OBSERVATION } + applyFilters(*getSelectedFilters().filter { it.type != Filter.FilterType.TAXONOMY } .toTypedArray()) } @@ -582,11 +648,11 @@ class TaxaFragment : Fragment(), tag = selectedTaxonomy text = selectedTaxonomy.group setOnClickListener { - applyFilters(*(getSelectedFilters().filter { filter -> filter.type == Filter.FilterType.AREA_OBSERVATION } + applyFilters(*(getSelectedFilters().filter { filter -> filter.type != Filter.FilterType.TAXONOMY } .toTypedArray() + mutableListOf(FilterTaxonomy(Taxonomy((it.tag as Taxonomy).kingdom))))) } setOnCloseIconClickListener { - applyFilters(*(getSelectedFilters().filter { filter -> filter.type == Filter.FilterType.AREA_OBSERVATION } + applyFilters(*(getSelectedFilters().filter { filter -> filter.type != Filter.FilterType.TAXONOMY } .toTypedArray() + mutableListOf(FilterTaxonomy(Taxonomy((it.tag as Taxonomy).kingdom))))) } diff --git a/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/TaxaRecyclerViewAdapter.kt b/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/TaxaRecyclerViewAdapter.kt index 77d064ac..fa58d62e 100644 --- a/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/TaxaRecyclerViewAdapter.kt +++ b/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/TaxaRecyclerViewAdapter.kt @@ -28,10 +28,12 @@ class TaxaRecyclerViewAdapter(private val listener: OnTaxaRecyclerViewAdapterLis RecyclerView.Adapter(), FastScroller.SectionIndexer { private var cursor: Cursor? = null + private var showCommonName = false private var selectedTaxon: AbstractTaxon? = null private val onClickListener: View.OnClickListener init { + setHasStableIds(true) this.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { override fun onChanged() { super.onChanged() @@ -82,6 +84,9 @@ class TaxaRecyclerViewAdapter(private val listener: OnTaxaRecyclerViewAdapterLis val checkbox: CheckBox = v.findViewById(android.R.id.checkbox) checkbox.isChecked = !checkbox.isChecked + val text2: TextView = v.findViewById(android.R.id.text2) + text2.isSelected = true + val taxon = v.tag as AbstractTaxon if (checkbox.isChecked) { @@ -117,13 +122,22 @@ class TaxaRecyclerViewAdapter(private val listener: OnTaxaRecyclerViewAdapterLis holder.bind(position) } + override fun getItemId(position: Int): Long { + val cursor = cursor ?: return super.getItemId(position) + cursor.moveToPosition(position) + + val taxon = Taxon.fromCursor(cursor) ?: return super.getItemId(position) + + return taxon.id + } + override fun getSectionText(position: Int): CharSequence { val cursor = cursor ?: return "" cursor.moveToPosition(position) + val taxon = Taxon.fromCursor(cursor) ?: return "" - val name = taxon.name - return name.elementAt(0) + return taxonName(taxon).elementAt(0) .toString() } @@ -139,6 +153,15 @@ class TaxaRecyclerViewAdapter(private val listener: OnTaxaRecyclerViewAdapterLis scrollToFirstItemSelected() } + fun toggleCommonName(toggle: Boolean = false, notify: Boolean = false) { + this.showCommonName = toggle + + if (notify) { + notifyDataSetChanged() + scrollToFirstItemSelected() + } + } + private fun getItemPosition(taxon: AbstractTaxon?): Int { var itemPosition = -1 val cursor = cursor ?: return itemPosition @@ -170,6 +193,10 @@ class TaxaRecyclerViewAdapter(private val listener: OnTaxaRecyclerViewAdapterLis } } + private fun taxonName(taxon: AbstractTaxon): String { + return if (showCommonName) taxon.commonName ?: taxon.name else taxon.name + } + inner class ViewHolder(parent: ViewGroup) : RecyclerView.ViewHolder( LayoutInflater.from(parent.context).inflate( R.layout.list_item_taxon, @@ -183,6 +210,7 @@ class TaxaRecyclerViewAdapter(private val listener: OnTaxaRecyclerViewAdapterLis private val text2: TextView = itemView.findViewById(android.R.id.text2) private val checkbox: CheckBox = itemView.findViewById(android.R.id.checkbox) private val taxonColorView: View = itemView.findViewById(R.id.taxon_color_view) + private val taxonObserversImageView: View = itemView.findViewById(R.id.taxon_observers_image_view) private val taxonObserversView: TextView = itemView.findViewById(R.id.taxon_observers_view) private val taxonLastUpdatedAtView: TextView = itemView.findViewById(R.id.taxon_last_updated_at_view) @@ -197,26 +225,28 @@ class TaxaRecyclerViewAdapter(private val listener: OnTaxaRecyclerViewAdapterLis val previousTitle = if (position > 0) { cursor.moveToPosition(position - 1) TaxonWithArea.fromCursor(cursor) - ?.name?.elementAt(0) - .toString() + ?.let { taxonName(it).elementAt(0).toString() } ?: "" } else { "" } if (taxon != null) { - val currentTitle = taxon.name.elementAt(0) + val taxonName = taxonName(taxon) + val currentTitle = taxonName.elementAt(0) .toString() title.text = if (previousTitle == currentTitle) "" else currentTitle - text1.text = taxon.name + text1.text = taxonName text2.text = HtmlCompat.fromHtml( - taxon.description ?: "", + "${if (taxon.description.isNullOrBlank()) "" else "${taxon.description ?: ""}"}${if (taxon.rank.isNullOrBlank()) "" else "${if (taxon.description.isNullOrBlank()) "" else " - [${taxon.rank}]"} "}", HtmlCompat.FROM_HTML_MODE_COMPACT ) + text2.isSelected = selectedTaxon?.id == taxon.id checkbox.isChecked = selectedTaxon?.id == taxon.id with(taxon.taxonArea) { if (this == null) { taxonColorView.setBackgroundColor(Color.TRANSPARENT) + taxonObserversImageView.visibility = View.GONE taxonObserversView.text = "" taxonLastUpdatedAtView.text = "" @@ -224,6 +254,7 @@ class TaxaRecyclerViewAdapter(private val listener: OnTaxaRecyclerViewAdapterLis } taxonColorView.setBackgroundColor(if (color.isNullOrBlank()) Color.TRANSPARENT else Color.parseColor(color)) + taxonObserversImageView.visibility = View.VISIBLE taxonObserversView.text = NumberFormat.getNumberInstance().format(numberOfObservers) taxonLastUpdatedAtView.text = diff --git a/occtax/src/main/res/drawable/ic_obs.xml b/occtax/src/main/res/drawable/ic_obs.xml new file mode 100644 index 00000000..a3e222a2 --- /dev/null +++ b/occtax/src/main/res/drawable/ic_obs.xml @@ -0,0 +1,10 @@ + + + diff --git a/occtax/src/main/res/layout/list_item_filter_name.xml b/occtax/src/main/res/layout/list_item_filter_name.xml new file mode 100644 index 00000000..9a4a9d39 --- /dev/null +++ b/occtax/src/main/res/layout/list_item_filter_name.xml @@ -0,0 +1,20 @@ + + + + + + \ No newline at end of file diff --git a/occtax/src/main/res/layout/list_item_taxon.xml b/occtax/src/main/res/layout/list_item_taxon.xml index 5d1a06a4..39de7ec7 100644 --- a/occtax/src/main/res/layout/list_item_taxon.xml +++ b/occtax/src/main/res/layout/list_item_taxon.xml @@ -43,8 +43,9 @@ android:ellipsize="end" android:maxLines="1" android:textAppearance="?attr/textAppearanceListItem" + android:textStyle="bold" app:layout_constraintBottom_toBottomOf="@android:id/text2" - app:layout_constraintEnd_toStartOf="@+id/taxon_observers_view" + app:layout_constraintEnd_toStartOf="@+id/taxon_observers_image_view" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:text="@tools:sample/last_names" /> @@ -55,19 +56,33 @@ android:layout_height="wrap_content" android:layout_marginStart="?attr/listPreferredItemHeight" android:layout_marginEnd="?attr/listPreferredItemPaddingEnd" - android:ellipsize="end" - android:maxLines="1" + android:ellipsize="marquee" + android:marqueeRepeatLimit="marquee_forever" + android:scrollHorizontally="true" + android:singleLine="true" android:textAppearance="?attr/textAppearanceListItemSecondary" app:layout_constraintEnd_toStartOf="@+id/taxon_last_updated_at_view" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@android:id/text1" tools:text="@tools:sample/first_names" /> + + %d taxon trouvé %d taxons trouvés + + Afficher le nom vernaculaire + Nom vernaculaire Selon la durée d\'observation Selon le rang taxonomique Observé depuis plus %1$s diff --git a/occtax/src/main/res/values/strings.xml b/occtax/src/main/res/values/strings.xml index d4f24cd0..e08f971d 100644 --- a/occtax/src/main/res/values/strings.xml +++ b/occtax/src/main/res/values/strings.xml @@ -86,6 +86,8 @@ %d taxa found + Show common name + Common name By area observation By taxonomy Last observed for more than %1$s diff --git a/occtax/version.properties b/occtax/version.properties index 8c6d67fe..16bbab97 100644 --- a/occtax/version.properties +++ b/occtax/version.properties @@ -1,2 +1,2 @@ -#Sun Jun 21 17:06:07 CEST 2020 -VERSION_CODE=1890 +#Sun Jul 19 16:09:07 CEST 2020 +VERSION_CODE=1940