Improved TUI for a better UX

This commit is contained in:
2025-12-31 12:06:37 +03:30
parent 9744b2a788
commit 6462fa0409
8 changed files with 305 additions and 130 deletions

View File

@@ -16,54 +16,54 @@ namespace TBDel.Commands
if (File.Exists(absolutePath))
{
Console.WriteLine($"Adding: {absolutePath}");
TuiHelper.DisplayInfo($"Adding file: {absolutePath}");
if (await dbService.EtryExists(absolutePath))
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("File already exists in the list - No actions performed.");
TuiHelper.DisplayWarning("File already exists in the list - No actions performed.");
return;
}
var entry = new FileEntry { Id = GenerateUniqueId(dbService), Path = absolutePath, DateAdded = DateTime.Now };
if (await dbService.AddFileEntryAsync(entry))
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("File added successfully.");
Console.ResetColor();
TuiHelper.DisplaySuccess("File added successfully.");
return;
}
else
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Failed to add file.");
Console.ResetColor();
TuiHelper.DisplayError("Failed to add file.");
return;
}
}
else if (Directory.Exists(absolutePath))
{
Console.WriteLine($"Adding: {absolutePath}");
TuiHelper.DisplayInfo($"Adding directory: {absolutePath}");
if (await dbService.EtryExists(absolutePath))
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("Folder already exists in the list - No actions performed.");
TuiHelper.DisplayWarning("Folder already exists in the list - No actions performed.");
return;
}
var entry = new FolderEntry() { Id = GenerateUniqueId(dbService), Path = absolutePath, DateAdded = DateTime.Now };
if (await dbService.AddFolderEntryAsync(entry))
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Directory added successfully.");
Console.ResetColor();
TuiHelper.DisplaySuccess("Directory added successfully.");
return;
}
else
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Failed to add directory.");
Console.ResetColor();
TuiHelper.DisplayError("Failed to add directory.");
return;
}
}
else
{
TuiHelper.DisplayError($"Path does not exist: {absolutePath}");
return;
}
}
else
{
TuiHelper.DisplayError("No path provided. Please specify a file or folder to add.");
return;
}
}

View File

@@ -12,81 +12,92 @@ public class DeleteAllCommand
if (allFiles.Count == 0 && allFolders.Count == 0)
{
Console.WriteLine("No files or folders found.");
TuiHelper.DisplayInfo("No files or folders found.");
return;
}
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write(
$"Are you sure you want to permanently delete {allFiles.Count} file(s) and {allFolders.Count} folder(s)? (y/N) ");
Console.ResetColor();
var input = Console.ReadLine();
if (input != "y")
TuiHelper.DisplayHeader("TBDel - Delete All Entries");
// Display summary before confirmation
TuiHelper.DisplaySummary("Deletion Summary",
("Files to delete", allFiles.Count.ToString()),
("Folders to delete", allFolders.Count.ToString()),
("Total items", (allFiles.Count + allFolders.Count).ToString())
);
if (!TuiHelper.GetConfirmation("Permanently delete ALL entries?"))
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Operation cancelled.");
Console.ResetColor();
TuiHelper.DisplayInfo("Operation cancelled.");
return;
}
int deletedFiles = 0;
int deletedFolders = 0;
int failedDeletions = 0;
foreach (var file in allFiles)
{
if (!File.Exists(file.Path))
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"File {file.Path} does not exist, removing from list.");
Console.ResetColor();
TuiHelper.DisplayWarning($"File {file.Path} does not exist, removing from list.");
await dbService.RemoveFileEntryAsync(file.Id);
continue;
}
Console.WriteLine($"Deleting file: {file.Path}");
TuiHelper.DisplayInfo($"Deleting file: {file.Path}");
try
{
File.Delete(file.Path);
await dbService.RemoveFileEntryAsync(file.Id);
deletedFiles++;
}
catch (Exception e)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Something went wrong while deleting the file.");
TuiHelper.DisplayError("Something went wrong while deleting the file.");
Console.WriteLine(e.Message);
Console.ResetColor();
return;
failedDeletions++;
}
await dbService.RemoveFileEntryAsync(file.Id);
}
foreach (var folder in allFolders)
{
if (!Directory.Exists(folder.Path))
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"Directory {folder.Path} does not exist, removing from list.");
Console.ResetColor();
TuiHelper.DisplayWarning($"Directory {folder.Path} does not exist, removing from list.");
await dbService.RemoveFolderEntryAsync(folder.Id);
continue;
}
Console.WriteLine($"Deleting directory: {folder.Path}");
TuiHelper.DisplayInfo($"Deleting directory: {folder.Path}");
try
{
Directory.Delete(folder.Path, true);
await dbService.RemoveFolderEntryAsync(folder.Id);
deletedFolders++;
}
catch (Exception e)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Something went wrong while deleting the directory.");
TuiHelper.DisplayError("Something went wrong while deleting the directory.");
Console.WriteLine(e.Message);
Console.ResetColor();
return;
failedDeletions++;
}
await dbService.RemoveFolderEntryAsync(folder.Id);
}
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("All files and folders deleted successfully.");
Console.ResetColor();
// Display final results
TuiHelper.DisplayHeader("Deletion Results");
TuiHelper.DisplaySummary("Summary",
("Files deleted", deletedFiles.ToString()),
("Folders deleted", deletedFolders.ToString()),
("Failed deletions", failedDeletions.ToString())
);
if (failedDeletions == 0)
{
TuiHelper.DisplaySuccess("All files and folders deleted successfully.");
}
else
{
TuiHelper.DisplayWarning("Some items could not be deleted.");
}
}
}

View File

@@ -8,21 +8,26 @@ namespace TBDel.Commands
public static async Task DeleteEntry(string[] args)
{
var dbService = new DbService();
if (args.Length > 1 && uint.TryParse(args[1], out uint id))
{
var filePath = await dbService.GetEntryPath(id);
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write($"Are you sure you want to permanently delete entry with ID {id}? (y/N) ");
Console.ResetColor();
var input = Console.ReadLine();
if (input != "y")
if (string.IsNullOrEmpty(filePath))
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Operation cancelled.");
Console.ResetColor();
TuiHelper.DisplayError($"No entry found with ID {id}.");
return;
}
// Display entry details before confirmation
TuiHelper.DisplayHeader("TBDel - Delete Entry");
Console.WriteLine($"Entry ID: {id}");
Console.WriteLine($"Path: {filePath}");
Console.WriteLine();
if (!TuiHelper.GetConfirmation($"Permanently delete this entry?"))
{
TuiHelper.DisplayInfo("Operation cancelled.");
return;
}
@@ -31,15 +36,11 @@ namespace TBDel.Commands
File.Delete(filePath);
if (await dbService.RemoveFileEntryAsync(id))
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("File deleted successfully.");
Console.ResetColor();
TuiHelper.DisplaySuccess("File deleted successfully.");
}
else
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Something went wrong while deleting the file.");
Console.ResetColor();
TuiHelper.DisplayError("Something went wrong while deleting the file.");
}
}
else if (Directory.Exists(filePath))
@@ -50,34 +51,31 @@ namespace TBDel.Commands
}
catch (Exception e)
{
Console.ForegroundColor = ConsoleColor.Red;
if (e.Message.Contains("Directory not empty"))
{
Console.WriteLine("Directory is not empty. It must be empty before it can be deleted or deleted manually.");
TuiHelper.DisplayError("Directory is not empty. It must be empty before it can be deleted or deleted manually.");
}
else
{
TuiHelper.DisplayError("Something went wrong while deleting the directory.");
Console.WriteLine(e.Message);
}
Console.WriteLine("Something went wrong while deleting the directory.");
Console.ResetColor();
Console.WriteLine(e.Message);
return;
}
if (await dbService.RemoveFolderEntryAsync(id))
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Directory deleted successfully.");
Console.ResetColor();
TuiHelper.DisplaySuccess("Directory deleted successfully.");
}
else
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Something went wrong while deleting the directory.");
Console.ResetColor();
TuiHelper.DisplayError("Something went wrong while deleting the directory.");
}
}
}
else
{
TuiHelper.DisplayError("Invalid ID provided. Please provide a valid numeric ID.");
}
}
}

View File

@@ -1,4 +1,6 @@
using TBDel.Services;
namespace TBDel.Commands;
public static class HelpCommand
@@ -13,17 +15,47 @@ public static class HelpCommand
{
if (showOnWrongCommand)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.Error.WriteLine("Invalid command. Use 'tbdel help' for help.");
Console.ResetColor();
TuiHelper.DisplayError("Invalid command. Use 'tbdel help' for help.");
}
TuiHelper.DisplayHeader("TBDel - Help");
Console.WriteLine("Usage: tbdel <command> [arguments]");
Console.WriteLine("Available commands:");
Console.WriteLine(" add <path to file or folder> Add a file or folder to the list");
Console.WriteLine(" delete <file or folder ID> Deletes a file or folder");
Console.WriteLine(" deleteall Deletes all items in the list");
Console.WriteLine(" rmflist Remove an entry ONLY from the list");
Console.WriteLine(" list Lists all items in the list");
Console.WriteLine(" help Shows this help message");
Console.WriteLine();
TuiHelper.DisplayInfo("Available commands:");
Console.WriteLine();
Console.WriteLine(" add <path to file or folder> │ Add a file or folder to the list");
Console.WriteLine(" │ Example: tbdel add ./myfile.txt");
Console.WriteLine();
Console.WriteLine(" delete <file or folder ID> │ Delete a file or folder permanently");
Console.WriteLine(" │ Example: tbdel delete 12345");
Console.WriteLine();
Console.WriteLine(" deleteall │ Delete all items in the list");
Console.WriteLine(" │ Example: tbdel deleteall");
Console.WriteLine();
Console.WriteLine(" rmflist <entry ID> │ Remove an entry ONLY from the list");
Console.WriteLine(" │ Example: tbdel rmflist 12345");
Console.WriteLine();
Console.WriteLine(" list │ List all items in the list");
Console.WriteLine(" │ Example: tbdel list");
Console.WriteLine();
Console.WriteLine(" list files │ List only files in the list");
Console.WriteLine(" │ Example: tbdel list files");
Console.WriteLine();
Console.WriteLine(" list folders │ List only folders in the list");
Console.WriteLine(" │ Example: tbdel list folders");
Console.WriteLine();
Console.WriteLine(" help │ Show this help message");
Console.WriteLine(" │ Example: tbdel help");
Console.WriteLine();
}
}

View File

@@ -9,26 +9,27 @@ namespace TBDel.Commands
{
if (args.Length > 2)
{
Console.WriteLine("Too many arguments.");
TuiHelper.DisplayError("Too many arguments.");
return;
}
if (args.Length == 1)
{
Console.WriteLine("Listing both files and folders.");
TuiHelper.DisplayHeader("TBDel - List All Items");
TuiHelper.DisplayInfo("Listing both files and folders.");
await ListFiles();
for (int i = 0; i < 110; i++)
{
Console.Write("-");
}
Console.Write("\n");
TuiHelper.DisplaySectionSeparator();
await ListFolders();
}
else if (args[1] == "files")
{
TuiHelper.DisplayHeader("TBDel - List Files");
await ListFiles();
}
else if (args[1] == "folders")
{
TuiHelper.DisplayHeader("TBDel - List Folders");
await ListFolders();
}
}
@@ -40,17 +41,17 @@ namespace TBDel.Commands
if (filesList.Count == 0)
{
Console.WriteLine("No files found.");
TuiHelper.DisplayInfo("No files found.");
return;
}
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Found {0} file(s):\n", filesList.Count);
Console.WriteLine("{0,-10} {1,-90} {2,10}\n", "ID", "Path", "Date added");
Console.ResetColor();
TuiHelper.DisplayInfo($"Found {filesList.Count} file(s):");
Console.WriteLine();
TuiHelper.DisplayTableHeader("ID", "Path", "Date Added", 10, 60, 20);
foreach (var file in filesList)
{
Console.WriteLine("{0,-10} {1,-90} {2,10}", file.Id, file.Path, file.DateAdded);
TuiHelper.DisplayTableRow(file.Id, file.Path, file.DateAdded, 10, 60, 20);
}
}
@@ -61,17 +62,17 @@ namespace TBDel.Commands
if (foldersList.Count == 0)
{
Console.WriteLine("No folders found.");
TuiHelper.DisplayInfo("No folders found.");
return;
}
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Found {0} folder(s):\n", foldersList.Count);
Console.WriteLine("{0,-10} {1,-90} {2,10}\n", "ID", "Path", "Date added");
Console.ResetColor();
TuiHelper.DisplayInfo($"Found {foldersList.Count} folder(s):");
Console.WriteLine();
TuiHelper.DisplayTableHeader("ID", "Path", "Date Added", 10, 60, 20);
foreach (var folder in foldersList)
{
Console.WriteLine("{0,-10} {1,-90} {2,10}", folder.Id, folder.Path, folder.DateAdded);
TuiHelper.DisplayTableRow(folder.Id, folder.Path, folder.DateAdded, 10, 60, 20);
}
}
}

View File

@@ -9,33 +9,37 @@ public class RemoveFromListCommand
var dbService = new DbService();
if (args.Length > 1 && uint.TryParse(args[1], out uint id))
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write($"Are you sure you want to remove the entry with ID {id} ONLY from the list? (y/N) ");
Console.ResetColor();
var input = Console.ReadLine();
if (input != "y")
var filePath = await dbService.GetEntryPath(id);
if (string.IsNullOrEmpty(filePath))
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Operation cancelled.");
Console.ResetColor();
TuiHelper.DisplayError($"No entry found with ID {id}.");
return;
}
TuiHelper.DisplayHeader("TBDel - Remove from List");
Console.WriteLine($"Entry ID: {id}");
Console.WriteLine($"Path: {filePath}");
Console.WriteLine();
if (!TuiHelper.GetConfirmation("Remove this entry ONLY from the list?"))
{
TuiHelper.DisplayInfo("Operation cancelled.");
return;
}
if (await dbService.RemoveFileEntryAsync(id) || await dbService.RemoveFolderEntryAsync(id))
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Entry removed from the list.");
Console.ResetColor();
TuiHelper.DisplaySuccess("Entry removed from the list.");
}
else
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Something went wrong while removing the entry from list.");
Console.ResetColor();
TuiHelper.DisplayError("Something went wrong while removing the entry from list.");
}
}
else
{
TuiHelper.DisplayError("Invalid ID provided. Please provide a valid numeric ID.");
}
}
}

129
Services/TuiHelper.cs Normal file
View File

@@ -0,0 +1,129 @@
using System;
using TBDel.Models;
namespace TBDel.Services
{
public static class TuiHelper
{
// Color constants for consistent styling
public static readonly ConsoleColor HeaderColor = ConsoleColor.Cyan;
public static readonly ConsoleColor SuccessColor = ConsoleColor.Green;
public static readonly ConsoleColor WarningColor = ConsoleColor.Yellow;
public static readonly ConsoleColor ErrorColor = ConsoleColor.Red;
public static readonly ConsoleColor InfoColor = ConsoleColor.White;
public static readonly ConsoleColor BorderColor = ConsoleColor.DarkGray;
// Display a styled header
public static void DisplayHeader(string title)
{
var border = new string('═', Math.Min(title.Length + 4, 80));
Console.ForegroundColor = HeaderColor;
Console.WriteLine($"\n╔{border}╗");
Console.WriteLine($"║ {title} ║");
Console.WriteLine($"╚{border}╝");
Console.ResetColor();
}
// Display a styled section separator
public static void DisplaySectionSeparator(int length = 80)
{
Console.ForegroundColor = BorderColor;
Console.WriteLine(new string('─', length));
Console.ResetColor();
}
// Display a styled table header
public static void DisplayTableHeader(string idLabel, string pathLabel, string dateLabel, int idWidth = 10, int pathWidth = 70, int dateWidth = 20)
{
Console.ForegroundColor = HeaderColor;
Console.WriteLine("{0,-" + idWidth + "} │ {1,-" + pathWidth + "} │ {2,-" + dateWidth + "}", idLabel, pathLabel, dateLabel);
DisplayTableSeparator(idWidth, pathWidth, dateWidth);
Console.ResetColor();
}
// Display a table separator line
public static void DisplayTableSeparator(int idWidth = 10, int pathWidth = 70, int dateWidth = 20)
{
Console.ForegroundColor = BorderColor;
var totalWidth = idWidth + pathWidth + dateWidth + 4; // +4 for the spaces and separators
Console.WriteLine(new string('─', totalWidth));
Console.ResetColor();
}
// Display a table row
public static void DisplayTableRow(uint id, string path, DateTime dateAdded, int idWidth = 10, int pathWidth = 70, int dateWidth = 20)
{
var formattedDate = dateAdded.ToString("yyyy-MM-dd HH:mm");
var truncatedPath = path.Length > pathWidth ? path.Substring(0, pathWidth - 3) + "..." : path;
Console.WriteLine("{0,-" + idWidth + "} │ {1,-" + pathWidth + "} │ {2,-" + dateWidth + "}", id, truncatedPath, formattedDate);
}
// Display a confirmation prompt with styled formatting
public static bool GetConfirmation(string message)
{
Console.ForegroundColor = WarningColor;
Console.Write($"⚠ {message} (y/N): ");
Console.ResetColor();
var input = Console.ReadLine();
return input?.ToLowerInvariant() == "y";
}
// Display a success message
public static void DisplaySuccess(string message)
{
Console.ForegroundColor = SuccessColor;
Console.WriteLine($"✓ {message}");
Console.ResetColor();
}
// Display an error message
public static void DisplayError(string message)
{
Console.ForegroundColor = ErrorColor;
Console.WriteLine($"✗ {message}");
Console.ResetColor();
}
// Display an info message
public static void DisplayInfo(string message)
{
Console.ForegroundColor = InfoColor;
Console.WriteLine($" {message}");
Console.ResetColor();
}
// Display a warning message
public static void DisplayWarning(string message)
{
Console.ForegroundColor = WarningColor;
Console.WriteLine($"⚠ {message}");
Console.ResetColor();
}
// Display a styled summary box
public static void DisplaySummary(string title, params (string label, string value)[] items)
{
Console.ForegroundColor = HeaderColor;
Console.WriteLine($"\n┌─ {title} ─{'─'.Repeat(Math.Max(0, 50 - title.Length))}");
Console.ResetColor();
foreach (var (label, value) in items)
{
Console.WriteLine($"│ {label}: {value}");
}
Console.ForegroundColor = HeaderColor;
Console.WriteLine($"└{'─'.Repeat(50)}┘");
Console.ResetColor();
}
}
// Extension method to repeat a character
public static class StringExtensions
{
public static string Repeat(this char c, int count)
{
return new string(c, count);
}
}
}

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PublishAot>true</PublishAot>