This repository has been archived by the owner on Feb 16, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 15
W8G05A #11
Open
frsaba
wants to merge
14
commits into
CsharptutorialHungary:main
Choose a base branch
from
frsaba:main
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+636
−0
Open
W8G05A #11
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
cc71c8d
TodoItems, basic treeview
frsaba 44b2986
Editor view
frsaba 9eb9f2a
Save changes on exiting edit mode
frsaba 304553f
Task list view status bar
frsaba 3496630
Create new task
frsaba fe306c3
Delete task
frsaba 4872528
JSON serialization
frsaba d5941aa
Removed SpectreTodo
frsaba 489d268
Display status bar message
frsaba 5940c60
Merge remote-tracking branch 'origin/main' into main
frsaba 49d7e9e
Show saved status message
frsaba b0e364b
Save automatically
frsaba 769b23b
Seperate TaskListTree
frsaba 920fb6f
Search filter
frsaba File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
using System.Linq.Expressions; | ||
using System.Text; | ||
using Terminal.Gui; | ||
using Terminal.Gui.Trees; | ||
using TUITodo.Utils; | ||
using TUITodo.Views; | ||
|
||
namespace TUITodo | ||
{ | ||
internal class Program | ||
{ | ||
#region Views | ||
public static View MainWindow { get; } = new Window("Task list") | ||
{ | ||
X = 0, | ||
Y = 1, | ||
Width = Dim.Fill(), | ||
Height = Dim.Fill() - 3 | ||
}; | ||
|
||
|
||
public static TaskListView TaskListView { get; } = new() | ||
{ | ||
X = 1, | ||
Y = 1, | ||
Width = Dim.Fill(), | ||
Height = Dim.Fill(2) - 2 | ||
}; | ||
|
||
public static EditorView EditorView { get; } = new() | ||
{ | ||
X = 1, | ||
Y = 1, | ||
Width = Dim.Fill(), | ||
Height = Dim.Fill() - 2 | ||
}; | ||
|
||
|
||
public static Label statusBarMessage { get; } = new() | ||
{ | ||
X = 1, | ||
Y = Pos.Bottom(MainWindow), | ||
Width = Dim.Fill(), | ||
Height = 2, | ||
}; | ||
|
||
#endregion | ||
|
||
|
||
public static async void DisplayStatusNotification(string message, int expireSeconds = 2) | ||
{ | ||
statusBarMessage.Text = message; | ||
if(expireSeconds > 0) | ||
{ | ||
await Task.Delay(TimeSpan.FromSeconds(expireSeconds)); | ||
statusBarMessage.Text = ""; | ||
} | ||
|
||
} | ||
|
||
static StatusBar? activeStatusbar; | ||
static void SetStatusBar(StatusBar statusBar) | ||
{ | ||
Application.Top.Remove(activeStatusbar); | ||
activeStatusbar = statusBar; | ||
Application.Top.Add(activeStatusbar); | ||
} | ||
|
||
|
||
private static void SwitchToView(View view) | ||
{ | ||
MainWindow.RemoveAll(); | ||
MainWindow.Add(view); | ||
} | ||
|
||
public static void EnterEditMode(TodoItem editedItem) | ||
{ | ||
SwitchToView(EditorView); | ||
SetStatusBar(EditorView.statusBar); | ||
EditorView.StartEditing(editedItem); | ||
} | ||
|
||
public static void ShowTaskListView() | ||
{ | ||
SetStatusBar(TaskListView.statusBar); | ||
SwitchToView(TaskListView); | ||
} | ||
|
||
static void Main() | ||
{ | ||
|
||
Application.Init(); | ||
|
||
Application.MainLoop.Invoke(async () => | ||
{ | ||
await TaskListView.LoadSavedTasks(); | ||
}); | ||
|
||
#region Color scheme, style setup | ||
Colors.Base.Normal = Application.Driver.MakeAttribute(Color.Green, Color.Black); | ||
Colors.Base.HotNormal = Application.Driver.MakeAttribute(Color.Brown, Color.Black); | ||
|
||
#endregion | ||
|
||
#region MenuBar | ||
|
||
var menu = new MenuBar(new MenuBarItem[] { | ||
new MenuBarItem ("_File", new MenuItem [] { | ||
new MenuItem ("_Quit", "", () => { | ||
Application.RequestStop(); | ||
}), | ||
new MenuItem ("_Save", "", () => { | ||
SaveTasks(); | ||
}) | ||
}), | ||
}); | ||
|
||
#endregion | ||
//TaskListView.LoadSavedTasks(savedTodos); | ||
ShowTaskListView(); | ||
|
||
Application.Top.Add(menu, MainWindow, statusBarMessage); | ||
|
||
Application.Driver.SetCursorVisibility(CursorVisibility.Invisible); | ||
Application.Run(); | ||
|
||
Application.Shutdown(); | ||
} | ||
|
||
public static void SaveTasks() | ||
{ | ||
DisplayStatusNotification("Saving...", 0); | ||
Task.Run(async () => { | ||
await TaskListView.SaveTasks(); | ||
DisplayStatusNotification("Saved"); | ||
}); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net6.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Terminal.Gui" Version="1.8.2" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Text.Json.Serialization; | ||
using System.Threading.Tasks; | ||
using System.Xml.Linq; | ||
using Terminal.Gui.Trees; | ||
|
||
namespace TUITodo | ||
{ | ||
|
||
|
||
internal record class TodoItem : ITreeNode | ||
{ | ||
private const string Unchecked = "O"; | ||
private const string Checked = "X"; | ||
|
||
public TodoItem? parentTask { get; protected set; } | ||
|
||
public bool Done { get; protected set; } | ||
[JsonInclude] | ||
public string name; | ||
[JsonInclude] | ||
public string description; | ||
|
||
public List<TodoItem> Subtasks { get; set; } | ||
public TodoItem(string name, string description = "") : this(name, description, new List<TodoItem>()) { } | ||
|
||
public TodoItem(string name, string description, List<TodoItem> subtasks) | ||
{ | ||
this.Done = false; | ||
this.name = name; | ||
this.description = description; | ||
|
||
this.Subtasks = new(); | ||
subtasks.ForEach(AddSubtask); | ||
|
||
} | ||
|
||
[JsonConstructor] | ||
public TodoItem() | ||
{ | ||
Done = false; ; | ||
this.name = ""; | ||
this.description = ""; | ||
Subtasks = new List<TodoItem>(); | ||
} | ||
|
||
[JsonIgnore] | ||
public string Text | ||
{ | ||
get => $"{(Done ? Checked : Unchecked)} {name}"; set { name = value; } | ||
} | ||
|
||
[JsonIgnore] | ||
public IList<ITreeNode> Children => Subtasks.Cast<ITreeNode>().ToList(); | ||
|
||
[JsonIgnore] | ||
public object Tag | ||
{ | ||
get => name; set { name = (string)value; } | ||
} | ||
|
||
/// <param name="chainToSubtasks"> Make every subtask recursively inherit the done value</param> | ||
public void ToggleDone(bool chainToSubtasks = true) | ||
{ | ||
SetDone(!Done, chainToSubtasks); | ||
} | ||
|
||
/// <param name="chainToSubtasks"> Make every subtask recursively inherit the done value</param> | ||
public void SetDone(bool value, bool chainToSubtasks = true) | ||
{ | ||
Done = value; | ||
if (chainToSubtasks) | ||
Subtasks.ForEach(t => t.SetDone(value, chainToSubtasks)); | ||
|
||
//complete parent task if all of its subtasks are done | ||
if (parentTask != null) | ||
parentTask.SetDone(parentTask.Subtasks.All(t => t.Done), chainToSubtasks:false); | ||
|
||
} | ||
|
||
public void AddSubtask(TodoItem task) | ||
{ | ||
Subtasks.Add(task); | ||
task.parentTask = this; | ||
} | ||
|
||
public void RemoveSubtask(TodoItem task) | ||
{ | ||
task.parentTask = null; | ||
Subtasks.Remove(task); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using System.Text.Json; | ||
using System.Text.Json.Serialization; | ||
using System.Diagnostics; | ||
|
||
namespace TUITodo.Utils | ||
{ | ||
internal static class TodoItemSerializer | ||
{ | ||
static JsonSerializerOptions options = new() | ||
{ | ||
ReferenceHandler = ReferenceHandler.Preserve, | ||
WriteIndented = true | ||
}; | ||
|
||
public static async Task Serialize(IList<TodoItem> items, string path = "todos.json") | ||
{ | ||
string json = JsonSerializer.Serialize(items, options); | ||
//Trace.WriteLine(json); | ||
using (StreamWriter writer = File.CreateText(path)) | ||
{ | ||
await writer.WriteAsync(json); | ||
Program.DisplayStatusNotification($"Saved"); | ||
} | ||
} | ||
|
||
public async static Task<List<TodoItem>?> Deserialize(string path = "todos.json") | ||
{ | ||
if (!File.Exists(path)) return null; | ||
|
||
try | ||
{ | ||
using (StreamReader sr = new StreamReader(path)) | ||
{ | ||
string json = await sr.ReadToEndAsync(); | ||
|
||
return JsonSerializer.Deserialize<List<TodoItem>>(json, options); | ||
|
||
} | ||
} | ||
catch (Exception e) | ||
{ | ||
Program.DisplayStatusNotification($"Could not deserialize: {e}"); | ||
return null; | ||
} | ||
|
||
} | ||
|
||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Kompakt & effektív házi. Egy dologba tudok belekötni: A felelősségek szétválasztása. Az MVVM-et és a MVC-t nem véletlen találták ki. Jelen esetben a programod 1:1-ben függ a konzolos GUI rendszeredtől és a komponenseid így nem Single Responsible-ök, mert logikát csinálnak ÉS megjelenítenek. Jelen egyetemi házi keretében Okés, de tipik nem így szokás a való életben.