Author: Adam Evyčędo <git@apiote.xyz>
show journeys basic info
%!v(PANIC=String method: strings: negative Repeat count)
diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/dashboard/ui/journey/JourneyFragment.kt b/app/src/main/java/xyz/apiote/bimba/czwek/dashboard/ui/journey/JourneyFragment.kt index af3d1b59cff4373b33955ed25b1556f568a42a11..544558c0bcfc8f8cf128054e8e2f6daa9fcd17cb 100644 --- a/app/src/main/java/xyz/apiote/bimba/czwek/dashboard/ui/journey/JourneyFragment.kt +++ b/app/src/main/java/xyz/apiote/bimba/czwek/dashboard/ui/journey/JourneyFragment.kt @@ -11,13 +11,15 @@ import android.view.ViewGroup import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider import xyz.apiote.bimba.czwek.databinding.FragmentJourneyBinding +import xyz.apiote.bimba.czwek.journeys.JourneysActivity +import xyz.apiote.bimba.czwek.repo.ChangeOption +import xyz.apiote.bimba.czwek.repo.Place +import xyz.apiote.bimba.czwek.repo.Position +import xyz.apiote.bimba.czwek.repo.Stop class JourneyFragment : Fragment() { private var _binding: FragmentJourneyBinding? = null - - // This property is only valid between onCreateView and - // onDestroyView. private val binding get() = _binding!! override fun onCreateView( @@ -31,7 +33,20 @@ _binding = FragmentJourneyBinding.inflate(inflater, container, false) val root: View = binding.root - journeyViewModel.getJourney(requireContext()) + val intent = JourneysActivity.getIntent( + requireContext(), + Place( + Stop("", "", "", "", "", Position(0.0, 0.0), emptyList<ChangeOption>(), ""), + 52.402815, + 16.911795 + ), + Place( + Stop("", "", "", "", "", Position(0.0, 0.0), emptyList<ChangeOption>(), ""), + 52.445433, + 17.079231 + ) + ) + startActivity(intent) return root } diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/dashboard/ui/journey/JourneyViewModel.kt b/app/src/main/java/xyz/apiote/bimba/czwek/dashboard/ui/journey/JourneyViewModel.kt index 34c5c75a8496d97d672af81e4d7a6128f964c080..87c80d7c047df700c968d48c73e0600f1e474384 100644 --- a/app/src/main/java/xyz/apiote/bimba/czwek/dashboard/ui/journey/JourneyViewModel.kt +++ b/app/src/main/java/xyz/apiote/bimba/czwek/dashboard/ui/journey/JourneyViewModel.kt @@ -4,17 +4,9 @@ // SPDX-License-Identifier: GPL-3.0-or-later package xyz.apiote.bimba.czwek.dashboard.ui.journey -import android.content.Context -import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import kotlinx.coroutines.launch -import xyz.apiote.bimba.czwek.repo.ChangeOption -import xyz.apiote.bimba.czwek.repo.Place -import xyz.apiote.bimba.czwek.repo.Position -import xyz.apiote.bimba.czwek.repo.Stop class JourneyViewModel : ViewModel() { @@ -23,20 +15,4 @@ value = "This is voyage Fragment" } val text: LiveData<String> = _text - fun getJourney(context: Context) { - viewModelScope.launch { - Log.i("Journeys", "getting journeys") - val journeys = xyz.apiote.bimba.czwek.api.getJourney( - Place(Stop("", "", "", "", "", Position(0.0, 0.0), emptyList<ChangeOption>(), ""), 52.402815, 16.911795), - Place(Stop("", "", "", "", "", Position(0.0, 0.0), emptyList<ChangeOption>(), ""), 52.445433, 17.079231), - context - ) - Log.i("Journeys", "got ${journeys.size} journeys") - - journeys.forEach { - Log.i("Journeys", "$it") - } - } - - } } diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/journeys/Journeys.kt b/app/src/main/java/xyz/apiote/bimba/czwek/journeys/Journeys.kt new file mode 100644 index 0000000000000000000000000000000000000000..8a4aaacd2d2d7f8e5e24133eae1e752527e347d3 --- /dev/null +++ b/app/src/main/java/xyz/apiote/bimba/czwek/journeys/Journeys.kt @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: Adam Evyčędo +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package xyz.apiote.bimba.czwek.journeys + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.LinearLayout +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.RecyclerView.ViewHolder +import com.google.android.material.card.MaterialCardView +import xyz.apiote.bimba.czwek.R +import xyz.apiote.bimba.czwek.repo.Journey + +class JourneysViewHolder(itemView: View) : ViewHolder(itemView) { + val root: MaterialCardView = itemView.findViewById(R.id.journey) + val startTime: TextView = itemView.findViewById(R.id.start_time) + val lines: TextView = itemView.findViewById(R.id.lines) + val endTime: TextView = itemView.findViewById(R.id.end_time) + val legs: LinearLayout = itemView.findViewById(R.id.legs) + + companion object { + fun bind( + holder: JourneysViewHolder, + onClickListener: (Journey) -> Unit, + journey: Journey, + context: Context + ) { + holder.root.setOnClickListener { onClickListener(journey) } + holder.startTime.text = + context.getString(R.string.time, journey.startTime.hour, journey.startTime.minute) + holder.endTime.text = + context.getString(R.string.time, journey.endTime.hour, journey.endTime.minute) + holder.lines.text = + journey.legs.map { it.start.vehicle.Line.name }.filter { it.isNotBlank() }.joinToString() + } + } +} + +class JourneysAdapter( + private val inflater: LayoutInflater, + private val context: Context, + private var items: List<Journey>, + private val onClickListener: ((Journey) -> Unit), +) : + RecyclerView.Adapter<JourneysViewHolder>() { + override fun onCreateViewHolder( + parent: ViewGroup, + viewType: Int + ): JourneysViewHolder { + val rowView = inflater.inflate(R.layout.journey, parent, false) + return JourneysViewHolder(rowView) + } + + override fun onBindViewHolder( + holder: JourneysViewHolder, + position: Int + ) { + JourneysViewHolder.bind(holder, onClickListener, items[position], context) + } + + override fun getItemCount(): Int = items.size +} \ No newline at end of file diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/journeys/JourneysActivity.kt b/app/src/main/java/xyz/apiote/bimba/czwek/journeys/JourneysActivity.kt index 943d9ac58206d6b431ff049c580e2796e8b30538..e807424c10d11689a915fbbbd984354d5c0474ff 100644 --- a/app/src/main/java/xyz/apiote/bimba/czwek/journeys/JourneysActivity.kt +++ b/app/src/main/java/xyz/apiote/bimba/czwek/journeys/JourneysActivity.kt @@ -4,15 +4,51 @@ // SPDX-License-Identifier: GPL-3.0-or-later package xyz.apiote.bimba.czwek.journeys +import android.content.Context +import android.content.Intent +import android.os.Build import android.os.Bundle import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AppCompatActivity import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat import androidx.lifecycle.ViewModelProvider +import androidx.recyclerview.widget.LinearLayoutManager +import org.osmdroid.util.BoundingBox import xyz.apiote.bimba.czwek.databinding.ActivityJourneysBinding +import xyz.apiote.bimba.czwek.repo.Place +import kotlin.math.max +import kotlin.math.min class JourneysActivity : AppCompatActivity() { + companion object { + const val ORIGIN_PARAM = "origin" + const val DESTINATION_PARAM = "destination" + + fun getIntent( + context: Context, + origin: Place, + destination: Place, + ) = Intent(context, JourneysActivity::class.java).apply { + putExtra(ORIGIN_PARAM, origin) + putExtra(DESTINATION_PARAM, destination) + } + } + + private fun getOrigin(): Place = if (Build.VERSION.SDK_INT > Build.VERSION_CODES.TIRAMISU) { + intent.getParcelableExtra(ORIGIN_PARAM, Place::class.java) + } else { + @Suppress("DEPRECATION") + intent.getParcelableExtra(ORIGIN_PARAM) + } ?: throw Exception("Origin not given") + + private fun getDestination(): Place = if (Build.VERSION.SDK_INT > Build.VERSION_CODES.TIRAMISU) { + intent.getParcelableExtra(DESTINATION_PARAM, Place::class.java) + } else { + @Suppress("DEPRECATION") + intent.getParcelableExtra(DESTINATION_PARAM) + } ?: throw Exception("Destination not given") + private lateinit var binding: ActivityJourneysBinding override fun onCreate(savedInstanceState: Bundle?) { enableEdgeToEdge() @@ -28,5 +64,25 @@ val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) insets } + + val origin = getOrigin() + val destination = getDestination() + // FIXME + binding.map.zoomToBoundingBox(BoundingBox( + max(origin.latitude, destination.latitude), + max(origin.longitude, destination.longitude), + min(origin.latitude, destination.latitude), + min(origin.longitude, destination.longitude), + ), false) + + binding.journeys.layoutManager = LinearLayoutManager(this) + + journeysViewModel.journeys.observe(this) { + binding.journeys.adapter = JourneysAdapter(layoutInflater, this, it) { + // todo move map accordingly + // todo show shape on map + } + } + journeysViewModel.getJourneys(this, origin, destination) } } \ No newline at end of file diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/journeys/JourneysViewModel.kt b/app/src/main/java/xyz/apiote/bimba/czwek/journeys/JourneysViewModel.kt index bda6a077e6ae6089630285ae8ebd9d4bec1776f5..4081f971ed450472ea46d74b26238ba8d4aa8e22 100644 --- a/app/src/main/java/xyz/apiote/bimba/czwek/journeys/JourneysViewModel.kt +++ b/app/src/main/java/xyz/apiote/bimba/czwek/journeys/JourneysViewModel.kt @@ -3,14 +3,31 @@ // // SPDX-License-Identifier: GPL-3.0-or-later package xyz.apiote.bimba.czwek.journeys +import android.content.Context +import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.launch +import xyz.apiote.bimba.czwek.repo.Journey +import xyz.apiote.bimba.czwek.repo.Place class JourneysViewModel : ViewModel() { - private val _text = MutableLiveData<String>().apply { - value = "This is voyage Fragment" + private val _journeys = MutableLiveData<List<Journey>>() + val journeys: LiveData<List<Journey>> = _journeys + + fun getJourneys(context: Context, origin: Place, destination: Place) { + viewModelScope.launch { + Log.i("Journeys", "getting journeys") + _journeys.value = xyz.apiote.bimba.czwek.api.getJourney(origin, destination, context) + Log.i("Journeys", "got ${journeys.value?.size} journeys") + + journeys.value?.forEach { + Log.i("Journeys", "$it") + } + } + } - val text: LiveData<String> = _text } \ No newline at end of file diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/repo/ChangeOption.kt b/app/src/main/java/xyz/apiote/bimba/czwek/repo/ChangeOption.kt index 110e85d8f3bea00613dcb3c89ed024dac1a4f4f4..0ada3ee4188402935fc57d74074377addb39ee71 100644 --- a/app/src/main/java/xyz/apiote/bimba/czwek/repo/ChangeOption.kt +++ b/app/src/main/java/xyz/apiote/bimba/czwek/repo/ChangeOption.kt @@ -4,10 +4,13 @@ // SPDX-License-Identifier: GPL-3.0-or-later package xyz.apiote.bimba.czwek.repo +import android.os.Parcelable +import kotlinx.parcelize.Parcelize import xyz.apiote.bimba.czwek.api.ChangeOptionV1 import xyz.apiote.bimba.czwek.api.ChangeOptionV2 -data class ChangeOption(val line: LineStub, val headsigns: List<String>) { +@Parcelize +data class ChangeOption(val line: LineStub, val headsigns: List<String>): Parcelable { constructor(c: ChangeOptionV1) : this(LineStub(c.line, LineType.UNKNOWN, Colour(0u,0u,0u)), listOf(c.headsign)) constructor(c: ChangeOptionV2) : this(LineStub(c.line), c.headsigns) } \ No newline at end of file diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/repo/Colour.kt b/app/src/main/java/xyz/apiote/bimba/czwek/repo/Colour.kt index 01fea09a4f4c194afb4d5092864db448f821989b..5b33a56f8235911686e8e41586e7fcac87c39a40 100644 --- a/app/src/main/java/xyz/apiote/bimba/czwek/repo/Colour.kt +++ b/app/src/main/java/xyz/apiote/bimba/czwek/repo/Colour.kt @@ -4,9 +4,12 @@ // SPDX-License-Identifier: GPL-3.0-or-later package xyz.apiote.bimba.czwek.repo +import android.os.Parcelable +import kotlinx.parcelize.Parcelize import xyz.apiote.bimba.czwek.api.ColourV1 -data class Colour(val R: UByte, val G: UByte, val B: UByte) { +@Parcelize +data class Colour(val R: UByte, val G: UByte, val B: UByte): Parcelable { constructor(c: ColourV1) : this(c.R, c.G, c.B) fun toInt(): Int { diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/repo/Journey.kt b/app/src/main/java/xyz/apiote/bimba/czwek/repo/Journey.kt index e4086f2b9190b63bde8d95d160183a1320ee4d3c..90e2b6064503ef5cddf50cbcbd9be446256e856f 100644 --- a/app/src/main/java/xyz/apiote/bimba/czwek/repo/Journey.kt +++ b/app/src/main/java/xyz/apiote/bimba/czwek/repo/Journey.kt @@ -4,6 +4,8 @@ // SPDX-License-Identifier: GPL-3.0-or-later package xyz.apiote.bimba.czwek.repo +import android.os.Parcelable +import kotlinx.parcelize.Parcelize import xyz.apiote.bimba.czwek.api.transitous.model.Place import xyz.apiote.bimba.czwek.units.DistanceUnit import xyz.apiote.bimba.czwek.units.TimeUnit @@ -26,7 +28,8 @@ val rental: Rental?, val steps: List<StepInstruction>?,*/ ) -class Place(val stop: Stop, val latitude: Double, val longitude: Double) { +@Parcelize +class Place(val stop: Stop, val latitude: Double, val longitude: Double): Parcelable { constructor(place: Place) : this( stop = Stop(place), latitude = place.lat.toDouble(), diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/repo/LineStub.kt b/app/src/main/java/xyz/apiote/bimba/czwek/repo/LineStub.kt index d3bade3b09ff976a2ab0b60898a875359004e671..86565ae24cf1322fba82acae25063e71bb026d28 100644 --- a/app/src/main/java/xyz/apiote/bimba/czwek/repo/LineStub.kt +++ b/app/src/main/java/xyz/apiote/bimba/czwek/repo/LineStub.kt @@ -7,11 +7,14 @@ import android.content.Context import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable +import android.os.Parcelable +import kotlinx.parcelize.Parcelize import xyz.apiote.bimba.czwek.api.LineStubV1 import xyz.apiote.bimba.czwek.api.LineStubV2 import xyz.apiote.bimba.czwek.api.LineStubV3 -data class LineStub(val name: String, val kind: LineType, val colour: Colour) : LineAbstract { +@Parcelize +data class LineStub(val name: String, val kind: LineType, val colour: Colour) : LineAbstract, Parcelable { constructor(l: LineStubV1) : this(l.name, LineType.of(l.kind), Colour(l.colour)) constructor(l: LineStubV2) : this(l.name, LineType.of(l.kind), Colour(l.colour)) constructor(l: LineStubV3) : this(l.name, LineType.of(l.kind), Colour(l.colour)) diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/repo/Position.kt b/app/src/main/java/xyz/apiote/bimba/czwek/repo/Position.kt index 39ec428637d1165e0c41b12da12f7420de27a8e9..3d0e6cfcf66b180d0f53ee9b11bb6573c5105f36 100644 --- a/app/src/main/java/xyz/apiote/bimba/czwek/repo/Position.kt +++ b/app/src/main/java/xyz/apiote/bimba/czwek/repo/Position.kt @@ -5,9 +5,12 @@ package xyz.apiote.bimba.czwek.repo import android.location.Location +import android.os.Parcelable +import kotlinx.parcelize.Parcelize import xyz.apiote.bimba.czwek.api.PositionV1 -data class Position(val latitude: Double, val longitude: Double) { +@Parcelize +data class Position(val latitude: Double, val longitude: Double): Parcelable { constructor(p: PositionV1) : this(p.latitude, p.longitude) fun isZero(): Boolean { diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/repo/Stop.kt b/app/src/main/java/xyz/apiote/bimba/czwek/repo/Stop.kt index 6d17c0280d508948271195823838d292d570be3c..1f0f19b8282e80f48a826ec163380a09b270afc6 100644 --- a/app/src/main/java/xyz/apiote/bimba/czwek/repo/Stop.kt +++ b/app/src/main/java/xyz/apiote/bimba/czwek/repo/Stop.kt @@ -7,6 +7,7 @@ import android.content.Context import android.graphics.Typeface import android.graphics.drawable.Drawable +import android.os.Parcelable import android.text.Annotation import android.text.Spannable import android.text.SpannableStringBuilder @@ -14,6 +15,7 @@ import android.text.Spanned import android.text.SpannedString import android.text.style.StyleSpan import androidx.preference.PreferenceManager +import kotlinx.parcelize.Parcelize import xyz.apiote.bimba.czwek.R import xyz.apiote.bimba.czwek.RoundedBackgroundSpan import xyz.apiote.bimba.czwek.api.StopV1 @@ -23,6 +25,7 @@ import xyz.apiote.bimba.czwek.api.transitous.model.Match import xyz.apiote.bimba.czwek.api.transitous.model.Place +@Parcelize data class Stop( val code: String, val name: String, @@ -32,7 +35,7 @@ val feedID: String?, val position: Position, val changeOptions: List<ChangeOption>, val description: String? -) : Queryable, Locatable, StopAbstract { +) : Queryable, Locatable, StopAbstract, Parcelable { companion object { fun distanceComparator(centre: Position) = object : Comparator<Stop> { override fun compare( diff --git a/app/src/main/res/layout/activity_journeys.xml b/app/src/main/res/layout/activity_journeys.xml index f1d8a143cb724bf7167bc25eb3a5bb95393c501c..245ab2b24414a10047326b0a6e871574f155987e 100644 --- a/app/src/main/res/layout/activity_journeys.xml +++ b/app/src/main/res/layout/activity_journeys.xml @@ -16,10 +16,12 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> <androidx.constraintlayout.widget.ConstraintLayout + app:behavior_hideable="false" android:id="@+id/standard_bottom_sheet" style="@style/Widget.Material3.BottomSheet" android:layout_width="match_parent" android:layout_height="match_parent" + app:behavior_peekHeight="256dp" app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"> <com.google.android.material.bottomsheet.BottomSheetDragHandleView diff --git a/app/src/main/res/layout/journey.xml b/app/src/main/res/layout/journey.xml index d04636e4844916d6078c6106ef1a7e4c0f8b707a..ecc05a3f4474b5cfd7e418ac9610bb451d3ae3e5 100644 --- a/app/src/main/res/layout/journey.xml +++ b/app/src/main/res/layout/journey.xml @@ -1,18 +1,20 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- +<?xml version="1.0" encoding="utf-8"?><!-- SPDX-FileCopyrightText: Adam Evyčędo SPDX-License-Identifier: GPL-3.0-or-later --> <com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/journey" + android:layout_margin="8dp" android:layout_width="match_parent" - android:layout_height="wrap_content" - xmlns:tools="http://schemas.android.com/tools"> + android:layout_height="wrap_content"> + <androidx.constraintlayout.widget.ConstraintLayout - android:padding="16dp" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:padding="16dp"> <com.google.android.material.textview.MaterialTextView android:id="@+id/start_time" @@ -52,12 +54,7 @@ android:layout_height="wrap_content" android:layout_margin="8dp" android:orientation="vertical" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/lines"> - - <include layout="@layout/journey_leg" /> - - <include layout="@layout/journey_leg" /> - </LinearLayout> + app:layout_constraintTop_toBottomOf="@+id/lines" /> </androidx.constraintlayout.widget.ConstraintLayout> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4862655599185439634aa2e2a553ef48e471d2c4..04ed881557c310fb27e0ee81e4aa3dc498b4e343 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -131,6 +131,7 @@towards %1$s <string name="departure_momentarily">momentarily</string> <string name="departure_departed">departed</string> <string name="departure_now">now</string> + <string name="time">%1$02d:%2$02d</string> <string name="at_time">at %1$02d:%2$02d</string> <string name="about_time">about %1$02d:%2$02d</string> <string name="at_time_realtime">at %1$02d:%2$02d:%3$02d</string>