diff --git a/Directory.Build.props b/Directory.Build.props
index 4b6986f..423df1b 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -9,8 +9,8 @@
disable
latest
- 5.7.6
- 48
+ 5.8.0
+ 46
FitEdit
EnduraByte LLC 2024
diff --git a/FitEdit.sln b/FitEdit.sln
index bf52942..0fa561c 100644
--- a/FitEdit.sln
+++ b/FitEdit.sln
@@ -149,7 +149,6 @@ Global
{9B06A0E5-9409-4D7C-B532-364C12264BE1}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{9B06A0E5-9409-4D7C-B532-364C12264BE1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9B06A0E5-9409-4D7C-B532-364C12264BE1}.Release|Any CPU.Build.0 = Release|Any CPU
- {9B06A0E5-9409-4D7C-B532-364C12264BE1}.Release|Any CPU.Deploy.0 = Release|Any CPU
{21ECAE7A-E6E1-4857-9631-F24951E3CA17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{21ECAE7A-E6E1-4857-9631-F24951E3CA17}.Debug|Any CPU.Build.0 = Debug|Any CPU
{21ECAE7A-E6E1-4857-9631-F24951E3CA17}.Release|Any CPU.ActiveCfg = Release|Any CPU
diff --git a/Infrastructure/FitEdit.Adapters.Fit/Decode.cs b/Infrastructure/FitEdit.Adapters.Fit/Decode.cs
index f4cb2d2..e9de169 100644
--- a/Infrastructure/FitEdit.Adapters.Fit/Decode.cs
+++ b/Infrastructure/FitEdit.Adapters.Fit/Decode.cs
@@ -283,17 +283,17 @@ public void DecodeNextMessage(Stream fitStream)
long sourceIndex = fitStream.Position;
byte nextByte = br.ReadByte();
- Log.Debug($"Message header: {nextByte:X2}");
+ //Log.Debug($"Message header: {nextByte:X2}");
bool isCompressedHeader = (nextByte & Fit.CompressedHeaderMask) == Fit.CompressedHeaderMask;
bool isMesgDefinition = (nextByte & Fit.MesgDefinitionMask) == Fit.MesgDefinitionMask;
bool isDataMessage = (nextByte & Fit.MesgDefinitionMask) == Fit.MesgHeaderMask;
bool isDevData = (nextByte & Fit.DevDataMask) == Fit.DevDataMask;
- Log.Debug($" Compressed: {isCompressedHeader}");
- Log.Debug($" Definition: {isMesgDefinition}");
- Log.Debug($" Data: {isDataMessage}");
- Log.Debug($" DevData: {isDevData}");
+ //Log.Debug($" Compressed: {isCompressedHeader}");
+ //Log.Debug($" Definition: {isMesgDefinition}");
+ //Log.Debug($" Data: {isDataMessage}");
+ //Log.Debug($" DevData: {isDevData}");
// Is it a compressed timestamp mesg?
if (isCompressedHeader)
@@ -331,7 +331,7 @@ private void ReadDataMesg(Stream fitStream, BinaryReader br, long sourceIndex, b
}
MesgDefinition def = _localMesgDefs[localMesgNum];
- Log.Debug($" (global, local) message num: ({localMesgNum}, {def.GlobalMesgNum})");
+ //Log.Debug($" (global, local) message num: ({localMesgNum}, {def.GlobalMesgNum})");
int fieldsSize = def.GetMesgSize() - 1;
if (FitConfig.Discard.DataMessages.OfLargeSize
diff --git a/Infrastructure/FitEdit.Data/Fit/Edits/RemoveGapsEdit.cs b/Infrastructure/FitEdit.Data/Fit/Edits/RemoveGapsEdit.cs
new file mode 100644
index 0000000..81547aa
--- /dev/null
+++ b/Infrastructure/FitEdit.Data/Fit/Edits/RemoveGapsEdit.cs
@@ -0,0 +1,58 @@
+namespace FitEdit.Data.Fit.Edits;
+
+public class RemoveGapsEdit(FitFile fit) : IEdit
+{
+ public FitFile Apply()
+ {
+ var minGap = TimeSpan.FromSeconds(60);
+
+ var copy = new FitFile(fit);
+ var records = copy.Records;
+
+ // Algorithm:
+ // For each pair of successive records i and i + 1
+ // where time span between them differs by more than the min gap,
+ // make the time span between them 1s and update all later timestamps accordingly.
+ foreach (int i in Enumerable.Range(0, records.Count - 1))
+ {
+ DateTime start = records[i].GetTimestamp().GetDateTime();
+ DateTime end = records[i + 1].GetTimestamp().GetDateTime();
+ TimeSpan gap = end - start;
+
+ if (gap < minGap)
+ continue;
+
+ SetRecordStartTimeCascading(records, i + 1, start + TimeSpan.FromSeconds(1));
+ }
+
+ copy.BackfillEvents();
+
+ return copy;
+ }
+
+ ///
+ /// Set record i to the given start time, and shift all subsequent record timestamps by the time diff.
+ ///
+ private static void SetRecordStartTimeCascading(List records, int i, DateTime start)
+ {
+ // Set record i to the given start time. Keep track of the time diff.
+ DateTime oldEnd = records[i].GetTimestamp().GetDateTime();
+ records[i].SetTimestamp(new Dynastream.Fit.DateTime(start));
+ DateTime newEnd = records[i].GetTimestamp().GetDateTime();
+
+ TimeSpan diff = oldEnd - newEnd;
+
+ // Shift all subsequent record timestamps
+ ShiftTimestamps(records, i + 1, diff);
+ }
+
+ private static void ShiftTimestamps(List records, int i, TimeSpan diff)
+ {
+ for (int j = i; j < records.Count - 1; j++)
+ {
+ DateTime start = records[j].GetTimestamp().GetDateTime();
+
+ records[j].SetTimestamp(new Dynastream.Fit.DateTime(start - diff));
+ }
+ }
+}
diff --git a/Infrastructure/FitEdit.Data/Fit/FitFileExtensions.cs b/Infrastructure/FitEdit.Data/Fit/FitFileExtensions.cs
index c0958d0..8e08b08 100644
--- a/Infrastructure/FitEdit.Data/Fit/FitFileExtensions.cs
+++ b/Infrastructure/FitEdit.Data/Fit/FitFileExtensions.cs
@@ -472,7 +472,7 @@ private static List FindAll(this FitFile f, Type t) => f.Events.OfType fits, out Decode deco
decoder.FitFileRead += () =>
{
- Log.Debug($"Read FIT file with {tmp.Events.Count} messages");
+ //Log.Debug($"Read FIT file with {tmp.Events.Count} messages");
tmp = new FitFile();
};
@@ -143,4 +143,4 @@ public bool TryGetDecoder(Stream stream, out List fits, out Decode deco
public static class FitLog
{
-}
\ No newline at end of file
+}
diff --git a/Infrastructure/FitEdit.Data/Fit/Writer.cs b/Infrastructure/FitEdit.Data/Fit/Writer.cs
index 4dd7cff..6bc4412 100644
--- a/Infrastructure/FitEdit.Data/Fit/Writer.cs
+++ b/Infrastructure/FitEdit.Data/Fit/Writer.cs
@@ -56,4 +56,4 @@ public void Write(FitFile fitFile, Stream dest)
Log.Info($"Wrote {fitFile.Messages.Count} messages and {fitFile.MessageDefinitions.Count} definitions");
encoder.Close();
}
-}
\ No newline at end of file
+}
diff --git a/Ui/FitEdit.Ui.Infra/appsettings.json b/Ui/FitEdit.Ui.Infra/appsettings.json
index b31f65d..8f813c4 100644
--- a/Ui/FitEdit.Ui.Infra/appsettings.json
+++ b/Ui/FitEdit.Ui.Infra/appsettings.json
@@ -13,7 +13,7 @@
"Default": "Information",
"Override": {
"Microsoft": "Warning"
- //"CompositionRoot": "Debug"
+ //, "CompositionRoot": "Debug"
}
},
"Using": [ "Serilog.Sinks.File", "Serilog.Sinks.Debug" ],
diff --git a/Ui/FitEdit.Ui.iOS/Info.plist b/Ui/FitEdit.Ui.iOS/Info.plist
index c4480b6..ef1cd36 100644
--- a/Ui/FitEdit.Ui.iOS/Info.plist
+++ b/Ui/FitEdit.Ui.iOS/Info.plist
@@ -7,7 +7,7 @@
CFBundleIdentifier
com.endurabyte.fitedit
CFBundleShortVersionString
- 5.7.5
+ 5.8.0
LSRequiresIPhoneOS
MinimumOSVersion
@@ -57,5 +57,6 @@
CFBundleVersion
+ 46
-
\ No newline at end of file
+
diff --git a/Ui/FitEdit.Ui/ViewModels/FileViewModel.cs b/Ui/FitEdit.Ui/ViewModels/FileViewModel.cs
index 6b31fef..3e1adbe 100644
--- a/Ui/FitEdit.Ui/ViewModels/FileViewModel.cs
+++ b/Ui/FitEdit.Ui/ViewModels/FileViewModel.cs
@@ -5,6 +5,7 @@
using FitEdit.Adapters.Strava;
using FitEdit.Data;
using FitEdit.Data.Fit;
+using FitEdit.Data.Fit.Edits;
using FitEdit.Model;
using FitEdit.Model.Extensions;
using FitEdit.Model.GarminConnect;
@@ -17,6 +18,7 @@
using FitEdit.Ui.Infra;
using FitEdit.Ui.Model.Supabase;
using Microsoft.Extensions.Logging.Abstractions;
+using Newtonsoft.Json.Bson;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
@@ -735,6 +737,20 @@ public void HandleRepairBackfillClicked(UiFile uif)
));
}
+ public void HandleRemoveGapsClicked(UiFile file)
+ {
+ FitFile? fit = new RemoveGapsEdit(file.FitFile).Apply();
+
+ Task.Run(async () =>
+ {
+ await Persist(new FileReference
+ (
+ $"(No Gaps) {file.Activity?.Name}",
+ fit.GetBytes()
+ ));
+ });
+ }
+
public async Task HandleOpenGarminUploadPageClicked() => await browser_.OpenAsync("https://connect.garmin.com/modern/import-data");
public async Task HandleOpenStravaUploadPageClicked() => await browser_.OpenAsync("https://www.strava.com/upload/select");
diff --git a/Ui/FitEdit.Ui/ViewModels/PlotViewModel.cs b/Ui/FitEdit.Ui/ViewModels/PlotViewModel.cs
index 7eac134..050d8a7 100644
--- a/Ui/FitEdit.Ui/ViewModels/PlotViewModel.cs
+++ b/Ui/FitEdit.Ui/ViewModels/PlotViewModel.cs
@@ -178,7 +178,7 @@ protected void Add(UiFile file)
foreach (var record in fit.Records)
{
- var speed = (double?)record.GetEnhancedSpeed() ?? 0;
+ var speed = (double?)(record.GetSpeed() ?? record.GetEnhancedSpeed()) ?? 0;
var hr = (double?)record.GetHeartRate() ?? 0;
var cadence = (double?)record.GetCadence() ?? 0;
var time = record.InstantOfTime();
diff --git a/Ui/FitEdit.Ui/Views/FileView.axaml b/Ui/FitEdit.Ui/Views/FileView.axaml
index 760104d..2ab670a 100644
--- a/Ui/FitEdit.Ui/Views/FileView.axaml
+++ b/Ui/FitEdit.Ui/Views/FileView.axaml
@@ -75,6 +75,17 @@
+