diff --git a/.gitignore b/.gitignore index 49976e11..94e93c97 100644 --- a/.gitignore +++ b/.gitignore @@ -478,3 +478,6 @@ $RECYCLE.BIN/ *.lnk /MathGame2 /CodingTracker.TomDonegan/TextFile1.txt + +# DB +*.db \ No newline at end of file diff --git a/Tenebris-06.CodingTracker/CodingTracker.csproj b/Tenebris-06.CodingTracker/CodingTracker.csproj new file mode 100644 index 00000000..12273964 --- /dev/null +++ b/Tenebris-06.CodingTracker/CodingTracker.csproj @@ -0,0 +1,24 @@ + + + + Exe + net10.0 + enable + enable + + + + + + + + + + + + + PreserveNewest + + + + diff --git a/Tenebris-06.CodingTracker/Data/DataAccess.cs b/Tenebris-06.CodingTracker/Data/DataAccess.cs new file mode 100644 index 00000000..dccc7e11 --- /dev/null +++ b/Tenebris-06.CodingTracker/Data/DataAccess.cs @@ -0,0 +1,72 @@ +using System.Collections.Immutable; +using Microsoft.Data.Sqlite; +using Dapper; + +public class DataAccess +{ + string _ConnectionString; + + public DataAccess(string Connectionstring) + { + _ConnectionString = Connectionstring; + } + + public void Initialize() + { + using var connection = new SqliteConnection(_ConnectionString); + connection.Open(); + + connection.Execute(""" + CREATE TABLE IF NOT EXISTS CodingSessions( + Id INTEGER PRIMARY KEY AUTOINCREMENT, + StartTime TEXT NOT NULL, + EndTime TEXT NOT NULL, + Duration TEXT NOT NULL, + Description TEXT) + """); + } + + public void CreateSession(Session session) + { + var sql = """ + INSERT INTO CodingSessions (StartTime, EndTime, Duration, Description) + VALUES (@StartTime, @EndTime, @Duration, @Description) + """; + using var connection = new SqliteConnection(_ConnectionString); + connection.Execute(sql, session); + } + + public void DeleteSession(int SessionId) + { + var sql = """ + DELETE FROM CodingSessions WHERE Id = @Id + """; + using var connection = new SqliteConnection(_ConnectionString); + connection.Execute(sql, new {Id = SessionId}); + } + + public void UpdateSession(Session session) + { + var sql = """ + UPDATE CodingSessions + SET StartTime = @StartTime, EndTime = @EndTime, + Duration = @Duration, Description = @Description + WHERE + Id = @Id + """; + using var connection = new SqliteConnection(_ConnectionString); + connection.Execute(sql, session); + } + + public List ReadSessions() + { + var sql = """ + SELECT * FROM CodingSessions + """; + using var connection = new SqliteConnection(_ConnectionString); + + var sessions = connection.Query(sql); + + return sessions.ToList(); + } +} \ No newline at end of file diff --git a/Tenebris-06.CodingTracker/Helpers/DateTimeHelper.cs b/Tenebris-06.CodingTracker/Helpers/DateTimeHelper.cs new file mode 100644 index 00000000..6f36cf25 --- /dev/null +++ b/Tenebris-06.CodingTracker/Helpers/DateTimeHelper.cs @@ -0,0 +1,23 @@ +using System.Globalization; +using System.Security.Cryptography.X509Certificates; +using Spectre.Console; + +public static class DateTimeHelper{ + public static bool TryGetDateTime(string input, out DateTime result) +{ + if (string.IsNullOrWhiteSpace(input)) + { + result = DateTime.Now; + return true; + } + + return DateTime.TryParseExact( + input, + "yyyy-MM-dd HH:mm:ss", + CultureInfo.InvariantCulture, + DateTimeStyles.None, + out result + ); +} + +} \ No newline at end of file diff --git a/Tenebris-06.CodingTracker/Helpers/TimeSpanHandler.cs b/Tenebris-06.CodingTracker/Helpers/TimeSpanHandler.cs new file mode 100644 index 00000000..adc68938 --- /dev/null +++ b/Tenebris-06.CodingTracker/Helpers/TimeSpanHandler.cs @@ -0,0 +1,15 @@ +using System.Data; +using Dapper; + +public class TimeSpanHandler : SqlMapper.TypeHandler +{ + public override void SetValue(IDbDataParameter parameter, TimeSpan value) + { + parameter.Value = value.ToString(@"hh\:mm\:ss"); + } + + public override TimeSpan Parse(object value) + { + return TimeSpan.Parse(value.ToString()!); + } +} \ No newline at end of file diff --git a/Tenebris-06.CodingTracker/Models/Session.cs b/Tenebris-06.CodingTracker/Models/Session.cs new file mode 100644 index 00000000..bd81005b --- /dev/null +++ b/Tenebris-06.CodingTracker/Models/Session.cs @@ -0,0 +1,8 @@ +public class Session +{ + public int Id { get; set; } + public DateTime StartTime { get; set; } + public DateTime EndTime { get; set; } + public TimeSpan Duration { get; set; } + public string? Description { get; set; } +} \ No newline at end of file diff --git a/Tenebris-06.CodingTracker/Program.cs b/Tenebris-06.CodingTracker/Program.cs new file mode 100644 index 00000000..e4795dc9 --- /dev/null +++ b/Tenebris-06.CodingTracker/Program.cs @@ -0,0 +1,24 @@ +using System; +using Dapper; +using Microsoft.Extensions.Configuration; +using Spectre.Console; + +class Program { + static void Main(string[] args) + { + + SqlMapper.AddTypeHandler(new TimeSpanHandler()); + + var configuration = new ConfigurationBuilder() + .SetBasePath(AppContext.BaseDirectory) + .AddJsonFile("appsettings.json") + .Build(); + + DataAccess db = new DataAccess(configuration["Database:ConnectionString"]); + db.Initialize(); + + var UI = new Menu(db); + UI.MainMenu(); + + } +} \ No newline at end of file diff --git a/Tenebris-06.CodingTracker/Services/SessionService.cs b/Tenebris-06.CodingTracker/Services/SessionService.cs new file mode 100644 index 00000000..e44159a5 --- /dev/null +++ b/Tenebris-06.CodingTracker/Services/SessionService.cs @@ -0,0 +1,24 @@ +public class SessionService +{ + public DateTime startTime; + public void StartSession() + { + startTime = DateTime.Now; + } + + public Session EndSession() + { + DateTime endTime = DateTime.Now; + return new Session + { + StartTime = startTime, + EndTime = endTime, + Duration = endTime - startTime + }; + } + + public TimeSpan GetElapsedTime() + { + return DateTime.Now - startTime; + } +} \ No newline at end of file diff --git a/Tenebris-06.CodingTracker/UI/Menu.cs b/Tenebris-06.CodingTracker/UI/Menu.cs new file mode 100644 index 00000000..a7bba1f6 --- /dev/null +++ b/Tenebris-06.CodingTracker/UI/Menu.cs @@ -0,0 +1,238 @@ +using System.Formats.Asn1; +using Spectre.Console; +public class Menu +{ + private readonly DataAccess _db; + public Menu(DataAccess db) + { + _db = db; + } + public void MainMenu() + { + + while (true) + { + Console.Clear(); + // AnsiConsole.MarkupLine("[green] Coding Tracker[/]").Centered(); + + AnsiConsole.Write( + new Align( + new Markup("[green]Coding Tracker[/]"), + HorizontalAlignment.Center + ) + ); + + + var choice = AnsiConsole.Prompt( + new SelectionPrompt() + .Title("Select an option: ") + .AddChoices("Add a Session", "Delete a Session", "View All Sessions", + "Start a Session with a Timer") + ); + + switch (choice) + { + case "Add a Session": + AddSessionMenu(); + break; + + case "Delete a Session": + DeleteSessionMenu(); + break; + + case "View All Sessions": + ViewSessionsMenu(); + break; + + case "Start a Session with a Timer": + StartSessionMenu(); + break; + + default: + AnsiConsole.MarkupLine("[yellow] Please choose an option[/]"); + continue; + } + } + } + + public void AddSessionMenu() + { + Console.Clear(); + while (true) + { + DateTime startTime; + DateTime endTime; + + AnsiConsole.MarkupLine("Enter Dates and Times in this format [green]yyyy-MM-dd HH:mm:ss[/]"); + AnsiConsole.MarkupLine("[yellow] Or leave empty to enter the current datetime! [/]"); + + while (true) + { + string input = AnsiConsole.Prompt( + new TextPrompt("Enter the start time:") + .AllowEmpty() + ); + + if (DateTimeHelper.TryGetDateTime(input, out startTime)) + break; + + AnsiConsole.MarkupLine( + "[red]Invalid input, please try again.[/]" + ); + } + + while (true) + { + string input = AnsiConsole.Prompt( + new TextPrompt("Enter the end time:") + .AllowEmpty() + ); + + if (DateTimeHelper.TryGetDateTime(input, out endTime)) + break; + + AnsiConsole.MarkupLine( + "[red]Invalid input, please try again.[/]" + ); + } + + TimeSpan duration = endTime - startTime; + string description = AnsiConsole.Prompt( + new TextPrompt("Enter a Description or a Note [yellow](optional)[/]") + .AllowEmpty() + ); + + if (AnsiConsole.Confirm("Add Session?")) + { + _db.CreateSession(new Session { StartTime = startTime, EndTime = endTime, + Duration = duration, Description = description}); + + AnsiConsole.MarkupLine("[green]Session Added[/]"); + + break; + } else + { + break; + } + } + + + + } + + public void DeleteSessionMenu() + { + Console.Clear(); + + List sessions = _db.ReadSessions(); + AnsiConsole.MarkupLine("Enter the [blue]ID[/] of the session you would like to delete:"); + DisplayTable(sessions); + + while (true) + { + int IdToDelete = AnsiConsole.Ask("ID:"); + + + if (sessions.Any(s => s.Id == IdToDelete) + && AnsiConsole.Confirm("Delete session?") + ) + { + _db.DeleteSession(IdToDelete); + AnsiConsole.MarkupLine("[green]Session Deleted[/]"); + break; + } else + { + AnsiConsole.MarkupLine("[red]Session does not exist, please try again.[/]"); + continue; + } + } + + } + + public void ViewSessionsMenu() + { + Console.Clear(); + + List sessions = _db.ReadSessions(); + DisplayTable(sessions); + AnsiConsole.MarkupLine("Press [blue]ESC[/] to go back"); + + while (Console.ReadKey(true).Key != ConsoleKey.Escape) + { + + } + } + + public void StartSessionMenu() + { + Console.Clear(); + SessionService stopWatchData = new SessionService(); + stopWatchData.StartSession(); + while (true) + { + Console.Clear(); + var stopWatch = new Panel( + new Rows( + new Markup(" "), + new Markup($"[bold green]{stopWatchData.GetElapsedTime() + .ToString(@"hh\:mm\:ss")}[/]").Centered(), + new Markup(" "), + new Markup("[yellow]Press ESC to stop[/]").Centered() + ) + ) + .Header("[bold blue] Live Session [/]", Justify.Center) + .DoubleBorder() + .Expand(); + + AnsiConsole.Write(stopWatch); + + if (Console.KeyAvailable) + { + var key = Console.ReadKey(true); + + if (key.Key == ConsoleKey.Escape) + { + if (AnsiConsole.Confirm("[bold] Add this session? [/]")) + { + string description = AnsiConsole.Prompt( + new TextPrompt("Enter a Description or a Note [yellow](optional)[/]") + .AllowEmpty() + ); + Session s = stopWatchData.EndSession(); + s.Description = description; + _db.CreateSession(s); + AnsiConsole.MarkupLine("[bold green] Session Created![/]"); + } + Console.Clear(); + break; + } + } + + Thread.Sleep(1000); + + } + } + public void DisplayTable(List list) + { + var table = new Table() + .Title("[green]Session List[/]"); + + table.AddColumn("ID") + .AddColumn("Start Time") + .AddColumn("End Time") + .AddColumn("Duration") + .AddColumn("Description"); + + foreach (var v in list) + { + table.AddRow( + v.Id.ToString(), + v.StartTime.ToString("yyyy-MM-dd HH:mm:ss"), + v.EndTime.ToString("yyyy-MM-dd HH:mm:ss"), + v.Duration.ToString(@"hh\:mm\:ss"), + v.Description ?? "" + ); + } + AnsiConsole.Write(table); + } +} \ No newline at end of file diff --git a/Tenebris-06.CodingTracker/appsettings.json b/Tenebris-06.CodingTracker/appsettings.json new file mode 100644 index 00000000..8d3e2aff --- /dev/null +++ b/Tenebris-06.CodingTracker/appsettings.json @@ -0,0 +1,6 @@ +{ + "AppName": "Coding Tracker", + "Database": { + "ConnectionString": "Data Source=app.db" + } +} \ No newline at end of file