Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 60 additions & 18 deletions KidsIdKit.Mobile/Data/DataAccessService.cs
Original file line number Diff line number Diff line change
@@ -1,42 +1,84 @@
using System.Text.Json;
using System.IO.Compression;

namespace KidsIdKit.Data
{
public class DataAccessService : IDataAccess
{
private static readonly string localApplicationDataFolder = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + Path.DirectorySeparatorChar;
private readonly string fileName = localApplicationDataFolder + "kidsidkitdata.dat";
private readonly string backupFileName = localApplicationDataFolder + "kidsidkitdata.bak";
// TODO: Could use reflection to derive the name of the project
private const string projectName = "kidsidkitdata";

public Task<Family?> GetDataAsync()
//-----------------------------------------------------------------------------------------------------------------------------------
// An enumeration member in the.NET framework's System.Environment class. It represents a special folder on the user's system
// specifically designated for storing application-specific data that is local to the current user and not intended to roam
// between different machines or profiles.
//
// The directory that serves as a common repository for application-specific data for the current, non-roaming user.
private const Environment.SpecialFolder appSpecificDataDirForCurrentNonRoamingUser = Environment.SpecialFolder.LocalApplicationData;
//-----------------------------------------------------------------------------------------------------------------------------------
private static readonly string localApplicationDataFolder = Environment.GetFolderPath(appSpecificDataDirForCurrentNonRoamingUser) +
Path.DirectorySeparatorChar;

private readonly string zipFileName = localApplicationDataFolder + projectName + ".zip";
private readonly string jsonFileName = projectName + ".dat";
private readonly string backupZipFileName = localApplicationDataFolder + projectName + ".bak.zip";

public async Task<Family?> GetDataAsync()
{
try
{
if (File.Exists(fileName))
{
var json = File.ReadAllText(fileName);
// TODO: add decryption
return Task.FromResult(JsonSerializer.Deserialize<Family>(json));
}
else
//File.Delete(zipFileName); // DEVELOPMENT CODE ONLY (in case you need to start with a tabula rasa)

if (File.Exists(zipFileName))
{
return Task.FromResult<Family?>(new Family());
// Unzip the file to a memory stream and read the JSON
using var zipFileStream = File.OpenRead(zipFileName);
using var zipArchiveEntry = new ZipArchive(zipFileStream, ZipArchiveMode.Read);
var entry = zipArchiveEntry.GetEntry(jsonFileName);
if (entry != null)
{
using var stream = entry.Open();
using var streamReader = new StreamReader(stream);
var jsonString = await streamReader.ReadToEndAsync();
// TODO: add decryption
return JsonSerializer.Deserialize<Family>(jsonString);
}
}

return new Family();
}
catch
{
return Task.FromResult<Family?>(new Family());
return new Family();
}
}

public Task SaveDataAsync(Family data)
public async Task SaveDataAsync(Family data)
{
if (File.Exists(fileName))
File.Copy(fileName, backupFileName, true);
if (File.Exists(zipFileName))
{
File.Copy(zipFileName, backupZipFileName, true);
}

var json = JsonSerializer.Serialize(data);
// TODO: add encryption
File.WriteAllText(fileName, json);
return Task.CompletedTask;

// Write JSON to a memory stream
using var memoryStream = new MemoryStream();

// Zip it, zip it good ...
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
var zipArchiveEntry = archive.CreateEntry(jsonFileName, CompressionLevel.Optimal);
using var entryStream = zipArchiveEntry.Open();
using var streamWriter = new StreamWriter(entryStream);
await streamWriter.WriteAsync(json);
}

// Save the zip file
using var zipFileStream = File.Create(zipFileName);
memoryStream.Seek(0, SeekOrigin.Begin);
await memoryStream.CopyToAsync(zipFileStream);
}
}
}
3 changes: 3 additions & 0 deletions KidsIdKit.Mobile/KidsIdKit.Mobile.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@
</ItemGroup>

<ItemGroup>
<Content Update="wwwroot\Kid.ico">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\PdfGenerator\HtmlToPdf.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
Expand Down
4 changes: 3 additions & 1 deletion KidsIdKit.Mobile/ReadMe.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
KidsIdKit.Mobile is actually for both Mobile and Desktop platforms.
KidsIdKit.Mobile is a .NET MAUI Blazor Hybrid app.

Even though the name suggests it's only for mobile devices, .NET MAUI allows it to run on both mobile and desktop platforms.

As a result, it could be renamed to something more comprehensive, such as:
- KidsIdKit.MobileAndDesktop or
Expand Down
Binary file added KidsIdKit.Mobile/wwwroot/Information-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added KidsIdKit.Mobile/wwwroot/Kid.ico
Binary file not shown.
12 changes: 10 additions & 2 deletions KidsIdKit.Shared/Shared/NavMenu.razor
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,21 @@
<nav class="flex-column">
<div class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="oi oi-home" aria-hidden="true"></span> Kids
<span style="display: inline-flex; align-items: center;">
<img src="Kid.ico" alt="Picture of 2 kids" width="64" height="64" class="ms-2 me-2" />
@* <img src="Kids.png" alt="Picture of 2 kids" width="64" height="64" class="ms-2 me-2" /> *@
Kids
</span>

</NavLink>
</div>

<div class="nav-item px-3">
<NavLink class="nav-link" href="Information">
<span class="oi oi-list-rich" aria-hidden="true"></span> Information
<span style="display: inline-flex; align-items: center;">
<img src="Information-icon.png" alt="Information icon" width="64" height="64" class="ms-2 me-2" />
Information
</span>
</NavLink>
</div>
</nav>
Expand Down
40 changes: 33 additions & 7 deletions KidsIdKit.Web/Data/DataAccessService.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,32 @@
using System.Text.Json;
using Blazored.LocalStorage;
using ICSharpCode.SharpZipLib.Zip;
using System.Text.Json;

namespace KidsIdKit.Data
{
public class DataAccessService(Blazored.LocalStorage.ILocalStorageService localStorage) : IDataAccess
public class DataAccessService(ILocalStorageService localStorage) : IDataAccess
{
private const string ZipKey = "familyZip";
private const string EntryName = "family.json";

public async Task<Family?> GetDataAsync()
{
try
{
var json = await localStorage.GetItemAsync<string>("family");
if (!string.IsNullOrEmpty(json))
var zipBytes = await localStorage.GetItemAsync<byte[]>(ZipKey);
if (zipBytes != null && zipBytes.Length > 0)
{
// TODO: add decryption
return JsonSerializer.Deserialize<Family>(json);
using var zipStream = new MemoryStream(zipBytes);
using var zipFile = new ZipFile(zipStream);
var entry = zipFile.GetEntry(EntryName);
if (entry != null)
{
using var entryStream = zipFile.GetInputStream(entry);
using var streamReader = new StreamReader(entryStream);
var json = await streamReader.ReadToEndAsync();
// TODO: add decryption
return JsonSerializer.Deserialize<Family>(json);
}
}
return new Family();
}
Expand All @@ -26,7 +40,19 @@ public async Task SaveDataAsync(Family data)
{
var json = JsonSerializer.Serialize(data);
// TODO: add encryption
await localStorage.SetItemAsync("family", json);

using var memStream = new MemoryStream();
using (var zipStream = new ZipOutputStream(memStream))
{
var entry = new ZipEntry(EntryName);
zipStream.PutNextEntry(entry);
var jsonBytes = System.Text.Encoding.UTF8.GetBytes(json);
await zipStream.WriteAsync(jsonBytes, 0, jsonBytes.Length);
zipStream.CloseEntry();
zipStream.IsStreamOwner = false;
zipStream.Finish();
}
await localStorage.SetItemAsync(ZipKey, memStream.ToArray());
}
}
}
7 changes: 7 additions & 0 deletions KidsIdKit.Web/KidsIdKit.Web.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.10" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.10" PrivateAssets="all" />
<PackageReference Include="SharpZipLib" Version="1.4.2" />
</ItemGroup>

<ItemGroup>
Expand All @@ -25,6 +26,12 @@
<Content Update="wwwroot/index.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\Kid.ico">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\Kids.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 2 additions & 0 deletions KidsIdKit.Web/ReadMe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
KidsIdKit.Web is a WASM (WebAssembly) app built with Blazor - it's designed to run in web browsers (it's primarily useful for testers of the app since it does not require that
the mobile version be installed on their Android or iPhone).
Binary file added KidsIdKit.Web/wwwroot/Information-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added KidsIdKit.Web/wwwroot/Kid.ico
Binary file not shown.
Binary file added KidsIdKit.Web/wwwroot/Kids.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.