Bimba.git

commit 7ded471c231769afce82b2b1fd585b3351947878

Author: Adam Evyčędo <git@apiote.xyz>

colour lines in journeys summaries

 app/src/main/java/xyz/apiote/bimba/czwek/RoundedBackgroundSpan.kt | 33 
 app/src/main/java/xyz/apiote/bimba/czwek/journeys/Journeys.kt | 23 
 app/src/main/java/xyz/apiote/bimba/czwek/repo/LineStub.kt | 51 
 app/src/main/java/xyz/apiote/bimba/czwek/repo/Stop.kt | 36 
 app/src/main/res/layout/journey.xml | 16 


diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/RoundedBackgroundSpan.kt b/app/src/main/java/xyz/apiote/bimba/czwek/RoundedBackgroundSpan.kt
index e38daad84e9aba836e3195be5c442c0abf6aa678..b410764e4abb270111a89221bf2c8fe6b5198b4d 100644
--- a/app/src/main/java/xyz/apiote/bimba/czwek/RoundedBackgroundSpan.kt
+++ b/app/src/main/java/xyz/apiote/bimba/czwek/RoundedBackgroundSpan.kt
@@ -9,7 +9,13 @@ import android.graphics.Paint
 import android.graphics.RectF
 import android.text.style.ReplacementSpan
 
-class RoundedBackgroundSpan(private val bgColour: Int, private val fgColour: Int) : ReplacementSpan() {
+class RoundedBackgroundSpan(private val bgColour: Int, private val fgColour: Int) :
+	ReplacementSpan() {
+
+		companion object {
+			const val PADDING = 20  // TODO based on small text, make dependent on eg. em-dash length
+		}
+
 	override fun getSize(
 		paint: Paint,
 		text: CharSequence,
@@ -17,7 +23,15 @@ 		start: Int,
 		end: Int,
 		fm: Paint.FontMetricsInt?
 	): Int {
-		return (paint.measureText(text, start, end)+20).toInt()
+		val l = paint.measureText(text, start, end) + PADDING
+		if (fm != null) {
+			fm.ascent = paint.fontMetrics.ascent.toInt()
+			fm.bottom = paint.fontMetrics.bottom.toInt()
+			fm.descent = paint.fontMetrics.descent.toInt()
+			fm.leading = paint.fontMetrics.leading.toInt()
+			fm.top = paint.fontMetrics.top.toInt()
+		}
+		return l.toInt()
 	}
 
 	override fun draw(
@@ -31,12 +45,19 @@ 		y: Int,
 		bottom: Int,
 		paint: Paint
 	) {
-		val length = paint.measureText(text, start, end) + 20
-		val rect = RectF(x, top.toFloat() - 5f, x + length, y.toFloat() + 5f)
+		val length = paint.measureText(text, start, end) + PADDING
+		/*
+		Log.i("BackgroundSpan", "x: $x, y: $y, start: $start, end: $end, top: $top, bottom: $bottom")
+		Log.i("BackgroundSpan", "text: $text, length: $length")
+		Log.i("BackgroundSpan", "fontMetrics:: bottom: ${paint.fontMetricsInt.bottom}, top: ${paint.fontMetricsInt.top}, ascent: ${paint.fontMetricsInt.ascent}, descent: ${paint.fontMetricsInt.descent}, leading: ${paint.fontMetricsInt.leading}")
+		Log.i("BackgroundSpan", "fontSpacing: ${paint.fontSpacing}; 1dp=${dpToPixelI(1f)}")
+		*/
+		val height = y - top
+		val rect = RectF(x, top.toFloat()-(height/6), x + length, y.toFloat()+(height/6))
 		paint.color = bgColour
-		canvas.drawRoundRect(rect, 10f, 10f, paint)
+		canvas.drawRoundRect(rect, height/4f, height/4f, paint)
 		paint.color = fgColour
 		paint.textAlign = Paint.Align.CENTER
-		canvas.drawText(text, start, end, x+(length/2), y.toFloat(), paint)
+		canvas.drawText(text, start, end, x + (length / 2), y.toFloat(), paint)
 	}
 }
\ No newline at end of file




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
index ff1d71676d397e60dcf7203f80d6cfa180069dc9..2f4d18ccb8bbebd0cd076fefb7d802efd9acc97e 100644
--- a/app/src/main/java/xyz/apiote/bimba/czwek/journeys/Journeys.kt
+++ b/app/src/main/java/xyz/apiote/bimba/czwek/journeys/Journeys.kt
@@ -6,6 +6,7 @@ package xyz.apiote.bimba.czwek.journeys
 
 import android.annotation.SuppressLint
 import android.content.Context
+import android.text.SpannableStringBuilder
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
@@ -17,6 +18,7 @@ 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
+import xyz.apiote.bimba.czwek.repo.Stop.LineDecoration
 import xyz.apiote.bimba.czwek.units.UnitSystem
 
 class JourneysViewHolder(itemView: View) : ViewHolder(itemView) {
@@ -43,8 +45,19 @@ 			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()
+			holder.lines.text = journey.legs.filter { it.start.vehicle.Line.name.isNotBlank() }
+				.fold(SpannableStringBuilder("")) { acc, leg ->
+					if (acc.isNotBlank()) {
+						acc.append(" ")
+					}
+					val s = leg.start.vehicle.Line.decorate(
+						SpannableStringBuilder(leg.start.vehicle.Line.name),
+						LineDecoration.COLOUR,
+						null
+					)
+					acc.append(s)
+					acc
+				}
 
 			holder.legs.removeAllViews()
 			journey.legs.forEach {
@@ -98,7 +111,11 @@ 					context.getString(R.string.journey_stops_headsign, stops, headsign)
 				}
 
 				val legDestination = legView.findViewById<TextView>(R.id.leg_destination)
-				if (it.destination.stop.name.isBlank() || it.destination.stop.name in arrayOf("START", "END")) {
+				if (it.destination.stop.name.isBlank() || it.destination.stop.name in arrayOf(
+						"START",
+						"END"
+					)
+				) {
 					legDestination.visibility = View.GONE
 				} else {
 					legDestination.apply {




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 86565ae24cf1322fba82acae25063e71bb026d28..26b4b729f25698d95be373a282a99c6066da3fb9 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
@@ -5,13 +5,21 @@
 package xyz.apiote.bimba.czwek.repo
 
 import android.content.Context
-import android.graphics.drawable.BitmapDrawable
+import android.graphics.Typeface
 import android.graphics.drawable.Drawable
 import android.os.Parcelable
+import android.text.Annotation
+import android.text.SpannableStringBuilder
+import android.text.Spanned
+import android.text.style.StyleSpan
+import android.util.Log
+import androidx.core.graphics.drawable.toDrawable
 import kotlinx.parcelize.Parcelize
+import xyz.apiote.bimba.czwek.RoundedBackgroundSpan
 import xyz.apiote.bimba.czwek.api.LineStubV1
 import xyz.apiote.bimba.czwek.api.LineStubV2
 import xyz.apiote.bimba.czwek.api.LineStubV3
+import xyz.apiote.bimba.czwek.repo.Stop.LineDecoration
 
 @Parcelize
 data class LineStub(val name: String, val kind: LineType, val colour: Colour) : LineAbstract, Parcelable {
@@ -20,6 +28,45 @@ 	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))
 
 	fun icon(context: Context, scale: Float = 1f): Drawable {
-		return BitmapDrawable(context.resources, super.icon(context, kind, colour, scale))
+		return super.icon(context, kind, colour, scale).toDrawable(context.resources)
+	}
+
+	fun decorate(
+		str: SpannableStringBuilder,
+		decoration: LineDecoration,
+		annotation: Annotation?
+	): SpannableStringBuilder {
+		val spanStart = if (annotation != null) {
+			str.getSpanStart(annotation)
+		} else {
+			0
+		}
+		val spanEnd = if (annotation != null) {
+			str.getSpanEnd(annotation)
+		} else {
+			str.length
+		}
+
+		val background = RoundedBackgroundSpan(colour.toInt(), textColour(colour))
+		val ital = StyleSpan(Typeface.ITALIC)
+		when (decoration) {
+			LineDecoration.ITALICS -> str.setSpan(
+				ital,
+				spanStart, spanEnd,
+				Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
+			)
+
+			LineDecoration.COLOUR -> {
+				str.setSpan(
+					background,
+					spanStart, spanEnd,
+					Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
+				)
+			}
+
+			LineDecoration.NONE -> {}
+		}
+
+		return str
 	}
 }
\ No newline at end of file




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 1f0f19b8282e80f48a826ec163380a09b270afc6..6359c8153f193f226c7a4665a8760bd266f4c79c 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
@@ -5,19 +5,15 @@
 package xyz.apiote.bimba.czwek.repo
 
 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
-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
 import xyz.apiote.bimba.czwek.api.StopV2
 import xyz.apiote.bimba.czwek.api.StopV3
@@ -167,29 +163,7 @@ 				"decoration" -> {
 					if (args.isNotEmpty()) {
 						return@forEach
 					}
-					// TODO rounded corners/padding
-					val background = RoundedBackgroundSpan(line.colour.toInt(), line.textColour(line.colour))
-					val ital = StyleSpan(Typeface.ITALIC)
-					when (decoration) {
-						LineDecoration.ITALICS -> str.setSpan(
-							ital,
-							str.getSpanStart(it),
-							str.getSpanEnd(it),
-							Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
-						)
-
-						LineDecoration.COLOUR -> {
-							str.setSpan(
-								background,
-								str.getSpanStart(it),
-								str.getSpanEnd(it),
-								Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
-							)
-							// str.setSpan(foreground, str.getSpanStart(it), str.getSpanEnd(it), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
-						}
-
-						LineDecoration.NONE -> {}
-					}
+					line.decorate(str, decoration, it)
 				}
 			}
 		}
@@ -215,10 +189,10 @@ 		companion object {
 			fun fromPreferences(context: Context) =
 				when (PreferenceManager.getDefaultSharedPreferences(context)
 					.getString("line_decoration", "italics")) {
-					"italics" -> Stop.LineDecoration.ITALICS
-					"colour" -> Stop.LineDecoration.COLOUR
-					"none" -> Stop.LineDecoration.NONE
-					else -> Stop.LineDecoration.ITALICS
+					"italics" -> ITALICS
+					"colour" -> COLOUR
+					"none" -> NONE
+					else -> ITALICS
 				}
 		}
 	}




diff --git a/app/src/main/res/layout/journey.xml b/app/src/main/res/layout/journey.xml
index be5120d120ac8514a2a112c47feef904733d0a6b..3ee0cb0a56ec6137a7dc092b3796f6ac35ed865d 100644
--- a/app/src/main/res/layout/journey.xml
+++ b/app/src/main/res/layout/journey.xml
@@ -25,17 +25,21 @@ 			app:layout_constraintStart_toStartOf="parent"
 			app:layout_constraintTop_toTopOf="parent"
 			tools:text="11:25" />
 
+		<!-- TODO line height multiplier -->
 		<com.google.android.material.textview.MaterialTextView
 			android:id="@+id/lines"
 			android:layout_width="0dp"
 			android:layout_height="wrap_content"
-			android:layout_marginStart="16dp"
-			android:layout_marginEnd="16dp"
+			android:layout_marginStart="8dp"
+			android:layout_marginTop="4dp"
+			android:layout_marginEnd="8dp"
+			android:lineSpacingExtra="18sp"
+			android:padding="4dp"
 			android:textAlignment="center"
 			android:textAppearance="@style/TextAppearance.Material3.HeadlineSmall"
-			app:layout_constraintEnd_toStartOf="@+id/end_time"
-			app:layout_constraintStart_toEndOf="@+id/start_time"
-			app:layout_constraintTop_toTopOf="@+id/start_time"
+			app:layout_constraintEnd_toEndOf="parent"
+			app:layout_constraintStart_toStartOf="parent"
+			app:layout_constraintTop_toBottomOf="@+id/start_time"
 			tools:text="Metropolitan, Circle, Hammersmith&amp;City" />
 
 		<com.google.android.material.textview.MaterialTextView
@@ -44,7 +48,7 @@ 			android:layout_width="wrap_content"
 			android:layout_height="wrap_content"
 			android:textAppearance="@style/TextAppearance.Material3.HeadlineSmall"
 			app:layout_constraintEnd_toEndOf="parent"
-			app:layout_constraintTop_toTopOf="@+id/lines"
+			app:layout_constraintTop_toTopOf="@+id/start_time"
 			tools:text="12:30" />
 
 		<LinearLayout