From 22b1ecce6bb2f9918dec55c78b4cec761aba21aa Mon Sep 17 00:00:00 2001 From: Ledana Date: Mon, 13 Apr 2026 11:13:49 +0200 Subject: [PATCH 1/5] Added my project --- StackFlashcards.Ledana/.gitattributes | 63 +++ StackFlashcards.Ledana/.gitignore | 363 ++++++++++++++++++ StackFlashcards.Ledana/App.config | 6 + StackFlashcards.Ledana/Flashcard.cs | 18 + StackFlashcards.Ledana/Program.cs | 14 + StackFlashcards.Ledana/README.md | 1 + StackFlashcards.Ledana/Stack.cs | 8 + .../StackFlashcardServices.cs | 216 +++++++++++ StackFlashcards.Ledana/StackFlashcards.csproj | 18 + StackFlashcards.Ledana/StackFlashcards.slnx | 3 + StackFlashcards.Ledana/StudySession.cs | 21 + StackFlashcards.Ledana/TableVisualisation.cs | 73 ++++ StackFlashcards.Ledana/UI.cs | 320 +++++++++++++++ 13 files changed, 1124 insertions(+) create mode 100644 StackFlashcards.Ledana/.gitattributes create mode 100644 StackFlashcards.Ledana/.gitignore create mode 100644 StackFlashcards.Ledana/App.config create mode 100644 StackFlashcards.Ledana/Flashcard.cs create mode 100644 StackFlashcards.Ledana/Program.cs create mode 100644 StackFlashcards.Ledana/README.md create mode 100644 StackFlashcards.Ledana/Stack.cs create mode 100644 StackFlashcards.Ledana/StackFlashcardServices.cs create mode 100644 StackFlashcards.Ledana/StackFlashcards.csproj create mode 100644 StackFlashcards.Ledana/StackFlashcards.slnx create mode 100644 StackFlashcards.Ledana/StudySession.cs create mode 100644 StackFlashcards.Ledana/TableVisualisation.cs create mode 100644 StackFlashcards.Ledana/UI.cs diff --git a/StackFlashcards.Ledana/.gitattributes b/StackFlashcards.Ledana/.gitattributes new file mode 100644 index 00000000..1ff0c423 --- /dev/null +++ b/StackFlashcards.Ledana/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/StackFlashcards.Ledana/.gitignore b/StackFlashcards.Ledana/.gitignore new file mode 100644 index 00000000..9491a2fd --- /dev/null +++ b/StackFlashcards.Ledana/.gitignore @@ -0,0 +1,363 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd \ No newline at end of file diff --git a/StackFlashcards.Ledana/App.config b/StackFlashcards.Ledana/App.config new file mode 100644 index 00000000..b8f5657f --- /dev/null +++ b/StackFlashcards.Ledana/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/StackFlashcards.Ledana/Flashcard.cs b/StackFlashcards.Ledana/Flashcard.cs new file mode 100644 index 00000000..033b4fe2 --- /dev/null +++ b/StackFlashcards.Ledana/Flashcard.cs @@ -0,0 +1,18 @@ +namespace StackFlashcards +{ + internal class Flashcard + { + public int Id { get; set; } + public int StackId { get; set; } + public string Front { get; set; } = null!; + public string Back { get; set; } = null!; + } + + internal class FlashcardDto + { + public int Id { get; set; } + public string Front { get; set; } = null!; + public string Back { get; set; } = null!; + public int RowNum { get; set; } + } +} \ No newline at end of file diff --git a/StackFlashcards.Ledana/Program.cs b/StackFlashcards.Ledana/Program.cs new file mode 100644 index 00000000..dcf11e19 --- /dev/null +++ b/StackFlashcards.Ledana/Program.cs @@ -0,0 +1,14 @@ +namespace StackFlashcards +{ + internal class Program + { + static void Main(string[] args) + { + Console.WriteLine("Welcome in our Application"); + UI ui = new(); + ui.WelcomeUser(); + + Console.WriteLine("Good bye"); + } + } +} diff --git a/StackFlashcards.Ledana/README.md b/StackFlashcards.Ledana/README.md new file mode 100644 index 00000000..692915fb --- /dev/null +++ b/StackFlashcards.Ledana/README.md @@ -0,0 +1 @@ +# StackFlashcards \ No newline at end of file diff --git a/StackFlashcards.Ledana/Stack.cs b/StackFlashcards.Ledana/Stack.cs new file mode 100644 index 00000000..4412ff8f --- /dev/null +++ b/StackFlashcards.Ledana/Stack.cs @@ -0,0 +1,8 @@ +namespace StackFlashcards +{ + internal class Stack + { + public int Id { get; set; } + public string Name { get; set; } = null!; + } +} \ No newline at end of file diff --git a/StackFlashcards.Ledana/StackFlashcardServices.cs b/StackFlashcards.Ledana/StackFlashcardServices.cs new file mode 100644 index 00000000..c165eaa7 --- /dev/null +++ b/StackFlashcards.Ledana/StackFlashcardServices.cs @@ -0,0 +1,216 @@ +using Dapper; +using Microsoft.Data.SqlClient; +using System.Configuration; + +namespace StackFlashcards +{ + internal class StackFlashcardServices + { + readonly string connectionString = ConfigurationManager.AppSettings.Get("ConnectionString"); + + //creating a new flashcard in a new stack + internal void CreateFlashCard(string name, string front, string back) + { + using SqlConnection connection = new(connectionString); + + Stack? stack = GetStackByName(name); + + var createFlashcardQuery = @"INSERT INTO Flashcard (StackId, Front, Back) + VALUES (@StackId, @Front, @Back)"; + + connection.Execute(createFlashcardQuery, new { StackId = stack.Id, Front = front, Back = back }); + } + + //creating a new stack with name + internal void CreateStack(string name) + { + using SqlConnection connection = new(connectionString); + + var createStackQuery = "INSERT INTO Stack ([Name]) VALUES (@Name)"; + + connection.Execute(createStackQuery, new { Name = name }); + } + + //deleting a stack with ame + internal void DeleteStack(string name) + { + using SqlConnection connection = new(connectionString); + + var deleteStackQuery = "DELETE FROM Stack WHERE [Name] = @Name"; + + connection.Execute(deleteStackQuery, new { Name = name }); + } + + //getting all the flashcards in the db with their true id + internal List GetAllFlashcards() + { + using SqlConnection connection = new(connectionString); + + var getAllFlashcardsQuery = "SELECT ROW_NUMBER() OVER (ORDER BY Id) AS RowNum, Id, Front, Back FROM Flashcard"; + + return connection.Query(getAllFlashcardsQuery).ToList(); + } + + //getting the number of flashcards in a stack to calculate score + internal int? GetFlashcardNumber(string name) + { + using SqlConnection connection = new(connectionString); + + Stack? stack = GetStackByName(name); + if (stack is null) return null; + + var getFlashcardCountQuery = "SELECT COUNT(*) FROM Flashcard WHERE StackId = @StackId"; + + return connection.ExecuteScalar(getFlashcardCountQuery, new { StackId = stack.Id }); + } + + //getting the front part of a card to show to user when in study session + internal string? GetFront(string name, int id) + { + using SqlConnection connection = new(connectionString); + + Stack? stack = GetStackByName(name); + if (stack is null) return null; + + var flashcards = GetFlashcardsByStackId(stack.Id); + var card = flashcards.FirstOrDefault(f => f.RowNum == id); + + return card?.Front; + } + //getting the back side of the card to show it to user + internal string? GetRightAnswer(string name, int id) + { + using SqlConnection connection = new(connectionString); + + Stack? stack = GetStackByName(name); + if (stack is null) return null; + + var flashcards = GetFlashcardsByStackId(stack.Id); + var card = flashcards.FirstOrDefault(f => f.RowNum == id); + + return card?.Back; + } + + //helper method to get a stack by id + internal List GetFlashcardsByStackId(int Id) + { + using SqlConnection connection = new(connectionString); + var getFlashcardsQuery = "SELECT ROW_NUMBER() OVER (ORDER BY Id) AS RowNum, Id, Front, Back FROM Flashcard WHERE StackId = @StackId"; + + return connection.Query(getFlashcardsQuery, new { StackId = Id }).ToList(); + } + + //getting all study sessions with a query with joins so other details show also + internal List GetStudySessionsDetails() + { + using SqlConnection connection = new(connectionString); + + var getStudySessionDetailsQuery = "SELECT s.[Name], f.Front, f.Back, ss.[Date], ss.Score\r\nFROM StudySessions ss\r\nJOIN Stack s ON s.Id = ss.StackId\r\nJOIN Flashcard f ON f.StackId = s.Id"; + + return connection.Query(getStudySessionDetailsQuery).ToList(); + } + + //inserting a new row in studysessions with the stackid, date and score + internal void OpenStudySession(string name, DateTime date, string score) + { + using SqlConnection connection = new(connectionString); + + Stack? stack = GetStackByName(name); + if (stack is null) + { + Console.WriteLine("Stack not found"); + return; + } + + var insertQuery = "INSERT INTO StudySessions (Date, StackId, Score) VALUES (@Date, @StackId, @Score)"; + + connection.Execute(insertQuery, new StudySession() { Date = date, StackId = stack.Id, Score = score }); + } + + //comparig the back side of the card with the given answer by user with the name of stack, rownum shown as id. + internal bool ValidateAnswer(string name, int id, string answer) + { + using SqlConnection connection = new(connectionString); + + Stack? stack = GetStackByName(name); + + var getFlashcardsQuery = "SELECT ROW_NUMBER() OVER (ORDER BY Id) AS RowNum, Front, Back FROM Flashcard WHERE StackId = @StackId"; + var flashcards = connection.Query(getFlashcardsQuery, new { StackId = stack.Id }).ToList(); + var card = flashcards.FirstOrDefault(f => f.RowNum == id); + + return answer == card?.Back; + } + //checking if id form user matches any card with rownum as id when deleting or vstuding + internal bool ValidateIdInput(string name, int num) + { + using SqlConnection connection = new(connectionString); + + Stack? stack = GetStackByName(name); + + var getFlashcardsQuery = "SELECT ROW_NUMBER() OVER (ORDER BY Id) AS RowNum, Front, Back FROM Flashcard WHERE StackId = @StackId"; + + var flashcards = connection.Query(getFlashcardsQuery, new { StackId = stack.Id }).ToList(); + + return flashcards.Any(c => c.RowNum == num); + } + //checking if stack name is in the db + internal bool ValidateStackName(string name) + { + using SqlConnection connection = new(connectionString); + + var checkNamesQuery = "SELECT COUNT(*) FROM Stack WHERE [Name] = @Name"; + + var nameExists = connection.ExecuteScalar(checkNamesQuery, new { Name = name }); + + return nameExists > 0; + } + //getting the list of all stacks in db + internal List ViewStackList() + { + using SqlConnection connection = new(connectionString); + + var getStackListQuery = "SELECT * FROM Stack ORDER BY Id"; + + return connection.Query(getStackListQuery).ToList(); + } + //getting the list of cards in a stack given its name + internal List? GetStack(string name) + { + using SqlConnection connection = new(connectionString); + + Stack? stack = GetStackByName(name); + if (stack is null) return null; + + var getFlashcardQuery = "SELECT ROW_NUMBER() OVER (ORDER BY Id) AS RowNum, Front FROM Flashcard WHERE StackId = @StackId"; + + return connection.Query(getFlashcardQuery, new { StackId = stack.Id }).ToList(); + } + //helper method to get a stack by its name + internal Stack? GetStackByName(string name) + { + using SqlConnection connection = new(connectionString); + + var getStackQuery = "SELECT * FROM Stack WHERE [Name] = @Name"; + + return connection.QuerySingleOrDefault(getStackQuery, new { Name = name }); + } + + //deleting a row in flashcard table given the id + internal void DeleteFlashcard(string name, int id) + { + using SqlConnection connection = new(connectionString); + + Stack? stack = GetStackByName(name); + + var getFlashcardsQuery = "SELECT ROW_NUMBER() OVER (ORDER BY Id) AS RowNum, Id, Front, Back FROM Flashcard WHERE StackId = @StackId"; + List cards = connection.Query(getFlashcardsQuery, new { StackId = stack.Id }).ToList(); + + var cardToDelete = cards.FirstOrDefault(f => f.RowNum == id); + + var deleteFlashcardQuery = "DELETE FROM Flashcard WHERE Id = @Id"; + + connection.Execute(deleteFlashcardQuery, new { Id = cardToDelete.Id }); + } + + } +} \ No newline at end of file diff --git a/StackFlashcards.Ledana/StackFlashcards.csproj b/StackFlashcards.Ledana/StackFlashcards.csproj new file mode 100644 index 00000000..b976e5c3 --- /dev/null +++ b/StackFlashcards.Ledana/StackFlashcards.csproj @@ -0,0 +1,18 @@ + + + + Exe + net10.0 + enable + enable + + + + + + + + + + + diff --git a/StackFlashcards.Ledana/StackFlashcards.slnx b/StackFlashcards.Ledana/StackFlashcards.slnx new file mode 100644 index 00000000..ae8c5998 --- /dev/null +++ b/StackFlashcards.Ledana/StackFlashcards.slnx @@ -0,0 +1,3 @@ + + + diff --git a/StackFlashcards.Ledana/StudySession.cs b/StackFlashcards.Ledana/StudySession.cs new file mode 100644 index 00000000..d726f7ea --- /dev/null +++ b/StackFlashcards.Ledana/StudySession.cs @@ -0,0 +1,21 @@ +namespace StackFlashcards +{ + internal class StudySession + { + public int Id { get; set; } + public DateTime Date { get; set; } + public string? Score { get; set; } + public int StackId { get; set; } + } + //creating another class for studysessions so when showing the list show other details from stack and cards with the right query + internal class StudySessionDetails + { + public int Id { get; set; } + public DateTime Date { get; set; } + public string? Score { get; set; } + public int StackId { get; set; } + public string Front { get; set; } = null!; + public string Back { get; set; } = null!; + public string Name { get; set; } = null!; + } +} \ No newline at end of file diff --git a/StackFlashcards.Ledana/TableVisualisation.cs b/StackFlashcards.Ledana/TableVisualisation.cs new file mode 100644 index 00000000..ea0f1a49 --- /dev/null +++ b/StackFlashcards.Ledana/TableVisualisation.cs @@ -0,0 +1,73 @@ +using Spectre.Console; +namespace StackFlashcards +{ + internal class TableVisualisation + { + internal void ShowStacks(List allStacks) + { + var table = new Table() + .RoundedBorder() + .BorderColor(Color.Red); + table.AddColumn("Name"); + + foreach (var item in allStacks) + { + table.AddRow(item.Name); + } + AnsiConsole.Write(table); + } + + //when showing a stack show the flashcards with stacks name as title + internal void ShowFlashCards(string name, List stack) + { + var table = new Table() + .Title(name) + .RoundedBorder() + .BorderColor(Color.Red); + table.AddColumn("Id"); + table.AddColumn("Front"); + + foreach (var item in stack) + { + table.AddRow(item.RowNum.ToString(), item.Front); + } + AnsiConsole.Write(table); + } + //when showing all stacks list them without a title + internal void ShowFlashCards(List flashcards) + { + var table = new Table() + .RoundedBorder() + .BorderColor(Color.Red); + table.AddColumn("Id"); + table.AddColumn("Front"); + table.AddColumn("Back"); + + foreach (var item in flashcards) + { + table.AddRow(item.RowNum.ToString(), item.Front, item.Back); + } + AnsiConsole.Write(table); + } + internal void ShowStudySessions(List studySessions) + { + var table = new Table() + .RoundedBorder() + .BorderColor(Color.Red); + table.ShowRowSeparators = true; + + table.AddColumn("Name"); + table.AddColumn("Front"); + table.AddColumn("Back"); + table.AddColumn("Date"); + table.AddColumn("Score"); + + foreach (var item in studySessions) + { + //if score is null show 0 in table + table.AddRow(item.Name, item.Front, item.Back, item.Date.ToString("d"), (item.Score == null ? "0" : item.Score)); + } + AnsiConsole.Write(table); + } + } +} \ No newline at end of file diff --git a/StackFlashcards.Ledana/UI.cs b/StackFlashcards.Ledana/UI.cs new file mode 100644 index 00000000..53ed2f41 --- /dev/null +++ b/StackFlashcards.Ledana/UI.cs @@ -0,0 +1,320 @@ +using System.Xml.Linq; + +namespace StackFlashcards +{ + internal class UI + { + readonly StackFlashcardServices stackFlashcardServices = new(); + private readonly TableVisualisation tableVisualisation = new(); + public void WelcomeUser() + { + //keep running this method till the user inputs 0 + while (true) //////////// + { + ShowMenu(); + + string input = GetUserInput("Please type a number between 0 and 7"); + + switch (input) + { + case "0": + return; + case "1": + OpenStudySession(); + break; + case "2": + CreateStack(); + break; + case "3": + ViewStack(); + break; + case "4": + ViewAllFlashcards(); + break; + case "5": + ViewStudySessions(); + break; + case "6": + DeleteStack(); + break; + case "7": + DeleteFlashcard(); + break; + + default: + Console.WriteLine("Invalid input. Please type a number between 0 and 7"); + break; + } + } + } + + private void DeleteFlashcard() + { + ViewAllStacks(); + string stackName = GetExistingStackName("PLease put the name of stack you want to delete flashcard in"); + if (stackName == "0") return; + + List? stack = stackFlashcardServices.GetStack(stackName); + if (stack is null) + { + Console.WriteLine("Stack not found"); + return; + } + + tableVisualisation.ShowFlashCards(stackName, stack); + + int id = GetValidatedInt("Please put the id of the flashcard you want to delete or type 0 to return\n"); + + //check if the id exists in the db, if not keep asking for an id or 0 to exit + + while (!stackFlashcardServices.ValidateIdInput(stackName, id)) + { + id = GetValidatedInt("Please put the id of the flashcard you want to delete or type 0 to return"); + if (id == 0) return; + + } + + //if the id is found in db and user didn't type 0 to exit then delete the card and notify user in console + stackFlashcardServices.DeleteFlashcard(stackName, id); + + Console.WriteLine($"\nFlashcard with Id {id} was deleted"); + } + + private static void ShowMenu() + { + Console.WriteLine("\nWhat do you want to do?"); + Console.WriteLine("0. Close the App"); + Console.WriteLine("1. Study a stack of flashcards"); + Console.WriteLine("2. Create a stack of flashcard"); + Console.WriteLine("3. View a stack"); + Console.WriteLine("4. View all flashcards"); + Console.WriteLine("5. View Study Sessions"); + Console.WriteLine("6. Delete a stack"); + Console.WriteLine("7. Delete a Flashcard"); + } + + private void DeleteStack() + { + ViewAllStacks(); + string name = GetExistingStackName("Please put the name of the stack you want to delete or type '0' to return to main menu"); + if (name == "0") return; + + stackFlashcardServices.DeleteStack(name); + Console.WriteLine($"\nStack {name} was deleted"); + } + + private void ViewAllFlashcards() + { + //getting all the cards from the db and showing them with spectre.console + List allFlashcards = stackFlashcardServices.GetAllFlashcards(); + tableVisualisation.ShowFlashCards(allFlashcards); + } + + private void ViewStudySessions() + { + List studySessionsDetails = stackFlashcardServices.GetStudySessionsDetails(); + tableVisualisation.ShowStudySessions(studySessionsDetails); + } + private void ViewAllStacks() + { + List allStacks = stackFlashcardServices.ViewStackList(); + tableVisualisation.ShowStacks(allStacks); + } + private void ViewStack() + { + ViewAllStacks(); + string name = GetExistingStackName("Please put the name of the stack you want or type '0' to return to main menu"); + if (name == "0") return; + + List? stack = stackFlashcardServices.GetStack(name); + if (stack is null) + { + Console.WriteLine("Stack not found"); + return; + } + + tableVisualisation.ShowFlashCards(name, stack); + } + + private void CreateStack() + { + string name = GetNewStackName("Please enter the name of the stack or type '0' to exit"); + if (name == "0") return; + + stackFlashcardServices.CreateStack(name); + + bool addFlashcard = AskUserToAddFlashcard(); + + while (addFlashcard) + { + string front = GetFrontOfStack(); + string back = GetBackOfStack(); + stackFlashcardServices.CreateFlashCard(name, front, back); + addFlashcard = AskUserToAddFlashcard(); + } + } + + private bool AskUserToAddFlashcard() + { + Console.WriteLine("Do you want to add a flashcard to the stack?"); + string input = GetUserInput("Type 'y' to add or '0' to continue"); + if (input == "y") return true; + + return false; + } + + private string GetBackOfStack() + { + return GetUserInput("Please put the back part of the stack"); + } + + private string GetFrontOfStack() + { + return GetUserInput("Please put the front part of the stack"); + } + + private void OpenStudySession() + { + ViewAllStacks(); + string name = GetExistingStackName("Please enter the name of the stack you want to study or type '0' to return to main menu"); + if (name == "0") return; + + DateTime date = DateTime.Today.Date; + string? score = StudyStack(name); + + if (score is null) + { + return; + } + + //if the stack was empty not add the study session + if (score == "0") return; + + Console.WriteLine($"\nYour score is {score}"); + + stackFlashcardServices.OpenStudySession(name, date, score); + } + + private string? StudyStack(string name) + { + int score = 0; + int? maxScore = stackFlashcardServices.GetFlashcardNumber(name); + + if (maxScore is null) return null; + //counting question answered so the user doesn't answer the same one more than once + int question = 0; + + //if the stack doesn't have cards return 0 + if (maxScore == 0) + { + Console.WriteLine("The stack is empty"); + return "0"; + } + + var flashcards = stackFlashcardServices.GetStack(name); + if (flashcards is null) + { + Console.WriteLine("Stack not found"); + return null; + } + + tableVisualisation.ShowFlashCards(name, flashcards); + + while (question < maxScore) + { + int id = GetValidatedInt("Please put the id of the flashcard you want to study or '0' to exit"); + + if (id == 0) break; + + while (!stackFlashcardServices.ValidateIdInput(name, id)) + { + Console.WriteLine($"The card with Id {id} doesn't exist\n"); + id = GetValidatedInt("Please put the id of the flashcard you want to study or '0' to exit"); + } + if (id == 0) break; + + string? front = stackFlashcardServices.GetFront(name, id); + Console.WriteLine(); + Console.WriteLine(front); + string? answer = GetUserInput("Please type the answer of the flashcard\n"); + + if (stackFlashcardServices.ValidateAnswer(name, id, answer)) + { + score++; + question++; + RightAnswer(name, id); + } + else + { + question++; + WrongAnswer(name, id); + } + } + return score + "/" + maxScore; + } + private void RightAnswer(string name, int id) + { + Console.WriteLine("\nCorrect answer"); + Console.WriteLine(stackFlashcardServices.GetRightAnswer(name, id)); + } + private void WrongAnswer(string name, int id) + { + Console.WriteLine("\nWrong answer"); + Console.WriteLine("The correct answer was: "); + Console.WriteLine(stackFlashcardServices.GetRightAnswer(name, id)); + } + + private string GetUserInput(string message) + { + Console.WriteLine(message); + string? input = Console.ReadLine(); + + while (string.IsNullOrEmpty(input)) + { + Console.WriteLine(message); + input = Console.ReadLine(); + } + + return input; + } + + //helper method to validate input as int and as a name in the db or not + private int GetValidatedInt(string message) + { + string input = GetUserInput(message); + if (input == "0") return 0; + + int num; + while (!int.TryParse(input, out num)) + { + input = GetUserInput(message); + if (input == "0") return 0; + } + return num; + } + private string GetExistingStackName(string message) + { + string name = GetUserInput(message); + if (name == "0") return "0"; + + while (!stackFlashcardServices.ValidateStackName(name)) + { + name = GetUserInput(message); + if (name == "0") return "0"; + } + return name; + } + private string GetNewStackName(string message) + { + string name = GetUserInput(message); + if (name.Trim() == "0") return "0"; + + while (stackFlashcardServices.ValidateStackName(name)) + { + name = GetUserInput(message); + if (name.Trim() == "0") return "0"; + } + return name; + } + } +} \ No newline at end of file From 9b1b950dc890a2da58cd7290ae1eee4118a6f5d7 Mon Sep 17 00:00:00 2001 From: Ledana Date: Mon, 13 Apr 2026 11:21:21 +0200 Subject: [PATCH 2/5] Create database schema and initial data for study app --- StackFlashcards.Ledana/dbFile.md | 33 ++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 StackFlashcards.Ledana/dbFile.md diff --git a/StackFlashcards.Ledana/dbFile.md b/StackFlashcards.Ledana/dbFile.md new file mode 100644 index 00000000..102bca42 --- /dev/null +++ b/StackFlashcards.Ledana/dbFile.md @@ -0,0 +1,33 @@ +CREATE TABLE Stack ( + Id INT PRIMARY KEY IDENTITY (1, 1), + [NAME] NVARCHAR (25) NOT NULL UNIQUE +); + +CREATE TABLE Flashcard ( +Id INT IDENTITY (1,1) PRIMARY KEY, +Front NVARCHAR(MAX) NOT NULL, +Back NVARCHAR(MAX) NOT NULL, +StackId INT NOT NULL, +CONSTRAINT FK_Flashcard_Stack FOREIGN KEY (StackId) REFERENCES Stack(Id) ON DELETE CASCADE +); + +CREATE TABLE StudySessions ( +Id INT PRIMARY KEY IDENTITY (1,1), +[Date] DATE NOT NULL, +Score NVARCHAR(25) NOT NULL, +StackId INT NOT NULL, +CONSTRAINT FK_StudySessions_Stack FOREIGN KEY (StackId) REFERENCES Stack(Id) ON DELETE CASCADE +); + + INSERT INTO Stack([Name]) +VALUES ('Biology'); + +INSERT INTO Flashcard (Front, Back, StackId) +VALUES ('What does the heart do?', 'The heart pumps blood into all our body and brain', 1), +('What does liver do?', 'Liver stores sugar, fat and carbs for us', 1), +('what do lungs do?', 'Lungs take oxygen and tranforms it into monoxyde carbon', 1); + +INSERT INTO StudySessions ([Date], Score, StackId) +VALUES ('2026-04-01', '2/3', 1), +('2026-04-04', '3/3', 1); + From 745fcafa9adfff332c4057d22fbf03ffabde6122 Mon Sep 17 00:00:00 2001 From: Ledana Date: Mon, 13 Apr 2026 11:30:54 +0200 Subject: [PATCH 3/5] Edited readme --- StackFlashcards.Ledana/README.md | 55 +++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/StackFlashcards.Ledana/README.md b/StackFlashcards.Ledana/README.md index 692915fb..d02373e9 100644 --- a/StackFlashcards.Ledana/README.md +++ b/StackFlashcards.Ledana/README.md @@ -1 +1,54 @@ -# StackFlashcards \ No newline at end of file +# StackFlashcards📖 Overview +This is a console-based flashcards application designed to help users create, manage, and study flashcard stacks. +The project was built with SQL Server for database management and Dapper for data access, with a focus on clean, reusable code and minimal repetition. + +⚙️ Features +• Stack Management +• Create new stacks and assign them a name. +• Delete stacks (all cards within the stack are deleted automatically). +• Card Management +• Add cards to a stack with front and back text. +• Delete individual cards. +• View all cards with sequential IDs (no gaps). +• Study Mode +• Choose a stack to study. +- See only the front of each card. +- Indicate whether you know the back → score updates accordingly. +- Sessions Tracking +- View study sessions with: +- Stack name +- Cards studied +- Score per stack +- Date of study +- DTOs +- First-time use of Data Transfer Objects (DTOs) to structure data between layers. + +🗄️ Database +- Database and tables were created in SQL Server Management Studio (SSMS). +- Code for table creation and population is stored in dbFile. +- Relationships: +- Stacks → Cards (cascade delete: deleting a stack removes its cards). +- Sessions → Stacks/Cards (tracks study history). + +💻 Code Design +- Dapper used for lightweight ORM functionality. +- Main Program kept as plain as possible: +- Delegates logic to service classes and helpers. +- Focuses on user interaction and menu flow. +- Clean Code Principles +- Reduced repetition with reusable helpers. +- Clear separation of concerns (DB operations, DTOs, UI flow). + +🚀 How to Use +- Create a stack → give it a name. +- Add cards → define front and back text. +- View cards → see IDs, front, and back. +- Study a stack → test yourself on the front, check if you know the back, and track your score. +- Delete stacks/cards → manage your collection. +- View study sessions → review past performance and progress. + +📌 Notes +- This is my first time using DTOs — they helped me structure data flow between layers. +- The app emphasizes auditability and clean control flow. +- IDs are processed with Row_Number function in console to avoid gaps when items are deleted. + From 484ba6f5623facc8e113ba1a27e636ae6990e5f4 Mon Sep 17 00:00:00 2001 From: Ledana Date: Thu, 23 Apr 2026 18:28:32 +0200 Subject: [PATCH 4/5] Removed the insert statements in dbFile so the db starts fresh and the user creates cards and are to be the first cards in the app --- StackFlashcards.Ledana/dbFile.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/StackFlashcards.Ledana/dbFile.md b/StackFlashcards.Ledana/dbFile.md index 102bca42..839f0dcd 100644 --- a/StackFlashcards.Ledana/dbFile.md +++ b/StackFlashcards.Ledana/dbFile.md @@ -19,15 +19,5 @@ StackId INT NOT NULL, CONSTRAINT FK_StudySessions_Stack FOREIGN KEY (StackId) REFERENCES Stack(Id) ON DELETE CASCADE ); - INSERT INTO Stack([Name]) -VALUES ('Biology'); -INSERT INTO Flashcard (Front, Back, StackId) -VALUES ('What does the heart do?', 'The heart pumps blood into all our body and brain', 1), -('What does liver do?', 'Liver stores sugar, fat and carbs for us', 1), -('what do lungs do?', 'Lungs take oxygen and tranforms it into monoxyde carbon', 1); - -INSERT INTO StudySessions ([Date], Score, StackId) -VALUES ('2026-04-01', '2/3', 1), -('2026-04-04', '3/3', 1); From e00ef0cc042701993e97303b2cd60af25e4c50dc Mon Sep 17 00:00:00 2001 From: Ledana Date: Fri, 24 Apr 2026 08:47:17 +0200 Subject: [PATCH 5/5] Did the project from scratch. i used enums to show menu with spectre.console, and use ef to create and do crud operations on the tables. --- .../Controllers/FlashCardController.cs | 65 ++++ .../Controllers/StackController.cs | 33 ++ .../Controllers/StudySessionController.cs | 57 +++ Flashcards.Ledana/DTOs/FlashCardDTO.cs | 12 + Flashcards.Ledana/DTOs/StudySessionDTO.cs | 10 + Flashcards.Ledana/Enums.cs | 32 ++ Flashcards.Ledana/Flashcards.Ledana.csproj | 24 ++ Flashcards.Ledana/Flashcards.Ledana.slnx | 3 + Flashcards.Ledana/FlashcardsContext.cs | 16 + .../20260423194041_InitailCreate.Designer.cs | 127 ++++++ .../20260423194041_InitailCreate.cs | 98 +++++ ...cardInStudyRemovedStackInStudy.Designer.cs | 133 +++++++ ...ddedFlashcardInStudyRemovedStackInStudy.cs | 102 +++++ ...AddedFlashcardIdInstudySession.Designer.cs | 135 +++++++ ...23224005_AddedFlashcardIdInstudySession.cs | 59 +++ .../FlashcardsContextModelSnapshot.cs | 132 +++++++ Flashcards.Ledana/Models/FlashCard.cs | 13 + Flashcards.Ledana/Models/Stack.cs | 11 + Flashcards.Ledana/Models/StudySession.cs | 11 + Flashcards.Ledana/Program.cs | 4 + .../Services/FlashCardService.cs | 68 ++++ Flashcards.Ledana/Services/StackService.cs | 80 ++++ .../Services/StudySessionService.cs | 70 ++++ Flashcards.Ledana/UI.cs | 162 ++++++++ StackFlashcards.Ledana/.gitattributes | 63 --- StackFlashcards.Ledana/.gitignore | 363 ------------------ StackFlashcards.Ledana/App.config | 6 - StackFlashcards.Ledana/Flashcard.cs | 18 - StackFlashcards.Ledana/Program.cs | 14 - StackFlashcards.Ledana/README.md | 54 --- StackFlashcards.Ledana/Stack.cs | 8 - .../StackFlashcardServices.cs | 216 ----------- StackFlashcards.Ledana/StackFlashcards.csproj | 18 - StackFlashcards.Ledana/StackFlashcards.slnx | 3 - StackFlashcards.Ledana/StudySession.cs | 21 - StackFlashcards.Ledana/TableVisualisation.cs | 73 ---- StackFlashcards.Ledana/UI.cs | 320 --------------- StackFlashcards.Ledana/dbFile.md | 23 -- 38 files changed, 1457 insertions(+), 1200 deletions(-) create mode 100644 Flashcards.Ledana/Controllers/FlashCardController.cs create mode 100644 Flashcards.Ledana/Controllers/StackController.cs create mode 100644 Flashcards.Ledana/Controllers/StudySessionController.cs create mode 100644 Flashcards.Ledana/DTOs/FlashCardDTO.cs create mode 100644 Flashcards.Ledana/DTOs/StudySessionDTO.cs create mode 100644 Flashcards.Ledana/Enums.cs create mode 100644 Flashcards.Ledana/Flashcards.Ledana.csproj create mode 100644 Flashcards.Ledana/Flashcards.Ledana.slnx create mode 100644 Flashcards.Ledana/FlashcardsContext.cs create mode 100644 Flashcards.Ledana/Migrations/20260423194041_InitailCreate.Designer.cs create mode 100644 Flashcards.Ledana/Migrations/20260423194041_InitailCreate.cs create mode 100644 Flashcards.Ledana/Migrations/20260423223541_AddedDatetimeInStudyRemovedAnserInCardsAddedFlashcardInStudyRemovedStackInStudy.Designer.cs create mode 100644 Flashcards.Ledana/Migrations/20260423223541_AddedDatetimeInStudyRemovedAnserInCardsAddedFlashcardInStudyRemovedStackInStudy.cs create mode 100644 Flashcards.Ledana/Migrations/20260423224005_AddedFlashcardIdInstudySession.Designer.cs create mode 100644 Flashcards.Ledana/Migrations/20260423224005_AddedFlashcardIdInstudySession.cs create mode 100644 Flashcards.Ledana/Migrations/FlashcardsContextModelSnapshot.cs create mode 100644 Flashcards.Ledana/Models/FlashCard.cs create mode 100644 Flashcards.Ledana/Models/Stack.cs create mode 100644 Flashcards.Ledana/Models/StudySession.cs create mode 100644 Flashcards.Ledana/Program.cs create mode 100644 Flashcards.Ledana/Services/FlashCardService.cs create mode 100644 Flashcards.Ledana/Services/StackService.cs create mode 100644 Flashcards.Ledana/Services/StudySessionService.cs create mode 100644 Flashcards.Ledana/UI.cs delete mode 100644 StackFlashcards.Ledana/.gitattributes delete mode 100644 StackFlashcards.Ledana/.gitignore delete mode 100644 StackFlashcards.Ledana/App.config delete mode 100644 StackFlashcards.Ledana/Flashcard.cs delete mode 100644 StackFlashcards.Ledana/Program.cs delete mode 100644 StackFlashcards.Ledana/README.md delete mode 100644 StackFlashcards.Ledana/Stack.cs delete mode 100644 StackFlashcards.Ledana/StackFlashcardServices.cs delete mode 100644 StackFlashcards.Ledana/StackFlashcards.csproj delete mode 100644 StackFlashcards.Ledana/StackFlashcards.slnx delete mode 100644 StackFlashcards.Ledana/StudySession.cs delete mode 100644 StackFlashcards.Ledana/TableVisualisation.cs delete mode 100644 StackFlashcards.Ledana/UI.cs delete mode 100644 StackFlashcards.Ledana/dbFile.md diff --git a/Flashcards.Ledana/Controllers/FlashCardController.cs b/Flashcards.Ledana/Controllers/FlashCardController.cs new file mode 100644 index 00000000..0c46622c --- /dev/null +++ b/Flashcards.Ledana/Controllers/FlashCardController.cs @@ -0,0 +1,65 @@ +using Flashcards.Ledana.DTOs; +using Flashcards.Ledana.Models; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Flashcards.Ledana.Controllers +{ + internal class FlashCardController + { + internal static void AddFlashCard(FlashCard card) + { + using var db = new FlashcardsContext(); + db.Flashcards.Add(card); + db.SaveChanges(); + } + + internal static void DeleteCard(FlashCard card) + { + using var db = new FlashcardsContext(); + db.Flashcards.Remove(card); + db.SaveChanges(); + } + + internal static List GetFlashCardDTOs(int id) + { + try + { + using var db = new FlashcardsContext(); + var cards = db.Flashcards + .AsEnumerable() + .Where(f => f.StackId == id) + .Select((f, index) => new FlashCardDTO + { + Id = index + 1, + Front = f.Front + }) + .ToList(); + return cards; + } + catch (Exception e) + { + Console.WriteLine("Query didn't work. " + e.Message); + return []; + } + } + + internal static int GetFlashCardNumberPerStack(int id) + { + using var db = new FlashcardsContext(); + return db.Flashcards + .Where(f => f.StackId == id) + .Count(); + } + + internal static List GetFlashCards(int id) + { + using var db = new FlashcardsContext(); + return db.Flashcards + .Where(f => f.StackId == id) + .ToList(); + } + } +} diff --git a/Flashcards.Ledana/Controllers/StackController.cs b/Flashcards.Ledana/Controllers/StackController.cs new file mode 100644 index 00000000..c8e6ab40 --- /dev/null +++ b/Flashcards.Ledana/Controllers/StackController.cs @@ -0,0 +1,33 @@ +using Flashcards.Ledana.Models; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Flashcards.Ledana.Controllers +{ + internal static class StackController + { + internal static void AddStack(Stack stack) + { + using var db = new FlashcardsContext(); + db.Stacks.Add(stack); + db.SaveChanges(); + } + + internal static void DeleteStack(Stack stack) + { + using var db = new FlashcardsContext(); + db.Stacks.Remove(stack); + db.SaveChanges(); + } + + internal static List GetAllStacks() + { + using var db = new FlashcardsContext(); + return db.Stacks + .Include(s => s.Flashcards) + .ToList(); + } + } +} diff --git a/Flashcards.Ledana/Controllers/StudySessionController.cs b/Flashcards.Ledana/Controllers/StudySessionController.cs new file mode 100644 index 00000000..eb19839e --- /dev/null +++ b/Flashcards.Ledana/Controllers/StudySessionController.cs @@ -0,0 +1,57 @@ +using Flashcards.Ledana.DTOs; +using Flashcards.Ledana.Models; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Flashcards.Ledana.Controllers +{ + internal class StudySessionController + { + internal static void AddStudySession(StudySession studySession) + { + try + { + using var db = new FlashcardsContext(); + db.StudySessions.Add(studySession); + db.SaveChanges(); + } + catch (Exception e) + { + Console.WriteLine("Query didn't work to add study session " + e.Message); + } + } + + internal static List GetSessions() + { + try + { + using var db = new FlashcardsContext(); + var sessions = db.StudySessions + .Select(s => new StudySessionDTO + { + StackName = s.FlashCard.Stack.Name, + FrontCard = s.FlashCard.Front, + BackCard = s.FlashCard.Back, + Answer = s.Answer, + Score = s.Score + }) + .ToList(); + return sessions; + } + catch (Exception e) + { + Console.WriteLine("Query didn't work. " + e.Message); + return []; + } + } + + internal static bool ValidateAnswer(int id, string answer) + { + using var db = new FlashcardsContext(); + var result = db.Flashcards + .Any(f => f.Id == id && f.Back == answer); + return result; + } + } +} diff --git a/Flashcards.Ledana/DTOs/FlashCardDTO.cs b/Flashcards.Ledana/DTOs/FlashCardDTO.cs new file mode 100644 index 00000000..a1f898cc --- /dev/null +++ b/Flashcards.Ledana/DTOs/FlashCardDTO.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Flashcards.Ledana.DTOs +{ + internal class FlashCardDTO + { + public int Id { get; set; } + public string Front { get; set; } = null!; + } +} diff --git a/Flashcards.Ledana/DTOs/StudySessionDTO.cs b/Flashcards.Ledana/DTOs/StudySessionDTO.cs new file mode 100644 index 00000000..5f8474b2 --- /dev/null +++ b/Flashcards.Ledana/DTOs/StudySessionDTO.cs @@ -0,0 +1,10 @@ +namespace Flashcards.Ledana.DTOs; + internal class StudySessionDTO + { + public string StackName { get; set; } = null!; + public DateTime DateTime { get; set; } + public string FrontCard { get; set; } = null!; + public string BackCard { get; set; } = null!; + public string Answer { get; set; } = null!; + public string Score { get; set; } = null!; + } diff --git a/Flashcards.Ledana/Enums.cs b/Flashcards.Ledana/Enums.cs new file mode 100644 index 00000000..6bbbd836 --- /dev/null +++ b/Flashcards.Ledana/Enums.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Flashcards.Ledana +{ + internal class Enums + { + internal enum MainMenuOptions + { + ManageStacks, + ManageFlashCards, + Study, + ViewStudySession, + Quit + } + internal enum ManageStacksOptions + { + AddStack, + DeleteStack, + ViewStack, + ViewAllStacks, + GoBack + } + internal enum ManageFlashCardsOptions + { + AddFlashCard, + DeleteFlashCard, + GoBack + } + } +} diff --git a/Flashcards.Ledana/Flashcards.Ledana.csproj b/Flashcards.Ledana/Flashcards.Ledana.csproj new file mode 100644 index 00000000..db23aded --- /dev/null +++ b/Flashcards.Ledana/Flashcards.Ledana.csproj @@ -0,0 +1,24 @@ + + + + Exe + net10.0 + enable + enable + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + diff --git a/Flashcards.Ledana/Flashcards.Ledana.slnx b/Flashcards.Ledana/Flashcards.Ledana.slnx new file mode 100644 index 00000000..f128475c --- /dev/null +++ b/Flashcards.Ledana/Flashcards.Ledana.slnx @@ -0,0 +1,3 @@ + + + diff --git a/Flashcards.Ledana/FlashcardsContext.cs b/Flashcards.Ledana/FlashcardsContext.cs new file mode 100644 index 00000000..211cd4e8 --- /dev/null +++ b/Flashcards.Ledana/FlashcardsContext.cs @@ -0,0 +1,16 @@ +using Flashcards.Ledana.Models; +using Microsoft.EntityFrameworkCore; + +namespace Flashcards.Ledana; + +internal class FlashcardsContext : DbContext +{ + public DbSet Flashcards { get; set; } + public DbSet Stacks { get; set; } + public DbSet StudySessions { get; set; } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + optionsBuilder.UseSqlServer("Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=FlashCardDb;"); + } +} diff --git a/Flashcards.Ledana/Migrations/20260423194041_InitailCreate.Designer.cs b/Flashcards.Ledana/Migrations/20260423194041_InitailCreate.Designer.cs new file mode 100644 index 00000000..0bee8538 --- /dev/null +++ b/Flashcards.Ledana/Migrations/20260423194041_InitailCreate.Designer.cs @@ -0,0 +1,127 @@ +// +using Flashcards.Ledana; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Flashcards.Ledana.Migrations +{ + [DbContext(typeof(FlashcardsContext))] + [Migration("20260423194041_InitailCreate")] + partial class InitailCreate + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Flashcards.Ledana.Models.Flashcard", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Answer") + .HasColumnType("nvarchar(max)"); + + b.Property("Back") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Front") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StackId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("StackId"); + + b.ToTable("Flashcards"); + }); + + modelBuilder.Entity("Flashcards.Ledana.Models.Stack", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Stacks"); + }); + + modelBuilder.Entity("Flashcards.Ledana.Models.StudySession", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Score") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StackId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("StackId"); + + b.ToTable("StudySessions"); + }); + + modelBuilder.Entity("Flashcards.Ledana.Models.Flashcard", b => + { + b.HasOne("Flashcards.Ledana.Models.Stack", "Stack") + .WithMany("Flashcards") + .HasForeignKey("StackId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Stack"); + }); + + modelBuilder.Entity("Flashcards.Ledana.Models.StudySession", b => + { + b.HasOne("Flashcards.Ledana.Models.Stack", "Stack") + .WithMany() + .HasForeignKey("StackId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Stack"); + }); + + modelBuilder.Entity("Flashcards.Ledana.Models.Stack", b => + { + b.Navigation("Flashcards"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Flashcards.Ledana/Migrations/20260423194041_InitailCreate.cs b/Flashcards.Ledana/Migrations/20260423194041_InitailCreate.cs new file mode 100644 index 00000000..1e888872 --- /dev/null +++ b/Flashcards.Ledana/Migrations/20260423194041_InitailCreate.cs @@ -0,0 +1,98 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Flashcards.Ledana.Migrations +{ + /// + public partial class InitailCreate : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Stacks", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Name = table.Column(type: "nvarchar(450)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Stacks", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Flashcards", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + StackId = table.Column(type: "int", nullable: false), + Front = table.Column(type: "nvarchar(max)", nullable: false), + Back = table.Column(type: "nvarchar(max)", nullable: false), + Answer = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Flashcards", x => x.Id); + table.ForeignKey( + name: "FK_Flashcards_Stacks_StackId", + column: x => x.StackId, + principalTable: "Stacks", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "StudySessions", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + StackId = table.Column(type: "int", nullable: false), + Score = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_StudySessions", x => x.Id); + table.ForeignKey( + name: "FK_StudySessions_Stacks_StackId", + column: x => x.StackId, + principalTable: "Stacks", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Flashcards_StackId", + table: "Flashcards", + column: "StackId"); + + migrationBuilder.CreateIndex( + name: "IX_Stacks_Name", + table: "Stacks", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_StudySessions_StackId", + table: "StudySessions", + column: "StackId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Flashcards"); + + migrationBuilder.DropTable( + name: "StudySessions"); + + migrationBuilder.DropTable( + name: "Stacks"); + } + } +} diff --git a/Flashcards.Ledana/Migrations/20260423223541_AddedDatetimeInStudyRemovedAnserInCardsAddedFlashcardInStudyRemovedStackInStudy.Designer.cs b/Flashcards.Ledana/Migrations/20260423223541_AddedDatetimeInStudyRemovedAnserInCardsAddedFlashcardInStudyRemovedStackInStudy.Designer.cs new file mode 100644 index 00000000..d1b7bfb1 --- /dev/null +++ b/Flashcards.Ledana/Migrations/20260423223541_AddedDatetimeInStudyRemovedAnserInCardsAddedFlashcardInStudyRemovedStackInStudy.Designer.cs @@ -0,0 +1,133 @@ +// +using System; +using Flashcards.Ledana; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Flashcards.Ledana.Migrations +{ + [DbContext(typeof(FlashcardsContext))] + [Migration("20260423223541_AddedDatetimeInStudyRemovedAnserInCardsAddedFlashcardInStudyRemovedStackInStudy")] + partial class AddedDatetimeInStudyRemovedAnserInCardsAddedFlashcardInStudyRemovedStackInStudy + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Flashcards.Ledana.Models.FlashCard", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Back") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Front") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StackId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("StackId"); + + b.ToTable("Flashcards"); + }); + + modelBuilder.Entity("Flashcards.Ledana.Models.Stack", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Stacks"); + }); + + modelBuilder.Entity("Flashcards.Ledana.Models.StudySession", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Answer") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetime2"); + + b.Property("FlashCardId") + .HasColumnType("int"); + + b.Property("Score") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StackId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("FlashCardId"); + + b.ToTable("StudySessions"); + }); + + modelBuilder.Entity("Flashcards.Ledana.Models.FlashCard", b => + { + b.HasOne("Flashcards.Ledana.Models.Stack", "Stack") + .WithMany("Flashcards") + .HasForeignKey("StackId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Stack"); + }); + + modelBuilder.Entity("Flashcards.Ledana.Models.StudySession", b => + { + b.HasOne("Flashcards.Ledana.Models.FlashCard", "FlashCard") + .WithMany() + .HasForeignKey("FlashCardId"); + + b.Navigation("FlashCard"); + }); + + modelBuilder.Entity("Flashcards.Ledana.Models.Stack", b => + { + b.Navigation("Flashcards"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Flashcards.Ledana/Migrations/20260423223541_AddedDatetimeInStudyRemovedAnserInCardsAddedFlashcardInStudyRemovedStackInStudy.cs b/Flashcards.Ledana/Migrations/20260423223541_AddedDatetimeInStudyRemovedAnserInCardsAddedFlashcardInStudyRemovedStackInStudy.cs new file mode 100644 index 00000000..f816034e --- /dev/null +++ b/Flashcards.Ledana/Migrations/20260423223541_AddedDatetimeInStudyRemovedAnserInCardsAddedFlashcardInStudyRemovedStackInStudy.cs @@ -0,0 +1,102 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Flashcards.Ledana.Migrations +{ + /// + public partial class AddedDatetimeInStudyRemovedAnserInCardsAddedFlashcardInStudyRemovedStackInStudy : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_StudySessions_Stacks_StackId", + table: "StudySessions"); + + migrationBuilder.DropIndex( + name: "IX_StudySessions_StackId", + table: "StudySessions"); + + migrationBuilder.DropColumn( + name: "Answer", + table: "Flashcards"); + + migrationBuilder.AddColumn( + name: "Answer", + table: "StudySessions", + type: "nvarchar(max)", + nullable: false, + defaultValue: ""); + + migrationBuilder.AddColumn( + name: "DateTime", + table: "StudySessions", + type: "datetime2", + nullable: false, + defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)); + + migrationBuilder.AddColumn( + name: "FlashCardId", + table: "StudySessions", + type: "int", + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_StudySessions_FlashCardId", + table: "StudySessions", + column: "FlashCardId"); + + migrationBuilder.AddForeignKey( + name: "FK_StudySessions_Flashcards_FlashCardId", + table: "StudySessions", + column: "FlashCardId", + principalTable: "Flashcards", + principalColumn: "Id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_StudySessions_Flashcards_FlashCardId", + table: "StudySessions"); + + migrationBuilder.DropIndex( + name: "IX_StudySessions_FlashCardId", + table: "StudySessions"); + + migrationBuilder.DropColumn( + name: "Answer", + table: "StudySessions"); + + migrationBuilder.DropColumn( + name: "DateTime", + table: "StudySessions"); + + migrationBuilder.DropColumn( + name: "FlashCardId", + table: "StudySessions"); + + migrationBuilder.AddColumn( + name: "Answer", + table: "Flashcards", + type: "nvarchar(max)", + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_StudySessions_StackId", + table: "StudySessions", + column: "StackId"); + + migrationBuilder.AddForeignKey( + name: "FK_StudySessions_Stacks_StackId", + table: "StudySessions", + column: "StackId", + principalTable: "Stacks", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/Flashcards.Ledana/Migrations/20260423224005_AddedFlashcardIdInstudySession.Designer.cs b/Flashcards.Ledana/Migrations/20260423224005_AddedFlashcardIdInstudySession.Designer.cs new file mode 100644 index 00000000..11410548 --- /dev/null +++ b/Flashcards.Ledana/Migrations/20260423224005_AddedFlashcardIdInstudySession.Designer.cs @@ -0,0 +1,135 @@ +// +using System; +using Flashcards.Ledana; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Flashcards.Ledana.Migrations +{ + [DbContext(typeof(FlashcardsContext))] + [Migration("20260423224005_AddedFlashcardIdInstudySession")] + partial class AddedFlashcardIdInstudySession + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Flashcards.Ledana.Models.FlashCard", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Back") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Front") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StackId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("StackId"); + + b.ToTable("Flashcards"); + }); + + modelBuilder.Entity("Flashcards.Ledana.Models.Stack", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Stacks"); + }); + + modelBuilder.Entity("Flashcards.Ledana.Models.StudySession", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Answer") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetime2"); + + b.Property("FlashCardId") + .HasColumnType("int"); + + b.Property("Score") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StackId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("FlashCardId"); + + b.ToTable("StudySessions"); + }); + + modelBuilder.Entity("Flashcards.Ledana.Models.FlashCard", b => + { + b.HasOne("Flashcards.Ledana.Models.Stack", "Stack") + .WithMany("Flashcards") + .HasForeignKey("StackId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Stack"); + }); + + modelBuilder.Entity("Flashcards.Ledana.Models.StudySession", b => + { + b.HasOne("Flashcards.Ledana.Models.FlashCard", "FlashCard") + .WithMany() + .HasForeignKey("FlashCardId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FlashCard"); + }); + + modelBuilder.Entity("Flashcards.Ledana.Models.Stack", b => + { + b.Navigation("Flashcards"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Flashcards.Ledana/Migrations/20260423224005_AddedFlashcardIdInstudySession.cs b/Flashcards.Ledana/Migrations/20260423224005_AddedFlashcardIdInstudySession.cs new file mode 100644 index 00000000..2b97b061 --- /dev/null +++ b/Flashcards.Ledana/Migrations/20260423224005_AddedFlashcardIdInstudySession.cs @@ -0,0 +1,59 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Flashcards.Ledana.Migrations +{ + /// + public partial class AddedFlashcardIdInstudySession : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_StudySessions_Flashcards_FlashCardId", + table: "StudySessions"); + + migrationBuilder.AlterColumn( + name: "FlashCardId", + table: "StudySessions", + type: "int", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "int", + oldNullable: true); + + migrationBuilder.AddForeignKey( + name: "FK_StudySessions_Flashcards_FlashCardId", + table: "StudySessions", + column: "FlashCardId", + principalTable: "Flashcards", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_StudySessions_Flashcards_FlashCardId", + table: "StudySessions"); + + migrationBuilder.AlterColumn( + name: "FlashCardId", + table: "StudySessions", + type: "int", + nullable: true, + oldClrType: typeof(int), + oldType: "int"); + + migrationBuilder.AddForeignKey( + name: "FK_StudySessions_Flashcards_FlashCardId", + table: "StudySessions", + column: "FlashCardId", + principalTable: "Flashcards", + principalColumn: "Id"); + } + } +} diff --git a/Flashcards.Ledana/Migrations/FlashcardsContextModelSnapshot.cs b/Flashcards.Ledana/Migrations/FlashcardsContextModelSnapshot.cs new file mode 100644 index 00000000..cc7432bc --- /dev/null +++ b/Flashcards.Ledana/Migrations/FlashcardsContextModelSnapshot.cs @@ -0,0 +1,132 @@ +// +using System; +using Flashcards.Ledana; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Flashcards.Ledana.Migrations +{ + [DbContext(typeof(FlashcardsContext))] + partial class FlashcardsContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Flashcards.Ledana.Models.FlashCard", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Back") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Front") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StackId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("StackId"); + + b.ToTable("Flashcards"); + }); + + modelBuilder.Entity("Flashcards.Ledana.Models.Stack", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Stacks"); + }); + + modelBuilder.Entity("Flashcards.Ledana.Models.StudySession", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Answer") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetime2"); + + b.Property("FlashCardId") + .HasColumnType("int"); + + b.Property("Score") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StackId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("FlashCardId"); + + b.ToTable("StudySessions"); + }); + + modelBuilder.Entity("Flashcards.Ledana.Models.FlashCard", b => + { + b.HasOne("Flashcards.Ledana.Models.Stack", "Stack") + .WithMany("Flashcards") + .HasForeignKey("StackId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Stack"); + }); + + modelBuilder.Entity("Flashcards.Ledana.Models.StudySession", b => + { + b.HasOne("Flashcards.Ledana.Models.FlashCard", "FlashCard") + .WithMany() + .HasForeignKey("FlashCardId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FlashCard"); + }); + + modelBuilder.Entity("Flashcards.Ledana.Models.Stack", b => + { + b.Navigation("Flashcards"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Flashcards.Ledana/Models/FlashCard.cs b/Flashcards.Ledana/Models/FlashCard.cs new file mode 100644 index 00000000..cde23e52 --- /dev/null +++ b/Flashcards.Ledana/Models/FlashCard.cs @@ -0,0 +1,13 @@ + + +namespace Flashcards.Ledana.Models +{ + internal class FlashCard + { + public int Id { get; set; } + public int StackId { get; set; } + public string Front { get; set; } = null!; + public string Back { get; set; } = null!; + public Stack Stack { get; set; } = null!; + } +} diff --git a/Flashcards.Ledana/Models/Stack.cs b/Flashcards.Ledana/Models/Stack.cs new file mode 100644 index 00000000..6602530b --- /dev/null +++ b/Flashcards.Ledana/Models/Stack.cs @@ -0,0 +1,11 @@ +using Microsoft.EntityFrameworkCore; + +namespace Flashcards.Ledana.Models; + + [Index(nameof(Name), IsUnique = true)] + internal class Stack + { + public string Name { get; set; } = null!; + public int Id { get; set; } + public List Flashcards { get; set; } = []; + } diff --git a/Flashcards.Ledana/Models/StudySession.cs b/Flashcards.Ledana/Models/StudySession.cs new file mode 100644 index 00000000..ea67cff2 --- /dev/null +++ b/Flashcards.Ledana/Models/StudySession.cs @@ -0,0 +1,11 @@ +namespace Flashcards.Ledana.Models; + internal class StudySession + { + public int Id { get; set; } + public int StackId { get; set; } + public int FlashCardId { get; set; } + public string Score { get; set; } = null!; + public DateTime DateTime { get; set; } + public FlashCard? FlashCard { get; set; } + public string Answer { get; set; } = null!; + } diff --git a/Flashcards.Ledana/Program.cs b/Flashcards.Ledana/Program.cs new file mode 100644 index 00000000..7c47dba9 --- /dev/null +++ b/Flashcards.Ledana/Program.cs @@ -0,0 +1,4 @@ +using Flashcards.Ledana; + +UI uI = new(); +uI.MainMenu(); diff --git a/Flashcards.Ledana/Services/FlashCardService.cs b/Flashcards.Ledana/Services/FlashCardService.cs new file mode 100644 index 00000000..f4a9c4bb --- /dev/null +++ b/Flashcards.Ledana/Services/FlashCardService.cs @@ -0,0 +1,68 @@ +using Flashcards.Ledana.Controllers; +using Flashcards.Ledana.Models; +using Spectre.Console; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Flashcards.Ledana.Services +{ + internal class FlashCardService + { + internal static void AddFlashCard() + { + var stack = StackService.GetStackOptionInput(); + if (stack is null) + { + Console.WriteLine("Stack was not found"); + return; + } + while (AnsiConsole.Confirm("Do you want to add a card?")) + { + var card = new FlashCard + { + StackId = stack.Id, + Front = AnsiConsole.Ask("Put the front part: "), + Back = AnsiConsole.Ask("Put the back part: ") + }; + FlashCardController.AddFlashCard(card); + } + } + + internal static void DeleteFlashCard() + { + var stack = StackService.GetStackOptionInput(); + if (stack is null) + { + Console.WriteLine("Stack not found"); + return; + } + + FlashCard card = GetCardOptionInput(stack.Id); + if (card is null) + { + Console.WriteLine("Card nout found"); + return; + } + FlashCardController.DeleteCard(card); + Console.WriteLine("Card deleted!"); + } + + internal static FlashCard? GetCardOptionInput(int stackId) + { + List FlashCards = FlashCardController.GetFlashCards(stackId); + if (FlashCards.Count == 0) + { + Console.WriteLine("List of FlashCard is empty"); + return null; + } + var stacksArray = FlashCards.Select(c => c.Front).ToArray(); + var option = AnsiConsole.Prompt(new SelectionPrompt() + .Title("Choose card") + .AddChoices(stacksArray)); + var card = FlashCards.SingleOrDefault(s => s.Front == option); + return card; + } + + } +} diff --git a/Flashcards.Ledana/Services/StackService.cs b/Flashcards.Ledana/Services/StackService.cs new file mode 100644 index 00000000..4eafd218 --- /dev/null +++ b/Flashcards.Ledana/Services/StackService.cs @@ -0,0 +1,80 @@ +using Flashcards.Ledana.Controllers; +using Flashcards.Ledana.DTOs; +using Flashcards.Ledana.Models; +using Spectre.Console; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Flashcards.Ledana.Services +{ + internal class StackService + { + internal static void AddStack() + { + var stack = new Stack + { + Name = AnsiConsole.Ask("Enter name for stack: ") + }; + StackController.AddStack(stack); + while(AnsiConsole.Confirm("Do you want to add a card?")) + { + var card = new FlashCard + { + StackId = stack.Id, + Front = AnsiConsole.Ask("Put the front part: "), + Back = AnsiConsole.Ask("Put the back part: ") + }; + FlashCardController.AddFlashCard(card); + } + + } + + internal static void DeleteStack() + { + var stack = GetStackOptionInput(); + if (stack is null) + { + Console.WriteLine("Stack doesn't exist"); + return; + } + StackController.DeleteStack(stack); + Console.WriteLine("Stack deleted!"); + } + + internal static void ViewAllStacks() + { + List stacks = StackController.GetAllStacks(); + UI.ShowAllStacks(stacks); + } + + internal static void ViewStack() + { + var stack = GetStackOptionInput(); + if (stack is null) + { + Console.WriteLine("Stack doesn't exist"); + return; + } + + List flashCards = FlashCardController.GetFlashCardDTOs(stack.Id); + UI.ShowStackOfFlashCards(stack, flashCards); + } + + internal static Stack? GetStackOptionInput() + { + List stacks = StackController.GetAllStacks(); + if (stacks.Count == 0) + { + Console.WriteLine("List of stacks is empty"); + return null; + } + var stacksArray = stacks.Select(s => s.Name).ToArray(); + var option = AnsiConsole.Prompt(new SelectionPrompt() + .Title("Choose stack") + .AddChoices(stacksArray)); + var stack = stacks.SingleOrDefault(s => s.Name == option); + return stack; + } + } +} diff --git a/Flashcards.Ledana/Services/StudySessionService.cs b/Flashcards.Ledana/Services/StudySessionService.cs new file mode 100644 index 00000000..842958b9 --- /dev/null +++ b/Flashcards.Ledana/Services/StudySessionService.cs @@ -0,0 +1,70 @@ +using Flashcards.Ledana.Controllers; +using Flashcards.Ledana.DTOs; +using Flashcards.Ledana.Models; +using Spectre.Console; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Flashcards.Ledana.Services +{ + internal class StudySessionService + { + internal static void OpenStudySession() + { + string stringScore = ""; + string response = ""; + int score = 0; + + var stack = StackService.GetStackOptionInput(); + if (stack is null) + { + Console.WriteLine("Stack not found"); + return; + } + + int maxScore = FlashCardController.GetFlashCardNumberPerStack(stack.Id); + bool studying = true; + DateTime dateTime = DateTime.Today; + while (studying) + { + var card = FlashCardService.GetCardOptionInput(stack.Id); + if (card is null) + { + Console.WriteLine("Card not found"); + return; + } + var answer = AnsiConsole.Ask("Your answer: "); + + bool answeredRight = StudySessionController.ValidateAnswer(card.Id, answer); + if (answeredRight) score++; + + response = answeredRight ? "Correct" : "Wrong"; + Console.WriteLine("Your answer was " + response); + studying = AnsiConsole.Confirm("Do you want to keep studying?"); + stringScore = $"{score}/{maxScore}"; + AddStudySession(stack.Id, card.Id, stringScore, dateTime, response); + } + + + } + internal static void AddStudySession(int stackId, int cardId, string score, DateTime dateTime, string response) + { + StudySession studySession = new() + { + StackId = stackId, + FlashCardId = cardId, + Score = score, + DateTime = dateTime, + Answer = response + }; + StudySessionController.AddStudySession(studySession); + } + + internal static void ViewSessions() + { + List studySessionDTOs = StudySessionController.GetSessions(); + UI.ShowStudySessions(studySessionDTOs); + } + } +} diff --git a/Flashcards.Ledana/UI.cs b/Flashcards.Ledana/UI.cs new file mode 100644 index 00000000..24b5dc6f --- /dev/null +++ b/Flashcards.Ledana/UI.cs @@ -0,0 +1,162 @@ +using Flashcards.Ledana.DTOs; +using Flashcards.Ledana.Models; +using Flashcards.Ledana.Services; +using Spectre.Console; +using System.Collections; +using static Flashcards.Ledana.Enums; +using Stack = Flashcards.Ledana.Models.Stack; + +namespace Flashcards.Ledana; + internal class UI + { + internal static void ShowAllStacks(List stacks) + { + var table = new Table(); + table.AddColumn("Id"); + table.AddColumn("Name"); + foreach (var item in stacks) + { + table.AddRow(item.Id.ToString(), item.Name); + } + AnsiConsole.Write(table); + } + + internal static void ShowStackOfFlashCards(Stack stack, List flashCards) + { + var table = new Table() + .Title(stack.Name); + table.AddColumn("Id"); + table.AddColumn("Front"); + foreach(var item in flashCards) + { + table.AddRow(item.Id.ToString(), item.Front); + } + AnsiConsole.Write(table); + } + + internal static void ShowStudySessions(List studySessionDTOs) + { + var table = new Table(); + table.AddColumn("StackName"); + table.AddColumn("DateTime"); + table.AddColumn("FrontCard"); + table.AddColumn("BackCard"); + table.AddColumn("Answer"); + table.AddColumn("Score"); + + foreach (var item in studySessionDTOs) + { + table.AddRow(item.StackName, item.DateTime.ToString("d"), + item.FrontCard, item.BackCard, + item.Answer, item.Score); + } + AnsiConsole.Write(table); + } + + public void MainMenu() + { + Console.Clear(); + bool isAppRunning = true; + + while (isAppRunning) + { + var option = AnsiConsole.Prompt( + new SelectionPrompt() + .Title("What do you want to do?") + .AddChoices( + MainMenuOptions.ManageStacks, + MainMenuOptions.ManageFlashCards, + MainMenuOptions.Study, + MainMenuOptions.ViewStudySession, + MainMenuOptions.Quit + )); + switch(option) + { + case MainMenuOptions.ManageStacks: + StacksMenu(); + break; + case MainMenuOptions.ManageFlashCards: + FlashCardsMenu(); + break; + case MainMenuOptions.Study: + StudySessionService.OpenStudySession(); + break; + case MainMenuOptions.ViewStudySession: + StudySessionService.ViewSessions(); + break; + case MainMenuOptions.Quit: + Console.WriteLine("Goodbye"); + isAppRunning = false; + break; + } + } + } + + + + private void FlashCardsMenu() + { + bool isFlashCardsMenuRunning = true; + + while (isFlashCardsMenuRunning) + { + var option = AnsiConsole.Prompt( + new SelectionPrompt() + .Title("What do you want to do?") + .AddChoices( + ManageFlashCardsOptions.AddFlashCard, + ManageFlashCardsOptions.DeleteFlashCard, + ManageFlashCardsOptions.GoBack + )); + switch (option) + { + case ManageFlashCardsOptions.AddFlashCard: + FlashCardService.AddFlashCard(); + break; + case ManageFlashCardsOptions.DeleteFlashCard: + FlashCardService.DeleteFlashCard(); + break; + case ManageFlashCardsOptions.GoBack: + isFlashCardsMenuRunning = false; + break; + } + } + } + + private void StacksMenu() + { + bool isStacksMenuRunning = true; + + while (isStacksMenuRunning) + { + var option = AnsiConsole.Prompt( + new SelectionPrompt() + .Title("What do you want to do?") + .AddChoices( + ManageStacksOptions.AddStack, + ManageStacksOptions.DeleteStack, + ManageStacksOptions.ViewStack, + ManageStacksOptions.ViewAllStacks, + ManageStacksOptions.GoBack + )); + switch (option) + { + case ManageStacksOptions.AddStack: + StackService.AddStack(); + break; + case ManageStacksOptions.DeleteStack: + StackService.DeleteStack(); + break; + case ManageStacksOptions.ViewStack: + StackService.ViewStack(); + break; + case ManageStacksOptions.ViewAllStacks: + StackService.ViewAllStacks(); + break; + case ManageStacksOptions.GoBack: + isStacksMenuRunning = false; + break; + } + } + } +} diff --git a/StackFlashcards.Ledana/.gitattributes b/StackFlashcards.Ledana/.gitattributes deleted file mode 100644 index 1ff0c423..00000000 --- a/StackFlashcards.Ledana/.gitattributes +++ /dev/null @@ -1,63 +0,0 @@ -############################################################################### -# Set default behavior to automatically normalize line endings. -############################################################################### -* text=auto - -############################################################################### -# Set default behavior for command prompt diff. -# -# This is need for earlier builds of msysgit that does not have it on by -# default for csharp files. -# Note: This is only used by command line -############################################################################### -#*.cs diff=csharp - -############################################################################### -# Set the merge driver for project and solution files -# -# Merging from the command prompt will add diff markers to the files if there -# are conflicts (Merging from VS is not affected by the settings below, in VS -# the diff markers are never inserted). Diff markers may cause the following -# file extensions to fail to load in VS. An alternative would be to treat -# these files as binary and thus will always conflict and require user -# intervention with every merge. To do so, just uncomment the entries below -############################################################################### -#*.sln merge=binary -#*.csproj merge=binary -#*.vbproj merge=binary -#*.vcxproj merge=binary -#*.vcproj merge=binary -#*.dbproj merge=binary -#*.fsproj merge=binary -#*.lsproj merge=binary -#*.wixproj merge=binary -#*.modelproj merge=binary -#*.sqlproj merge=binary -#*.wwaproj merge=binary - -############################################################################### -# behavior for image files -# -# image files are treated as binary by default. -############################################################################### -#*.jpg binary -#*.png binary -#*.gif binary - -############################################################################### -# diff behavior for common document formats -# -# Convert binary document formats to text before diffing them. This feature -# is only available from the command line. Turn it on by uncommenting the -# entries below. -############################################################################### -#*.doc diff=astextplain -#*.DOC diff=astextplain -#*.docx diff=astextplain -#*.DOCX diff=astextplain -#*.dot diff=astextplain -#*.DOT diff=astextplain -#*.pdf diff=astextplain -#*.PDF diff=astextplain -#*.rtf diff=astextplain -#*.RTF diff=astextplain diff --git a/StackFlashcards.Ledana/.gitignore b/StackFlashcards.Ledana/.gitignore deleted file mode 100644 index 9491a2fd..00000000 --- a/StackFlashcards.Ledana/.gitignore +++ /dev/null @@ -1,363 +0,0 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. -## -## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore - -# User-specific files -*.rsuser -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Mono auto generated files -mono_crash.* - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -[Ww][Ii][Nn]32/ -[Aa][Rr][Mm]/ -[Aa][Rr][Mm]64/ -bld/ -[Bb]in/ -[Oo]bj/ -[Oo]ut/ -[Ll]og/ -[Ll]ogs/ - -# Visual Studio 2015/2017 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# Visual Studio 2017 auto generated files -Generated\ Files/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUnit -*.VisualState.xml -TestResult.xml -nunit-*.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# Benchmark Results -BenchmarkDotNet.Artifacts/ - -# .NET Core -project.lock.json -project.fragment.lock.json -artifacts/ - -# ASP.NET Scaffolding -ScaffoldingReadMe.txt - -# StyleCop -StyleCopReport.xml - -# Files built by Visual Studio -*_i.c -*_p.c -*_h.h -*.ilk -*.meta -*.obj -*.iobj -*.pch -*.pdb -*.ipdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*_wpftmp.csproj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# Visual Studio Trace Files -*.e2e - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# AxoCover is a Code Coverage Tool -.axoCover/* -!.axoCover/settings.json - -# Coverlet is a free, cross platform Code Coverage Tool -coverage*.json -coverage*.xml -coverage*.info - -# Visual Studio code coverage results -*.coverage -*.coveragexml - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# Note: Comment the next line if you want to checkin your web deploy settings, -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# NuGet Symbol Packages -*.snupkg -# The packages folder can be ignored because of Package Restore -**/[Pp]ackages/* -# except build/, which is used as an MSBuild target. -!**/[Pp]ackages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/[Pp]ackages/repositories.config -# NuGet v3's project.json files produces more ignorable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt -*.appx -*.appxbundle -*.appxupload - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!?*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -orleans.codegen.cs - -# Including strong name files can present a security risk -# (https://github.com/github/gitignore/pull/2483#issue-259490424) -#*.snk - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm -ServiceFabricBackup/ -*.rptproj.bak - -# SQL Server files -*.mdf -*.ldf -*.ndf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings -*.rptproj.rsuser -*- [Bb]ackup.rdl -*- [Bb]ackup ([0-9]).rdl -*- [Bb]ackup ([0-9][0-9]).rdl - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat -node_modules/ - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) -*.vbw - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - -# CodeRush personal settings -.cr/personal - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc - -# Cake - Uncomment if you are using it -# tools/** -# !tools/packages.config - -# Tabs Studio -*.tss - -# Telerik's JustMock configuration file -*.jmconfig - -# BizTalk build output -*.btp.cs -*.btm.cs -*.odx.cs -*.xsd.cs - -# OpenCover UI analysis results -OpenCover/ - -# Azure Stream Analytics local run output -ASALocalRun/ - -# MSBuild Binary and Structured Log -*.binlog - -# NVidia Nsight GPU debugger configuration file -*.nvuser - -# MFractors (Xamarin productivity tool) working folder -.mfractor/ - -# Local History for Visual Studio -.localhistory/ - -# BeatPulse healthcheck temp database -healthchecksdb - -# Backup folder for Package Reference Convert tool in Visual Studio 2017 -MigrationBackup/ - -# Ionide (cross platform F# VS Code tools) working folder -.ionide/ - -# Fody - auto-generated XML schema -FodyWeavers.xsd \ No newline at end of file diff --git a/StackFlashcards.Ledana/App.config b/StackFlashcards.Ledana/App.config deleted file mode 100644 index b8f5657f..00000000 --- a/StackFlashcards.Ledana/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/StackFlashcards.Ledana/Flashcard.cs b/StackFlashcards.Ledana/Flashcard.cs deleted file mode 100644 index 033b4fe2..00000000 --- a/StackFlashcards.Ledana/Flashcard.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace StackFlashcards -{ - internal class Flashcard - { - public int Id { get; set; } - public int StackId { get; set; } - public string Front { get; set; } = null!; - public string Back { get; set; } = null!; - } - - internal class FlashcardDto - { - public int Id { get; set; } - public string Front { get; set; } = null!; - public string Back { get; set; } = null!; - public int RowNum { get; set; } - } -} \ No newline at end of file diff --git a/StackFlashcards.Ledana/Program.cs b/StackFlashcards.Ledana/Program.cs deleted file mode 100644 index dcf11e19..00000000 --- a/StackFlashcards.Ledana/Program.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace StackFlashcards -{ - internal class Program - { - static void Main(string[] args) - { - Console.WriteLine("Welcome in our Application"); - UI ui = new(); - ui.WelcomeUser(); - - Console.WriteLine("Good bye"); - } - } -} diff --git a/StackFlashcards.Ledana/README.md b/StackFlashcards.Ledana/README.md deleted file mode 100644 index d02373e9..00000000 --- a/StackFlashcards.Ledana/README.md +++ /dev/null @@ -1,54 +0,0 @@ -# StackFlashcards📖 Overview -This is a console-based flashcards application designed to help users create, manage, and study flashcard stacks. -The project was built with SQL Server for database management and Dapper for data access, with a focus on clean, reusable code and minimal repetition. - -⚙️ Features -• Stack Management -• Create new stacks and assign them a name. -• Delete stacks (all cards within the stack are deleted automatically). -• Card Management -• Add cards to a stack with front and back text. -• Delete individual cards. -• View all cards with sequential IDs (no gaps). -• Study Mode -• Choose a stack to study. -- See only the front of each card. -- Indicate whether you know the back → score updates accordingly. -- Sessions Tracking -- View study sessions with: -- Stack name -- Cards studied -- Score per stack -- Date of study -- DTOs -- First-time use of Data Transfer Objects (DTOs) to structure data between layers. - -🗄️ Database -- Database and tables were created in SQL Server Management Studio (SSMS). -- Code for table creation and population is stored in dbFile. -- Relationships: -- Stacks → Cards (cascade delete: deleting a stack removes its cards). -- Sessions → Stacks/Cards (tracks study history). - -💻 Code Design -- Dapper used for lightweight ORM functionality. -- Main Program kept as plain as possible: -- Delegates logic to service classes and helpers. -- Focuses on user interaction and menu flow. -- Clean Code Principles -- Reduced repetition with reusable helpers. -- Clear separation of concerns (DB operations, DTOs, UI flow). - -🚀 How to Use -- Create a stack → give it a name. -- Add cards → define front and back text. -- View cards → see IDs, front, and back. -- Study a stack → test yourself on the front, check if you know the back, and track your score. -- Delete stacks/cards → manage your collection. -- View study sessions → review past performance and progress. - -📌 Notes -- This is my first time using DTOs — they helped me structure data flow between layers. -- The app emphasizes auditability and clean control flow. -- IDs are processed with Row_Number function in console to avoid gaps when items are deleted. - diff --git a/StackFlashcards.Ledana/Stack.cs b/StackFlashcards.Ledana/Stack.cs deleted file mode 100644 index 4412ff8f..00000000 --- a/StackFlashcards.Ledana/Stack.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace StackFlashcards -{ - internal class Stack - { - public int Id { get; set; } - public string Name { get; set; } = null!; - } -} \ No newline at end of file diff --git a/StackFlashcards.Ledana/StackFlashcardServices.cs b/StackFlashcards.Ledana/StackFlashcardServices.cs deleted file mode 100644 index c165eaa7..00000000 --- a/StackFlashcards.Ledana/StackFlashcardServices.cs +++ /dev/null @@ -1,216 +0,0 @@ -using Dapper; -using Microsoft.Data.SqlClient; -using System.Configuration; - -namespace StackFlashcards -{ - internal class StackFlashcardServices - { - readonly string connectionString = ConfigurationManager.AppSettings.Get("ConnectionString"); - - //creating a new flashcard in a new stack - internal void CreateFlashCard(string name, string front, string back) - { - using SqlConnection connection = new(connectionString); - - Stack? stack = GetStackByName(name); - - var createFlashcardQuery = @"INSERT INTO Flashcard (StackId, Front, Back) - VALUES (@StackId, @Front, @Back)"; - - connection.Execute(createFlashcardQuery, new { StackId = stack.Id, Front = front, Back = back }); - } - - //creating a new stack with name - internal void CreateStack(string name) - { - using SqlConnection connection = new(connectionString); - - var createStackQuery = "INSERT INTO Stack ([Name]) VALUES (@Name)"; - - connection.Execute(createStackQuery, new { Name = name }); - } - - //deleting a stack with ame - internal void DeleteStack(string name) - { - using SqlConnection connection = new(connectionString); - - var deleteStackQuery = "DELETE FROM Stack WHERE [Name] = @Name"; - - connection.Execute(deleteStackQuery, new { Name = name }); - } - - //getting all the flashcards in the db with their true id - internal List GetAllFlashcards() - { - using SqlConnection connection = new(connectionString); - - var getAllFlashcardsQuery = "SELECT ROW_NUMBER() OVER (ORDER BY Id) AS RowNum, Id, Front, Back FROM Flashcard"; - - return connection.Query(getAllFlashcardsQuery).ToList(); - } - - //getting the number of flashcards in a stack to calculate score - internal int? GetFlashcardNumber(string name) - { - using SqlConnection connection = new(connectionString); - - Stack? stack = GetStackByName(name); - if (stack is null) return null; - - var getFlashcardCountQuery = "SELECT COUNT(*) FROM Flashcard WHERE StackId = @StackId"; - - return connection.ExecuteScalar(getFlashcardCountQuery, new { StackId = stack.Id }); - } - - //getting the front part of a card to show to user when in study session - internal string? GetFront(string name, int id) - { - using SqlConnection connection = new(connectionString); - - Stack? stack = GetStackByName(name); - if (stack is null) return null; - - var flashcards = GetFlashcardsByStackId(stack.Id); - var card = flashcards.FirstOrDefault(f => f.RowNum == id); - - return card?.Front; - } - //getting the back side of the card to show it to user - internal string? GetRightAnswer(string name, int id) - { - using SqlConnection connection = new(connectionString); - - Stack? stack = GetStackByName(name); - if (stack is null) return null; - - var flashcards = GetFlashcardsByStackId(stack.Id); - var card = flashcards.FirstOrDefault(f => f.RowNum == id); - - return card?.Back; - } - - //helper method to get a stack by id - internal List GetFlashcardsByStackId(int Id) - { - using SqlConnection connection = new(connectionString); - var getFlashcardsQuery = "SELECT ROW_NUMBER() OVER (ORDER BY Id) AS RowNum, Id, Front, Back FROM Flashcard WHERE StackId = @StackId"; - - return connection.Query(getFlashcardsQuery, new { StackId = Id }).ToList(); - } - - //getting all study sessions with a query with joins so other details show also - internal List GetStudySessionsDetails() - { - using SqlConnection connection = new(connectionString); - - var getStudySessionDetailsQuery = "SELECT s.[Name], f.Front, f.Back, ss.[Date], ss.Score\r\nFROM StudySessions ss\r\nJOIN Stack s ON s.Id = ss.StackId\r\nJOIN Flashcard f ON f.StackId = s.Id"; - - return connection.Query(getStudySessionDetailsQuery).ToList(); - } - - //inserting a new row in studysessions with the stackid, date and score - internal void OpenStudySession(string name, DateTime date, string score) - { - using SqlConnection connection = new(connectionString); - - Stack? stack = GetStackByName(name); - if (stack is null) - { - Console.WriteLine("Stack not found"); - return; - } - - var insertQuery = "INSERT INTO StudySessions (Date, StackId, Score) VALUES (@Date, @StackId, @Score)"; - - connection.Execute(insertQuery, new StudySession() { Date = date, StackId = stack.Id, Score = score }); - } - - //comparig the back side of the card with the given answer by user with the name of stack, rownum shown as id. - internal bool ValidateAnswer(string name, int id, string answer) - { - using SqlConnection connection = new(connectionString); - - Stack? stack = GetStackByName(name); - - var getFlashcardsQuery = "SELECT ROW_NUMBER() OVER (ORDER BY Id) AS RowNum, Front, Back FROM Flashcard WHERE StackId = @StackId"; - var flashcards = connection.Query(getFlashcardsQuery, new { StackId = stack.Id }).ToList(); - var card = flashcards.FirstOrDefault(f => f.RowNum == id); - - return answer == card?.Back; - } - //checking if id form user matches any card with rownum as id when deleting or vstuding - internal bool ValidateIdInput(string name, int num) - { - using SqlConnection connection = new(connectionString); - - Stack? stack = GetStackByName(name); - - var getFlashcardsQuery = "SELECT ROW_NUMBER() OVER (ORDER BY Id) AS RowNum, Front, Back FROM Flashcard WHERE StackId = @StackId"; - - var flashcards = connection.Query(getFlashcardsQuery, new { StackId = stack.Id }).ToList(); - - return flashcards.Any(c => c.RowNum == num); - } - //checking if stack name is in the db - internal bool ValidateStackName(string name) - { - using SqlConnection connection = new(connectionString); - - var checkNamesQuery = "SELECT COUNT(*) FROM Stack WHERE [Name] = @Name"; - - var nameExists = connection.ExecuteScalar(checkNamesQuery, new { Name = name }); - - return nameExists > 0; - } - //getting the list of all stacks in db - internal List ViewStackList() - { - using SqlConnection connection = new(connectionString); - - var getStackListQuery = "SELECT * FROM Stack ORDER BY Id"; - - return connection.Query(getStackListQuery).ToList(); - } - //getting the list of cards in a stack given its name - internal List? GetStack(string name) - { - using SqlConnection connection = new(connectionString); - - Stack? stack = GetStackByName(name); - if (stack is null) return null; - - var getFlashcardQuery = "SELECT ROW_NUMBER() OVER (ORDER BY Id) AS RowNum, Front FROM Flashcard WHERE StackId = @StackId"; - - return connection.Query(getFlashcardQuery, new { StackId = stack.Id }).ToList(); - } - //helper method to get a stack by its name - internal Stack? GetStackByName(string name) - { - using SqlConnection connection = new(connectionString); - - var getStackQuery = "SELECT * FROM Stack WHERE [Name] = @Name"; - - return connection.QuerySingleOrDefault(getStackQuery, new { Name = name }); - } - - //deleting a row in flashcard table given the id - internal void DeleteFlashcard(string name, int id) - { - using SqlConnection connection = new(connectionString); - - Stack? stack = GetStackByName(name); - - var getFlashcardsQuery = "SELECT ROW_NUMBER() OVER (ORDER BY Id) AS RowNum, Id, Front, Back FROM Flashcard WHERE StackId = @StackId"; - List cards = connection.Query(getFlashcardsQuery, new { StackId = stack.Id }).ToList(); - - var cardToDelete = cards.FirstOrDefault(f => f.RowNum == id); - - var deleteFlashcardQuery = "DELETE FROM Flashcard WHERE Id = @Id"; - - connection.Execute(deleteFlashcardQuery, new { Id = cardToDelete.Id }); - } - - } -} \ No newline at end of file diff --git a/StackFlashcards.Ledana/StackFlashcards.csproj b/StackFlashcards.Ledana/StackFlashcards.csproj deleted file mode 100644 index b976e5c3..00000000 --- a/StackFlashcards.Ledana/StackFlashcards.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - Exe - net10.0 - enable - enable - - - - - - - - - - - diff --git a/StackFlashcards.Ledana/StackFlashcards.slnx b/StackFlashcards.Ledana/StackFlashcards.slnx deleted file mode 100644 index ae8c5998..00000000 --- a/StackFlashcards.Ledana/StackFlashcards.slnx +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/StackFlashcards.Ledana/StudySession.cs b/StackFlashcards.Ledana/StudySession.cs deleted file mode 100644 index d726f7ea..00000000 --- a/StackFlashcards.Ledana/StudySession.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace StackFlashcards -{ - internal class StudySession - { - public int Id { get; set; } - public DateTime Date { get; set; } - public string? Score { get; set; } - public int StackId { get; set; } - } - //creating another class for studysessions so when showing the list show other details from stack and cards with the right query - internal class StudySessionDetails - { - public int Id { get; set; } - public DateTime Date { get; set; } - public string? Score { get; set; } - public int StackId { get; set; } - public string Front { get; set; } = null!; - public string Back { get; set; } = null!; - public string Name { get; set; } = null!; - } -} \ No newline at end of file diff --git a/StackFlashcards.Ledana/TableVisualisation.cs b/StackFlashcards.Ledana/TableVisualisation.cs deleted file mode 100644 index ea0f1a49..00000000 --- a/StackFlashcards.Ledana/TableVisualisation.cs +++ /dev/null @@ -1,73 +0,0 @@ -using Spectre.Console; -namespace StackFlashcards -{ - internal class TableVisualisation - { - internal void ShowStacks(List allStacks) - { - var table = new Table() - .RoundedBorder() - .BorderColor(Color.Red); - table.AddColumn("Name"); - - foreach (var item in allStacks) - { - table.AddRow(item.Name); - } - AnsiConsole.Write(table); - } - - //when showing a stack show the flashcards with stacks name as title - internal void ShowFlashCards(string name, List stack) - { - var table = new Table() - .Title(name) - .RoundedBorder() - .BorderColor(Color.Red); - table.AddColumn("Id"); - table.AddColumn("Front"); - - foreach (var item in stack) - { - table.AddRow(item.RowNum.ToString(), item.Front); - } - AnsiConsole.Write(table); - } - //when showing all stacks list them without a title - internal void ShowFlashCards(List flashcards) - { - var table = new Table() - .RoundedBorder() - .BorderColor(Color.Red); - table.AddColumn("Id"); - table.AddColumn("Front"); - table.AddColumn("Back"); - - foreach (var item in flashcards) - { - table.AddRow(item.RowNum.ToString(), item.Front, item.Back); - } - AnsiConsole.Write(table); - } - internal void ShowStudySessions(List studySessions) - { - var table = new Table() - .RoundedBorder() - .BorderColor(Color.Red); - table.ShowRowSeparators = true; - - table.AddColumn("Name"); - table.AddColumn("Front"); - table.AddColumn("Back"); - table.AddColumn("Date"); - table.AddColumn("Score"); - - foreach (var item in studySessions) - { - //if score is null show 0 in table - table.AddRow(item.Name, item.Front, item.Back, item.Date.ToString("d"), (item.Score == null ? "0" : item.Score)); - } - AnsiConsole.Write(table); - } - } -} \ No newline at end of file diff --git a/StackFlashcards.Ledana/UI.cs b/StackFlashcards.Ledana/UI.cs deleted file mode 100644 index 53ed2f41..00000000 --- a/StackFlashcards.Ledana/UI.cs +++ /dev/null @@ -1,320 +0,0 @@ -using System.Xml.Linq; - -namespace StackFlashcards -{ - internal class UI - { - readonly StackFlashcardServices stackFlashcardServices = new(); - private readonly TableVisualisation tableVisualisation = new(); - public void WelcomeUser() - { - //keep running this method till the user inputs 0 - while (true) //////////// - { - ShowMenu(); - - string input = GetUserInput("Please type a number between 0 and 7"); - - switch (input) - { - case "0": - return; - case "1": - OpenStudySession(); - break; - case "2": - CreateStack(); - break; - case "3": - ViewStack(); - break; - case "4": - ViewAllFlashcards(); - break; - case "5": - ViewStudySessions(); - break; - case "6": - DeleteStack(); - break; - case "7": - DeleteFlashcard(); - break; - - default: - Console.WriteLine("Invalid input. Please type a number between 0 and 7"); - break; - } - } - } - - private void DeleteFlashcard() - { - ViewAllStacks(); - string stackName = GetExistingStackName("PLease put the name of stack you want to delete flashcard in"); - if (stackName == "0") return; - - List? stack = stackFlashcardServices.GetStack(stackName); - if (stack is null) - { - Console.WriteLine("Stack not found"); - return; - } - - tableVisualisation.ShowFlashCards(stackName, stack); - - int id = GetValidatedInt("Please put the id of the flashcard you want to delete or type 0 to return\n"); - - //check if the id exists in the db, if not keep asking for an id or 0 to exit - - while (!stackFlashcardServices.ValidateIdInput(stackName, id)) - { - id = GetValidatedInt("Please put the id of the flashcard you want to delete or type 0 to return"); - if (id == 0) return; - - } - - //if the id is found in db and user didn't type 0 to exit then delete the card and notify user in console - stackFlashcardServices.DeleteFlashcard(stackName, id); - - Console.WriteLine($"\nFlashcard with Id {id} was deleted"); - } - - private static void ShowMenu() - { - Console.WriteLine("\nWhat do you want to do?"); - Console.WriteLine("0. Close the App"); - Console.WriteLine("1. Study a stack of flashcards"); - Console.WriteLine("2. Create a stack of flashcard"); - Console.WriteLine("3. View a stack"); - Console.WriteLine("4. View all flashcards"); - Console.WriteLine("5. View Study Sessions"); - Console.WriteLine("6. Delete a stack"); - Console.WriteLine("7. Delete a Flashcard"); - } - - private void DeleteStack() - { - ViewAllStacks(); - string name = GetExistingStackName("Please put the name of the stack you want to delete or type '0' to return to main menu"); - if (name == "0") return; - - stackFlashcardServices.DeleteStack(name); - Console.WriteLine($"\nStack {name} was deleted"); - } - - private void ViewAllFlashcards() - { - //getting all the cards from the db and showing them with spectre.console - List allFlashcards = stackFlashcardServices.GetAllFlashcards(); - tableVisualisation.ShowFlashCards(allFlashcards); - } - - private void ViewStudySessions() - { - List studySessionsDetails = stackFlashcardServices.GetStudySessionsDetails(); - tableVisualisation.ShowStudySessions(studySessionsDetails); - } - private void ViewAllStacks() - { - List allStacks = stackFlashcardServices.ViewStackList(); - tableVisualisation.ShowStacks(allStacks); - } - private void ViewStack() - { - ViewAllStacks(); - string name = GetExistingStackName("Please put the name of the stack you want or type '0' to return to main menu"); - if (name == "0") return; - - List? stack = stackFlashcardServices.GetStack(name); - if (stack is null) - { - Console.WriteLine("Stack not found"); - return; - } - - tableVisualisation.ShowFlashCards(name, stack); - } - - private void CreateStack() - { - string name = GetNewStackName("Please enter the name of the stack or type '0' to exit"); - if (name == "0") return; - - stackFlashcardServices.CreateStack(name); - - bool addFlashcard = AskUserToAddFlashcard(); - - while (addFlashcard) - { - string front = GetFrontOfStack(); - string back = GetBackOfStack(); - stackFlashcardServices.CreateFlashCard(name, front, back); - addFlashcard = AskUserToAddFlashcard(); - } - } - - private bool AskUserToAddFlashcard() - { - Console.WriteLine("Do you want to add a flashcard to the stack?"); - string input = GetUserInput("Type 'y' to add or '0' to continue"); - if (input == "y") return true; - - return false; - } - - private string GetBackOfStack() - { - return GetUserInput("Please put the back part of the stack"); - } - - private string GetFrontOfStack() - { - return GetUserInput("Please put the front part of the stack"); - } - - private void OpenStudySession() - { - ViewAllStacks(); - string name = GetExistingStackName("Please enter the name of the stack you want to study or type '0' to return to main menu"); - if (name == "0") return; - - DateTime date = DateTime.Today.Date; - string? score = StudyStack(name); - - if (score is null) - { - return; - } - - //if the stack was empty not add the study session - if (score == "0") return; - - Console.WriteLine($"\nYour score is {score}"); - - stackFlashcardServices.OpenStudySession(name, date, score); - } - - private string? StudyStack(string name) - { - int score = 0; - int? maxScore = stackFlashcardServices.GetFlashcardNumber(name); - - if (maxScore is null) return null; - //counting question answered so the user doesn't answer the same one more than once - int question = 0; - - //if the stack doesn't have cards return 0 - if (maxScore == 0) - { - Console.WriteLine("The stack is empty"); - return "0"; - } - - var flashcards = stackFlashcardServices.GetStack(name); - if (flashcards is null) - { - Console.WriteLine("Stack not found"); - return null; - } - - tableVisualisation.ShowFlashCards(name, flashcards); - - while (question < maxScore) - { - int id = GetValidatedInt("Please put the id of the flashcard you want to study or '0' to exit"); - - if (id == 0) break; - - while (!stackFlashcardServices.ValidateIdInput(name, id)) - { - Console.WriteLine($"The card with Id {id} doesn't exist\n"); - id = GetValidatedInt("Please put the id of the flashcard you want to study or '0' to exit"); - } - if (id == 0) break; - - string? front = stackFlashcardServices.GetFront(name, id); - Console.WriteLine(); - Console.WriteLine(front); - string? answer = GetUserInput("Please type the answer of the flashcard\n"); - - if (stackFlashcardServices.ValidateAnswer(name, id, answer)) - { - score++; - question++; - RightAnswer(name, id); - } - else - { - question++; - WrongAnswer(name, id); - } - } - return score + "/" + maxScore; - } - private void RightAnswer(string name, int id) - { - Console.WriteLine("\nCorrect answer"); - Console.WriteLine(stackFlashcardServices.GetRightAnswer(name, id)); - } - private void WrongAnswer(string name, int id) - { - Console.WriteLine("\nWrong answer"); - Console.WriteLine("The correct answer was: "); - Console.WriteLine(stackFlashcardServices.GetRightAnswer(name, id)); - } - - private string GetUserInput(string message) - { - Console.WriteLine(message); - string? input = Console.ReadLine(); - - while (string.IsNullOrEmpty(input)) - { - Console.WriteLine(message); - input = Console.ReadLine(); - } - - return input; - } - - //helper method to validate input as int and as a name in the db or not - private int GetValidatedInt(string message) - { - string input = GetUserInput(message); - if (input == "0") return 0; - - int num; - while (!int.TryParse(input, out num)) - { - input = GetUserInput(message); - if (input == "0") return 0; - } - return num; - } - private string GetExistingStackName(string message) - { - string name = GetUserInput(message); - if (name == "0") return "0"; - - while (!stackFlashcardServices.ValidateStackName(name)) - { - name = GetUserInput(message); - if (name == "0") return "0"; - } - return name; - } - private string GetNewStackName(string message) - { - string name = GetUserInput(message); - if (name.Trim() == "0") return "0"; - - while (stackFlashcardServices.ValidateStackName(name)) - { - name = GetUserInput(message); - if (name.Trim() == "0") return "0"; - } - return name; - } - } -} \ No newline at end of file diff --git a/StackFlashcards.Ledana/dbFile.md b/StackFlashcards.Ledana/dbFile.md deleted file mode 100644 index 839f0dcd..00000000 --- a/StackFlashcards.Ledana/dbFile.md +++ /dev/null @@ -1,23 +0,0 @@ -CREATE TABLE Stack ( - Id INT PRIMARY KEY IDENTITY (1, 1), - [NAME] NVARCHAR (25) NOT NULL UNIQUE -); - -CREATE TABLE Flashcard ( -Id INT IDENTITY (1,1) PRIMARY KEY, -Front NVARCHAR(MAX) NOT NULL, -Back NVARCHAR(MAX) NOT NULL, -StackId INT NOT NULL, -CONSTRAINT FK_Flashcard_Stack FOREIGN KEY (StackId) REFERENCES Stack(Id) ON DELETE CASCADE -); - -CREATE TABLE StudySessions ( -Id INT PRIMARY KEY IDENTITY (1,1), -[Date] DATE NOT NULL, -Score NVARCHAR(25) NOT NULL, -StackId INT NOT NULL, -CONSTRAINT FK_StudySessions_Stack FOREIGN KEY (StackId) REFERENCES Stack(Id) ON DELETE CASCADE -); - - -