From f92f5f2a79852894d7ff77a83e92d05eccb91679 Mon Sep 17 00:00:00 2001 From: syneffort Date: Fri, 12 Apr 2024 15:46:13 +0900 Subject: [PATCH] implant mvvm --- MyFirstMauiApp/NotesNet8/Models/Note.cs | 41 +++++++++ MyFirstMauiApp/NotesNet8/NotesNet8.csproj | 1 + .../NotesNet8/ViewModels/AboutViewModel.cs | 26 ++++++ .../NotesNet8/ViewModels/NoteViewModel.cs | 86 +++++++++++++++++++ .../NotesNet8/ViewModels/NotesViewModel.cs | 60 +++++++++++++ MyFirstMauiApp/NotesNet8/Views/AboutPage.xaml | 6 +- .../NotesNet8/Views/AboutPage.xaml.cs | 8 -- .../NotesNet8/Views/AllNotesPage.xaml | 20 +++-- .../NotesNet8/Views/AllNotesPage.xaml.cs | 24 +----- MyFirstMauiApp/NotesNet8/Views/NotePage.xaml | 12 +-- .../NotesNet8/Views/NotePage.xaml.cs | 41 --------- 11 files changed, 238 insertions(+), 87 deletions(-) create mode 100644 MyFirstMauiApp/NotesNet8/ViewModels/AboutViewModel.cs create mode 100644 MyFirstMauiApp/NotesNet8/ViewModels/NoteViewModel.cs create mode 100644 MyFirstMauiApp/NotesNet8/ViewModels/NotesViewModel.cs diff --git a/MyFirstMauiApp/NotesNet8/Models/Note.cs b/MyFirstMauiApp/NotesNet8/Models/Note.cs index 1e059c6..08d5eb0 100644 --- a/MyFirstMauiApp/NotesNet8/Models/Note.cs +++ b/MyFirstMauiApp/NotesNet8/Models/Note.cs @@ -11,5 +11,46 @@ namespace NotesNet8.Models public string Filename { get; set; } public string Text { get; set; } public DateTime Date { get; set; } + + public Note() + { + Filename = $"{Path.GetRandomFileName()}.notes.txt"; + Date = DateTime.Now; + Text = ""; + } + + public static Note Load(string filename) + { + filename = Path.Combine(FileSystem.AppDataDirectory, filename); + if (!File.Exists(filename)) + throw new FileNotFoundException("Unable to find file on local storage.", filename); + + return new Note() + { + Filename = Path.GetFileName(filename), + Text = File.ReadAllText(filename), + Date = File.GetLastWriteTime(filename) + }; + } + + public static IEnumerable LoadAll() + { + string appDataPath = FileSystem.AppDataDirectory; + + return Directory + .EnumerateFiles(appDataPath, "*.notes.txt") + .Select(filename => Note.Load(Path.GetFileName(filename))) + .OrderByDescending(note => note.Date); + } + + public void Save() + { + File.WriteAllText(Path.Combine(FileSystem.AppDataDirectory, Filename), Text); + } + + public void Delete() + { + File.Delete(Path.Combine(FileSystem.AppDataDirectory, Filename)); + } } } diff --git a/MyFirstMauiApp/NotesNet8/NotesNet8.csproj b/MyFirstMauiApp/NotesNet8/NotesNet8.csproj index 84f530b..3ce153a 100644 --- a/MyFirstMauiApp/NotesNet8/NotesNet8.csproj +++ b/MyFirstMauiApp/NotesNet8/NotesNet8.csproj @@ -62,6 +62,7 @@ + diff --git a/MyFirstMauiApp/NotesNet8/ViewModels/AboutViewModel.cs b/MyFirstMauiApp/NotesNet8/ViewModels/AboutViewModel.cs new file mode 100644 index 0000000..a27164d --- /dev/null +++ b/MyFirstMauiApp/NotesNet8/ViewModels/AboutViewModel.cs @@ -0,0 +1,26 @@ +using CommunityToolkit.Mvvm.Input; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Input; + +namespace NotesNet8.ViewModels +{ + internal class AboutViewModel + { + public string Title => AppInfo.Name; + public string Version => AppInfo.VersionString; + public string MoreInfoUrl => "https://aka.ms/maui"; + public string Message => "This app is written in XAML and C# with .NET MAUI"; + public ICommand ShowMoreInfoCommand { get; } + + public AboutViewModel() + { + ShowMoreInfoCommand = new AsyncRelayCommand(ShowMoreInfo); + } + + async Task ShowMoreInfo() => await Launcher.Default.OpenAsync(MoreInfoUrl); + } +} diff --git a/MyFirstMauiApp/NotesNet8/ViewModels/NoteViewModel.cs b/MyFirstMauiApp/NotesNet8/ViewModels/NoteViewModel.cs new file mode 100644 index 0000000..68cdc4b --- /dev/null +++ b/MyFirstMauiApp/NotesNet8/ViewModels/NoteViewModel.cs @@ -0,0 +1,86 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using NotesNet8.Models; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Input; + +namespace NotesNet8.ViewModels +{ + internal class NoteViewModel : ObservableObject, IQueryAttributable + { + private Note _note; + + public NoteViewModel() + { + _note = new Note(); + SaveCommand = new AsyncRelayCommand(Save); + DeleteCommand = new AsyncRelayCommand(Delete); + } + + public NoteViewModel(Note note) + { + _note = note; + SaveCommand = new AsyncRelayCommand(Save); + DeleteCommand = new AsyncRelayCommand(Delete); + } + + public string Text + { + get => _note.Text; + set + { + if (_note.Text != value) + { + _note.Text = value; + OnPropertyChanged(); + } + } + } + + public ICommand SaveCommand { get; private set; } + public ICommand DeleteCommand { get; private set; } + + public DateTime Date => _note.Date; + + public string Identifier => _note.Filename; + + private async Task Save() + { + _note.Date = DateTime.Now; + _note.Save(); + await Shell.Current.GoToAsync($"..?saved={_note.Filename}"); + } + + private async Task Delete() + { + _note.Delete(); + await Shell.Current.GoToAsync($"..?deleted={_note.Filename}"); + } + + public void ApplyQueryAttributes(IDictionary query) + { + if (query.ContainsKey("load")) + { + _note = Note.Load(query["load"].ToString()); + RefreshProperties(); + } + } + + public void Reload() + { + _note = Note.Load(_note.Filename); + RefreshProperties(); + } + + private void RefreshProperties() + { + OnPropertyChanged(nameof(Text)); + OnPropertyChanged(nameof(Date)); + } + } +} diff --git a/MyFirstMauiApp/NotesNet8/ViewModels/NotesViewModel.cs b/MyFirstMauiApp/NotesNet8/ViewModels/NotesViewModel.cs new file mode 100644 index 0000000..30c1c20 --- /dev/null +++ b/MyFirstMauiApp/NotesNet8/ViewModels/NotesViewModel.cs @@ -0,0 +1,60 @@ +using CommunityToolkit.Mvvm.Input; +using NotesNet8.Models; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Input; + +namespace NotesNet8.ViewModels +{ + internal class NotesViewModel : IQueryAttributable + { + public ObservableCollection AllNotes { get; } + public ICommand NewCommand { get; } + public ICommand SelectNoteCommand { get; } + + public NotesViewModel() + { + AllNotes = new ObservableCollection(Note.LoadAll().Select(n => new NoteViewModel(n))); + NewCommand = new AsyncRelayCommand(NewNoteAsync); + SelectNoteCommand = new AsyncRelayCommand(SelectNoteAsync); + } + + public void ApplyQueryAttributes(IDictionary query) + { + if (query.ContainsKey("deleted")) + { + string noteId = query["deleted"].ToString(); + NoteViewModel matchedNote = AllNotes.Where(n => n.Identifier == noteId).FirstOrDefault(); + if (matchedNote != null) + AllNotes.Remove(matchedNote); + } + else if (query.ContainsKey("saved")) + { + string noteId = query["saved"].ToString(); + NoteViewModel matchedNote = AllNotes.Where(n => n.Identifier == noteId).FirstOrDefault(); + if (matchedNote != null) + { + matchedNote.Reload(); + AllNotes.Move(AllNotes.IndexOf(matchedNote), 0); + } + else + AllNotes.Insert(0, new NoteViewModel(Note.Load(noteId))); + } + } + + private async Task NewNoteAsync() + { + await Shell.Current.GoToAsync(nameof(Views.NotePage)); + } + + private async Task SelectNoteAsync(ViewModels.NoteViewModel note) + { + if (note != null) + await Shell.Current.GoToAsync($"{nameof(Views.NotePage)}?load={note.Identifier}"); + } + } +} diff --git a/MyFirstMauiApp/NotesNet8/Views/AboutPage.xaml b/MyFirstMauiApp/NotesNet8/Views/AboutPage.xaml index 78a7114..929c898 100644 --- a/MyFirstMauiApp/NotesNet8/Views/AboutPage.xaml +++ b/MyFirstMauiApp/NotesNet8/Views/AboutPage.xaml @@ -2,10 +2,10 @@ - + @@ -20,6 +20,6 @@