-
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.
This commit adds a plaintext export, in CSV format. It exports the users sessions as '1 row per set'.
- Loading branch information
1 parent
7967738
commit 21eb066
Showing
19 changed files
with
271 additions
and
21 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
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" T="PlaintextExportFormat" Options="Formats" Value="Format" 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<PlaintextExportFormat>.SelectOption> Formats = [new("CSV", PlaintextExportFormat.CSV)]; | ||
|
||
protected override void OnInitialized() | ||
{ | ||
Dispatcher.Dispatch(new SetPageTitleAction("Plain Text Export")); | ||
Dispatcher.Dispatch(new SetBackNavigationUrlAction("/settings/backup-and-restore")); | ||
base.OnInitialized(); | ||
} | ||
|
||
private void SelectFormat(PlaintextExportFormat format) | ||
{ | ||
Format = 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,80 @@ | ||
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(), | ||
session.Date.ToDateTime(set.Set!.CompletionTime!).ToString("o"), | ||
exercise.Blueprint.Name, | ||
set.Weight, | ||
unit, | ||
set.Set.RepsCompleted, | ||
exercise.Blueprint.RepsPerSet, | ||
exercise.Notes ?? "" | ||
)); | ||
} | ||
} |
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,43 @@ | ||
@inject IJSRuntime JsRuntime | ||
@typeparam T | ||
|
||
@switch(TextFieldType){ | ||
case TextFieldType.Outlined: | ||
<md-outlined-select value=@Value @attributes="AdditionalAttributes"> | ||
@foreach (var option in Options) | ||
{ | ||
<md-select-option value="@option.Value"> | ||
<div slot="headline">@option.Title</div> | ||
</md-select-option> | ||
} | ||
</md-outlined-select> | ||
break; | ||
case TextFieldType.Filled: | ||
<md-filled-select value=@Value @attributes="AdditionalAttributes" > | ||
@foreach (var option in Options) | ||
{ | ||
<md-select-option value="@option.Value"> | ||
<div slot="headline">@option.Title</div> | ||
</md-select-option> | ||
} | ||
</md-filled-select> | ||
break; | ||
default: | ||
throw new ArgumentOutOfRangeException(nameof(TextFieldType), TextFieldType, null); | ||
|
||
} | ||
|
||
|
||
@code { | ||
[Parameter] [EditorRequired] public T Value { get; set; } = default!; | ||
|
||
[Parameter] [EditorRequired] public List<SelectOption> Options { get; set; } = null!; | ||
|
||
[Parameter] [EditorRequired] public EventCallback<T> ValueChanged { get; set; } | ||
|
||
[Parameter] public TextFieldType TextFieldType { get; set; } = TextFieldType.Outlined; | ||
|
||
[Parameter(CaptureUnmatchedValues = true)] public Dictionary<string, object>? AdditionalAttributes { get; set; } | ||
|
||
public record SelectOption(string Title, T Value); | ||
} |
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
Oops, something went wrong.