Merge pull request 'Add toasts to notify user' (#55) from user-notifier into master
continuous-integration/drone/push Build is passing Details

Reviewed-on: ShopNCook/ShopNCook#55
master
Maxime BATISTA 2 years ago
commit e6ccd28f20

@ -1,4 +1,7 @@
[*.cs]
# CS0618: Le type ou le membre est obsolète
dotnet_diagnostic.CS0618.severity = silent
# CS1998: Async method lacks 'await' operators and will run synchronously
dotnet_diagnostic.CS1998.severity = none

@ -8,8 +8,6 @@ public partial class App : Application, ConnectionObserver, IApp
private IEndpoint Endpoint = new LocalEndpoint();
public IUserNotifier Notifier => new ConsoleUserNotifier();
public App()
{
InitializeComponent();
@ -25,7 +23,7 @@ public partial class App : Application, ConnectionObserver, IApp
public void ForceLogin()
{
Shell shell = new ConnectAppShell(this, Endpoint.AuthService, Notifier);
Shell shell = new ConnectAppShell(this, Endpoint.AuthService);
shell.GoToAsync("//Splash");
MainPage = shell;
}

@ -7,9 +7,9 @@ using ShoopNCook.Pages;
public partial class ConnectAppShell : Shell
{
public ConnectAppShell(ConnectionObserver observer, IAuthService accounts, IUserNotifier notifier)
public ConnectAppShell(ConnectionObserver observer, IAuthService accounts)
{
ConnectionController controller = new ConnectionController(observer, accounts, notifier);
ConnectionController controller = new ConnectionController(observer, accounts);
InitializeComponent();
LoginPage.ContentTemplate = new DataTemplate(() => new LoginPage(controller));
RegisterPage.ContentTemplate = new DataTemplate(() => new RegisterPage(controller));

@ -1,31 +0,0 @@
namespace ShoopNCook
{
/// <summary>
/// A notice reporter implementation that prints in console the applications's user notices.
/// </summary>
public class ConsoleUserNotifier :
IUserNotifier
{
public void Success(string message)
{
Console.WriteLine("<User Notice> Success: " + message);
}
public void Error(string message)
{
Console.WriteLine("<User Notice> Error: " + message);
}
public void Notice(string message)
{
Console.WriteLine("<User Notice> Notice: " + message);
}
public void Warn(string message)
{
Console.WriteLine("<User Notice> Warn: " + message);
}
}
}

@ -7,19 +7,27 @@ namespace ShoopNCook.Controllers
{
private readonly ConnectionObserver observer;
private readonly IAuthService accounts;
private readonly IUserNotifier notifier;
public ConnectionController(ConnectionObserver observer, IAuthService accounts, IUserNotifier notifier) {
public ConnectionController(ConnectionObserver observer, IAuthService accounts) {
this.observer = observer;
this.accounts = accounts;
this.notifier = notifier;
}
public void Login(string email, string password)
{
if (email == null)
{
UserNotifier.Notice("Please provide an email address");
return;
}
if (password == null)
{
UserNotifier.Notice("Please provide your password");
return;
}
Account? acc = accounts.Login(email, password);
if (acc == null)
{
notifier.Error("Email or password invalid.");
UserNotifier.Error("Email or password invalid.");
return;
}
observer.OnAccountConnected(acc);
@ -27,10 +35,25 @@ namespace ShoopNCook.Controllers
public void Register(string username, string email, string password)
{
if (email == null)
{
UserNotifier.Notice("Please provide an email address");
return;
}
if (password == null)
{
UserNotifier.Notice("Please provide your password");
return;
}
if (username == null)
{
UserNotifier.Notice("Please provide an username");
return;
}
Account? acc = accounts.Register(username, email, password);
if (acc == null)
{
notifier.Error("Invalid credentials.");
UserNotifier.Error("Invalid credentials.");
return;
}
observer.OnAccountConnected(acc);

@ -20,13 +20,13 @@ namespace ShoopNCook.Controllers
public void Logout()
{
app.Notifier.Notice("You have been loged out.");
UserNotifier.Notice("You have been loged out.");
app.ForceLogin();
}
public async void GoToMyRecipesPage()
{
await Shell.Current.Navigation.PushAsync(new MyRecipesPage(account, endpoint.RecipesService, app.Notifier));
await Shell.Current.Navigation.PushAsync(new MyRecipesPage(account, endpoint.RecipesService));
}
public async void GoToProfilePage()

@ -9,8 +9,6 @@ namespace ShoopNCook
{
public interface IApp
{
public IUserNotifier Notifier { get; }
public void ForceLogin();
}
}

@ -1,19 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ShoopNCook
{
public interface IUserNotifier
{
public void Success(string message);
public void Notice(string message);
public void Error(string message);
public void Warn(string message);
}
}

@ -9,9 +9,9 @@ public partial class MainAppShell : Shell
public MainAppShell(Account account, IEndpoint endpoint, IApp app)
{
InitializeComponent();
HomeTab.ContentTemplate = new DataTemplate(() => new HomePage(account, app.Notifier, endpoint));
FavoritesTab.ContentTemplate = new DataTemplate(() => new FavoritesPage(account, app.Notifier, endpoint.RecipesService));
MyListTab.ContentTemplate = new DataTemplate(() => new MyListPage(account, app.Notifier, endpoint.RecipesService));
HomeTab.ContentTemplate = new DataTemplate(() => new HomePage(account, endpoint));
FavoritesTab.ContentTemplate = new DataTemplate(() => new FavoritesPage(account, endpoint.RecipesService));
MyListTab.ContentTemplate = new DataTemplate(() => new MyListPage(account, endpoint.RecipesService));
MoreTab.ContentTemplate = new DataTemplate(() => new MorePage(account, new MorePageController(account, endpoint, app)));
}
}

@ -1,4 +1,5 @@
using Microsoft.Extensions.Logging;
using CommunityToolkit.Maui;
using Microsoft.Extensions.Logging;
namespace ShoopNCook;
@ -9,6 +10,7 @@ public static class MauiProgram
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.UseMauiCommunityToolkit()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");

Binary file not shown.

After

Width:  |  Height:  |  Size: 826 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 812 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 633 B

@ -113,6 +113,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Maui" Version="5.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="7.0.0" />
<PackageReference Include="xunit" Version="2.4.2" />
</ItemGroup>
@ -142,6 +143,9 @@
<MauiXaml Update="ConnectAppShell.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
<MauiXaml Update="Views\Components\NoticePopup.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
<MauiXaml Update="Views\CreateRecipePage.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>

@ -10,7 +10,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Models", "Models\Models.csp
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LocalServices", "LocalServices\LocalServices.csproj", "{57732316-93B9-4DA0-A212-F8892D3D968B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Services", "Services\Services.csproj", "{C976BDD8-710D-4162-8A42-973B634491F9}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Services", "Services\Services.csproj", "{C976BDD8-710D-4162-8A42-973B634491F9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6DEA92EF-71CD-4A21-9CC0-67F228E1155D}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution

@ -0,0 +1,48 @@
using CommunityToolkit.Maui.Alerts;
using CommunityToolkit.Maui.Core;
using CommunityToolkit.Maui.Views;
using ShoopNCook.Views.Components;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ShoopNCook
{
internal class UserNotifier
{
private static async Task Show(string message, string messageType)
{
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
// Vous pouvez configurer la durée et la taille de police ici.
ToastDuration duration = ToastDuration.Short;
double fontSize = 14;
var toast = Toast.Make(message, duration, fontSize);
await toast.Show(cancellationTokenSource.Token);
}
public static void Error(string message)
{
Show(message, "Error");
}
public static void Warn(string message)
{
Show(message, "Warning");
}
public static void Notice(string message)
{
Show(message, "Notice");
}
public static void Success(string message)
{
Show(message, "Success");
}
}
}

@ -0,0 +1,10 @@
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ShoopNCook.Views.Components.NoticePopup">
<VerticalStackLayout>
<Label
x:Name="MessageLabel"
VerticalOptions="Center"
HorizontalOptions="Center" />
</VerticalStackLayout>
</ContentView>

@ -0,0 +1,39 @@
namespace ShoopNCook.Views.Components;
using Microsoft.Maui.Graphics;
public partial class NoticePopup : ContentView
{
public NoticePopup(string message, string messageType)
{
InitializeComponent();
MessageLabel.Text = message;
switch (messageType)
{
case "Error":
this.BackgroundColor = Microsoft.Maui.Graphics.Colors.Red;
break;
case "Warning":
this.BackgroundColor = Microsoft.Maui.Graphics.Colors.Yellow;
break;
case "Notice":
this.BackgroundColor = Microsoft.Maui.Graphics.Colors.Blue;
break;
case "Success":
this.BackgroundColor = Microsoft.Maui.Graphics.Colors.Green;
break;
}
// Display the toast for 3 seconds
Device.StartTimer(TimeSpan.FromSeconds(3), () =>
{
// Close the toast
// You need to replace this with your actual code to close the toast
this.IsVisible = false;
return false;
});
}
}

@ -8,31 +8,29 @@ public partial class CreateRecipePage : ContentPage
private User owner;
private Action<Recipe> onRecipeCreated;
private IUserNotifier notifier;
public CreateRecipePage(User owner, IUserNotifier notifier, Action<Recipe> onRecipeCreated)
public CreateRecipePage(User owner, Action<Recipe> onRecipeCreated)
{
InitializeComponent();
this.owner = owner;
this.onRecipeCreated = onRecipeCreated;
this.notifier = notifier;
}
private async void OnAddIngredientTapped(object sender, TappedEventArgs e)
private void OnAddIngredientTapped(object sender, TappedEventArgs e)
{
IngredientList.Children.Add(new IngredientEntry());
}
private async void OnAddStepTapped(object sender, TappedEventArgs e)
private void OnAddStepTapped(object sender, TappedEventArgs e)
{
StepList.Children.Add(new StepEntry((uint) StepList.Children.Count() + 1));
}
private async void OnBackButtonClicked(object sender, EventArgs e)
{
Navigation.PopAsync();
await Navigation.PopAsync();
}
private async void OnUploadRecipeClicked(object sender, EventArgs e)
private void OnUploadRecipeClicked(object sender, EventArgs e)
{
uint callPerPers;
@ -53,7 +51,7 @@ public partial class CreateRecipePage : ContentPage
if (hadErrors)
{
notifier.Error("You need to fix input errors before upload.");
UserNotifier.Error("You need to fix input errors before upload.");
return;
}

@ -10,14 +10,12 @@ public partial class FavoritesPage : ContentPage
{
private readonly Account account;
private readonly IUserNotifier notifier;
private IRecipesService service;
public FavoritesPage(Account account, IUserNotifier notifier, IRecipesService service)
public FavoritesPage(Account account, IRecipesService service)
{
InitializeComponent();
this.account = account;
this.notifier = notifier;
this.service = service;
UpdateFavorites();
@ -31,13 +29,13 @@ public partial class FavoritesPage : ContentPage
{
RecipeViewLayout.Children.Add(new RecipeView(info, async () =>
{
Recipe? recipe = service.GetRecipe(info);
await Shell.Current.Navigation.PushAsync(new RecipePage(recipe, notifier, preferences, 1));
Recipe recipe = service.GetRecipe(info);
await Shell.Current.Navigation.PushAsync(new RecipePage(recipe, preferences, 1));
}));
});
}
private async void ContentPage_NavigatedTo(object sender, NavigatedToEventArgs e)
private void ContentPage_NavigatedTo(object sender, NavigatedToEventArgs e)
{
UpdateFavorites();
}

@ -1,4 +1,3 @@
namespace ShoopNCook.Pages;
using Models;
using ShoopNCook.Views;
@ -7,7 +6,7 @@ using LocalEndpoint;
public partial class HomePage : ContentPage
{
public HomePage(Account account, IUserNotifier notifier, IEndpoint endpoint)
public HomePage(Account account, IEndpoint endpoint)
{
InitializeComponent();
@ -20,12 +19,12 @@ public partial class HomePage : ContentPage
{
layout.Children.Add(new RecipeView(info, () =>
{
Recipe? recipe = service.GetRecipe(info);
Recipe recipe = service.GetRecipe(info);
if (recipe != null)
Shell.Current.Navigation.PushAsync(new RecipePage(recipe, notifier, preferences, 1));
Shell.Current.Navigation.PushAsync(new RecipePage(recipe, preferences, 1));
else
{
notifier.Error("Could not find recipe");
UserNotifier.Error("Could not find recipe");
}
}));
}
@ -37,9 +36,6 @@ public partial class HomePage : ContentPage
ProfilePictureName.Text = account.User.Name;
}
private async void OnSyncButtonClicked(object sender, EventArgs e)
{
await Shell.Current.Navigation.PushAsync(new SearchPage());

@ -11,7 +11,7 @@ public partial class LoginPage : ContentPage
InitializeComponent();
this.controller = controller;
}
private async void OnLoginButtonClicked(object sender, EventArgs e)
private void OnLoginButtonClicked(object sender, EventArgs e)
{
string email = EmailEntry.Text;
string password = PasswordEntry.Text;

@ -9,15 +9,13 @@ public partial class MyListPage : ContentPage
{
private readonly IAccountRecipesPreferences preferences;
private readonly IUserNotifier notifier;
private readonly IRecipesService service;
public MyListPage(Account account, IUserNotifier notifier, IRecipesService service)
public MyListPage(Account account, IRecipesService service)
{
InitializeComponent();
this.preferences = service.GetPreferencesOf(account);
this.notifier = notifier;
this.service = service;
UpdateMyList();
@ -32,7 +30,7 @@ public partial class MyListPage : ContentPage
RecipesLayout.Children.Add(new StoredRecipeView(info, tuple.Item2, amount =>
{
Recipe recipe = service.GetRecipe(info);
Shell.Current.Navigation.PushAsync(new RecipePage(recipe, notifier, preferences, amount));
Shell.Current.Navigation.PushAsync(new RecipePage(recipe, preferences, amount));
}));
});
}

@ -8,18 +8,15 @@ namespace ShoopNCook.Pages;
public partial class MyRecipesPage : ContentPage
{
private IUserNotifier notifier;
private IRecipesService service;
private Account account;
public MyRecipesPage(
Account account,
IRecipesService service,
IUserNotifier notifier)
IRecipesService service)
{
InitializeComponent();
this.notifier = notifier;
this.service = service;
this.account = account;
@ -35,7 +32,7 @@ public partial class MyRecipesPage : ContentPage
{
Recipe recipe = service.GetRecipe(info);
IAccountRecipesPreferences preferences = service.GetPreferencesOf(account);
Shell.Current.Navigation.PushAsync(new RecipePage(recipe, notifier, preferences, 1));
Shell.Current.Navigation.PushAsync(new RecipePage(recipe, preferences, 1));
},
() => RemoveRecipe(info)
));
@ -47,7 +44,7 @@ public partial class MyRecipesPage : ContentPage
if (!recipes.RemoveRecipe(info))
{
notifier.Error("Could not remove recipe");
UserNotifier.Error("Could not remove recipe");
return;
}
foreach (OwnedRecipeView view in RecipesLayout.Children)
@ -58,7 +55,7 @@ public partial class MyRecipesPage : ContentPage
break;
}
}
notifier.Success("Recipe successfully removed");
UserNotifier.Success("Recipe successfully removed");
}
private async void OnBackButtonClicked(object sender, EventArgs e)
@ -69,14 +66,14 @@ public partial class MyRecipesPage : ContentPage
{
IAccountOwnedRecipes recipes = service.GetRecipesOf(account);
var page = new CreateRecipePage(account.User, notifier, recipe =>
var page = new CreateRecipePage(account.User, recipe =>
{
if (!recipes.UploadRecipe(recipe))
{
notifier.Error("Could not upload recipe.");
UserNotifier.Error("Could not upload recipe.");
return;
}
notifier.Success("Recipe Successfuly uploaded !");
UserNotifier.Success("Recipe Successfuly uploaded !");
AddRecipeView(recipe.Info);
Shell.Current.Navigation.PopAsync(); //go back to current recipe page.
});

@ -14,17 +14,15 @@ public partial class RecipePage : ContentPage
private IAccountRecipesPreferences preferences;
private IUserNotifier notifier;
private RecipeInfo info;
public ICommand StarCommand => new Command<string>(count => SetNote(uint.Parse(count)));
public RecipePage(Recipe recipe, IUserNotifier notifier, IAccountRecipesPreferences preferences, uint amount)
public RecipePage(Recipe recipe, IAccountRecipesPreferences preferences, uint amount)
{
InitializeComponent();
this.preferences = preferences;
this.notifier = notifier;
this.info = recipe.Info;
RecipeRate rate = preferences.GetRate(recipe.Info);
@ -89,15 +87,15 @@ public partial class RecipePage : ContentPage
private async void OnSubmitReviewClicked(object o, EventArgs e)
{
preferences.SetReviewScore(info, note);
notifier.Success("Your review has been successfuly submited");
UserNotifier.Success("Your review has been successfuly submited");
}
private async void OnAddToMyListClicked(object o, EventArgs e)
{
if (!preferences.AddToWeeklyList(info, Counter.Count))
notifier.Notice("You already added this recipe to you weekly list!");
UserNotifier.Notice("You already added this recipe to you weekly list!");
else
notifier.Success("Recipe added to your weekly list.");
UserNotifier.Success("Recipe added to your weekly list.");
}
private void SetFavorite(bool isFavorite)

Loading…
Cancel
Save