Bimba.git

commit b0881fb276ed55b86209dd05c18777bad7a5a456

Author: Adam <git@apiote.xyz>

line and time filters

%!v(PANIC=String method: strings: negative Repeat count)


diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/departures/Departures.kt b/app/src/main/java/xyz/apiote/bimba/czwek/departures/Departures.kt
index b1075c10180fb11455713a1a54b273f982d8872e..b42ef754e0fa53865187fc849c90534c58f318ff 100644
--- a/app/src/main/java/xyz/apiote/bimba/czwek/departures/Departures.kt
+++ b/app/src/main/java/xyz/apiote/bimba/czwek/departures/Departures.kt
@@ -115,7 +115,6 @@ 		return BimbaDepartureViewHolder(rowView)
 	}
 
 	override fun onBindViewHolder(holder: BimbaDepartureViewHolder, position: Int) {
-		Log.i("show as time?", "$showAsTime")
 		BimbaDepartureViewHolder.bind(departures[position], holder, context, showAsTime, onClickListener)
 	}
 




diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/departures/DeparturesActivity.kt b/app/src/main/java/xyz/apiote/bimba/czwek/departures/DeparturesActivity.kt
index cc2c30cb53c2df594b2e983e3b4444b136d9d8d5..d7b5e04ee08a2a9ad3261b7c57fbc19f1be4b1f2 100644
--- a/app/src/main/java/xyz/apiote/bimba/czwek/departures/DeparturesActivity.kt
+++ b/app/src/main/java/xyz/apiote/bimba/czwek/departures/DeparturesActivity.kt
@@ -19,7 +19,10 @@ import androidx.lifecycle.ViewModelProvider
 import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.RecyclerView
 import com.google.android.material.datepicker.MaterialDatePicker
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
 import com.google.android.material.snackbar.Snackbar
+import com.google.android.material.timepicker.MaterialTimePicker
+import com.google.android.material.timepicker.TimeFormat
 import kotlinx.coroutines.Runnable
 import xyz.apiote.bimba.czwek.R
 import xyz.apiote.bimba.czwek.api.Error
@@ -28,6 +31,7 @@ import xyz.apiote.bimba.czwek.repo.Departure
 import xyz.apiote.bimba.czwek.repo.Stop
 import java.time.Instant
 import java.time.LocalDate
+import java.time.LocalTime
 import java.time.ZoneId
 import java.time.ZonedDateTime
 
@@ -46,10 +50,17 @@
 	private lateinit var viewModel: DeparturesViewModel
 
 	private val datePicker =
-		MaterialDatePicker.Builder.datePicker().setTitleText("Select day of departures")
+		MaterialDatePicker.Builder.datePicker().setTitleText(R.string.title_select_date)
 			.setNegativeButtonText(R.string.clear_date_selection)
 			.build()
+	private var timePickerStart: MaterialTimePicker? = null
+	private var timePickerEnd: MaterialTimePicker? = null
+	private var linePicker: MaterialAlertDialogBuilder? = null
 	private var date: LocalDate? = null
+	private val linesFilter = mutableMapOf<String, Boolean>()
+	private val linesFilterTemporary = mutableMapOf<String, Boolean>()
+	private var startTime: LocalTime = LocalTime.MIN
+	private var endTime: LocalTime = LocalTime.MAX
 
 	override fun onCreate(savedInstanceState: Bundle?) {
 		super.onCreate(savedInstanceState)
@@ -58,21 +69,66 @@ 		setContentView(binding.root)
 
 		viewModel = ViewModelProvider(this)[DeparturesViewModel::class.java]
 
+		linePicker = MaterialAlertDialogBuilder(this)
+			.setTitle(resources.getString(R.string.title_select_line))
+			.setNegativeButton(R.string.clear_date_selection) { _, _ ->
+				linesFilter.clear()
+				getDepartures()
+			}
+			.setPositiveButton(R.string.ok) { _, _ ->
+				linesFilterTemporary.forEach { linesFilter[it.key] = it.value }
+				getDepartures()
+			}
+
 		viewModel.departures.observe(this) { stopDepartures ->
-			updateItems(stopDepartures.departures, stopDepartures.stop)
+			updateItems(
+				stopDepartures.departures
+					.filter { d ->
+						linesFilter.values.all { !it } or (linesFilter[d.vehicle.Line.name] ?: false)
+					}
+					.filter { d ->
+						val t = LocalTime.of(d.time.Hour.toInt(), d.time.Minute.toInt())
+						t >= startTime && t <= endTime
+					},
+				stopDepartures.stop
+			)
 			openBottomSheet?.departureID()?.let { adapter.get(it) }?.let { openBottomSheet?.update(it) }
+
+			val lines = stopDepartures.departures.map { it.vehicle.Line.name }.sortedWith { s1, s2 ->
+				val s1n = s1.toIntOrNull()
+				val s2n = s2.toIntOrNull()
+				if (s1n != null && s2n != null) {
+					s1.toInt() - s2.toInt()
+				} else {
+					s1.compareTo(s2)
+				}
+			}.toSet().toTypedArray()
+			val selections = lines.map { linesFilter.getOrDefault(it, false) }.toBooleanArray()
+
+			linePicker?.setMultiChoiceItems(lines, selections) { _, which, checked ->
+				linesFilterTemporary[lines[which]] = checked
+			}
 		}
 		viewModel.error.observe(this) {
 			showError(it)
 		}
 
+		binding.departuresAppBar.menu.findItem(R.id.departures_filter_bytime).setEnabled(false)
+
+
 		datePicker.addOnNegativeButtonClickListener {
 			date = null
+			binding.departuresAppBar.menu.findItem(R.id.departures_filter_bytime).setEnabled(false)
 			getDepartures()  // TODO force clear and error
 		}
 		datePicker.addOnPositiveButtonClickListener {
+			if (date == null) {
+				startTime = LocalTime.MIN
+				endTime = LocalTime.MAX
+			}
 			date = Instant.ofEpochMilli(it).atZone(ZoneId.systemDefault())
 				.toLocalDate()
+			binding.departuresAppBar.menu.findItem(R.id.departures_filter_bytime).setEnabled(true)
 			getDepartures()  // TODO force clear and error
 		}
 
@@ -86,6 +142,47 @@ 		binding.departuresAppBar.setOnMenuItemClickListener {
 			when (it.itemId) {
 				R.id.departures_calendar -> {
 					datePicker.show(supportFragmentManager, "datePicker")
+					true
+				}
+
+				R.id.departures_filter_byline -> {
+					linesFilterTemporary.clear()
+					linesFilter.forEach { filter -> linesFilterTemporary[filter.key] = filter.value }
+					linePicker?.show()
+					true
+				}
+
+				R.id.departures_filter_bytime -> {
+					timePickerStart =
+						MaterialTimePicker.Builder().setTitleText(R.string.title_select_time_start)
+							.setTimeFormat(TimeFormat.CLOCK_24H)
+							.setHour(startTime.hour)
+							.setMinute(startTime.minute)
+							.setNegativeButtonText(R.string.clear_date_selection)
+							.build()
+					timePickerEnd = MaterialTimePicker.Builder().setTitleText(R.string.title_select_time_end)
+						.setTimeFormat(TimeFormat.CLOCK_24H)
+						.setHour(endTime.hour)
+						.setMinute(endTime.minute)
+						.setNegativeButtonText(R.string.clear_date_selection)
+						.build()
+					timePickerEnd!!.addOnPositiveButtonClickListener {
+						endTime = LocalTime.of(timePickerEnd!!.hour, timePickerEnd!!.minute)
+						getDepartures()  // TODO force clear and error
+					}
+					timePickerEnd!!.addOnNegativeButtonClickListener {
+						endTime = LocalTime.MAX
+						getDepartures()  // TODO force clear and error
+					}
+					timePickerStart!!.addOnPositiveButtonClickListener {
+						startTime = LocalTime.of(timePickerStart!!.hour, timePickerStart!!.minute)
+						timePickerEnd!!.show(supportFragmentManager, "timePickerEnd")
+					}
+					timePickerStart!!.addOnNegativeButtonClickListener {
+						startTime = LocalTime.MIN
+						timePickerEnd!!.show(supportFragmentManager, "timePickerEnd")
+					}
+					timePickerStart!!.show(supportFragmentManager, "timePickerStart")
 					true
 				}
 




diff --git a/app/src/main/res/drawable/filter.xml b/app/src/main/res/drawable/filter.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ad60a385e7a13b29cfb1de54726bea32b04782dd
--- /dev/null
+++ b/app/src/main/res/drawable/filter.xml
@@ -0,0 +1,5 @@
+<vector android:height="24dp" android:tint="?attr/colorOnSurface"
+  android:viewportHeight="24" android:viewportWidth="24"
+  android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@android:color/white" android:pathData="M10,18h4v-2h-4v2zM3,6v2h18L21,6L3,6zM6,13h12v-2L6,11v2z"/>
+</vector>




diff --git a/app/src/main/res/menu/departures_menu.xml b/app/src/main/res/menu/departures_menu.xml
index cea228aa205e42352b56fc464f32fdf84982fd96..01899885cf4fa3dc3f797c6dab7a54f6cb5c9de3 100644
--- a/app/src/main/res/menu/departures_menu.xml
+++ b/app/src/main/res/menu/departures_menu.xml
@@ -2,9 +2,28 @@ 
 <menu xmlns:android="http://schemas.android.com/apk/res/android"
 	xmlns:app="http://schemas.android.com/apk/res-auto">
 	<item
+		android:id="@+id/departures_filter"
+		android:icon="@drawable/filter"
+		app:showAsAction="ifRoom"
+		android:contentDescription="@string/title_filter"
+		android:title="@string/title_filter" >
+		<menu>
+			<item
+				android:id="@+id/departures_filter_byline"
+				app:showAsAction="never"
+				android:contentDescription="@string/title_filter_byline"
+				android:title="@string/title_filter_byline" />
+			<item
+				android:id="@+id/departures_filter_bytime"
+				app:showAsAction="never"
+				android:contentDescription="@string/title_filter_bytime"
+				android:title="@string/title_filter_bytime" />
+		</menu>
+	</item>
+	<item
 		android:id="@+id/departures_calendar"
 		android:icon="@drawable/calendar"
-		app:showAsAction="always"
+		app:showAsAction="ifRoom"
 		android:contentDescription="@string/title_select_date"
-		android:title="@string/title_select_date" />
+		android:title="@string/title_select_date"/>
 </menu>
\ No newline at end of file




diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index dab2829c9c31bdbe31b3844513eb1d334283f95b..56f03e0edd2cd2a146841b1335f7688cf444dba5 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -114,7 +114,13 @@ 	App version is not compatible with the server
 	<string name="filter_localities">filter localities</string>
 	<string name="error_41">This locality is not supported by the server</string>
 	<string name="stop_from_qr_code">QR code stop</string>
-    <string name="departures_snackbar">Last update: %1$s</string>
-	<string name="title_select_date">select date</string>
+	<string name="departures_snackbar">Last update: %1$s</string>
+	<string name="title_select_date">Select day of departures</string>
+	<string name="title_select_line">Select line</string>
 	<string name="clear_date_selection">Clear</string>
+	<string name="title_filter">Filter</string>
+	<string name="title_filter_byline">Filter by line</string>
+	<string name="title_filter_bytime">Filter by time</string>
+	<string name="title_select_time_start">Select start time</string>
+	<string name="title_select_time_end">Select end time</string>
 </resources>
\ No newline at end of file