diff --git a/src/garmin/ActivityId.scala b/src/garmin/ActivityId.scala index 1ec74bf..855efe7 100644 --- a/src/garmin/ActivityId.scala +++ b/src/garmin/ActivityId.scala @@ -7,6 +7,7 @@ import scala.scalajs.js import org.scalajs.dom.HTMLElement import core.* +import core.Gauge.{BeatPerMinute as bpm, StepPerMinute as spm} import core.service.Fetch opaque type ActivityId = String @@ -14,30 +15,34 @@ opaque type ActivityId = String object ActivityId: def apply(s: String): ActivityId = s - given inject(using + given (using + Predicate[(bpm, spm, Intensity), js.Dynamic], Fetch[Get, js.Dynamic], Inject[History[js.Dynamic]] ): Inject[List[ActivityId]] with extension (ids: List[ActivityId]) def inject(e: HTMLElement): Unit = - for case Some(h) :: t <- Future.sequence(ids.map(splits)) do (h -> t.map(_.toList).flatten).inject(e) + for case Some(h) :: t <- Future.sequence(ids.map(splits[(bpm, spm, Intensity)])) do + (h -> t.map(_.toList).flatten).inject(e) - private def splits(id: ActivityId)(using Fetch[Get, js.Dynamic]) = + private def splits[T](id: ActivityId)(using Fetch[Get, js.Dynamic], Predicate[T, js.Dynamic]) = inline def url = s"https://connect.garmin.cn/activity-service/activity/$id/splits" inline def referrer = s"https://connect.garmin.cn/modern/activity/$id" - for d <- Get(url, referrer).request yield d.asInstanceOf[Splits].lapDTOs.toList.filter(_.isActive) match + for d <- Get(url, referrer).request + yield d.asInstanceOf[Splits].lapDTOs.toList.filter(Predicate[T, js.Dynamic]) match case h :: t => Some(h -> t) case _ => None - private trait Lap extends js.Object: - def intensityType: js.UndefOr[String] - - extension (l: Lap) - private inline def isActive = - l.intensityType == "ACTIVE" || l.intensityType == "INTERVAL" || l.intensityType == js.undefined - private trait Splits extends js.Object: - def lapDTOs: js.Array[Lap & js.Dynamic] + def lapDTOs: js.Array[js.Dynamic] + + sealed trait Intensity + object Intensity: + private trait Lap extends js.Object: + def intensityType: js.UndefOr[String] + given Predicate[Intensity, js.Dynamic] = Predicate: a => + val t = a.asInstanceOf[Lap].intensityType + t == "ACTIVE" || t == "INTERVAL" || t == js.undefined end ActivityId diff --git a/src/garmin/Predicate.scala b/src/garmin/Predicate.scala new file mode 100644 index 0000000..a5b7061 --- /dev/null +++ b/src/garmin/Predicate.scala @@ -0,0 +1,18 @@ +package garmin + +import core.Read + +opaque type Predicate[T, A] = A => Boolean +object Predicate: + def apply[T, A](f: A => Boolean): Predicate[T, A] = f + def apply[T, A](a: A)(using p: Predicate[T, A]): Boolean = p(a) + + given [A]: Predicate[EmptyTuple, A] = _ => true + given [H, T <: Tuple, A](using h: Predicate[H, A], t: Predicate[T, A]): Predicate[H *: T, A] = a => h(a) && t(a) + + given [T, A, B](using Read[T, A, B]): Predicate[T, A] = a => + try + Read[T, A, B](a) + true + catch case _ => false +end Predicate