Skip to content

Commit

Permalink
Release latest (#121)
Browse files Browse the repository at this point in the history
* bump FIT SDK for Go to latest version

* fix messages arrival ordering when exporting to FIT

* fix bug on combine on accumulation logic and split session logic

* fix UI missing sport in Lap section

---------

Co-authored-by: Hikmatulloh Hari Mukti <[email protected]>
  • Loading branch information
raditzlawliet and muktihari authored Sep 26, 2024
1 parent f69ea17 commit e305f58
Show file tree
Hide file tree
Showing 9 changed files with 295 additions and 158 deletions.
19 changes: 15 additions & 4 deletions src/components/OpenActivity.vue
Original file line number Diff line number Diff line change
Expand Up @@ -664,10 +664,21 @@ export default {

for (let i = 0; i < combinedSessions.value.length; i++) {
const ses = combinedSessions.value[i]
for (let j = 0; j < ses.records.length; j++) {
if (ses.records[j].distance == null) continue
ses.records[j].distance! += prevSessionlastDistance
lastDistance = ses.records[j].distance!
let shouldAccumulate = false
if (i != 0) {
// Test if first record distance is already >= prev last record.
for (let j = 0; j < ses.records.length; j++) {
if (ses.records[j].distance == null) continue
if (ses.records[j].distance! < prevSessionlastDistance) shouldAccumulate = true
break
}
}
if (shouldAccumulate || prevSessionlastDistance == 0) {
for (let j = 0; j < ses.records.length; j++) {
if (ses.records[j].distance == null) continue
ses.records[j].distance! += prevSessionlastDistance
lastDistance = ses.records[j].distance!
}
}
prevSessionlastDistance = lastDistance

Expand Down
3 changes: 2 additions & 1 deletion src/components/TheLap.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. -->
>
<div class="row text-start">
<div class="col-auto d-inline-block" style="height: 50px">
<h6 style="text-align: left">
<h6 style="text-align: left" class="mb-0">
<i class="fa-solid fa-caret-right collapse-indicator"></i>
<span class="px-1">Lap {{ index + 1 }}</span>
</h6>
<span>{{ lap.sport }}</span>
</div>
<div class="col">
<div class="row overview-title">Distance</div>
Expand Down
1 change: 1 addition & 0 deletions src/spec/activity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export enum WorkoutType {

export class Lap {
timestamp: string | null = null
sport: string = SPORT_GENERIC
totalMovingTime: number | null = null
totalElapsedTime: number | null = null
totalDistance: number | null = null
Expand Down
47 changes: 1 addition & 46 deletions src/wasm/activity-service/activity/activity.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,7 @@ import (
"errors"
"strconv"

"github.com/muktihari/fit/factory"
"github.com/muktihari/fit/kit/datetime"
"github.com/muktihari/fit/profile/filedef"
"github.com/muktihari/fit/profile/mesgdef"
"github.com/muktihari/fit/profile/untyped/fieldnum"
"github.com/muktihari/fit/profile/untyped/mesgnum"
"github.com/muktihari/fit/proto"
)

Expand All @@ -36,6 +31,7 @@ type Activity struct {
Timezone int8
Sessions []Session

Sports []*mesgdef.Sport
SplitSummaries []*mesgdef.SplitSummary // required for FIT file; entries must be unique within each split_type
Activity *mesgdef.Activity // required for FIT file.

Expand All @@ -52,47 +48,6 @@ func CreateActivity() Activity {
}
}

// ToFIT converts Activity into proto.FIT.
func (a *Activity) ToFIT(options *mesgdef.Options) proto.FIT {
size := 2 + len(a.Sessions) + len(a.SplitSummaries) + len(a.UnrelatedMessages)
for i := range a.Sessions {
ses := &a.Sessions[i]
size += len(ses.Records) + len(ses.Laps)
}

fit := proto.FIT{Messages: make([]proto.Message, 0, size)}
fit.Messages = append(fit.Messages, a.Creator.FileId.ToMesg(options))
fit.Messages = append(fit.Messages, a.UnrelatedMessages...)

for i := range a.SplitSummaries {
mesg := a.SplitSummaries[i].ToMesg(nil)
mesg.Fields = append([]proto.Field{
factory.CreateField(mesgnum.Session, fieldnum.SessionTimestamp).WithValue(datetime.ToUint32(a.Activity.Timestamp)),
}, mesg.Fields...)
fit.Messages = append(fit.Messages, mesg)
}

for i := range a.Sessions {
ses := &a.Sessions[i]

for j := range ses.Records {
rec := &ses.Records[j]
fit.Messages = append(fit.Messages, rec.Record.ToMesg(options))
}
for j := range ses.Laps {
lap := &ses.Laps[j]
fit.Messages = append(fit.Messages, lap.Lap.ToMesg(options))
}
fit.Messages = append(fit.Messages, ses.Session.ToMesg(options))
}

fit.Messages = append(fit.Messages, a.Activity.ToMesg(nil))

filedef.SortMessagesByTimestamp(fit.Messages[1:]) // Exclude FileId

return fit
}

// MarshalAppendJSON appends the JSON format encoding of Activity to b, returning the result.
func (a *Activity) MarshalAppendJSON(b []byte) []byte {
b = append(b, '{')
Expand Down
126 changes: 42 additions & 84 deletions src/wasm/activity-service/activity/fit/fit.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/muktihari/fit/decoder"
"github.com/muktihari/fit/encoder"
"github.com/muktihari/fit/kit/datetime"
"github.com/muktihari/fit/profile/basetype"
"github.com/muktihari/fit/profile/filedef"
"github.com/muktihari/fit/profile/mesgdef"
"github.com/muktihari/fit/profile/typedef"
Expand Down Expand Up @@ -57,6 +58,9 @@ func (s *DecodeEncoder) Decode(ctx context.Context, r io.Reader) ([]activity.Act
lis := filedef.NewListener()
defer lis.Close()

lis.Reset(filedef.WithFileFunc(typedef.FileActivity,
func() filedef.File { return &wrapActivity{activity: filedef.NewActivity()} }))

dec := decoderPool.Get().(*decoder.Decoder)
defer decoderPool.Put(dec)

Expand Down Expand Up @@ -85,12 +89,12 @@ func (s *DecodeEncoder) Decode(ctx context.Context, r io.Reader) ([]activity.Act
return nil, fmt.Errorf("could not decode: %w", err)
}

activityFile := lis.File().(*filedef.Activity)
if len(activityFile.Records) == 0 {
wa := lis.File().(*wrapActivity)
if len(wa.activity.Records) == 0 {
continue
}

activities = append(activities, s.convertToActivity(activityFile))
activities = append(activities, s.convertToActivity(wa.activity))
}

if len(activities) == 0 {
Expand Down Expand Up @@ -131,9 +135,10 @@ func (s *DecodeEncoder) convertToActivity(activityFile *filedef.Activity) activi
act := activity.Activity{
Creator: activity.CreateCreator(&fileId),
Timezone: timezone,
Sports: activityFile.Sports,
SplitSummaries: activityFile.SplitSummaries,
Activity: activityFile.Activity,
UnrelatedMessages: s.handleUnrelatedMessages(activityFile),
UnrelatedMessages: activityFile.UnrelatedMessages,
}

// Convert Records, Laps and Sessions to activity's structs
Expand Down Expand Up @@ -255,84 +260,6 @@ func (s *DecodeEncoder) recalculateSummary(ses *activity.Session) {
ses.Summarize()
}

func (s *DecodeEncoder) handleUnrelatedMessages(activityFile *filedef.Activity) []proto.Message {
size := len(activityFile.DeveloperDataIds) +
len(activityFile.FieldDescriptions) +
len(activityFile.DeviceInfos) +
len(activityFile.Events) +
len(activityFile.Lengths) +
len(activityFile.SegmentLaps) +
len(activityFile.ZonesTargets) +
len(activityFile.Workouts) +
len(activityFile.WorkoutSteps) +
len(activityFile.HRs) +
len(activityFile.HRVs) +
len(activityFile.GpsMetadatas) +
len(activityFile.TimeInZones) +
len(activityFile.Splits) +
len(activityFile.Sports) +
len(activityFile.UnrelatedMessages)

if activityFile.UserProfile != nil {
size += 1
}

unrelatedMessages := make([]proto.Message, 0, size)

for i := range activityFile.DeveloperDataIds {
unrelatedMessages = append(unrelatedMessages, activityFile.DeveloperDataIds[i].ToMesg(nil))
}
for i := range activityFile.FieldDescriptions {
unrelatedMessages = append(unrelatedMessages, activityFile.FieldDescriptions[i].ToMesg(nil))
}
if activityFile.UserProfile != nil {
unrelatedMessages = append(unrelatedMessages, activityFile.UserProfile.ToMesg(nil))
}
for i := range activityFile.DeviceInfos {
unrelatedMessages = append(unrelatedMessages, activityFile.DeviceInfos[i].ToMesg(nil))
}
for i := range activityFile.Events {
unrelatedMessages = append(unrelatedMessages, activityFile.Events[i].ToMesg(nil))
}
for i := range activityFile.Lengths {
unrelatedMessages = append(unrelatedMessages, activityFile.Lengths[i].ToMesg(nil))
}
for i := range activityFile.SegmentLaps {
unrelatedMessages = append(unrelatedMessages, activityFile.SegmentLaps[i].ToMesg(nil))
}
for i := range activityFile.ZonesTargets {
unrelatedMessages = append(unrelatedMessages, activityFile.ZonesTargets[i].ToMesg(nil))
}
for i := range activityFile.Workouts {
unrelatedMessages = append(unrelatedMessages, activityFile.Workouts[i].ToMesg(nil))
}
for i := range activityFile.WorkoutSteps {
unrelatedMessages = append(unrelatedMessages, activityFile.WorkoutSteps[i].ToMesg(nil))
}
for i := range activityFile.HRs {
unrelatedMessages = append(unrelatedMessages, activityFile.HRs[i].ToMesg(nil))
}
for i := range activityFile.HRVs {
unrelatedMessages = append(unrelatedMessages, activityFile.HRVs[i].ToMesg(nil))
}
for i := range activityFile.GpsMetadatas {
unrelatedMessages = append(unrelatedMessages, activityFile.GpsMetadatas[i].ToMesg(nil))
}
for i := range activityFile.TimeInZones {
unrelatedMessages = append(unrelatedMessages, activityFile.TimeInZones[i].ToMesg(nil))
}
for i := range activityFile.Splits {
unrelatedMessages = append(unrelatedMessages, activityFile.Splits[i].ToMesg(nil))
}
for i := range activityFile.Sports {
unrelatedMessages = append(unrelatedMessages, activityFile.Sports[i].ToMesg(nil))
}

unrelatedMessages = append(unrelatedMessages, activityFile.UnrelatedMessages...)

return unrelatedMessages
}

func (s *DecodeEncoder) Encode(ctx context.Context, activities []activity.Activity) ([][]byte, error) {
buf := mem.GetBuffer()
defer mem.PutBuffer(buf)
Expand All @@ -344,8 +271,26 @@ func (s *DecodeEncoder) Encode(ctx context.Context, activities []activity.Activi

bs := make([][]byte, len(activities))
for i := range activities {
s.makeLastSummary(&activities[i])
fit := activities[i].ToFIT(nil)
a := &activities[i]
s.makeLastSummary(a)

wa := wrapActivity{activity: filedef.NewActivity()}
wa.activity.FileId = *a.Creator.FileId
for j := range a.Sessions {
ses := &a.Sessions[j]
for k := range ses.Laps {
wa.activity.Laps = append(wa.activity.Laps, ses.Laps[k].Lap)
}
for k := range ses.Records {
wa.activity.Records = append(wa.activity.Records, ses.Records[k].Record)
}
wa.activity.Sessions = append(wa.activity.Sessions, ses.Session)
}
wa.activity.SplitSummaries = a.SplitSummaries
wa.activity.Activity = a.Activity
wa.activity.UnrelatedMessages = a.UnrelatedMessages

fit := wa.ToFIT(nil)

enc.Reset(bufAt,
encoder.WithProtocolVersion(proto.V2),
Expand Down Expand Up @@ -389,6 +334,19 @@ func (s *DecodeEncoder) makeLastSummary(a *activity.Activity) {
}
}

// Ensure we got the latest timestamp across all messages.
lastTimestampUint32 := datetime.ToUint32(lastTimestamp)
for i := range a.UnrelatedMessages {
timestamp := a.UnrelatedMessages[i].FieldValueByNum(proto.FieldNumTimestamp).Uint32()
if timestamp == basetype.Uint32Invalid {
continue
}
if timestamp < lastTimestampUint32 {
break
}
lastTimestamp = datetime.ToTime(timestamp) // We get latest timestamp
}

for i := range a.Sessions {
a.Sessions[i].Timestamp = lastTimestamp
}
Expand Down
Loading

0 comments on commit e305f58

Please sign in to comment.