Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add quality filter for routes #326

Merged
merged 1 commit into from
Feb 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions app/src/main/java/com/yacgroup/yacguide/RouteActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import com.yacgroup.yacguide.activity_properties.AscentFilterable
import com.yacgroup.yacguide.activity_properties.RouteSearchable
import com.yacgroup.yacguide.database.Rock
import com.yacgroup.yacguide.database.Route
import com.yacgroup.yacguide.database.comment.RouteComment
import com.yacgroup.yacguide.list_adapters.RouteViewAdapter
import com.yacgroup.yacguide.utils.IntentConstants
import com.yacgroup.yacguide.utils.ParserUtils
Expand All @@ -42,6 +43,7 @@ class RouteActivity : TableActivityWithOptionsMenu() {
private var _onlyOfficialRoutes: Boolean = false
private var _routeNamePart: String = ""
private var _filterName: String = ""
private var _filterMaxQualityId: Int = RouteComment.QUALITY_NONE
private var _filterProjects: Boolean = false
private var _filterBotches: Boolean = false
private var _rock: Rock? = null
Expand All @@ -50,6 +52,7 @@ class RouteActivity : TableActivityWithOptionsMenu() {
super.onCreate(savedInstanceState)

_filterName = intent.getStringExtra(IntentConstants.FILTER_NAME).orEmpty()
_filterMaxQualityId = intent.getIntExtra(IntentConstants.FILTER_RELEVANCE, RouteComment.QUALITY_NONE)
_filterProjects = intent.getBooleanExtra(IntentConstants.FILTER_PROJECTS, false)
_filterBotches = intent.getBooleanExtra(IntentConstants.FILTER_BOTCHES, false)

Expand All @@ -62,30 +65,35 @@ class RouteActivity : TableActivityWithOptionsMenu() {
ClimbingObjectLevel.eCountry to RouteGetter(
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm gonna move this huge map into RouteGetter in a separate PR (as well as for RockActivity) to improve readability.

getAll = { db.getRoutes() },
getByName = { db.getRoutesByName(_filterName) },
getByQuality = { db.getRoutesByQuality(_filterMaxQualityId) },
getProjects = { db.getProjectedRoutes() },
getBotches = { db.getBotchedRoutes() }
),
ClimbingObjectLevel.eRegion to RouteGetter(
getAll = { db.getRoutesForCountry(activityLevel.parentName) },
getByName = { db.getRoutesByNameForCountry(activityLevel.parentName, _filterName) },
getByQuality = { db.getRoutesByQualityForCountry(activityLevel.parentName, _filterMaxQualityId) },
getProjects = { db.getProjectedRoutesForCountry(activityLevel.parentName) },
getBotches = { db.getBotchedRoutesForCountry(activityLevel.parentName) }
),
ClimbingObjectLevel.eSector to RouteGetter(
getAll = { db.getRoutesForRegion(activityLevel.parentId) },
getByName = { db.getRoutesByNameForRegion(activityLevel.parentId, _filterName) },
getByQuality = { db.getRoutesByQualityForRegion(activityLevel.parentId, _filterMaxQualityId) },
getProjects = { db.getProjectedRoutesForRegion(activityLevel.parentId) },
getBotches = { db.getBotchedRoutesForRegion(activityLevel.parentId) }
),
ClimbingObjectLevel.eRock to RouteGetter(
getAll = { db.getRoutesForSector(activityLevel.parentId) },
getByName = { db.getRoutesByNameForSector(activityLevel.parentId, _filterName) },
getByQuality = { db.getRoutesByQualityForSector(activityLevel.parentId, _filterMaxQualityId) },
getProjects = { db.getProjectedRoutesForSector(activityLevel.parentId) },
getBotches = { db.getBotchedRoutesForSector(activityLevel.parentId) }
),
ClimbingObjectLevel.eRoute to RouteGetter(
getAll = { db.getRoutesForRock(activityLevel.parentId) },
getByName = { db.getRoutesByNameForRock(activityLevel.parentId, _filterName) },
getByQuality = { db.getRoutesByQualityForRock(activityLevel.parentId, _filterMaxQualityId) },
getProjects = { db.getProjectedRoutesForRock(activityLevel.parentId) },
getBotches = { db.getBotchedRoutesForRock(activityLevel.parentId) }
)
Expand Down Expand Up @@ -168,10 +176,18 @@ class RouteActivity : TableActivityWithOptionsMenu() {
routeGetter.getProjects()
} else if (_filterBotches) {
routeGetter.getBotches()
} else if (_filterName.isNotEmpty()) {
routeGetter.getByName()
} else {
} else if (_filterName.isEmpty() && _filterMaxQualityId == RouteComment.QUALITY_NONE) {
routeGetter.getAll()
} else {
val nameFilteredRoutes =
if (_filterName.isEmpty()) null
else routeGetter.getByName().toSet()
val qualityFilteredRoutes =
if (_filterMaxQualityId == RouteComment.QUALITY_NONE) null
else routeGetter.getByQuality().toSet()
listOfNotNull(nameFilteredRoutes, qualityFilteredRoutes).reduce {
intersection, filteredRoutes -> intersection.intersect(filteredRoutes)
}.toList()
}
}

Expand Down Expand Up @@ -215,6 +231,7 @@ class RouteActivity : TableActivityWithOptionsMenu() {
class RouteGetter(
val getAll: () -> List<Route>,
val getByName: () -> List<Route>,
val getByQuality: () -> List<Route>,
val getProjects: () -> List<Route>,
val getBotches: () -> List<Route>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,18 @@ class RockSearchable(private val _activity: TableActivityWithOptionsMenu) : Acti

searchDialog.findViewById<Button>(R.id.searchButton)?.setOnClickListener {
val rockName = searchDialog.findViewById<EditText>(R.id.dialogEditText)?.text.toString().trim { it <= ' ' }

_activity.startActivity(Intent(_activity, RockActivity::class.java).apply {
putExtra(IntentConstants.CLIMBING_OBJECT_LEVEL, _activity.activityLevel.level.value)
putExtra(IntentConstants.CLIMBING_OBJECT_PARENT_ID, _activity.activityLevel.parentId)
putExtra(IntentConstants.CLIMBING_OBJECT_PARENT_NAME, _activity.activityLevel.parentName)
putExtra(IntentConstants.FILTER_NAME, rockName)
putExtra(IntentConstants.FILTER_RELEVANCE, maxRelevanceId)
})

searchDialog.dismiss()
if (rockName.isEmpty() && maxRelevanceId == RockComment.RELEVANCE_NONE) {
Toast.makeText(searchDialog.context, R.string.no_filter_selected, Toast.LENGTH_SHORT).show()
} else {
_activity.startActivity(Intent(_activity, RockActivity::class.java).apply {
putExtra(IntentConstants.CLIMBING_OBJECT_LEVEL, _activity.activityLevel.level.value)
putExtra(IntentConstants.CLIMBING_OBJECT_PARENT_ID, _activity.activityLevel.parentId)
putExtra(IntentConstants.CLIMBING_OBJECT_PARENT_NAME, _activity.activityLevel.parentName)
putExtra(IntentConstants.FILTER_NAME, rockName)
putExtra(IntentConstants.FILTER_RELEVANCE, maxRelevanceId)
})
searchDialog.dismiss()
}
}

searchDialog.findViewById<Button>(R.id.cancelButton)?.setOnClickListener { searchDialog.dismiss() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@
package com.yacgroup.yacguide.activity_properties

import android.content.Intent
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import android.widget.*
import androidx.appcompat.app.AppCompatDialog
import com.yacgroup.yacguide.R
import com.yacgroup.yacguide.RouteActivity
import com.yacgroup.yacguide.TableActivityWithOptionsMenu
import com.yacgroup.yacguide.database.comment.RouteComment
import com.yacgroup.yacguide.utils.IntentConstants

class RouteSearchable(private val _activity: TableActivityWithOptionsMenu) : ActivityProperty {
Expand All @@ -37,18 +37,33 @@ class RouteSearchable(private val _activity: TableActivityWithOptionsMenu) : Act
searchDialog.setContentView(R.layout.route_search_dialog)
searchDialog.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);

var maxQualityId = RouteComment.QUALITY_NONE

val spinner = searchDialog.findViewById<Spinner>(R.id.routeQualitySpinner)
val adapter = ArrayAdapter<CharSequence>(searchDialog.context, R.layout.spinner_item, RouteComment.QUALITY_MAP.values.toTypedArray())
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spinner?.adapter = adapter
spinner?.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
val qualityName = parent.getItemAtPosition(position).toString()
maxQualityId = RouteComment.QUALITY_MAP.keys.first { RouteComment.QUALITY_MAP[it] == qualityName }
}
override fun onNothingSelected(parent: AdapterView<*>) {}
}
spinner?.setSelection(adapter.getPosition(RouteComment.QUALITY_MAP[maxQualityId]))

searchDialog.findViewById<Button>(R.id.searchButton)?.setOnClickListener {
val routeName = searchDialog.findViewById<EditText>(R.id.dialogEditText)?.text.toString().trim { it <= ' ' }
if (routeName.isEmpty()) {
Toast.makeText(searchDialog.context, R.string.hint_no_name, Toast.LENGTH_SHORT).show()
if (routeName.isEmpty() && maxQualityId == RouteComment.QUALITY_NONE) {
Toast.makeText(searchDialog.context, R.string.no_filter_selected, Toast.LENGTH_SHORT).show()
} else {
_activity.startActivity(Intent(_activity, RouteActivity::class.java).apply {
putExtra(IntentConstants.CLIMBING_OBJECT_LEVEL, _activity.activityLevel.level.value)
putExtra(IntentConstants.CLIMBING_OBJECT_PARENT_ID, _activity.activityLevel.parentId)
putExtra(IntentConstants.CLIMBING_OBJECT_PARENT_NAME, _activity.activityLevel.parentName)
putExtra(IntentConstants.FILTER_NAME, routeName)
putExtra(IntentConstants.FILTER_RELEVANCE, maxQualityId)
})

searchDialog.dismiss()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ class DatabaseWrapper(context: Context) {

fun getRoutesByNameForRock(rockId: Int, namePart: String) = _db.routeDao().getAllByNameAtRock(rockId, "%$namePart%")

fun getRoutesByQualityForRock(rockId: Int, maxQualityId: Int) = _db.routeDao().getAllByQualityAtRock(rockId, maxQualityId)

fun getProjectedRoutesForRock(rockId: Int) = _db.routeDao().getAllAtRockForStyle(rockId, AscendStyle.ePROJECT.id)

fun getBotchedRoutesForRock(rockId: Int) = _db.routeDao().getAllAtRockForStyle(rockId, AscendStyle.eBOTCHED.id)
Expand All @@ -101,6 +103,8 @@ class DatabaseWrapper(context: Context) {

fun getRoutesByNameForSector(sectorId: Int, namePart: String) = _db.routeDao().getAllByNameInSector(sectorId, "%$namePart%")

fun getRoutesByQualityForSector(sectorId: Int, maxQualityId: Int) = _db.routeDao().getAllByQualityInSector(sectorId, maxQualityId)

fun getProjectedRoutesForSector(sectorId: Int) = _db.routeDao().getAllInSectorForStyle(sectorId, AscendStyle.ePROJECT.id)

fun getBotchedRoutesForSector(sectorId: Int) = _db.routeDao().getAllInSectorForStyle(sectorId, AscendStyle.eBOTCHED.id)
Expand All @@ -109,6 +113,8 @@ class DatabaseWrapper(context: Context) {

fun getRoutesByNameForRegion(regionId: Int, namePart: String) = _db.routeDao().getAllByNameInRegion(regionId, "%$namePart%")

fun getRoutesByQualityForRegion(regionId: Int, maxQualityId: Int) = _db.routeDao().getAllByQualityInRegion(regionId, maxQualityId)

fun getProjectedRoutesForRegion(regionId: Int) = _db.routeDao().getAllInRegionForStyle(regionId, AscendStyle.ePROJECT.id)

fun getBotchedRoutesForRegion(regionId: Int) = _db.routeDao().getAllInRegionForStyle(regionId, AscendStyle.eBOTCHED.id)
Expand All @@ -117,6 +123,8 @@ class DatabaseWrapper(context: Context) {

fun getRoutesByNameForCountry(countryName: String, namePart: String) = _db.routeDao().getAllByNameInCountry(countryName, "%$namePart%")

fun getRoutesByQualityForCountry(countryName: String, maxQualityId: Int) = _db.routeDao().getAllByQualityInCountry(countryName, maxQualityId)

fun getProjectedRoutesForCountry(countryName: String) = _db.routeDao().getAllInCountryForStyle(countryName, AscendStyle.ePROJECT.id)

fun getBotchedRoutesForCountry(countryName: String) = _db.routeDao().getAllInCountryForStyle(countryName, AscendStyle.eBOTCHED.id)
Expand All @@ -125,6 +133,8 @@ class DatabaseWrapper(context: Context) {

fun getRoutesByName(namePart: String) = _db.routeDao().getAllByName("%$namePart%")

fun getRoutesByQuality(maxQualityId: Int) = _db.routeDao().getAllByQuality(maxQualityId)

fun getProjectedRoutes() = _db.routeDao().getAllForStyle(AscendStyle.ePROJECT.id)

fun getBotchedRoutes() = _db.routeDao().getAllForStyle(AscendStyle.eBOTCHED.id)
Expand Down
16 changes: 16 additions & 0 deletions app/src/main/java/com/yacgroup/yacguide/database/RouteDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import com.yacgroup.yacguide.database.SqlMacros.Companion.ORDERED_BY_SECTOR
import com.yacgroup.yacguide.database.SqlMacros.Companion.SELECT_ROUTES
import com.yacgroup.yacguide.database.SqlMacros.Companion.VIA_ROCKS_SECTOR
import com.yacgroup.yacguide.database.SqlMacros.Companion.VIA_ROUTES_ASCENDS
import com.yacgroup.yacguide.database.SqlMacros.Companion.VIA_ROUTES_QUALITY
import com.yacgroup.yacguide.database.SqlMacros.Companion.VIA_ROUTES_ROCK
import com.yacgroup.yacguide.database.SqlMacros.Companion.VIA_SECTORS_REGION

Expand All @@ -37,6 +38,9 @@ interface RouteDao {
@Query("$SELECT_ROUTES WHERE LOWER(Route.name) LIKE LOWER(:name)")
fun getAllByName(name: String): List<Route>

@Query("$SELECT_ROUTES $VIA_ROUTES_QUALITY WHERE QualityAvg.quality <= :maxQualityId")
fun getAllByQuality(maxQualityId: Int): List<Route>

@Query("$SELECT_ROUTES $VIA_ROUTES_ASCENDS WHERE Ascend.styleId = :styleId $ORDERED_BY_ROUTE")
fun getAllForStyle(styleId: Int): List<Route>

Expand All @@ -46,6 +50,9 @@ interface RouteDao {
@Query("$SELECT_ROUTES $VIA_ROUTES_ROCK $VIA_ROCKS_SECTOR $VIA_SECTORS_REGION WHERE Region.country = :countryName AND LOWER(Route.name) LIKE LOWER(:name) $ORDERED_BY_REGION")
fun getAllByNameInCountry(countryName: String, name: String): List<Route>

@Query("$SELECT_ROUTES $VIA_ROUTES_QUALITY $VIA_ROUTES_ROCK $VIA_ROCKS_SECTOR $VIA_SECTORS_REGION WHERE Region.country = :countryName AND QualityAvg.quality <= :maxQualityId")
fun getAllByQualityInCountry(countryName: String, maxQualityId: Int): List<Route>

@Query("$SELECT_ROUTES $VIA_ROUTES_ROCK $VIA_ROCKS_SECTOR $VIA_SECTORS_REGION $VIA_ROUTES_ASCENDS WHERE Region.country = :countryName AND Ascend.styleId = :styleId $ORDERED_BY_REGION")
fun getAllInCountryForStyle(countryName: String, styleId: Int): List<Route>

Expand All @@ -55,6 +62,9 @@ interface RouteDao {
@Query("$SELECT_ROUTES $VIA_ROUTES_ROCK $VIA_ROCKS_SECTOR WHERE Sector.parentId = :regionId AND LOWER(Route.name) LIKE LOWER(:name) $ORDERED_BY_SECTOR")
fun getAllByNameInRegion(regionId: Int, name: String): List<Route>

@Query("$SELECT_ROUTES $VIA_ROUTES_QUALITY $VIA_ROUTES_ROCK $VIA_ROCKS_SECTOR WHERE Sector.parentId = :regionId AND QualityAvg.quality <= :maxQualityId")
fun getAllByQualityInRegion(regionId: Int, maxQualityId: Int): List<Route>

@Query("$SELECT_ROUTES $VIA_ROUTES_ROCK $VIA_ROCKS_SECTOR $VIA_ROUTES_ASCENDS WHERE Sector.parentId = :regionId AND Ascend.styleId = :styleId $ORDERED_BY_SECTOR")
fun getAllInRegionForStyle(regionId: Int, styleId: Int): List<Route>

Expand All @@ -64,6 +74,9 @@ interface RouteDao {
@Query("$SELECT_ROUTES $VIA_ROUTES_ROCK WHERE Rock.parentId = :sectorId AND LOWER(Route.name) LIKE LOWER(:name) $ORDERED_BY_ROCK")
fun getAllByNameInSector(sectorId: Int, name: String): List<Route>

@Query("$SELECT_ROUTES $VIA_ROUTES_QUALITY $VIA_ROUTES_ROCK WHERE Rock.parentId = :sectorId AND QualityAvg.quality <= :maxQualityId")
fun getAllByQualityInSector(sectorId: Int, maxQualityId: Int): List<Route>

@Query("$SELECT_ROUTES $VIA_ROUTES_ROCK $VIA_ROUTES_ASCENDS WHERE Rock.parentId = :sectorId AND Ascend.styleId = :styleId $ORDERED_BY_ROCK")
fun getAllInSectorForStyle(sectorId: Int, styleId: Int): List<Route>

Expand All @@ -73,6 +86,9 @@ interface RouteDao {
@Query("$SELECT_ROUTES WHERE Route.parentId = :rockId AND LOWER(Route.name) LIKE LOWER(:name) $ORDERED_BY_ROUTE")
fun getAllByNameAtRock(rockId: Int, name: String): List<Route>

@Query("$SELECT_ROUTES $VIA_ROUTES_QUALITY WHERE Route.parentId = :rockId AND QualityAvg.quality <= :maxQualityId")
fun getAllByQualityAtRock(rockId: Int, maxQualityId: Int): List<Route>

@Query("$SELECT_ROUTES $VIA_ROUTES_ASCENDS WHERE Route.parentId = :rockId AND Ascend.styleId = :styleId $ORDERED_BY_ROUTE")
fun getAllAtRockForStyle(rockId: Int, styleId: Int): List<Route>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,6 @@ class SqlMacros {
const val VIA_COUNTRIES_REGIONS = "JOIN Region ON Region.country = Country.name"

const val VIA_ROCKS_RELEVANCE = "JOIN (SELECT RockComment.rockId, ROUND(AVG(RockComment.qualityId)) AS relevance FROM RockComment WHERE RockComment.qualityId > 0 GROUP BY RockComment.rockId) RelevanceAvg ON RelevanceAvg.rockId = Rock.id"
const val VIA_ROUTES_QUALITY = "JOIN (SELECT RouteComment.routeId, ROUND(AVG(RouteComment.qualityId)) AS quality FROM RouteComment WHERE RouteComment.qualityId > 0 GROUP BY RouteComment.routeId) QualityAvg ON QualityAvg.routeId = Route.id"
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 Fabian Kantereit
* Copyright (C) 2019, 2022 Axel Paetzold
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -35,9 +35,12 @@ class RouteComment {

companion object {

const val QUALITY_NONE = 0

// This needs to be in sync with sandsteinklettern.de!
val QUALITY_MAP: Map<Int, String> = object : HashMap<Int, String>() {
val QUALITY_MAP: Map<Int, String> = object : LinkedHashMap<Int, String>() {
init {
put(QUALITY_NONE, "keine Angabe")
put(1, "sehr lohnend")
put(2, "lohnend")
put(3, "ok")
Expand Down
23 changes: 23 additions & 0 deletions app/src/main/res/layout/route_search_dialog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,29 @@

<View style="@style/ThinDivider"/>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical"
android:layout_margin="10dp">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/route_quality_filter"/>

<Spinner
android:id="@+id/routeQualitySpinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>

</LinearLayout>

<View style="@style/ThinDivider"/>

<LinearLayout
style="?android:attr/buttonBarStyle"
android:orientation="horizontal"
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
<string name="route_search">Weg suchen</string>
<string name="partner_search">Partner suchen</string>
<string name="rock_relevance_filter">Bedeutung: mindestens</string>
<string name="route_quality_filter">Qualität: mindestens</string>

<!-- Toasts -->
<string name="successful_refresh">Aktualisierung erfolgreich</string>
Expand All @@ -89,6 +90,7 @@
<string name="ascend_deleted">Begehung gelöscht</string>
<string name="hint_no_name">Kein Name eingegeben</string>
<string name="hint_name_already_used">Name bereits vergeben</string>
<string name="no_filter_selected">Kein Filter ausgewählt</string>
<string name="no_internet_connection">Keine Internetverbindung</string>
<string name="no_map_app_available">Keine Karten-App verfügbar</string>
<string name="no_webbrowser_available">Kein Webbrowser verfügbar</string>
Expand Down