-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #316 from LiamMorrow/plaintext-export
- Loading branch information
Showing
23 changed files
with
297 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Plaintext Export | ||
|
||
LiftLog supports exporting your data as plaintext. Currently it supports CSV files. | ||
These exports must NOT be used as a backup mechanism, as LiftLog cannot read these CSVs. | ||
|
||
To create an export, simply navigate to `Settings -> Export, Backup, and Restore -> Plaintext Export`. | ||
Here, you can export a CSV file which contains your workout data. Sets which have not been completed are not included in the export. | ||
![Excluded Fields](./img/includedexcludedplaintext.png) | ||
|
||
An example of the produced CSV: | ||
|
||
```csv | ||
SessionId,Timestamp,Exercise,Weight,WeightUnit,Reps,TargetReps,Notes | ||
b59ab47f-8955-4a23-afa3-5d472dacc575,2024-10-16T10:45:06,Incline Dumbbell Bench Press,60,kg,8,8, | ||
8b929966-2426-4cbf-b678-ac8e811c8b2b,2024-10-16T10:44:39,Bench Press,67.5,kg,12,12, | ||
8b929966-2426-4cbf-b678-ac8e811c8b2b,2024-10-16T10:44:38,Bench Press,67.5,kg,12,12, | ||
8b929966-2426-4cbf-b678-ac8e811c8b2b,2024-10-16T10:44:38,Bench Press,67.5,kg,12,12, | ||
95bf84cb-1f11-4d51-ba6e-a4c3f1e40b08,2024-10-16T10:43:50,Pull-ups,84,kg,8,8, | ||
95bf84cb-1f11-4d51-ba6e-a4c3f1e40b08,2024-10-16T10:43:50,Pull-ups,84,kg,7,8, | ||
9c67f65a-3099-4d6b-b04d-428ce386f61d,2024-10-16T10:43:41,Squats,97.5,kg,8,8, | ||
9c67f65a-3099-4d6b-b04d-428ce386f61d,2024-10-16T10:43:41,Squats,97.5,kg,8,8, | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using LiftLog.Ui.Services; | ||
|
||
namespace LiftLog.Maui.Services; | ||
|
||
public class MauiFileExportService(IShare share) : IFileExportService | ||
{ | ||
public async Task ExportBytesAsync(string fileName, byte[] bytes, string contentType) | ||
{ | ||
string file = Path.Combine(FileSystem.CacheDirectory, fileName); | ||
|
||
using FileStream stream = File.Create(file); | ||
await stream.WriteAsync(bytes); | ||
|
||
await share.RequestAsync( | ||
new ShareFileRequest { Title = "Export Data", File = new ShareFile(file) } | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
namespace LiftLog.Ui.Models; | ||
|
||
public enum PlaintextExportFormat | ||
{ | ||
CSV, | ||
} |
54 changes: 54 additions & 0 deletions
54
LiftLog.Ui/Pages/Settings/BackupAndRestore/PlainTextExportPage.razor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
@page "/settings/backup-and-restore/plain-text-export" | ||
@inject IDispatcher Dispatcher | ||
@inject IState<SettingsState> SettingsState | ||
|
||
@inherits Fluxor.Blazor.Web.Components.FluxorComponent | ||
|
||
<Card Type="Card.CardType.Filled" class="mx-6 mb-4"> | ||
<div> | ||
This feature allows you to export your data in a plain text format such as CSV for use in other applications. | ||
It is not intended for backup purposes. For backups, please use the backup feature. | ||
LiftLog cannot restore data from plain text exports. | ||
</div> | ||
<AppButton OnClick="OpenDocumentation" Type="AppButtonType.Text">Read Documentation</AppButton> | ||
</Card> | ||
|
||
<LabelledForm> | ||
<LabelledFormRow Label="Format" Icon="description"> | ||
<SelectField data-cy="export-format-selector" Options="Formats" Value="@Format.ToString()" ValueChanged="SelectFormat"/> | ||
</LabelledFormRow> | ||
</LabelledForm> | ||
|
||
<div class="flex justify-end gap-4 m-6"> | ||
<AppButton Type="AppButtonType.Primary" OnClick="Export">Export</AppButton> | ||
</div> | ||
|
||
|
||
@code { | ||
|
||
private PlaintextExportFormat Format = PlaintextExportFormat.CSV; | ||
private List<SelectField.SelectOption> Formats = Enum.GetValues<PlaintextExportFormat>().Select(x=>new SelectField.SelectOption(x.ToString(), x.ToString())).ToList(); | ||
|
||
protected override void OnInitialized() | ||
{ | ||
Dispatcher.Dispatch(new SetPageTitleAction("Plain Text Export")); | ||
Dispatcher.Dispatch(new SetBackNavigationUrlAction("/settings/backup-and-restore")); | ||
base.OnInitialized(); | ||
} | ||
|
||
private void SelectFormat(string format) | ||
{ | ||
Format = Enum.Parse<PlaintextExportFormat>(format); | ||
StateHasChanged(); | ||
} | ||
|
||
private void Export(MouseEventArgs _) | ||
{ | ||
Dispatcher.Dispatch(new ExportPlainTextAction(Format)); | ||
} | ||
|
||
private void OpenDocumentation(MouseEventArgs _) | ||
{ | ||
Dispatcher.Dispatch(new NavigateAction("https://github.com/LiamMorrow/LiftLog/blob/main/Docs/PlaintextExport.md")); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
LiftLog.Ui/Services/IExporter.cs → LiftLog.Ui/Services/IBackupRestoreService.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
namespace LiftLog.Ui.Services; | ||
|
||
public interface IFileExportService | ||
{ | ||
Task ExportBytesAsync(string fileName, byte[] bytes, string contentType); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
using System.Globalization; | ||
using CsvHelper; | ||
using Fluxor; | ||
using LiftLog.Lib.Models; | ||
using LiftLog.Ui.Models; | ||
using LiftLog.Ui.Store.Settings; | ||
|
||
namespace LiftLog.Ui.Services; | ||
|
||
public class PlaintextExportService( | ||
IFileExportService fileExportService, | ||
ProgressRepository progressRepository, | ||
IState<SettingsState> settingsState | ||
) | ||
{ | ||
public async Task ExportAsync(PlaintextExportFormat format) | ||
{ | ||
var unit = settingsState.Value.UseImperialUnits ? "lbs" : "kg"; | ||
var sessions = progressRepository.GetOrderedSessions(); | ||
|
||
var (fileName, bytes, contentType) = format switch | ||
{ | ||
PlaintextExportFormat.CSV => ( | ||
"liftlog-export.csv", | ||
await ExportToCsv(sessions, unit), | ||
"text/csv" | ||
), | ||
}; | ||
|
||
await fileExportService.ExportBytesAsync(fileName, bytes, contentType); | ||
} | ||
|
||
private static async Task<byte[]> ExportToCsv(IAsyncEnumerable<Session> sessions, string unit) | ||
{ | ||
var exportedSets = await sessions | ||
.SelectMany(s => s.RecordedExercises.Select(ex => (s, ex)).ToAsyncEnumerable()) | ||
.SelectMany( | ||
(val) => ExportedSetCsvRow.FromModel(val.s, val.ex, unit).ToAsyncEnumerable() | ||
) | ||
.ToListAsync(); | ||
using var memoryStream = new MemoryStream(); | ||
using var writer = new StreamWriter(memoryStream); | ||
using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture); | ||
csv.WriteRecords(exportedSets); | ||
csv.Flush(); | ||
return memoryStream.ToArray(); | ||
} | ||
} | ||
|
||
public record ExportedSetCsvRow( | ||
string SessionId, | ||
string Timestamp, | ||
string Exercise, | ||
decimal Weight, | ||
string WeightUnit, | ||
int Reps, | ||
int TargetReps, | ||
string Notes | ||
) | ||
{ | ||
public static IEnumerable<ExportedSetCsvRow> FromModel( | ||
Session session, | ||
RecordedExercise exercise, | ||
string unit | ||
) | ||
{ | ||
return exercise | ||
.PotentialSets.Where(x => x.Set is not null) | ||
.Select(set => new ExportedSetCsvRow( | ||
session.Id.ToString(), | ||
// s=sortable, ISO 8601 format without milliseconds or timezone | ||
session | ||
.Date.ToDateTime(set.Set!.CompletionTime!, DateTimeKind.Local) | ||
.ToString("s"), | ||
exercise.Blueprint.Name, | ||
set.Weight, | ||
unit, | ||
set.Set.RepsCompleted, | ||
exercise.Blueprint.RepsPerSet, | ||
exercise.Notes ?? "" | ||
)); | ||
} | ||
} |
Oops, something went wrong.