Implement a ToDo overview based on a JSON file
This commit is contained in:
parent
37f27fa415
commit
468f66ab59
|
@ -2,46 +2,62 @@
|
|||
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:model="clr-namespace:TodoDetails.Model"
|
||||
x:Class="TodoDetails.MainPage">
|
||||
|
||||
<ScrollView>
|
||||
<CollectionView>
|
||||
<CollectionView.ItemsSource>
|
||||
<x:Array Type="{x:Type model:Todo}">
|
||||
<model:Todo Title="Create ViewModel"
|
||||
Description="Create a ViewModel in the next step to learn MVVM."
|
||||
Category="Default"
|
||||
IsDone="False"/>
|
||||
<model:Todo Title="Add Theming"
|
||||
Description="Integrate your own theme in the app."
|
||||
Category="Default"
|
||||
IsDone="False"/>
|
||||
<model:Todo Title="Add local database"
|
||||
Description="Learn how to add a local database to work with (optional)."
|
||||
Category="Default"
|
||||
IsDone="False"/>
|
||||
</x:Array>
|
||||
</CollectionView.ItemsSource>
|
||||
xmlns:viewmodel="clr-namespace:TodoDetails.ViewModel"
|
||||
x:DataType="viewmodel:TodosViewModel"
|
||||
x:Class="TodoDetails.MainPage"
|
||||
Title="{Binding Title}">
|
||||
<Grid ColumnSpacing="5"
|
||||
RowSpacing="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<CollectionView ItemsSource="{Binding Todos}"
|
||||
SelectionMode="None"
|
||||
Grid.ColumnSpan="2">
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate x:DataType="model:Todo">
|
||||
<HorizontalStackLayout Padding="10"
|
||||
Spacing="10"
|
||||
HorizontalOptions="FillAndExpand">
|
||||
<CheckBox IsChecked="{Binding IsDone}"
|
||||
VerticalOptions="Start"/>
|
||||
<VerticalStackLayout VerticalOptions="Center">
|
||||
<Label Text="{Binding Title}"
|
||||
VerticalOptions="Center"
|
||||
FontSize="16"
|
||||
TextColor="Gray"/>
|
||||
<Label Text="{Binding Category}"
|
||||
FontSize="12"
|
||||
TextColor="Gray"/>
|
||||
</VerticalStackLayout>
|
||||
</HorizontalStackLayout>
|
||||
<Grid Padding="10">
|
||||
<Border HeightRequest="125">
|
||||
<Grid Padding="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<CheckBox IsChecked="{Binding IsDone}"/>
|
||||
<VerticalStackLayout Grid.Column="1"
|
||||
VerticalOptions="Center"
|
||||
Padding="10">
|
||||
<Label Text="{Binding Title}"
|
||||
FontSize="16"/>
|
||||
<Label Text="{Binding Category}"
|
||||
FontSize="12"/>
|
||||
</VerticalStackLayout>
|
||||
<Label Text="{Binding DueDate}"
|
||||
Grid.Column="2"
|
||||
VerticalOptions="Center"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</CollectionView.ItemTemplate>
|
||||
</CollectionView>
|
||||
</ScrollView>
|
||||
|
||||
<Button Text="Fetch Todos"
|
||||
Command="{Binding GetTodosCommand}"
|
||||
IsEnabled="{Binding IsNotBusy}"
|
||||
Grid.Row="1"
|
||||
Margin="8"/>
|
||||
<ActivityIndicator IsVisible="{Binding IsBusy}"
|
||||
IsRunning="{Binding IsBusy}"
|
||||
HorizontalOptions="Fill"
|
||||
VerticalOptions="Center"
|
||||
Color="{DynamicResource Primary}"
|
||||
Grid.RowSpan="2"
|
||||
Grid.ColumnSpan="2"/>
|
||||
</Grid>
|
||||
</ContentPage>
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
using TodoDetails.ViewModel;
|
||||
|
||||
namespace TodoDetails
|
||||
{
|
||||
public partial class MainPage : ContentPage
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
public MainPage()
|
||||
public MainPage(TodosViewModel viewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
BindingContext = viewModel;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
using TodoDetails.Services;
|
||||
using TodoDetails.ViewModel;
|
||||
|
||||
namespace TodoDetails
|
||||
{
|
||||
|
@ -18,6 +20,9 @@ namespace TodoDetails
|
|||
#if DEBUG
|
||||
builder.Logging.AddDebug();
|
||||
#endif
|
||||
builder.Services.AddSingleton<TodoService>();
|
||||
builder.Services.AddSingleton<TodosViewModel>();
|
||||
builder.Services.AddSingleton<MainPage>();
|
||||
|
||||
return builder.Build();
|
||||
}
|
||||
|
|
23
Tasks/Lab12/TodoDetails/Resources/Raw/tododata.json
Normal file
23
Tasks/Lab12/TodoDetails/Resources/Raw/tododata.json
Normal file
|
@ -0,0 +1,23 @@
|
|||
[
|
||||
{
|
||||
"Title": "Create ViewModel",
|
||||
"Description": "Create a ViewModel in the next step to learn MVVM.",
|
||||
"IsDone": true,
|
||||
"Category": "Default",
|
||||
"DueDate": "2023-05-31T00:00:00"
|
||||
},
|
||||
{
|
||||
"Title": "Add Themeing",
|
||||
"Description": "Integrate your own theme in the app.",
|
||||
"IsDone": false,
|
||||
"Category": "Default",
|
||||
"DueDate": "2023-05-31T00:00:00"
|
||||
},
|
||||
{
|
||||
"Title": "Add local database",
|
||||
"Description": "Learn how to add a local database.",
|
||||
"IsDone": false,
|
||||
"Category": "Default",
|
||||
"DueDate": "2023-05-31T00:00:00"
|
||||
}
|
||||
]
|
40
Tasks/Lab12/TodoDetails/Services/TodoService.cs
Normal file
40
Tasks/Lab12/TodoDetails/Services/TodoService.cs
Normal file
|
@ -0,0 +1,40 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using TodoDetails.Model;
|
||||
|
||||
namespace TodoDetails.Services
|
||||
{
|
||||
public class TodoService
|
||||
{
|
||||
Lazy<Task<List<Todo>>> todoList;
|
||||
|
||||
public TodoService()
|
||||
{
|
||||
todoList = new Lazy<Task<List<Todo>>>(
|
||||
async () =>
|
||||
{
|
||||
List<Todo>? result = null;
|
||||
|
||||
using var stream = await FileSystem.OpenAppPackageFileAsync("tododata.json");
|
||||
using var reader = new StreamReader(stream);
|
||||
var contents = await reader.ReadToEndAsync();
|
||||
|
||||
if (contents != null)
|
||||
{
|
||||
result = JsonSerializer.Deserialize<List<Todo>>(contents);
|
||||
}
|
||||
|
||||
return result ?? new();
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<List<Todo>> GetTodos()
|
||||
{
|
||||
return await todoList.Value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -57,6 +57,11 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Resources\raw\tododata.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
|
||||
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
|
||||
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.0" />
|
||||
|
|
21
Tasks/Lab12/TodoDetails/ViewModel/BaseViewModel.cs
Normal file
21
Tasks/Lab12/TodoDetails/ViewModel/BaseViewModel.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TodoDetails.ViewModel
|
||||
{
|
||||
public partial class BaseViewModel : ObservableObject
|
||||
{
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(IsNotBusy))]
|
||||
bool isBusy;
|
||||
|
||||
[ObservableProperty]
|
||||
string? title;
|
||||
|
||||
public bool IsNotBusy => !IsBusy;
|
||||
}
|
||||
}
|
68
Tasks/Lab12/TodoDetails/ViewModel/TodosViewModel.cs
Normal file
68
Tasks/Lab12/TodoDetails/ViewModel/TodosViewModel.cs
Normal file
|
@ -0,0 +1,68 @@
|
|||
using CommunityToolkit.Mvvm.Input;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TodoDetails.Model;
|
||||
using TodoDetails.Services;
|
||||
|
||||
namespace TodoDetails.ViewModel
|
||||
{
|
||||
public partial class TodosViewModel : BaseViewModel
|
||||
{
|
||||
public ObservableCollection<Todo> Todos { get; } = new ObservableCollection<Todo>();
|
||||
TodoService todoService;
|
||||
|
||||
public TodosViewModel(TodoService todoService)
|
||||
{
|
||||
Title = "Todos";
|
||||
this.todoService = todoService;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
async Task GetTodosAsync()
|
||||
{
|
||||
if (IsBusy)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
IsBusy = true;
|
||||
var todos = await todoService.GetTodos();
|
||||
|
||||
if (Todos.Count != 0)
|
||||
{
|
||||
Todos.Clear();
|
||||
}
|
||||
|
||||
foreach (var todo in todos)
|
||||
{
|
||||
Todos.Add(todo);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.WriteLine($"UInable to get todos: {e.Message}");
|
||||
await Shell.Current.DisplayAlert("Error!", e.Message, "OK");
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsBusy = false;
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
async Task GoToDetails(Todo todo)
|
||||
{
|
||||
if (todo == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue