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; + } + } + } +}