diff --git a/fitnesstrax/core/src/bin/legacy-importer.rs b/fitnesstrax/core/src/bin/legacy-importer.rs
index 1f29c99..77b6423 100644
--- a/fitnesstrax/core/src/bin/legacy-importer.rs
+++ b/fitnesstrax/core/src/bin/legacy-importer.rs
@@ -14,19 +14,21 @@ General Public License for more details.
You should have received a copy of the GNU General Public License along with FitnessTrax. If not, see .
*/
-use std::{
- fs::File,
- io::{BufRead, BufReader, Read},
- fmt,
- str::FromStr,
-};
use chrono::SecondsFormat;
use chrono_tz::Etc::UTC;
-use emseries::{Record, Series, Timestamp, RecordId};
-use ft_core::TraxRecord;
-use serde::{Deserialize, Serialize, Deserializer, Serializer, de::{self, Visitor}};
-
-
+use dimensioned::si;
+use emseries::{Record, RecordId, Series, Timestamp};
+use ft_core::{self, DurationWorkout, DurationWorkoutActivity, SetRepActivity, TraxRecord};
+use serde::{
+ de::{self, Visitor},
+ Deserialize, Deserializer, Serialize, Serializer,
+};
+use std::{
+ fmt,
+ fs::File,
+ io::{BufRead, BufReader, Read},
+ str::FromStr,
+};
/// This is a wrapper around date time objects, using timezones from the chroon-tz database and
/// providing string representation and parsing of the form " ", i.e.,
@@ -116,11 +118,19 @@ impl<'de> Deserialize<'de> for DateTimeTz {
}
}
-
#[derive(Clone, Debug, Serialize, Deserialize)]
struct Steps {
date: DateTimeTz,
- steps: u64,
+ steps: u32,
+}
+
+impl From for ft_core::Steps {
+ fn from(s: Steps) -> Self {
+ Self {
+ date: s.date.0.naive_utc().date(),
+ count: s.steps,
+ }
+ }
}
#[derive(Clone, Debug, Serialize, Deserialize)]
@@ -129,13 +139,34 @@ struct Weight {
weight: f64,
}
+impl From for ft_core::Weight {
+ fn from(w: Weight) -> Self {
+ Self {
+ date: w.date.0.naive_utc().date(),
+ weight: w.weight * si::KG,
+ }
+ }
+}
+
#[derive(Clone, Debug, Serialize, Deserialize)]
enum TDActivity {
Cycling,
- Running,
- Walking,
- Swimming,
Rowing,
+ Running,
+ Swimming,
+ Walking,
+}
+
+impl From for ft_core::TimeDistanceActivity {
+ fn from(activity: TDActivity) -> Self {
+ match activity {
+ TDActivity::Cycling => ft_core::TimeDistanceActivity::Biking,
+ TDActivity::Rowing => ft_core::TimeDistanceActivity::Rowing,
+ TDActivity::Running => ft_core::TimeDistanceActivity::Running,
+ TDActivity::Swimming => ft_core::TimeDistanceActivity::Swimming,
+ TDActivity::Walking => ft_core::TimeDistanceActivity::Walking,
+ }
+ }
}
#[derive(Clone, Debug, Serialize, Deserialize)]
@@ -147,25 +178,63 @@ struct TimeDistance {
duration: Option,
}
+impl From for ft_core::TimeDistance {
+ fn from(td: TimeDistance) -> Self {
+ Self {
+ datetime: td.date.0.fixed_offset(),
+ activity: td.activity.into(),
+ comments: td.comments,
+ distance: td.distance.map(|d| d * si::M),
+ duration: td.duration.map(|d| d * si::S),
+ }
+ }
+}
+
#[derive(Clone, Debug, Serialize, Deserialize)]
enum SRActivity {
Pushups,
Situps,
}
+impl From for SetRepActivity {
+ fn from(activity: SRActivity) -> Self {
+ match activity {
+ SRActivity::Pushups => Self::Pushups,
+ SRActivity::Situps => Self::Situps,
+ }
+ }
+}
+
#[derive(Clone, Debug, Serialize, Deserialize)]
struct SetRep {
date: DateTimeTz,
activity: SRActivity,
- sets: Vec,
+ sets: Vec,
comments: Option,
}
+impl From for ft_core::SetRep {
+ fn from(sr: SetRep) -> Self {
+ Self {
+ date: sr.date.0.naive_utc().date(),
+ activity: sr.activity.into(),
+ sets: sr.sets,
+ comments: sr.comments,
+ }
+ }
+}
+
#[derive(Clone, Debug, Serialize, Deserialize)]
enum RDActivity {
MartialArts,
}
+impl From for DurationWorkoutActivity {
+ fn from(_: RDActivity) -> Self {
+ Self::MartialArts
+ }
+}
+
#[derive(Clone, Debug, Serialize, Deserialize)]
struct RepDuration {
date: DateTimeTz,
@@ -173,13 +242,24 @@ struct RepDuration {
sets: Vec,
}
+impl From for DurationWorkout {
+ fn from(rd: RepDuration) -> Self {
+ Self {
+ datetime: rd.date.0.fixed_offset(),
+ activity: rd.activity.into(),
+ duration: rd.sets.into_iter().map(|d| d * si::S).next(),
+ comments: None,
+ }
+ }
+}
+
#[derive(Clone, Debug, Serialize, Deserialize)]
enum LegacyData {
- Steps(Steps),
- Weight(Weight),
- TimeDistance(TimeDistance),
- SetRep(SetRep),
RepDuration(RepDuration),
+ SetRep(SetRep),
+ Steps(Steps),
+ TimeDistance(TimeDistance),
+ Weight(Weight),
}
#[derive(Clone, Debug, Serialize, Deserialize)]
@@ -188,11 +268,39 @@ struct LegacyRecord {
data: LegacyData,
}
+impl From for Record {
+ fn from(record: LegacyRecord) -> Self {
+ match record.data {
+ LegacyData::RepDuration(rd) => Record {
+ id: record.id,
+ data: TraxRecord::DurationWorkout(rd.into()),
+ },
+ LegacyData::SetRep(sr) => Record {
+ id: record.id,
+ data: TraxRecord::SetRep(sr.into()),
+ },
+ LegacyData::Steps(s) => Record {
+ id: record.id,
+ data: TraxRecord::Steps(s.into()),
+ },
+ LegacyData::TimeDistance(td) => Record {
+ id: record.id,
+ data: TraxRecord::TimeDistance(td.into()),
+ },
+ LegacyData::Weight(weight) => Record {
+ id: record.id,
+ data: TraxRecord::Weight(weight.into()),
+ },
+ }
+ }
+}
+
fn main() {
let mut args = std::env::args();
let _ = args.next().unwrap();
let input_filename = args.next().unwrap();
println!("input filename: {}", input_filename);
+ // let output: Series = Series::open_file("import.fitnesstrax").unwrap();
let input_file = File::open(input_filename).unwrap();
let mut buf_reader = BufReader::new(input_file);
@@ -211,7 +319,8 @@ fn main() {
Ok(0) => std::process::exit(0),
Ok(_) => {
let record = serde_json::from_str::(&line).unwrap();
- println!("[{}] {:?}", count, record);
+ let record: Record = record.into();
+ println!("{}", serde_json::to_string(&record).unwrap());
count += 1;
}
}
diff --git a/fitnesstrax/core/src/lib.rs b/fitnesstrax/core/src/lib.rs
index f579628..15f4871 100644
--- a/fitnesstrax/core/src/lib.rs
+++ b/fitnesstrax/core/src/lib.rs
@@ -2,5 +2,7 @@ mod legacy;
mod types;
pub use types::{
- Steps, TimeDistance, TimeDistanceActivity, TraxRecord, Weight, TIME_DISTANCE_ACTIVITIES,
+ SetRep, SetRepActivity, Steps, TimeDistance, TimeDistanceActivity, TraxRecord, Weight,
+ DurationWorkoutActivity, DurationWorkout,
+ SET_REP_ACTIVITIES, TIME_DISTANCE_ACTIVITIES,
};
diff --git a/fitnesstrax/core/src/types.rs b/fitnesstrax/core/src/types.rs
index d2ef95c..97a9d69 100644
--- a/fitnesstrax/core/src/types.rs
+++ b/fitnesstrax/core/src/types.rs
@@ -19,17 +19,38 @@ use dimensioned::si;
use emseries::{Recordable, Timestamp};
use serde::{Deserialize, Serialize};
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+pub enum SetRepActivity {
+ Pushups,
+ Situps,
+}
+
+pub const SET_REP_ACTIVITIES: [SetRepActivity; 2] =
+ [SetRepActivity::Pushups, SetRepActivity::Situps];
+
/// SetRep represents workouts like pushups or situps, which involve doing a "set" of a number of
/// actions, resting, and then doing another set.
-#[allow(dead_code)]
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct SetRep {
/// I assume that a set/rep workout is only done once in a day.
- date: NaiveDate,
+ pub date: NaiveDate,
+ /// The activity involved
+ pub activity: SetRepActivity,
/// Each set entry represents the number of times that the action was performed in a set. So, a
/// pushup workout that involved five sets would have five entries. Each entry would be x
/// number of pushups. A viable workout would be something like [6, 6, 4, 4, 5].
- sets: Vec,
- comments: Option,
+ pub sets: Vec,
+ pub comments: Option,
+}
+
+impl Recordable for SetRep {
+ fn timestamp(&self) -> Timestamp {
+ Timestamp::Date(self.date)
+ }
+
+ fn tags(&self) -> Vec {
+ vec![]
+ }
}
/// The number of steps one takes in a single day.
@@ -120,11 +141,45 @@ impl Recordable for Weight {
}
}
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+pub enum DurationWorkoutActivity {
+ MartialArts,
+ Yoga,
+}
+
+pub const DURATION_WORKOUT_ACTIVITIES: [DurationWorkoutActivity; 2] = [
+ DurationWorkoutActivity::MartialArts,
+ DurationWorkoutActivity::Yoga,
+];
+
+/// Generic workouts for which only duration really matters. This is for things
+/// such as Martial Arts or Yoga, which are activities done for an amount of
+/// time, but with no other details.
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+pub struct DurationWorkout {
+ pub datetime: DateTime,
+ pub activity: DurationWorkoutActivity,
+ pub duration: Option>,
+ pub comments: Option,
+}
+
+impl Recordable for DurationWorkout {
+ fn timestamp(&self) -> Timestamp {
+ Timestamp::DateTime(self.datetime)
+ }
+
+ fn tags(&self) -> Vec {
+ vec![]
+ }
+}
+
/// The unified data structure for all records that are part of the app.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum TraxRecord {
- TimeDistance(TimeDistance),
+ DurationWorkout(DurationWorkout),
+ SetRep(SetRep),
Steps(Steps),
+ TimeDistance(TimeDistance),
Weight(Weight),
}
@@ -164,8 +219,10 @@ impl Recordable for TraxRecord {
fn timestamp(&self) -> Timestamp {
match self {
TraxRecord::TimeDistance(rec) => Timestamp::DateTime(rec.datetime),
+ TraxRecord::SetRep(rec) => rec.timestamp(),
TraxRecord::Steps(rec) => rec.timestamp(),
TraxRecord::Weight(rec) => rec.timestamp(),
+ TraxRecord::DurationWorkout(rec) => rec.timestamp(),
}
}