From fa6a08263255eef23bf777924e1c5616f588f6e6 Mon Sep 17 00:00:00 2001 From: "S. Grimault" Date: Sat, 20 Jun 2020 15:03:33 +0200 Subject: [PATCH 1/3] feat(#50): configure area observation duration from app settings --- README.md | 48 +++++++++++-- .../geonature/occtax/settings/AppSettings.kt | 44 ++++++++---- .../io/OnAppSettingsJsonReaderListenerImpl.kt | 10 ++- .../ui/input/InputPagerFragmentActivity.kt | 2 +- .../ui/input/taxa/TaxaFilterActivity.kt | 13 +++- .../ui/input/taxa/TaxaFilterFragment.kt | 27 ++++++-- .../occtax/ui/input/taxa/TaxaFragment.kt | 16 ++++- .../fr/geonature/occtax/input/InputTest.kt | 4 +- .../occtax/input/io/InputJsonReaderTest.kt | 2 +- .../occtax/input/io/InputJsonWriterTest.kt | 2 +- .../settings/io/AppSettingsJsonReaderTest.kt | 68 ++++++++++--------- .../resources/fixtures/settings_occtax.json | 1 + 12 files changed, 170 insertions(+), 67 deletions(-) diff --git a/README.md b/README.md index 69014a5a..fa5defbe 100644 --- a/README.md +++ b/README.md @@ -7,15 +7,51 @@ GeoNature Android mobile application for Occtax module. +## Settings + +Example: + +```json +{ + "area_observation_duration": 365, + "map": { + "show_scale": true, + "show_compass": true, + "max_bounds": [ + [47.253369, -1.605721], + [47.173845, -1.482811] + ], + "center": [47.225827, -1.55447], + "start_zoom": 10.0, + "min_zoom": 8.0, + "max_zoom": 19.0, + "min_zoom_editing": 12.0, + "layers": [ + { + "label": "Nantes", + "source": "nantes.mbtiles" + } + ] + } +} +``` + +### Parameters description + +| Parameter | UI | Description | Default value | +| --------------------------- | ------- | ------------------------------------------------------------------------------ | ------------- | +| `area_observation_duration` | ☐ | Area observation duration period (in days) | 365 | +| `map` | ☐ | Maps settings (cf. https://github.com/PnX-SI/gn_mobile_maps/tree/develop/maps) | | + ## Upgrade git sub modules Do **NOT** modify directly any git sub modules (e.g. `commons`, `mountpoint`, `viewpager` and `maps`). Any changes should be made from each underlying git repository: -* `commons`: [gn_mobile_core](https://github.com/PnX-SI/gn_mobile_core) git repository -* `mountpoint`: [gn_mobile_core](https://github.com/PnX-SI/gn_mobile_core) git repository -* `viewpager`: [gn_mobile_core](https://github.com/PnX-SI/gn_mobile_core) git repository -* `maps`: [gn_mobile_maps](https://github.com/PnX-SI/gn_mobile_maps) git repository +- `commons`: [gn_mobile_core](https://github.com/PnX-SI/gn_mobile_core) git repository +- `mountpoint`: [gn_mobile_core](https://github.com/PnX-SI/gn_mobile_core) git repository +- `viewpager`: [gn_mobile_core](https://github.com/PnX-SI/gn_mobile_core) git repository +- `maps`: [gn_mobile_maps](https://github.com/PnX-SI/gn_mobile_maps) git repository ```bash ./upgrade_submodules.sh @@ -23,9 +59,9 @@ Any changes should be made from each underlying git repository: ## Troubleshooting -* Kotlin error, Redeclaration from class within imported module: +- Kotlin error, Redeclaration from class within imported module: - clean project from menu *Build -> Clean Project*, then rebuild project. + clean project from menu _Build -> Clean Project_, then rebuild project. ## Full Build diff --git a/occtax/src/main/java/fr/geonature/occtax/settings/AppSettings.kt b/occtax/src/main/java/fr/geonature/occtax/settings/AppSettings.kt index 79b04af0..e81cdbe7 100644 --- a/occtax/src/main/java/fr/geonature/occtax/settings/AppSettings.kt +++ b/occtax/src/main/java/fr/geonature/occtax/settings/AppSettings.kt @@ -10,9 +10,15 @@ import fr.geonature.maps.settings.MapSettings * * @author [S. Grimault](mailto:sebastien.grimault@gmail.com) */ -data class AppSettings(var mapSettings: MapSettings? = null) : IAppSettings { +data class AppSettings( + var areaObservationDuration: Int = DEFAULT_AREA_OBSERVATION_DURATION, + var mapSettings: MapSettings? = null +) : IAppSettings { - private constructor(source: Parcel) : this(source.readParcelable(MapSettings::class.java.classLoader) as MapSettings?) + private constructor(source: Parcel) : this( + source.readInt(), + source.readParcelable(MapSettings::class.java.classLoader) as MapSettings? + ) override fun describeContents(): Int { return 0 @@ -22,34 +28,44 @@ data class AppSettings(var mapSettings: MapSettings? = null) : IAppSettings { dest: Parcel?, flags: Int ) { - dest?.writeParcelable( + dest?.also { + it.writeInt(areaObservationDuration) + it.writeParcelable( mapSettings, 0 - ) + ) + } } override fun equals(other: Any?): Boolean { if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as AppSettings + if (other !is AppSettings) return false + if (areaObservationDuration != other.areaObservationDuration) return false if (mapSettings != other.mapSettings) return false return true } override fun hashCode(): Int { - return mapSettings.hashCode() + var result = areaObservationDuration + result = 31 * result + (mapSettings?.hashCode() ?: 0) + + return result } - companion object CREATOR : Parcelable.Creator { - override fun createFromParcel(parcel: Parcel): AppSettings { - return AppSettings(parcel) - } + companion object { + const val DEFAULT_AREA_OBSERVATION_DURATION = 365 + + @JvmField + val CREATOR: Parcelable.Creator = object : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): AppSettings { + return AppSettings(parcel) + } - override fun newArray(size: Int): Array { - return arrayOfNulls(size) + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } } } } diff --git a/occtax/src/main/java/fr/geonature/occtax/settings/io/OnAppSettingsJsonReaderListenerImpl.kt b/occtax/src/main/java/fr/geonature/occtax/settings/io/OnAppSettingsJsonReaderListenerImpl.kt index 57c62de9..ce41535e 100644 --- a/occtax/src/main/java/fr/geonature/occtax/settings/io/OnAppSettingsJsonReaderListenerImpl.kt +++ b/occtax/src/main/java/fr/geonature/occtax/settings/io/OnAppSettingsJsonReaderListenerImpl.kt @@ -11,7 +11,8 @@ import fr.geonature.occtax.settings.AppSettings * * @author [S. Grimault](mailto:sebastien.grimault@gmail.com) */ -class OnAppSettingsJsonReaderListenerImpl : AppSettingsJsonReader.OnAppSettingsJsonReaderListener { +class OnAppSettingsJsonReaderListenerImpl : + AppSettingsJsonReader.OnAppSettingsJsonReaderListener { override fun createAppSettings(): AppSettings { return AppSettings() @@ -23,10 +24,13 @@ class OnAppSettingsJsonReaderListenerImpl : AppSettingsJsonReader.OnAppSettingsJ appSettings: AppSettings ) { when (keyName) { + "area_observation_duration" -> appSettings.areaObservationDuration = reader.nextInt() "map" -> { if (reader.peek() == JsonToken.BEGIN_OBJECT) { - readMapSettings(reader, - appSettings) + readMapSettings( + reader, + appSettings + ) } else { reader.skipValue() } diff --git a/occtax/src/main/java/fr/geonature/occtax/ui/input/InputPagerFragmentActivity.kt b/occtax/src/main/java/fr/geonature/occtax/ui/input/InputPagerFragmentActivity.kt index dc5b922f..7833b1ab 100644 --- a/occtax/src/main/java/fr/geonature/occtax/ui/input/InputPagerFragmentActivity.kt +++ b/occtax/src/main/java/fr/geonature/occtax/ui/input/InputPagerFragmentActivity.kt @@ -82,7 +82,7 @@ class InputPagerFragmentActivity : AbstractNavigationHistoryPagerFragmentActivit ) put( R.string.pager_fragment_taxa_title, - TaxaFragment.newInstance() + TaxaFragment.newInstance(appSettings.areaObservationDuration) ) put( R.string.pager_fragment_information_title, diff --git a/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/TaxaFilterActivity.kt b/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/TaxaFilterActivity.kt index dae47fae..0fd21bd0 100644 --- a/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/TaxaFilterActivity.kt +++ b/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/TaxaFilterActivity.kt @@ -6,6 +6,7 @@ import android.content.Intent import android.os.Bundle import android.view.MenuItem import androidx.appcompat.app.AppCompatActivity +import fr.geonature.occtax.settings.AppSettings /** * Apply filters on taxa list. @@ -37,7 +38,11 @@ class TaxaFilterActivity : AppCompatActivity(), TaxaFilterFragment.OnTaxaFilterF EXTRA_WITH_AREA_OBSERVATION, false ), - *selectedFilters.toTypedArray() + intent.getIntExtra( + EXTRA_AREA_OBSERVATION_DURATION, + AppSettings.DEFAULT_AREA_OBSERVATION_DURATION + ), + * selectedFilters.toTypedArray() ) ) .commit() @@ -83,10 +88,12 @@ class TaxaFilterActivity : AppCompatActivity(), TaxaFilterFragment.OnTaxaFilterF const val EXTRA_SELECTED_FILTERS = "extra_selected_filters" const val EXTRA_WITH_AREA_OBSERVATION = "extra_with_area_observation" + const val EXTRA_AREA_OBSERVATION_DURATION = "extra_area_observation_duration" fun newIntent( context: Context, withAreaObservation: Boolean = false, + areaObservationDuration: Int = AppSettings.DEFAULT_AREA_OBSERVATION_DURATION, vararg filter: Filter<*> ): Intent { return Intent( @@ -97,6 +104,10 @@ class TaxaFilterActivity : AppCompatActivity(), TaxaFilterFragment.OnTaxaFilterF EXTRA_WITH_AREA_OBSERVATION, withAreaObservation ) + putExtra( + EXTRA_AREA_OBSERVATION_DURATION, + areaObservationDuration + ) putExtra( EXTRA_SELECTED_FILTERS, filter diff --git a/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/TaxaFilterFragment.kt b/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/TaxaFilterFragment.kt index 208dc8d8..2b019213 100644 --- a/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/TaxaFilterFragment.kt +++ b/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/TaxaFilterFragment.kt @@ -18,6 +18,7 @@ import androidx.recyclerview.widget.RecyclerView import fr.geonature.commons.data.Taxonomy import fr.geonature.commons.data.helper.Provider import fr.geonature.occtax.R +import fr.geonature.occtax.settings.AppSettings /** * [Fragment] to let the user to apply filters on taxa list. @@ -137,8 +138,17 @@ class TaxaFilterFragment : Fragment() { ) { progressBar?.visibility = View.VISIBLE - if (arguments?.getBoolean(ARG_WITH_AREA_OBSERVATION, false) == true) { - loadFilterAreaObservation() + if (arguments?.getBoolean( + ARG_WITH_AREA_OBSERVATION, + false + ) == true + ) { + loadFilterAreaObservation( + arguments?.getInt( + ARG_AREA_OBSERVATION_DURATION, + AppSettings.DEFAULT_AREA_OBSERVATION_DURATION + ) ?: AppSettings.DEFAULT_AREA_OBSERVATION_DURATION + ) } LoaderManager.getInstance(this) @@ -165,7 +175,7 @@ class TaxaFilterFragment : Fragment() { listener = null } - private fun loadFilterAreaObservation(duration: Int = 365) { + private fun loadFilterAreaObservation(duration: Int) { val context = context ?: return val formatDuration: (Int) -> String = { @@ -247,6 +257,7 @@ class TaxaFilterFragment : Fragment() { private val TAG = TaxaFilterFragment::class.java.name private const val ARG_WITH_AREA_OBSERVATION = "arg_with_area_observation" + private const val ARG_AREA_OBSERVATION_DURATION = "arg_area_observation_duration" private const val ARG_FILTERS = "arg_filters" private const val LOADER_TAXONOMY = 1 @@ -256,13 +267,21 @@ class TaxaFilterFragment : Fragment() { * @return A new instance of [TaxaFilterFragment] */ @JvmStatic - fun newInstance(withAreaObservation: Boolean = false, vararg filter: Filter<*>) = + fun newInstance( + withAreaObservation: Boolean = false, + areaObservationDuration: Int = AppSettings.DEFAULT_AREA_OBSERVATION_DURATION, + vararg filter: Filter<*> + ) = TaxaFilterFragment().apply { arguments = Bundle().apply { putBoolean( ARG_WITH_AREA_OBSERVATION, withAreaObservation ) + putInt( + ARG_AREA_OBSERVATION_DURATION, + areaObservationDuration + ) putParcelableArray( ARG_FILTERS, filter 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 6e76bdbc..9147f60e 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 @@ -34,6 +34,7 @@ import fr.geonature.commons.util.ThemeUtils import fr.geonature.occtax.R import fr.geonature.occtax.input.Input import fr.geonature.occtax.input.InputTaxon +import fr.geonature.occtax.settings.AppSettings import fr.geonature.occtax.ui.input.IInputFragment import fr.geonature.viewpager.ui.AbstractPagerFragmentActivity import fr.geonature.viewpager.ui.IValidateFragment @@ -350,6 +351,10 @@ class TaxaFragment : Fragment(), TaxaFilterActivity.newIntent( context, !savedState.getString(KEY_SELECTED_FEATURE_ID).isNullOrEmpty(), + arguments?.getInt( + ARG_AREA_OBSERVATION_DURATION, + AppSettings.DEFAULT_AREA_OBSERVATION_DURATION + ) ?: AppSettings.DEFAULT_AREA_OBSERVATION_DURATION, *getSelectedFilters().toTypedArray() ), RESULT_FILTER @@ -600,6 +605,7 @@ class TaxaFragment : Fragment(), private val TAG = TaxaFragment::class.java.name + private const val ARG_AREA_OBSERVATION_DURATION = "arg_area_observation_duration" private const val LOADER_TAXA = 1 private const val LOADER_TAXON = 2 private const val RESULT_FILTER = 3 @@ -614,6 +620,14 @@ class TaxaFragment : Fragment(), * @return A new instance of [TaxaFragment] */ @JvmStatic - fun newInstance() = TaxaFragment() + fun newInstance(areaObservationDuration: Int = AppSettings.DEFAULT_AREA_OBSERVATION_DURATION) = + TaxaFragment().apply { + arguments = Bundle().apply { + putInt( + ARG_AREA_OBSERVATION_DURATION, + areaObservationDuration + ) + } + } } } diff --git a/occtax/src/test/java/fr/geonature/occtax/input/InputTest.kt b/occtax/src/test/java/fr/geonature/occtax/input/InputTest.kt index 32f01079..eecc7740 100644 --- a/occtax/src/test/java/fr/geonature/occtax/input/InputTest.kt +++ b/occtax/src/test/java/fr/geonature/occtax/input/InputTest.kt @@ -3,7 +3,7 @@ package fr.geonature.occtax.input import android.os.Parcel import fr.geonature.commons.data.Taxon import fr.geonature.commons.data.Taxonomy -import fr.geonature.commons.util.IsoDateUtils +import fr.geonature.commons.util.toDate import java.util.Date import org.junit.Assert.assertEquals import org.junit.Test @@ -34,7 +34,7 @@ class InputTest { null, 133 ) - date = IsoDateUtils.toDate("2016-10-28") ?: Date() + date = toDate("2016-10-28") ?: Date() setPrimaryInputObserverId(1L) addInputObserverId(5L) addInputObserverId(2L) diff --git a/occtax/src/test/java/fr/geonature/occtax/input/io/InputJsonReaderTest.kt b/occtax/src/test/java/fr/geonature/occtax/input/io/InputJsonReaderTest.kt index 351dc0f7..81a5565e 100644 --- a/occtax/src/test/java/fr/geonature/occtax/input/io/InputJsonReaderTest.kt +++ b/occtax/src/test/java/fr/geonature/occtax/input/io/InputJsonReaderTest.kt @@ -4,7 +4,7 @@ import fr.geonature.commons.data.Taxon import fr.geonature.commons.data.Taxonomy import fr.geonature.commons.input.AbstractInputTaxon import fr.geonature.commons.input.io.InputJsonReader -import fr.geonature.commons.util.IsoDateUtils.toDate +import fr.geonature.commons.util.toDate import fr.geonature.occtax.FixtureHelper.getFixture import fr.geonature.occtax.input.CountingMetadata import fr.geonature.occtax.input.Input diff --git a/occtax/src/test/java/fr/geonature/occtax/input/io/InputJsonWriterTest.kt b/occtax/src/test/java/fr/geonature/occtax/input/io/InputJsonWriterTest.kt index 9b685e9f..5edffc1f 100644 --- a/occtax/src/test/java/fr/geonature/occtax/input/io/InputJsonWriterTest.kt +++ b/occtax/src/test/java/fr/geonature/occtax/input/io/InputJsonWriterTest.kt @@ -3,7 +3,7 @@ package fr.geonature.occtax.input.io import fr.geonature.commons.data.Taxon import fr.geonature.commons.data.Taxonomy import fr.geonature.commons.input.io.InputJsonWriter -import fr.geonature.commons.util.IsoDateUtils.toDate +import fr.geonature.commons.util.toDate import fr.geonature.occtax.FixtureHelper.getFixture import fr.geonature.occtax.input.CountingMetadata import fr.geonature.occtax.input.Input diff --git a/occtax/src/test/java/fr/geonature/occtax/settings/io/AppSettingsJsonReaderTest.kt b/occtax/src/test/java/fr/geonature/occtax/settings/io/AppSettingsJsonReaderTest.kt index a064b0e8..c13106ce 100644 --- a/occtax/src/test/java/fr/geonature/occtax/settings/io/AppSettingsJsonReaderTest.kt +++ b/occtax/src/test/java/fr/geonature/occtax/settings/io/AppSettingsJsonReaderTest.kt @@ -40,39 +40,41 @@ class AppSettingsJsonReaderTest { // then assertNotNull(appSettings) assertEquals( - AppSettings( - MapSettings( - arrayListOf( - LayerSettings( - "Nantes", - "nantes.mbtiles" - ) - ), - null, - showScale = true, - showCompass = true, - zoom = 10.0, - minZoomLevel = 8.0, - maxZoomLevel = 19.0, - minZoomEditing = 12.0, - maxBounds = BoundingBox.fromGeoPoints( - arrayListOf( - GeoPoint( - 47.253369, - -1.605721 - ), - GeoPoint( - 47.173845, - -1.482811 - ) - ) - ), - center = GeoPoint( - 47.225827, - -1.554470 - ) - )), - appSettings + AppSettings( + 365, + MapSettings( + arrayListOf( + LayerSettings( + "Nantes", + "nantes.mbtiles" + ) + ), + null, + showScale = true, + showCompass = true, + zoom = 10.0, + minZoomLevel = 8.0, + maxZoomLevel = 19.0, + minZoomEditing = 12.0, + maxBounds = BoundingBox.fromGeoPoints( + arrayListOf( + GeoPoint( + 47.253369, + -1.605721 + ), + GeoPoint( + 47.173845, + -1.482811 + ) + ) + ), + center = GeoPoint( + 47.225827, + -1.554470 + ) + ) + ), + appSettings ) } diff --git a/occtax/src/test/resources/fixtures/settings_occtax.json b/occtax/src/test/resources/fixtures/settings_occtax.json index c9c4e8e5..88983e57 100644 --- a/occtax/src/test/resources/fixtures/settings_occtax.json +++ b/occtax/src/test/resources/fixtures/settings_occtax.json @@ -1,4 +1,5 @@ { + "area_observation_duration": 365, "map": { "show_scale": true, "show_compass": true, From 9a93de4d41ab8fcb3b73c24404dc4ff3b2f78a9e Mon Sep 17 00:00:00 2001 From: "S. Grimault" Date: Sun, 21 Jun 2020 17:03:20 +0200 Subject: [PATCH 2/3] fix(#50): format duration as years/months or days as fallback --- .../fr/geonature/occtax/ui/input/taxa/TaxaFilterFragment.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/TaxaFilterFragment.kt b/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/TaxaFilterFragment.kt index 2b019213..74b4adc7 100644 --- a/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/TaxaFilterFragment.kt +++ b/occtax/src/main/java/fr/geonature/occtax/ui/input/taxa/TaxaFilterFragment.kt @@ -180,12 +180,12 @@ class TaxaFilterFragment : Fragment() { val formatDuration: (Int) -> String = { when { - (it >= 365) -> context.resources.getQuantityString( + (it % 365 == 0) -> context.resources.getQuantityString( R.plurals.duration_year, (it / 365), (it / 365) ) - (it >= 30) -> context.resources.getQuantityString( + (it % 30 == 0) -> context.resources.getQuantityString( R.plurals.duration_month, (it / 30), (it / 30) From ee84e5a0566f0c584139895a6ed457333a9d2eb7 Mon Sep 17 00:00:00 2001 From: "S. Grimault" Date: Sun, 21 Jun 2020 17:11:42 +0200 Subject: [PATCH 3/3] chore: 0.3.4 release --- occtax/build.gradle | 2 +- occtax/version.properties | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/occtax/build.gradle b/occtax/build.gradle index e6acaca5..42b0e304 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.3" +version = "0.3.4" android { compileSdkVersion 29 diff --git a/occtax/version.properties b/occtax/version.properties index a1b7da20..8c6d67fe 100644 --- a/occtax/version.properties +++ b/occtax/version.properties @@ -1,2 +1,2 @@ -#Sun Jun 14 15:20:51 CEST 2020 -VERSION_CODE=1880 +#Sun Jun 21 17:06:07 CEST 2020 +VERSION_CODE=1890