diff --git a/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner.slnx b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner.slnx
new file mode 100644
index 000000000..685fdbe04
--- /dev/null
+++ b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner.slnx
@@ -0,0 +1,3 @@
+
+
+
diff --git a/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner.csproj b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner.csproj
new file mode 100644
index 000000000..e31d2b818
--- /dev/null
+++ b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner.csproj
@@ -0,0 +1,24 @@
+
+
+
+ Exe
+ net10.0
+ CodingTracker.CSharpAcademy_Learner
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
diff --git a/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/Configuration.cs b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/Configuration.cs
new file mode 100644
index 000000000..332fcdfb3
--- /dev/null
+++ b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/Configuration.cs
@@ -0,0 +1,17 @@
+using Microsoft.Extensions.Configuration;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace CodingTracker.CSharpAcademy_Learner
+{
+ public static class Configuration
+ {
+ private static readonly IConfigurationRoot _config = new ConfigurationBuilder().SetBasePath(AppContext.BaseDirectory).AddJsonFile("appsettings.json", false, true).Build();
+
+ public static string GetConnectionString()
+ {
+ return _config.GetConnectionString("DefaultConnection") ?? "Data Source=coding-tracker.db";
+ }
+ }
+}
diff --git a/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/Controllers/CodingController.cs b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/Controllers/CodingController.cs
new file mode 100644
index 000000000..c5b99ae8a
--- /dev/null
+++ b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/Controllers/CodingController.cs
@@ -0,0 +1,53 @@
+using CodingTracker.CSharpAcademy_Learner.Models;
+using Dapper;
+using Microsoft.Data.Sqlite;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace CodingTracker.CSharpAcademy_Learner.Controllers
+{
+ internal class CodingController
+ {
+ internal List GetAllSessions()
+ {
+ using (var connection = new SqliteConnection(Configuration.GetConnectionString()))
+ {
+ var querySQL = "SELECT * FROM coding_sessions";
+ var sessions = connection.Query(querySQL).ToList();
+
+ return sessions;
+ }
+ }
+
+ internal void InsertSession(string startTime, string endTime, int duration)
+ {
+ using (var connection = new SqliteConnection(Configuration.GetConnectionString()))
+ {
+ var parameters = new { StartTime = startTime, EndTime = endTime, Duration = duration };
+ var insertSQL = "INSERT INTO coding_sessions(StartTime, EndTime, Duration) VALUES (@StartTime, @EndTime, @Duration)";
+ connection.Execute(insertSQL, parameters);
+ }
+ }
+
+ internal void UpdateSession(int sessionId, string startTime, string endTime, int duration)
+ {
+ using (var connection = new SqliteConnection(Configuration.GetConnectionString()))
+ {
+ var parameters = new { Id = sessionId, StartTime = startTime, EndTime = endTime, Duration = duration };
+ var updateSQL = "UPDATE coding_sessions SET StartTime = @StartTime, EndTime = @EndTime, Duration = @Duration WHERE Id = @Id";
+ connection.Execute(updateSQL, parameters);
+ }
+ }
+
+ internal void DeleteSession(int sessionId)
+ {
+ using (var connection = new SqliteConnection(Configuration.GetConnectionString()))
+ {
+ var parameters = new { Id = sessionId };
+ var deleteSQL = "DELETE FROM coding_sessions WHERE Id = @Id";
+ connection.Execute(deleteSQL, parameters);
+ }
+ }
+ }
+}
diff --git a/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/DatabaseManager.cs b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/DatabaseManager.cs
new file mode 100644
index 000000000..7401e6947
--- /dev/null
+++ b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/DatabaseManager.cs
@@ -0,0 +1,23 @@
+using Dapper;
+using Microsoft.Data.Sqlite;
+
+namespace CodingTracker.CSharpAcademy_Learner
+{
+ public static class DatabaseManager
+ {
+ public static void InitializeDatabase()
+ {
+ var createTableSQL = @"CREATE TABLE IF NOT EXISTS coding_sessions (
+ Id INTEGER PRIMARY KEY AUTOINCREMENT,
+ StartTime TEXT,
+ EndTime TEXT,
+ Duration INTEGER
+ )";
+
+ using (var connection = new SqliteConnection(Configuration.GetConnectionString()))
+ {
+ connection.Execute(createTableSQL);
+ }
+ }
+ }
+}
diff --git a/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/EnumExtensions.cs b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/EnumExtensions.cs
new file mode 100644
index 000000000..9ebc122b8
--- /dev/null
+++ b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/EnumExtensions.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Reflection;
+using System.Text;
+
+namespace CodingTracker.CSharpAcademy_Learner
+{
+ internal static class EnumExtensions
+ {
+ internal static string GetDisplayName(this Enum enumValue)
+ {
+ return enumValue.GetType().GetMember(enumValue.ToString()).FirstOrDefault()?.GetCustomAttribute()?.GetName() ?? enumValue.ToString();
+ }
+ }
+}
diff --git a/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/Enums.cs b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/Enums.cs
new file mode 100644
index 000000000..35ea99f12
--- /dev/null
+++ b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/Enums.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Text;
+
+namespace CodingTracker.CSharpAcademy_Learner
+{
+ internal class Enums
+ {
+ internal enum MenuAction
+ {
+ [Display(Name = "View Records")]
+ ViewRecords,
+
+ [Display(Name = "Add Record")]
+ AddRecord,
+
+ [Display(Name = "Update Record")]
+ UpdateRecord,
+
+ [Display(Name = "Delete Record")]
+ DeleteRecord,
+
+ [Display(Name = "Stopwatch")]
+ StopwatchService,
+ Exit
+ }
+ }
+}
diff --git a/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/Models/CodingSession.cs b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/Models/CodingSession.cs
new file mode 100644
index 000000000..c50ba8487
--- /dev/null
+++ b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/Models/CodingSession.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace CodingTracker.CSharpAcademy_Learner.Models
+{
+ internal class CodingSession
+ {
+ public int Id { get; set; }
+ public string StartTime { get; set; } = string.Empty;
+ public string EndTime { get; set; } = string.Empty;
+ public int Duration { get; set; } = 0;
+ }
+}
diff --git a/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/Program.cs b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/Program.cs
new file mode 100644
index 000000000..78a29e490
--- /dev/null
+++ b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/Program.cs
@@ -0,0 +1,7 @@
+using CodingTracker.CSharpAcademy_Learner;
+using CodingTracker.CSharpAcademy_Learner.Controllers;
+
+DatabaseManager.InitializeDatabase();
+var codingController = new CodingController();
+var userInterface = new UserInterface(codingController);
+userInterface.MainMenu();
\ No newline at end of file
diff --git a/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/README.md b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/README.md
new file mode 100644
index 000000000..417baf68f
--- /dev/null
+++ b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/README.md
@@ -0,0 +1,28 @@
+# Coding Tracker
+
+A console-based CRUD application to track coding sessions, written in C# and powered by SQLite.
+
+## How It Works
+
+The application connects to a local SQLite database using Dapper. Upon the very first execution, it automatically creates the coding_sessions table.
+The user can then add, view, update and delete records via the console.
+
+## Challenges Completed
+
+1. **Stopwatch**: Added the functionality of tracking the coding time via a stopwatch so the user can track the session as it happens.
+
+### What Was Easy?
+
+A lot of the concepts were carried on from the Habit Tracker, although they had to be separated instead of it all being in one big Program.cs file.
+
+### What Was Hard
+
+This was the first project without following a video tutorial, so I had find things out by searching online and reading through documentation. There were also quite a few new concepts.
+
+### What I Learned
+
+I got a better grasp of separation of concerns and how code in different files can interact with each other.
+
+### Extra Notes
+
+I probably got a bit acrried away with some things. For example, I preferred to use Enums for the menu options instead of hardcoded strings, this introduced a new issue of having the menu options look good, as Enums can't have spaces. I managed to find a way to use the Display Attribute instead. Also, I tried to make the application what I think is a bit more user friendly by giving the user the option to Escape to the main menu after selecting a menu option, in case they selected the wrong option.
diff --git a/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/StopwatchService.cs b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/StopwatchService.cs
new file mode 100644
index 000000000..9202cf002
--- /dev/null
+++ b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/StopwatchService.cs
@@ -0,0 +1,58 @@
+using CodingTracker.CSharpAcademy_Learner.Controllers;
+using Spectre.Console;
+using System.Diagnostics;
+
+namespace CodingTracker.CSharpAcademy_Learner
+{
+ internal class StopwatchService
+ {
+ private readonly CodingController _codingController;
+ public StopwatchService(CodingController codingController)
+ {
+ _codingController = codingController;
+ }
+ internal void TrackSession()
+ {
+
+ if (!UserInterfaceHelpers.WaitForEnterOrEscape_CheckForEnter("Tracking live session"))
+ {
+ return;
+ }
+
+ UserInterfaceHelpers.WaitForSpecificKey(ConsoleKey.Enter, "Press [green]ENTER[/] to start tracking.");
+
+ var stopwatch = Stopwatch.StartNew();
+ var startTime = DateTime.Now;
+
+ AnsiConsole.Status()
+ .Start("Tracking session... Press [green]ENTER[/] to stop...", ctx =>
+ {
+ while (!Console.KeyAvailable || Console.ReadKey(true).Key != ConsoleKey.Enter)
+ {
+ ctx.Status($"Tracking session... Elapsed time: {stopwatch.Elapsed:hh\\:mm\\:ss}... Press [green]ENTER[/] to stop...");
+ Thread.Sleep(500);
+ }
+ });
+
+ stopwatch.Stop();
+ var endTime = DateTime.Now;
+
+ var formattedStart = startTime.ToString(Validation.DatabaseDateFormat);
+ var formattedEnd = endTime.ToString(Validation.DatabaseDateFormat);
+ var duration = Validation.CalculateDurationInSeconds(startTime, endTime);
+
+ AnsiConsole.MarkupLine($"STOPPED. Start time: {formattedStart}. End time: {formattedEnd}. Duration: {duration} seconds");
+
+ if (AnsiConsole.Confirm("Do you want to save this session?"))
+ {
+ _codingController.InsertSession(formattedStart, formattedEnd, duration);
+ }
+ else
+ {
+ return;
+ }
+
+ Console.ReadKey();
+ }
+ }
+}
diff --git a/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/TableVisualisationEngine.cs b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/TableVisualisationEngine.cs
new file mode 100644
index 000000000..a9a668b64
--- /dev/null
+++ b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/TableVisualisationEngine.cs
@@ -0,0 +1,34 @@
+using CodingTracker.CSharpAcademy_Learner.Models;
+using Spectre.Console;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace CodingTracker.CSharpAcademy_Learner
+{
+ internal static class TableVisualisationEngine
+ {
+ internal static void DisplaySessions(List sessions)
+ {
+ var table = new Table();
+ table.Border(TableBorder.Rounded);
+
+ table.AddColumn("ID");
+ table.AddColumn("Start Date");
+ table.AddColumn("End Date");
+ table.AddColumn("Duration");
+
+ foreach(var session in sessions)
+ {
+ table.AddRow(
+ session.Id.ToString(),
+ session.StartTime,
+ session.EndTime,
+ Validation.ShowDurationInFriendlyFormat(session.Duration)
+ );
+ }
+
+ AnsiConsole.Write(table);
+ }
+ }
+}
diff --git a/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/UserInterface.cs b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/UserInterface.cs
new file mode 100644
index 000000000..c45e70df9
--- /dev/null
+++ b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/UserInterface.cs
@@ -0,0 +1,165 @@
+using CodingTracker.CSharpAcademy_Learner.Controllers;
+using CodingTracker.CSharpAcademy_Learner.Models;
+using Spectre.Console;
+using static CodingTracker.CSharpAcademy_Learner.Enums;
+using static System.Collections.Specialized.BitVector32;
+
+namespace CodingTracker.CSharpAcademy_Learner
+{
+ internal class UserInterface
+ {
+ private readonly CodingController _codingController;
+ private readonly StopwatchService _stopwatchService;
+
+ public UserInterface(CodingController codingController)
+ {
+ _codingController = codingController;
+ _stopwatchService = new StopwatchService(codingController);
+ }
+
+ internal void MainMenu()
+ {
+ bool closeApp = false;
+
+ while (!closeApp)
+ {
+ Console.Clear();
+
+ var choice = AnsiConsole.Prompt(
+ new SelectionPrompt()
+ .Title("[bold cyan]CODING TRACKER MENU[/]")
+ .UseConverter(choice => choice.GetDisplayName())
+ .AddChoices(Enum.GetValues())
+ );
+
+ switch (choice)
+ {
+ case MenuAction.ViewRecords:
+ ViewAllSessions();
+ break;
+ case MenuAction.AddRecord:
+ AddRecord();
+ break;
+ case MenuAction.UpdateRecord:
+ UpdateRecord();
+ break;
+ case MenuAction.DeleteRecord:
+ DeleteRecord();
+ break;
+ case MenuAction.StopwatchService:
+ _stopwatchService.TrackSession();
+ break;
+ case MenuAction.Exit:
+ AnsiConsole.MarkupLine("[cyan]Goodbye :)[/]");
+ closeApp = true;
+ Environment.Exit(0);
+ break;
+ }
+ }
+ }
+
+ private void ViewAllSessions()
+ {
+ var sessions = _codingController.GetAllSessions();
+
+ TableVisualisationEngine.DisplaySessions(sessions);
+
+ UserInterfaceHelpers.WaitForAnyKey();
+ }
+
+ private void AddRecord()
+ {
+ if(!UserInterfaceHelpers.WaitForEnterOrEscape_CheckForEnter("You are about to add a new record.")) { return; }
+
+ var sessionInfo = GetSessionInfoFromUserInput();
+
+ _codingController.InsertSession(sessionInfo.startDate.ToString(Validation.DatabaseDateFormat), sessionInfo.endDate.ToString(Validation.DatabaseDateFormat), sessionInfo.duration);
+
+ UserInterfaceHelpers.WaitForAnyKey();
+ }
+
+ private void UpdateRecord()
+ {
+ if (!UserInterfaceHelpers.WaitForEnterOrEscape_CheckForEnter("You are about to edit a record.")) { return; }
+
+ var selectedSession = SessionSelector("Choose a session to edit");
+
+ var sessionInfo = GetSessionInfoFromUserInput();
+
+ _codingController.UpdateSession(selectedSession.Id, sessionInfo.startDate.ToString(Validation.DatabaseDateFormat), sessionInfo.endDate.ToString(Validation.DatabaseDateFormat), sessionInfo.duration);
+
+ UserInterfaceHelpers.WaitForAnyKey();
+ }
+
+ private void DeleteRecord()
+ {
+ if (!UserInterfaceHelpers.WaitForEnterOrEscape_CheckForEnter("You are about to delete a record.")) { return; }
+
+ var selectedSession = SessionSelector("Choose a session to delete:");
+
+ AnsiConsole.MarkupLine(DisplaySessionInfo(selectedSession));
+
+ if (AnsiConsole.Confirm("Are you sure you want to delete this session?"))
+ {
+ _codingController.DeleteSession(selectedSession.Id);
+ AnsiConsole.MarkupLine("\nSucessfully deleted!");
+ }
+ else
+ {
+ AnsiConsole.MarkupLine("\nNOT DELETED");
+ }
+
+ UserInterfaceHelpers.WaitForAnyKey();
+ }
+
+ private DateTime GetDateInput(string prompt, DateTime? minDate = null)
+ {
+ while (true)
+ {
+ var dateInput = AnsiConsole.Ask($"[yellow]{prompt}[/]");
+
+ if (Validation.IsValidDate(dateInput, out DateTime parsedDate))
+ {
+ if (minDate.HasValue && !Validation.IsValidDateRange(minDate.Value, parsedDate))
+ {
+ AnsiConsole.MarkupLine("[red]Start date cannot be equal to or after the end date[/]");
+ continue;
+ }
+
+ return parsedDate;
+ }
+
+ AnsiConsole.MarkupLine("[red]Invalid format. Please use exactly dd-MM-yyyy HH:mm (e.g., 25-10-2026 14:30).[/]");
+ }
+ }
+
+ private CodingSession SessionSelector(string prompt)
+ {
+ var sessions = _codingController.GetAllSessions();
+
+ var selectedSession = AnsiConsole.Prompt(
+ new SelectionPrompt()
+ .Title(prompt)
+ .UseConverter(s => DisplaySessionInfo(s))
+ .AddChoices(sessions)
+ );
+
+ return selectedSession;
+ }
+
+ private (DateTime startDate, DateTime endDate, int duration) GetSessionInfoFromUserInput()
+ {
+ var startDate = GetDateInput("Enter the start date (use format dd/MM/yyyy HH:mm): ");
+ var endDate = GetDateInput("Enter the end date (use format dd/MM/yyyy HH:mm): ", startDate);
+
+ var duration = Validation.CalculateDurationInSeconds(startDate, endDate);
+
+ return (startDate, endDate, duration);
+ }
+
+ private string DisplaySessionInfo(CodingSession session)
+ {
+ return $"Start Time: {session.StartTime} - End Time: {session.EndTime} - Duration: {Validation.ShowDurationInFriendlyFormat(session.Duration)}";
+ }
+ }
+}
diff --git a/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/UserInterfaceHelpers.cs b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/UserInterfaceHelpers.cs
new file mode 100644
index 000000000..bab74d32b
--- /dev/null
+++ b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/UserInterfaceHelpers.cs
@@ -0,0 +1,45 @@
+using Spectre.Console;
+using SQLitePCL;
+using System;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using System.Text;
+
+namespace CodingTracker.CSharpAcademy_Learner
+{
+ internal static class UserInterfaceHelpers
+ {
+ internal static void WaitForAnyKey()
+ {
+ AnsiConsole.MarkupLine("[green]Press any key to continue...[/]");
+ Console.ReadKey();
+ }
+
+ internal static void WaitForSpecificKey(ConsoleKey key, string message)
+ {
+ AnsiConsole.MarkupLine(message);
+
+ while(Console.ReadKey(true).Key != key) { }
+ }
+
+ internal static bool WaitForEnterOrEscape_CheckForEnter(string? initialMessage = null)
+ {
+ if(initialMessage != null)
+ {
+ AnsiConsole.MarkupLine(initialMessage);
+ }
+
+ AnsiConsole.MarkupLine("Press [green]ENTER[/] to continue or [yellow]ESC[/] to go back to the main menu");
+
+ ConsoleKey key;
+
+ do
+ {
+ key = Console.ReadKey(true).Key;
+ }
+ while (key != ConsoleKey.Enter && key != ConsoleKey.Escape);
+
+ return key == ConsoleKey.Enter;
+ }
+ }
+}
diff --git a/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/Validation.cs b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/Validation.cs
new file mode 100644
index 000000000..24ed590ad
--- /dev/null
+++ b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/Validation.cs
@@ -0,0 +1,53 @@
+using Spectre.Console;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Text;
+
+namespace CodingTracker.CSharpAcademy_Learner
+{
+ internal static class Validation
+ {
+ internal const string ViewingDateFormat = "dd/MM/yyyy HH:mm";
+ internal const string DatabaseDateFormat = "dd/MM/yyyy HH:mm:ss";
+
+ internal static bool IsValidDate(string dateString, out DateTime parsedDate)
+ {
+ return DateTime.TryParseExact(dateString, ViewingDateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out parsedDate);
+ }
+
+ internal static bool IsValidDateRange(DateTime startDate, DateTime endDate)
+ {
+ return endDate > startDate;
+ }
+
+ internal static int CalculateDurationInSeconds(DateTime startDate, DateTime endDate)
+ {
+ return (int)(endDate - startDate).TotalSeconds;
+ }
+
+ internal static string ShowDurationInFriendlyFormat(int durationInSeconds)
+ {
+ var timeSpan = TimeSpan.FromSeconds(durationInSeconds);
+
+ var formattedDuration = "";
+
+ if (timeSpan.TotalHours >= 1)
+ {
+ int totalHours = (int)timeSpan.TotalHours;
+ formattedDuration += $"{totalHours} hour{(totalHours == 1 ? "" : "s")}, ";
+ }
+
+ if (timeSpan.Minutes >= 1)
+ {
+ int minutes = timeSpan.Minutes;
+ formattedDuration += $"{minutes} minute{(minutes == 1 ? "" : "s")}, ";
+ }
+
+ int seconds = timeSpan.Seconds;
+ formattedDuration += $"{seconds} second{(seconds == 1 ? "" : "s")}";
+
+ return formattedDuration;
+ }
+ }
+}
diff --git a/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/appsettings.json b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/appsettings.json
new file mode 100644
index 000000000..0908081bd
--- /dev/null
+++ b/CodingTracker.CSharpAcademy-Learner/CodingTracker.CSharpAcademy-Learner/appsettings.json
@@ -0,0 +1,5 @@
+{
+ "ConnectionStrings": {
+ "DefaultConnection": "Data Source=coding-tracker.db"
+ }
+}
\ No newline at end of file