├── MAUI.CleanArchitecture
├── Configuration
│ ├── appsettings.debug.json
│ └── appsettings.release.json
├── Resources
│ ├── Images
│ │ ├── login.png
│ │ ├── signup.png
│ │ ├── add_to_cart.png
│ │ ├── signup.svg
│ │ └── dotnet_bot.svg
│ ├── Fonts
│ │ └── OpenSans-Regular.ttf
│ ├── appicon.svg
│ ├── Raw
│ │ └── AboutAssets.txt
│ ├── appiconfg.svg
│ └── Splash
│ │ └── splash.svg
├── Properties
│ └── launchSettings.json
├── AppShell.xaml.cs
├── Platforms
│ ├── Android
│ │ ├── Resources
│ │ │ └── values
│ │ │ │ └── colors.xml
│ │ ├── AndroidManifest.xml
│ │ ├── MainApplication.cs
│ │ └── MainActivity.cs
│ ├── MacCatalyst
│ │ ├── AppDelegate.cs
│ │ ├── Program.cs
│ │ └── Info.plist
│ ├── Windows
│ │ ├── App.xaml
│ │ ├── app.manifest
│ │ ├── App.xaml.cs
│ │ └── Package.appxmanifest
│ └── iOS
│ │ ├── Program.cs
│ │ ├── AppDelegate.cs
│ │ ├── Info.plist
│ │ └── Resources
│ │ └── LaunchScreen.xib
├── Utils
│ ├── IPageManager.cs
│ └── PageManager.cs
├── Controls
│ ├── CustomStepper.cs
│ ├── Errors.xaml
│ └── Errors.xaml.cs
├── AppShell.xaml
├── Views
│ ├── ContentViews
│ │ ├── CardItemView.xaml.cs
│ │ └── CardItemView.xaml
│ └── Pages
│ │ ├── RegisterPageView.xaml.cs
│ │ ├── MainPageView.xaml.cs
│ │ ├── LoginPageView.xaml.cs
│ │ ├── UserInfoPageView.xaml.cs
│ │ ├── UserInfoPageView.xaml
│ │ ├── LoginPageView.xaml
│ │ ├── RegisterPageView.xaml
│ │ └── MainPageView.xaml
├── Converters
│ ├── DoubleToStringConverter.cs
│ └── ImageSourceConverter.cs
├── App.xaml.cs
├── ViewModels
│ ├── Base
│ │ ├── ViewModelBase.cs
│ │ └── ViewModelLocator.cs
│ ├── UserInfoPageViewModel.cs
│ ├── CardItemViewModel.cs
│ ├── LoginPageViewModel.cs
│ ├── RegisterPageViewModel.cs
│ └── MainPageViewModel.cs
├── App.xaml
├── MauiProgram.cs
└── MAUI.CleanArchitecture.csproj
├── MAUI.CleanArchitecture.Domain
├── MainModel.cs
├── MAUI.CleanArchitecture.Domain.csproj
├── Entities
│ ├── Rating.cs
│ ├── User.cs
│ ├── CardItem.cs
│ └── StoreItem.cs
├── User
│ └── LoginResponseModel.cs
└── SubItem.cs
├── MAUI.CleanArchitecture.Infrastructure
├── Persistence
│ ├── Constants.cs
│ ├── Configurations
│ │ ├── RatingConfiguration.cs
│ │ ├── CartItemConfiguration.cs
│ │ └── StoreItemConfiguration.cs
│ ├── StoreDbContext.cs
│ └── Migrations
│ │ ├── 20211214054413_InitialCreate.cs
│ │ ├── StoreDbContextModelSnapshot.cs
│ │ └── 20211214054413_InitialCreate.Designer.cs
├── Identity
│ └── ApplicationUser.cs
├── BackgroundServices
│ └── DbBackgroundService.cs
├── Services
│ ├── FakeStoreApiService.cs
│ └── AuthenticationService.cs
├── MAUI.CleanArchitecture.Infrastructure.csproj
└── DependencyInjection.cs
├── MAUI.CleanArchitecture.Application
├── Store
│ └── Queries
│ │ └── GetStoreItemsQuery
│ │ ├── GetStoreItemsQuery.cs
│ │ └── GetStoreItemsQueryHandler.cs
├── Common
│ ├── Interfaces
│ │ ├── IFakeStoreApiService.cs
│ │ ├── IAuthentication.cs
│ │ └── IStoreDbContext.cs
│ ├── Notificications
│ │ ├── AddCardItemNotification.cs
│ │ ├── SigninNotification.cs
│ │ └── SignupNotification.cs
│ ├── Exceptions
│ │ └── ValidationException.cs
│ └── Models
│ │ └── UserInfo.cs
├── Card
│ ├── Commands
│ │ ├── CreateCardItem
│ │ │ ├── CreateCardItemCommand.cs
│ │ │ └── CreateCardItemCommandHandler.cs
│ │ └── UpdateCardItem
│ │ │ ├── UpdateCardItemCommand.cs
│ │ │ └── UpdateCardItemCommandHandler.cs
│ └── Queries
│ │ └── GetCardItems
│ │ ├── GetCardItemsQuery.cs
│ │ └── GetCardItemsQueryHandler.cs
├── Settings
│ └── AppSettings.cs
├── User
│ └── Commands
│ │ ├── Login
│ │ ├── LoginCommand.cs
│ │ ├── LoginCommandValidator.cs
│ │ └── LoginCommandHandler.cs
│ │ └── Register
│ │ ├── RegisterCommand.cs
│ │ ├── RegisterCommandValidator.cs
│ │ └── RegisterComandHandler.cs
├── DependencyInjection.cs
└── MAUI.CleanArchitecture.Application.csproj
├── LICENSE
├── README.md
├── MAUI.CleanArchitecture.sln
└── .gitignore
/MAUI.CleanArchitecture/Configuration/appsettings.debug.json:
--------------------------------------------------------------------------------
1 | {
2 | "ConnectionStrings": {
3 | "DefaultConnection": "Data Source={0}\\store.db"
4 | }
5 | }
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Configuration/appsettings.release.json:
--------------------------------------------------------------------------------
1 | {
2 | "ConnectionStrings": {
3 | "DefaultConnection": "Data Source={0}store.db"
4 | }
5 | }
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Resources/Images/login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hflexgrig/MAUI---CleanArchitecture/HEAD/MAUI.CleanArchitecture/Resources/Images/login.png
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Resources/Images/signup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hflexgrig/MAUI---CleanArchitecture/HEAD/MAUI.CleanArchitecture/Resources/Images/signup.png
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Resources/Images/add_to_cart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hflexgrig/MAUI---CleanArchitecture/HEAD/MAUI.CleanArchitecture/Resources/Images/add_to_cart.png
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Resources/Fonts/OpenSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hflexgrig/MAUI---CleanArchitecture/HEAD/MAUI.CleanArchitecture/Resources/Fonts/OpenSans-Regular.ttf
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "Windows Machine": {
4 | "commandName": "MsixPackage",
5 | "nativeDebugging": false
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/AppShell.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace MAUI.CleanArchitecture;
2 |
3 | public partial class AppShell : Shell
4 | {
5 | public AppShell()
6 | {
7 | InitializeComponent();
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Resources/appicon.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Domain/MainModel.cs:
--------------------------------------------------------------------------------
1 | namespace MAUI.CleanArchitecture.Domain
2 | {
3 | public class MainModel
4 | {
5 | public int TotalQuantity => SubItems.Sum(x => x.Quantity);
6 | public IList SubItems { get; set; } = new List();
7 | }
8 | }
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Platforms/Android/Resources/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #512BD4
4 | #2B0B98
5 | #2B0B98
6 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Domain/MAUI.CleanArchitecture.Domain.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Utils/IPageManager.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace MAUI.CleanArchitecture.Utils
4 | {
5 | public interface IPageManager
6 | {
7 | Task PopPageAsync();
8 | Task PopToRootPageAsync();
9 | Task StartPageAsync(bool isModal = false);
10 | }
11 | }
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Controls/CustomStepper.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Maui.Controls;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace MAUI.CleanArchitecture.Controls
9 | {
10 | internal class CustomStepper:Stepper
11 | {
12 |
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Infrastructure/Persistence/Constants.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace MAUI.CleanArchitecture.Infrastructure.Persistence
8 | {
9 | static class Constants
10 | {
11 | public const string DefaultKey = "Id";
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Platforms/MacCatalyst/AppDelegate.cs:
--------------------------------------------------------------------------------
1 | using Foundation;
2 | using Microsoft.Maui;
3 | using Microsoft.Maui.Hosting;
4 |
5 | namespace MAUI.CleanArchitecture
6 | {
7 | [Register("AppDelegate")]
8 | public class AppDelegate : MauiUIApplicationDelegate
9 | {
10 | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
11 | }
12 | }
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Domain/Entities/Rating.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace MAUI.CleanArchitecture.Domain.Entities
8 | {
9 | public class Rating
10 | {
11 | public double Rate { get; set; }
12 | public int Count { get; set; }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Platforms/Windows/App.xaml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Domain/User/LoginResponseModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace MAUI.CleanArchitecture.Domain.User
8 | {
9 | public class LoginResponseModel
10 | {
11 | public bool IsSucceeded { get; set; }
12 | public string? FailReason { get; set; }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Domain/SubItem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace MAUI.CleanArchitecture.Domain
8 | {
9 | public class SubItem
10 | {
11 | public string Name { get; set; }
12 | public string Description { get; set; }
13 | public int Quantity { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Platforms/iOS/Program.cs:
--------------------------------------------------------------------------------
1 | using UIKit;
2 |
3 | namespace MAUI.CleanArchitecture
4 | {
5 | public class Program
6 | {
7 | // This is the main entry point of the application.
8 | static void Main(string[] args)
9 | {
10 | // if you want to use a different Application Delegate class from "AppDelegate"
11 | // you can specify it here.
12 | UIApplication.Main(args, null, typeof(AppDelegate));
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Platforms/MacCatalyst/Program.cs:
--------------------------------------------------------------------------------
1 | using UIKit;
2 |
3 | namespace MAUI.CleanArchitecture
4 | {
5 | public class Program
6 | {
7 | // This is the main entry point of the application.
8 | static void Main(string[] args)
9 | {
10 | // if you want to use a different Application Delegate class from "AppDelegate"
11 | // you can specify it here.
12 | UIApplication.Main(args, null, typeof(AppDelegate));
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Platforms/iOS/AppDelegate.cs:
--------------------------------------------------------------------------------
1 | using Foundation;
2 | using Microsoft.Maui;
3 | using Microsoft.Maui.Hosting;
4 |
5 | namespace MAUI.CleanArchitecture
6 | {
7 | [Register("AppDelegate")]
8 | public class AppDelegate : MauiUIApplicationDelegate
9 | {
10 | protected override MauiApp CreateMauiApp()
11 | {
12 | var app = MauiProgram.CreateMauiApp();
13 | return app;
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Application/Store/Queries/GetStoreItemsQuery/GetStoreItemsQuery.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Domain.Entities;
2 | using MediatR;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace MAUI.CleanArchitecture.Application.Store.Queries.GetStoreItemsQuery
10 | {
11 | public class GetStoreItemsQuery:IRequest>
12 | {
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Platforms/Android/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Infrastructure/Identity/ApplicationUser.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace MAUI.CleanArchitecture.Infrastructure.Identity
8 | {
9 | public class ApplicationUser
10 | {
11 | public string FirstName { get; set; }
12 | public string LastName { get; set; }
13 |
14 | public DateTime DateOfBirth { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Application/Common/Interfaces/IFakeStoreApiService.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Domain.Entities;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace MAUI.CleanArchitecture.Application.Common.Interfaces
9 | {
10 | public interface IFakeStoreApiService
11 | {
12 | Task> GetStoreItems(CancellationToken cancellationToken);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Application/Card/Commands/CreateCardItem/CreateCardItemCommand.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Domain.Entities;
2 | using MediatR;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace MAUI.CleanArchitecture.Application.Card.Commands.CreateCardItem
10 | {
11 | public class CreateCardItemCommand:IRequest
12 | {
13 | public CardItem CardItem { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Application/Common/Notificications/AddCardItemNotification.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Domain.Entities;
2 | using MediatR;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace MAUI.CleanArchitecture.Application.Common.Notificications
10 | {
11 | public class AddCardItemNotification : INotification
12 | {
13 | public CardItem CardItem { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Application/Common/Notificications/SigninNotification.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Application.Common.Models;
2 | using MediatR;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace MAUI.CleanArchitecture.Application.Common.Notificications
10 | {
11 | public class SigninNotification : INotification
12 | {
13 | public UserInfo? UserInfo { get; internal set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Application/Common/Notificications/SignupNotification.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Application.Common.Models;
2 | using MediatR;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace MAUI.CleanArchitecture.Application.Common.Notificications
10 | {
11 | public class SignupNotification : INotification
12 | {
13 | public UserInfo? UserInfo { get; internal set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Application/Settings/AppSettings.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace MAUI.CleanArchitecture.Application.Settings
8 | {
9 | public class AppSettings
10 | {
11 | public ConnectionStrings ConnectionStrings { get; set; }
12 |
13 | }
14 |
15 | public class ConnectionStrings
16 | {
17 | public string? DefaultConnection { get; set; }
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Domain/Entities/User.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace MAUI.CleanArchitecture.Domain.Entities
8 | {
9 | public class User
10 | {
11 | public Guid Id { get; set; }
12 | public string UserName { get; set; }
13 | public string Email { get; set; }
14 | public string FirstName { get; set; }
15 | public string LastName { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Application/Card/Commands/UpdateCardItem/UpdateCardItemCommand.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Domain.Entities;
2 | using MediatR;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace MAUI.CleanArchitecture.Application.Card.Commands.CreateCardItem
10 | {
11 | public class UpdateCardItemCommand : IRequest
12 | {
13 | public Guid UserId { get; set; }
14 | public Guid SessionId { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Application/Card/Queries/GetCardItems/GetCardItemsQuery.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Domain.Entities;
2 | using MediatR;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace MAUI.CleanArchitecture.Application.Card.Queries.GetCardItems
10 | {
11 | public class GetCardItemsQuery : IRequest>
12 | {
13 | public Guid SessionId { get; set; }
14 | public Guid? UserId { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Application/Common/Exceptions/ValidationException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace MAUI.CleanArchitecture.Application.Common.Exceptions
8 | {
9 | public class ValidationException : Exception
10 | {
11 | public ValidationException(string message) : base(message)
12 | {
13 |
14 | }
15 |
16 | public Dictionary? ValidationErrors { get; set; }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Application/Common/Models/UserInfo.cs:
--------------------------------------------------------------------------------
1 | using MediatR;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace MAUI.CleanArchitecture.Application.Common.Models
9 | {
10 | public class UserInfo
11 | {
12 | public bool IsSignedIn { get; internal set; }
13 | public Guid SessionId { get; } = Guid.NewGuid();
14 | public Domain.Entities.User User { get; internal set; } = new Domain.Entities.User();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Platforms/Android/MainApplication.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Android.App;
3 | using Android.Runtime;
4 | using Microsoft.Maui;
5 | using Microsoft.Maui.Hosting;
6 |
7 | namespace MAUI.CleanArchitecture
8 | {
9 | [Application]
10 | public class MainApplication : MauiApplication
11 | {
12 | public MainApplication(IntPtr handle, JniHandleOwnership ownership)
13 | : base(handle, ownership)
14 | {
15 | }
16 |
17 | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
18 | }
19 | }
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/AppShell.xaml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Views/ContentViews/CardItemView.xaml.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Maui;
2 | using Microsoft.Maui.Controls;
3 | using Microsoft.Maui.Controls.Xaml;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace MAUI.CleanArchitecture.Views
11 | {
12 | [XamlCompilation(XamlCompilationOptions.Compile)]
13 | public partial class CardItemView : ContentView
14 | {
15 | public CardItemView()
16 | {
17 | InitializeComponent();
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Views/Pages/RegisterPageView.xaml.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Maui;
2 | using Microsoft.Maui.Controls;
3 | using Microsoft.Maui.Controls.Xaml;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace MAUI.CleanArchitecture.Views
11 | {
12 | [XamlCompilation(XamlCompilationOptions.Compile)]
13 | public partial class RegisterPageView : ContentPage
14 | {
15 | public RegisterPageView()
16 | {
17 | InitializeComponent();
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Application/User/Commands/Login/LoginCommand.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Application.Common.Notificications;
2 | using MAUI.CleanArchitecture.Domain.User;
3 | using MediatR;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace MAUI.CleanArchitecture.Application.User.Commands.Login
11 | {
12 | public class LoginCommand:IRequest
13 | {
14 | public string Username { get; set; }
15 | public string Password { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Domain/Entities/CardItem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace MAUI.CleanArchitecture.Domain.Entities
8 | {
9 | public class CardItem
10 | {
11 | public int Quantity { get; set; }
12 |
13 | public StoreItem StoreItem { get; set; } = new StoreItem();
14 |
15 | public Guid? UserId { get; set; }
16 | public Guid SessionId { get; set; }
17 |
18 | public decimal CalculatedPrice => StoreItem.Price * Quantity;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Application/User/Commands/Login/LoginCommandValidator.cs:
--------------------------------------------------------------------------------
1 | using FluentValidation;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace MAUI.CleanArchitecture.Application.User.Commands.Login
9 | {
10 | public class LoginCommandValidator:AbstractValidator
11 | {
12 | public LoginCommandValidator()
13 | {
14 | RuleFor(x => x.Username).NotEmpty().MinimumLength(3).MaximumLength(20);
15 | RuleFor(x => x.Password).NotEmpty().MinimumLength(5);
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Domain/Entities/StoreItem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace MAUI.CleanArchitecture.Domain.Entities
8 | {
9 | public class StoreItem
10 | {
11 | public int Id { get; set; }
12 | public string? Title { get; set; }
13 | public decimal Price { get; set; }
14 | public string? Description { get; set; }
15 | public string? Category { get; set; }
16 | public string? Image { get; set; }
17 | public Rating Rating { get; set; } = new Rating();
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Views/Pages/MainPageView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using MAUI.CleanArchitecture.ViewModels.Base;
3 | using Microsoft.Maui.Controls;
4 |
5 | namespace MAUI.CleanArchitecture.Views
6 | {
7 | public partial class MainPageView : ContentPage
8 | {
9 |
10 | public MainPageView()
11 | {
12 | InitializeComponent();
13 | }
14 |
15 | private void NumericStepper_ValueChanged(object sender, ValueChangedEventArgs e)
16 | {
17 |
18 | }
19 |
20 | private void NumericStepper_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
21 | {
22 |
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Application/Common/Interfaces/IAuthentication.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Application.User.Commands.Login;
2 | using MAUI.CleanArchitecture.Application.User.Commands.Register;
3 |
4 | namespace MAUI.CleanArchitecture.Application.Common.Interfaces
5 | {
6 | public interface IAuthentication
7 | {
8 | Task CheckPassword(string email, string password);
9 | Task CreateUser(RegisterCommand registerCommand);
10 | Task SignInAsync(LoginCommand loginCommand);
11 | Task UpdatePassword(string email, string oldPassword, string newPassword);
12 | }
13 | }
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Application/Common/Interfaces/IStoreDbContext.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Domain.Entities;
2 | using Microsoft.EntityFrameworkCore;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace MAUI.CleanArchitecture.Application.Common.Interfaces
10 | {
11 | public interface IStoreDbContext
12 | {
13 | DbSet StoreItems { get; set; }
14 | DbSet CardItems { get; set; }
15 |
16 | Task MigrateAsync(CancellationToken token);
17 | Task SaveChangesAsync(CancellationToken cancellationToken);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Resources/Raw/AboutAssets.txt:
--------------------------------------------------------------------------------
1 | Any raw assets you want to be deployed with your application can be placed in
2 | this directory (and child directories). Deployment of the asset to your application
3 | is automatically handled by the following `MauiAsset` Build Action within your `.csproj`.
4 |
5 |
6 |
7 | These files will be deployed with you package and will be accessible using Essentials:
8 |
9 | async Task LoadMauiAsset()
10 | {
11 | using var stream = await FileSystem.OpenAppPackageFileAsync("AboutAssets.txt");
12 | using var reader = new StreamReader(stream);
13 |
14 | var contents = reader.ReadToEnd();
15 | }
16 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Infrastructure/Persistence/Configurations/RatingConfiguration.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Domain.Entities;
2 | using Microsoft.EntityFrameworkCore;
3 | using Microsoft.EntityFrameworkCore.Metadata.Builders;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace MAUI.CleanArchitecture.Infrastructure.Persistence.Configurations
11 | {
12 | public class Ratingfiguration : IEntityTypeConfiguration
13 | {
14 | public void Configure(EntityTypeBuilder builder)
15 | {
16 | builder.Property("StoreRef");
17 | builder.HasKey("StoreRef");
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Platforms/Android/MainActivity.cs:
--------------------------------------------------------------------------------
1 | using Android.App;
2 | using Android.Content.PM;
3 | using Android.OS;
4 | using Microsoft.Maui;
5 |
6 | namespace MAUI.CleanArchitecture
7 | {
8 | [Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize)]
9 | public class MainActivity : MauiAppCompatActivity
10 | {
11 | protected override void OnCreate(Bundle savedInstanceState)
12 | {
13 | //Java.Lang.JavaSystem.LoadLibrary("System.Security.Cryptography.Native.OpenSsl");
14 | base.OnCreate(savedInstanceState);
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Converters/DoubleToStringConverter.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Maui.Controls;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Globalization;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace MAUI.CleanArchitecture.Converters
10 | {
11 | public class DoubleToStringConverter : IValueConverter
12 | {
13 |
14 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
15 | {
16 | return value.ToString();
17 | }
18 |
19 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
20 | {
21 | return System.Convert.ToDouble(value);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Platforms/Windows/app.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 | true/PM
12 | PerMonitorV2, PerMonitor
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Utils/PageManager.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.ViewModels.Base;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace MAUI.CleanArchitecture.Utils
9 | {
10 | public class PageManager : IPageManager
11 | {
12 | public Task StartPageAsync(bool isModal = false)
13 | {
14 | return ViewModelLocator.StartPageAsync(isModal);
15 | }
16 |
17 | public Task PopPageAsync()
18 | {
19 | return ViewModelLocator.PopPageAsync();
20 | }
21 |
22 | public Task PopToRootPageAsync()
23 | {
24 | return ViewModelLocator.PopToRootPageAsync();
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Application/User/Commands/Register/RegisterCommand.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Application.Common.Models;
2 | using MAUI.CleanArchitecture.Application.Common.Notificications;
3 | using MAUI.CleanArchitecture.Domain.User;
4 | using MediatR;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 |
11 | namespace MAUI.CleanArchitecture.Application.User.Commands.Register
12 | {
13 | public class RegisterCommand : IRequest
14 | {
15 | public string Username { get; set; }
16 | public string Email { get; set; }
17 | public string Password { get; set; }
18 |
19 | public string FirstName { get; set; }
20 | public string LastName { get; set; }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Views/Pages/LoginPageView.xaml.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Maui;
2 | using Microsoft.Maui.Controls;
3 | using Microsoft.Maui.Controls.Xaml;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace MAUI.CleanArchitecture.Views
11 | {
12 | [XamlCompilation(XamlCompilationOptions.Compile)]
13 | public partial class LoginPageView : ContentPage
14 | {
15 | public LoginPageView()
16 | {
17 | InitializeComponent();
18 | }
19 |
20 | protected override void OnDisappearing()
21 | {
22 | base.OnDisappearing();
23 | if(BindingContext is IDisposable vm)
24 | {
25 | vm.Dispose();
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Application/DependencyInjection.cs:
--------------------------------------------------------------------------------
1 | using FluentValidation;
2 | using MAUI.CleanArchitecture.Application.Common.Models;
3 | using MAUI.CleanArchitecture.Application.Settings;
4 | using MediatR;
5 | using Microsoft.Extensions.DependencyInjection;
6 | using System.Reflection;
7 | using System.Text.Json;
8 |
9 | namespace MAUI.CleanArchitecture.Application
10 | {
11 | public static class DependencyInjection
12 | {
13 | public static IServiceCollection AddApplication(this IServiceCollection services)
14 | {
15 |
16 | services.AddMediatR(Assembly.GetExecutingAssembly());
17 |
18 | services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
19 |
20 | services.AddSingleton(new UserInfo());
21 | return services;
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Views/Pages/UserInfoPageView.xaml.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Maui;
2 | using Microsoft.Maui.Controls;
3 | using Microsoft.Maui.Controls.Xaml;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace MAUI.CleanArchitecture.Views
11 | {
12 | [XamlCompilation(XamlCompilationOptions.Compile)]
13 | public partial class UserInfoPageView : ContentPage
14 | {
15 | public UserInfoPageView()
16 | {
17 | InitializeComponent();
18 | }
19 |
20 | protected override void OnDisappearing()
21 | {
22 | base.OnDisappearing();
23 | if(BindingContext is IDisposable vm)
24 | {
25 | vm.Dispose();
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.ViewModels.Base;
2 | using MAUI.CleanArchitecture.Views;
3 | using Microsoft.Maui;
4 | using Microsoft.Maui.Controls;
5 | using Microsoft.Maui.Controls.PlatformConfiguration.WindowsSpecific;
6 |
7 | namespace MAUI.CleanArchitecture
8 | {
9 | public partial class App : Microsoft.Maui.Controls.Application
10 | {
11 | public App()
12 | {
13 | InitializeComponent();
14 |
15 | var mainPage = new AppShell();
16 | Navigation = new NavigationPage(mainPage);
17 | mainPage.Navigation.InitializeNavigation();
18 | }
19 |
20 | public NavigationPage Navigation { get; }
21 |
22 | protected override Window CreateWindow(IActivationState activationState) =>
23 | new Window(Navigation) { Title = "MAUI.CleanArchitecture" };
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Application/User/Commands/Register/RegisterCommandValidator.cs:
--------------------------------------------------------------------------------
1 | using FluentValidation;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace MAUI.CleanArchitecture.Application.User.Commands.Register
9 | {
10 | public class RegisterCommandValidator:AbstractValidator
11 | {
12 | public RegisterCommandValidator()
13 | {
14 | RuleFor(x => x.Username).NotEmpty().MinimumLength(3).MaximumLength(20);
15 | RuleFor(x => x.Email).NotEmpty().MinimumLength(3).MaximumLength(20);
16 | RuleFor(x => x.Password).NotEmpty().MinimumLength(5);
17 | RuleFor(x => x.FirstName).NotEmpty().MaximumLength(20);
18 | RuleFor(x => x.LastName).NotEmpty().MaximumLength(20);
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Converters/ImageSourceConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.IO;
4 | using System.Net;
5 | using System.Net.Http;
6 |
7 | namespace MAUI.CleanArchitecture.Converters;
8 | using Microsoft.Maui.Controls;
9 |
10 |
11 | public class ImageSourceConverter : IValueConverter
12 | {
13 | static readonly HttpClient Client = new();
14 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
15 | {
16 | if (value == null)
17 | return null;
18 |
19 | var byteArray = Client.GetByteArrayAsync(value.ToString()!).GetAwaiter().GetResult();
20 |
21 | return ImageSource.FromStream(() => new MemoryStream(byteArray));
22 | }
23 |
24 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
25 | {
26 | throw new NotImplementedException();
27 | }
28 | }
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Controls/Errors.xaml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Infrastructure/BackgroundServices/DbBackgroundService.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Application.Common.Interfaces;
2 | using Microsoft.Extensions.DependencyInjection;
3 | using Microsoft.Extensions.Hosting;
4 |
5 | namespace MAUI.CleanArchitecture.Infrastructure.BackgroundServices
6 | {
7 | public class DbBackgroundService : BackgroundService
8 | {
9 | private readonly IServiceProvider _serviceProvider;
10 |
11 | public DbBackgroundService(IServiceProvider serviceProvider)
12 | {
13 | _serviceProvider = serviceProvider;
14 | }
15 |
16 | protected override async Task ExecuteAsync(CancellationToken stoppingToken)
17 | {
18 | using (var scope = _serviceProvider.CreateScope())
19 | {
20 | var dbContext = scope.ServiceProvider.GetRequiredService();
21 |
22 | await dbContext.MigrateAsync(stoppingToken);
23 | }
24 |
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Application/MAUI.CleanArchitecture.Application.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Infrastructure/Services/FakeStoreApiService.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Application.Common.Interfaces;
2 | using MAUI.CleanArchitecture.Domain.Entities;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Net.Http.Json;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace MAUI.CleanArchitecture.Infrastructure.Services
11 | {
12 | public class FakeStoreApiService:IFakeStoreApiService
13 | {
14 | private readonly HttpClient _httpClient;
15 |
16 | public FakeStoreApiService(HttpClient httpClient)
17 | {
18 | _httpClient = httpClient;
19 | }
20 |
21 | public async Task> GetStoreItems(CancellationToken cancellationToken)
22 | {
23 | var response = await _httpClient.GetAsync("products", cancellationToken);
24 | return await response.Content.ReadFromJsonAsync>(cancellationToken: cancellationToken);
25 | }
26 |
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Views/Pages/UserInfoPageView.xaml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Application/Card/Commands/CreateCardItem/CreateCardItemCommandHandler.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Application.Common.Interfaces;
2 | using MediatR;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace MAUI.CleanArchitecture.Application.Card.Commands.CreateCardItem
10 | {
11 | public class CreateCardItemCommandHandler : IRequestHandler
12 | {
13 | private readonly IStoreDbContext _storeDbContext;
14 |
15 | public CreateCardItemCommandHandler(IStoreDbContext storeDbContext)
16 | {
17 | _storeDbContext = storeDbContext;
18 | }
19 |
20 | public async Task Handle(CreateCardItemCommand request, CancellationToken cancellationToken)
21 | {
22 | _storeDbContext.CardItems.Add(request.CardItem);
23 | await _storeDbContext.SaveChangesAsync(cancellationToken);
24 | return Unit.Value;
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Infrastructure/Persistence/Configurations/CartItemConfiguration.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Domain.Entities;
2 | using MAUI.CleanArchitecture.Infrastructure.Identity;
3 | using Microsoft.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore.Metadata.Builders;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 |
11 | namespace MAUI.CleanArchitecture.Infrastructure.Persistence.Configurations
12 | {
13 | public class CartItemConfiguration : IEntityTypeConfiguration
14 | {
15 | public void Configure(EntityTypeBuilder builder)
16 | {
17 | builder.Property("StoreRef");
18 | builder.HasKey("StoreRef");
19 |
20 | builder.HasOne(t => t.StoreItem).WithOne().HasForeignKey("CardRef");
21 |
22 | //var identityUser = "IdentityUser";
23 | //builder.Property(identityUser);
24 | //builder.HasOne(identityUser).WithMany();
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Infrastructure/Persistence/Configurations/StoreItemConfiguration.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Domain.Entities;
2 | using Microsoft.EntityFrameworkCore;
3 | using Microsoft.EntityFrameworkCore.Metadata.Builders;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace MAUI.CleanArchitecture.Infrastructure.Persistence.Configurations
11 | {
12 | public class StoreItemConfiguration : IEntityTypeConfiguration
13 | {
14 | public void Configure(EntityTypeBuilder builder)
15 | {
16 | builder.Property(t => t.Id).IsUnicode(true).ValueGeneratedNever();
17 | builder.HasKey(t => t.Id);
18 |
19 | builder.Property("CardRef");
20 | builder.HasKey("CardRef");
21 |
22 | builder.Property(t => t.Title).HasMaxLength(200);
23 | builder.Property(t => t.Price).HasPrecision(18, 2);
24 |
25 | builder.HasOne(t => t.Rating).WithOne().HasForeignKey("StoreRef");
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Platforms/MacCatalyst/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | UIDeviceFamily
6 |
7 | 1
8 | 2
9 |
10 | UIRequiredDeviceCapabilities
11 |
12 | arm64
13 |
14 | UISupportedInterfaceOrientations
15 |
16 | UIInterfaceOrientationPortrait
17 | UIInterfaceOrientationLandscapeLeft
18 | UIInterfaceOrientationLandscapeRight
19 |
20 | UISupportedInterfaceOrientations~ipad
21 |
22 | UIInterfaceOrientationPortrait
23 | UIInterfaceOrientationPortraitUpsideDown
24 | UIInterfaceOrientationLandscapeLeft
25 | UIInterfaceOrientationLandscapeRight
26 |
27 | XSAppIconAssets
28 | Assets.xcassets/appicon.appiconset
29 |
30 |
31 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Hayk Hakob Grigoryan
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Application/Card/Queries/GetCardItems/GetCardItemsQueryHandler.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Application.Common.Interfaces;
2 | using MAUI.CleanArchitecture.Domain.Entities;
3 | using MediatR;
4 | using Microsoft.EntityFrameworkCore;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 |
11 | namespace MAUI.CleanArchitecture.Application.Card.Queries.GetCardItems
12 | {
13 | public class GetCardItemsQueryHandler : IRequestHandler>
14 | {
15 | private readonly IStoreDbContext _storeDbContext;
16 |
17 | public GetCardItemsQueryHandler(IStoreDbContext storeDbContext)
18 | {
19 | _storeDbContext = storeDbContext;
20 | }
21 |
22 | public Task> Handle(GetCardItemsQuery request, CancellationToken cancellationToken)
23 | {
24 | return _storeDbContext.CardItems.AsNoTracking().Include(x => x.StoreItem)
25 | .Where(x => x.UserId == request.UserId || x.SessionId == request.SessionId)
26 | .ToListAsync(cancellationToken);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Infrastructure/MAUI.CleanArchitecture.Infrastructure.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/ViewModels/Base/ViewModelBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.ComponentModel;
5 | using System.Linq;
6 | using System.Runtime.CompilerServices;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace MAUI.CleanArchitecture.ViewModels.Base
11 | {
12 | public class ViewModelBase : INotifyPropertyChanged
13 | {
14 | public event PropertyChangedEventHandler PropertyChanged;
15 | private IEnumerable _errors;
16 |
17 | public virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) =>
18 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
19 |
20 | public IEnumerable Errors
21 | {
22 | get => _errors; set
23 | {
24 | _errors = value;
25 | OnPropertyChanged();
26 | }
27 | }
28 |
29 | private IEnumerable _customErrors;
30 |
31 | public IEnumerable CustomErrors
32 | {
33 | get { return _customErrors; }
34 | set { _customErrors = value; OnPropertyChanged(); }
35 | }
36 |
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Application/Store/Queries/GetStoreItemsQuery/GetStoreItemsQueryHandler.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Application.Common.Interfaces;
2 | using MAUI.CleanArchitecture.Domain.Entities;
3 | using MediatR;
4 | using Microsoft.EntityFrameworkCore;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 |
11 | namespace MAUI.CleanArchitecture.Application.Store.Queries.GetStoreItemsQuery
12 | {
13 | public class GetStoreItemsQueryHandler : IRequestHandler>
14 | {
15 | private readonly IFakeStoreApiService _fakeStoreApiService;
16 | private readonly IStoreDbContext _storeDbContext;
17 |
18 | public GetStoreItemsQueryHandler(IFakeStoreApiService fakeStoreApiService, IStoreDbContext storeDbContext)
19 | {
20 | _fakeStoreApiService = fakeStoreApiService;
21 | _storeDbContext = storeDbContext;
22 | }
23 |
24 | public Task> Handle(GetStoreItemsQuery request, CancellationToken cancellationToken)
25 | {
26 | return _fakeStoreApiService.GetStoreItems(cancellationToken);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Application/Card/Commands/UpdateCardItem/UpdateCardItemCommandHandler.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Application.Common.Interfaces;
2 | using MediatR;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace MAUI.CleanArchitecture.Application.Card.Commands.CreateCardItem
10 | {
11 | public class UpdateCardItemCommandHandler : IRequestHandler
12 | {
13 | private readonly IStoreDbContext _storeDbContext;
14 |
15 | public UpdateCardItemCommandHandler(IStoreDbContext storeDbContext)
16 | {
17 | _storeDbContext = storeDbContext;
18 | }
19 |
20 | public async Task Handle(UpdateCardItemCommand request, CancellationToken cancellationToken)
21 | {
22 | var cardItems = _storeDbContext.CardItems.Where(x => x.SessionId == request.SessionId);
23 | foreach (var cardItem in cardItems)
24 | {
25 | cardItem.UserId = request.UserId;
26 | }
27 |
28 | await _storeDbContext.SaveChangesAsync(cancellationToken);
29 | return Unit.Value;
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Platforms/iOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | LSRequiresIPhoneOS
6 |
7 | UIDeviceFamily
8 |
9 | 1
10 | 2
11 |
12 | UIRequiredDeviceCapabilities
13 |
14 | arm64
15 |
16 | UISupportedInterfaceOrientations
17 |
18 | UIInterfaceOrientationPortrait
19 | UIInterfaceOrientationLandscapeLeft
20 | UIInterfaceOrientationLandscapeRight
21 |
22 | UISupportedInterfaceOrientations~ipad
23 |
24 | UIInterfaceOrientationPortrait
25 | UIInterfaceOrientationPortraitUpsideDown
26 | UIInterfaceOrientationLandscapeLeft
27 | UIInterfaceOrientationLandscapeRight
28 |
29 | XSAppIconAssets
30 | Assets.xcassets/appicon.appiconset
31 | CFBundleIdentifier
32 | com.companyname.MAUI.CleanArchitecture
33 |
34 |
35 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Application/User/Commands/Login/LoginCommandHandler.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Application.Common.Interfaces;
2 | using MAUI.CleanArchitecture.Application.Common.Models;
3 | using MAUI.CleanArchitecture.Application.Common.Notificications;
4 | using MAUI.CleanArchitecture.Domain.User;
5 | using MediatR;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Linq;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 |
12 | namespace MAUI.CleanArchitecture.Application.User.Commands.Login
13 | {
14 | public class LoginCommandHandler : IRequestHandler
15 | {
16 | private readonly IAuthentication _authentication;
17 | private readonly UserInfo _userInfo;
18 |
19 | public LoginCommandHandler(IAuthentication authentication, UserInfo userInfo)
20 | {
21 | _authentication = authentication;
22 | _userInfo = userInfo;
23 | }
24 |
25 | public async Task Handle(LoginCommand request, CancellationToken cancellationToken)
26 | {
27 | var user = await _authentication.SignInAsync(request);
28 | _userInfo.User = user;
29 | _userInfo.IsSignedIn = true;
30 | return new SigninNotification { UserInfo = _userInfo };
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Application/User/Commands/Register/RegisterComandHandler.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Application.Common.Interfaces;
2 | using MAUI.CleanArchitecture.Application.Common.Models;
3 | using MAUI.CleanArchitecture.Application.Common.Notificications;
4 | using MAUI.CleanArchitecture.Domain.User;
5 | using MediatR;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Linq;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 |
12 | namespace MAUI.CleanArchitecture.Application.User.Commands.Register
13 | {
14 | public class RegisterCommandHandler : IRequestHandler
15 | {
16 | private readonly IAuthentication _authentication;
17 | private readonly UserInfo _userInfo;
18 |
19 | public RegisterCommandHandler(IAuthentication authentication, UserInfo userInfo)
20 | {
21 | _authentication = authentication;
22 | _userInfo = userInfo;
23 | }
24 |
25 | public async Task Handle(RegisterCommand request, CancellationToken cancellationToken)
26 | {
27 | var user = await _authentication.CreateUser(request);
28 | _userInfo.User = user;
29 | _userInfo.IsSignedIn = true;
30 |
31 | return new SignupNotification { UserInfo = _userInfo};
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Platforms/Windows/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Maui;
2 | using Microsoft.Maui.Hosting;
3 | using Microsoft.UI.Xaml;
4 | using Windows.ApplicationModel;
5 |
6 | // To learn more about WinUI, the WinUI project structure,
7 | // and more about our project templates, see: http://aka.ms/winui-project-info.
8 |
9 | namespace MAUI.CleanArchitecture.WinUI
10 | {
11 | ///
12 | /// Provides application-specific behavior to supplement the default Application class.
13 | ///
14 | public partial class App : MauiWinUIApplication
15 | {
16 | ///
17 | /// Initializes the singleton application object. This is the first line of authored code
18 | /// executed, and as such is the logical equivalent of main() or WinMain().
19 | ///
20 | public App()
21 | {
22 | this.InitializeComponent();
23 | }
24 |
25 | protected override MauiApp CreateMauiApp()
26 | {
27 | var app = MauiProgram.CreateMauiApp();
28 | //app.StartAsync().GetAwaiter().GetResult();
29 | return app;
30 | }
31 |
32 | protected override void OnLaunched(LaunchActivatedEventArgs args)
33 | {
34 | base.OnLaunched(args);
35 |
36 | // Microsoft.Maui.Essentials.Platform.OnLaunched(args);
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/App.xaml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 | #512bdf
11 | White
12 |
13 |
17 |
18 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Views/Pages/LoginPageView.xaml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Controls/Errors.xaml.cs:
--------------------------------------------------------------------------------
1 | using FluentValidation.Results;
2 | using Microsoft.Maui.Controls;
3 | using Microsoft.Maui.Controls.Xaml;
4 | using System.Collections;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 |
8 | namespace MAUI.CleanArchitecture.Controls
9 | {
10 | [XamlCompilation(XamlCompilationOptions.Compile)]
11 | public partial class Errors : ContentView
12 | {
13 | public Errors()
14 | {
15 | InitializeComponent();
16 | }
17 |
18 | public static readonly BindableProperty ForPropertyProperty = BindableProperty.Create(nameof(ForProperty), typeof(string), typeof(Errors), default(string));
19 |
20 | public string ForProperty
21 | {
22 | get => (string)GetValue(ForPropertyProperty);
23 | set => SetValue(ForPropertyProperty, value);
24 | }
25 |
26 | public static readonly BindableProperty ItemsSourceProperty = BindableProperty.Create(nameof(ItemsSource), typeof(IEnumerable), typeof(Errors), new List());
27 |
28 | public IEnumerable ItemsSource
29 | {
30 | get
31 | {
32 | var fullList = (IEnumerable)GetValue(ItemsSourceProperty);
33 | return fullList?.Where(x => string.IsNullOrEmpty(ForProperty) || x.PropertyName == ForProperty);
34 | }
35 |
36 | set => SetValue(ItemsSourceProperty, value);
37 | }
38 |
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/ViewModels/UserInfoPageViewModel.cs:
--------------------------------------------------------------------------------
1 | using FluentValidation;
2 | using FluentValidation.Results;
3 | using MAUI.CleanArchitecture.Application.Common.Interfaces;
4 | using MAUI.CleanArchitecture.Application.User.Commands.Login;
5 | using MAUI.CleanArchitecture.Domain;
6 | using MAUI.CleanArchitecture.ViewModels.Base;
7 | using MediatR;
8 | using Microsoft.Maui.Controls;
9 | using System;
10 | using System.Collections.Generic;
11 | using System.Collections.ObjectModel;
12 | using System.ComponentModel;
13 | using System.Linq;
14 | using System.Runtime.CompilerServices;
15 | using System.Text;
16 | using System.Threading.Tasks;
17 | using System.Windows.Input;
18 | using MAUI.CleanArchitecture.Application.Common.Exceptions;
19 | using MAUI.CleanArchitecture.Application.Common.Models;
20 | using System.Threading;
21 | using Microsoft.Extensions.DependencyInjection;
22 | using MAUI.CleanArchitecture.Utils;
23 |
24 | namespace MAUI.CleanArchitecture.ViewModels
25 | {
26 | public class UserInfoPageViewModel : ViewModelBase
27 | {
28 | private readonly IServiceProvider _serviceProvider;
29 | private readonly IMediator _mediator;
30 | private readonly IValidator _validator;
31 | private readonly IPageManager _pageManager;
32 | private LoginCommand _loginModel = new LoginCommand();
33 | private IServiceScope _scope;
34 |
35 | public UserInfoPageViewModel( UserInfo userInfo)
36 | {
37 | User = userInfo.User;
38 | }
39 |
40 | public Domain.Entities.User User { get; }
41 |
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Platforms/Windows/Package.appxmanifest:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 | $placeholder$
12 | User Name
13 | $placeholder$.png
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Resources/Images/signup.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Resources/appiconfg.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Resources/Splash/splash.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Infrastructure/DependencyInjection.cs:
--------------------------------------------------------------------------------
1 | using AutoMapper;
2 | using MAUI.CleanArchitecture.Application.Common.Interfaces;
3 | using MAUI.CleanArchitecture.Application.User.Commands.Login;
4 | using MAUI.CleanArchitecture.Application.User.Commands.Register;
5 | using MAUI.CleanArchitecture.Domain.Entities;
6 | using MAUI.CleanArchitecture.Infrastructure.BackgroundServices;
7 | using MAUI.CleanArchitecture.Infrastructure.Identity;
8 | using MAUI.CleanArchitecture.Infrastructure.Persistence;
9 | using MAUI.CleanArchitecture.Infrastructure.Services;
10 | using Microsoft.Extensions.DependencyInjection;
11 |
12 | namespace MAUI.CleanArchitecture.Infrastructure
13 | {
14 | public static class DependencyInjection
15 | {
16 | public static IServiceCollection AddInfrastructure(this IServiceCollection services)
17 | {
18 | services.AddHostedService();
19 |
20 | services.AddHttpClient(nameof(FakeStoreApiService), t =>
21 | {
22 | t.BaseAddress = new Uri("https://fakestoreapi.com");
23 | }).AddTypedClient();
24 |
25 | services.AddDbContext();
26 | // services.AddIdentity()
27 | // .AddEntityFrameworkStores()
28 | // .AddDefaultTokenProviders();
29 | // services.AddScoped();
30 |
31 |
32 | services.AddAutoMapper(cfg =>
33 | {
34 | cfg.CreateMap().ReverseMap();
35 | cfg.CreateMap().ReverseMap();
36 | cfg.CreateMap().ReverseMap();
37 | });
38 |
39 | return services;
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Views/Pages/RegisterPageView.xaml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/MauiProgram.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Maui;
2 | using Microsoft.Maui.Hosting;
3 | using Microsoft.Maui.Controls.Compatibility;
4 | using Microsoft.Maui.Controls.Hosting;
5 | using MAUI.CleanArchitecture.Application;
6 | using MAUI.CleanArchitecture.ViewModels.Base;
7 | using MAUI.CleanArchitecture.ViewModels;
8 | using MAUI.CleanArchitecture.Utils;
9 | using MAUI.CleanArchitecture.Infrastructure;
10 | using System.Reflection;
11 | using System;
12 | using System.IO;
13 | using System.Text.Json;
14 | using MAUI.CleanArchitecture.Application.Settings;
15 | using MAUI.CleanArchitecture.Infrastructure.BackgroundServices;
16 | using Microsoft.Extensions.Configuration;
17 |
18 | namespace MAUI.CleanArchitecture
19 | {
20 | public static class MauiProgram
21 | {
22 | public static MauiApp CreateMauiApp()
23 | {
24 | #if DEBUG
25 | var appSettingsStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("MAUI.CleanArchitecture.Configuration.appsettings.debug.json");
26 | #else
27 | var appSettingsStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("MAUI.CleanArchitecture.Configuration.appsettings.release.json");
28 | #endif
29 |
30 | var builder = MauiApp.CreateBuilder();
31 | var config = new ConfigurationBuilder()
32 | .AddJsonStream(appSettingsStream)
33 | .Build();
34 | builder.Configuration.AddConfiguration(config);
35 | builder.Services.AddSingleton();
36 | builder.Services.AddApplication();
37 | builder.Services.AddInfrastructure();
38 | ViewModelLocator.Initialize(builder.Services);
39 |
40 | builder
41 | .UseMauiApp()
42 | .ConfigureFonts(fonts =>
43 | {
44 | fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
45 | });
46 |
47 | return builder.Build();
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Infrastructure/Persistence/StoreDbContext.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Application.Common.Interfaces;
2 | using MAUI.CleanArchitecture.Domain.Entities;
3 | using MAUI.CleanArchitecture.Infrastructure.Identity;
4 | using Microsoft.EntityFrameworkCore;
5 | using Microsoft.Extensions.Configuration;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Linq;
9 | using System.Reflection;
10 | using System.Text;
11 | using System.Threading.Tasks;
12 |
13 | namespace MAUI.CleanArchitecture.Infrastructure.Persistence
14 | {
15 | public class StoreDbContext : DbContext, IStoreDbContext
16 | {
17 | private readonly IConfiguration _configuration;
18 |
19 | public StoreDbContext(DbContextOptions options, IConfiguration configuration) : base(options)
20 | {
21 | _configuration = configuration;
22 | }
23 |
24 | public DbSet StoreItems { get; set; }
25 | public DbSet CardItems { get; set; }
26 | public DbSet Users { get; set; }
27 |
28 | public Task MigrateAsync(CancellationToken token)
29 | {
30 | return Database.MigrateAsync(token);
31 | }
32 |
33 | protected override void OnConfiguring(DbContextOptionsBuilder options)
34 | {
35 | var folder = Environment.SpecialFolder.LocalApplicationData;
36 | var path = Path.Combine(Environment.GetFolderPath(folder), "Test");
37 | if (!Directory.Exists(path))
38 | {
39 | Directory.CreateDirectory(path);
40 | }
41 |
42 | var dbPath = string.Format(_configuration.GetConnectionString("DefaultConnection"), path);
43 | options.UseSqlite(dbPath);
44 | base.OnConfiguring(options);
45 | }
46 |
47 | protected override void OnModelCreating(ModelBuilder modelBuilder)
48 | {
49 | modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
50 |
51 | base.OnModelCreating(modelBuilder);
52 | }
53 |
54 | public override Task SaveChangesAsync(CancellationToken cancellationToken = default)
55 | {
56 | return base.SaveChangesAsync(cancellationToken);
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/ViewModels/CardItemViewModel.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Application.Card.Commands.CreateCardItem;
2 | using MAUI.CleanArchitecture.Application.Common.Notificications;
3 | using MAUI.CleanArchitecture.Domain.Entities;
4 | using MAUI.CleanArchitecture.ViewModels.Base;
5 | using MediatR;
6 | using Microsoft.Extensions.DependencyInjection;
7 | using Microsoft.Maui.Controls;
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Linq;
11 | using System.Text;
12 | using System.Threading.Tasks;
13 |
14 | namespace MAUI.CleanArchitecture.ViewModels
15 | {
16 | public class CardItemViewModel : ViewModelBase
17 | {
18 | private readonly IMediator _mediator;
19 | private readonly IServiceProvider _serviceProvider;
20 |
21 | public CardItemViewModel(IServiceProvider serviceProvider)
22 | {
23 | AddToCardCommand = new Command((obj) => AddToCardHandler(), (obj) => CardItem.Quantity > 0);
24 | _serviceProvider = serviceProvider;
25 | _mediator = _serviceProvider.GetService();
26 | }
27 |
28 | private async void AddToCardHandler()
29 | {
30 | try
31 | {
32 | using (var scope = _serviceProvider.CreateScope())
33 | {
34 | var mediator = scope.ServiceProvider.GetService();
35 | await mediator.Send(new CreateCardItemCommand { CardItem = CardItem });
36 | }
37 |
38 | await _mediator.Publish(new AddCardItemNotification { CardItem = CardItem });
39 | }
40 | catch (Exception ex)
41 | {
42 | //TODO: Show user facing
43 | }
44 | }
45 |
46 | public int Quantity
47 | {
48 | get { return CardItem.Quantity; }
49 | set
50 | {
51 | CardItem.Quantity = value;
52 | OnPropertyChanged();
53 | OnPropertyChanged(nameof(CardItem.CalculatedPrice));
54 | AddToCardCommand.ChangeCanExecute();
55 | }
56 | }
57 |
58 | public string CalculatedPrice => CardItem.CalculatedPrice.ToString();
59 |
60 | public CardItem CardItem { get; set; } = new CardItem();
61 | public Command AddToCardCommand { get; }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MAUI---CleanArchitecture
2 | MAUI application template following the principles of Clean Architecture
3 |
4 | WORK CURRENTLY IN PROGRESS
5 |
6 |
7 |
8 | https://user-images.githubusercontent.com/24684337/145751149-eea4dc3e-5168-4d3b-b373-2ea9b02e18b7.mp4
9 |
10 |
11 | # Technologies
12 | - [.NET 6 MAUI](https://github.com/dotnet/maui)
13 | - [Entity Framework Core 6](https://docs.microsoft.com/en-us/ef/core/)
14 | - [MediatR](https://github.com/jbogard/MediatR)
15 | - [AutoMapper](https://automapper.org/)
16 | - [FluentValidation](https://fluentvalidation.net/)
17 | - [Aspnet Identity authentication with SQLite database](https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity?view=aspnetcore-6.0&tabs=visual-studio)
18 |
19 | # Description
20 |
21 | This is sample EShop app. It retrieves data from [Fake Store API](https://fakestoreapi.com/) once, stores it into local SQLite database, consequent times it takes only from local storage. ASPNet Identity authentication used to create new user and sign in.
22 |
23 |
24 | Keep {viewname}**View** {viewModelName}**ViewModel** naming conventions, as assembly scanners from ViewModelLocator will be able to locate and assign BindingContext to it's view. Also on some views don't forget to add
25 |
26 |
2 |
3 |
9 |
10 |
11 |
12 |
13 |
14 |
17 |
21 |
22 |
23 |
24 |
27 |
28 |
29 |
30 |
32 |
34 |
36 |
37 |
38 |
39 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.0.31611.283
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MAUI.CleanArchitecture", "MAUI.CleanArchitecture\MAUI.CleanArchitecture.csproj", "{EBD8DD35-EB0E-4648-A536-233681BB8ED6}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MAUI.CleanArchitecture.Domain", "MAUI.CleanArchitecture.Domain\MAUI.CleanArchitecture.Domain.csproj", "{A082529D-EEC5-4103-A0C6-948B8C4D127A}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MAUI.CleanArchitecture.Application", "MAUI.CleanArchitecture.Application\MAUI.CleanArchitecture.Application.csproj", "{625DD3E0-6CB9-4F19-8037-8B95F8110236}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MAUI.CleanArchitecture.Infrastructure", "MAUI.CleanArchitecture.Infrastructure\MAUI.CleanArchitecture.Infrastructure.csproj", "{FA02702D-8CC8-470B-835C-0C202F30B65B}"
13 | EndProject
14 | Global
15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 | Debug|Any CPU = Debug|Any CPU
17 | Release|Any CPU = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {EBD8DD35-EB0E-4648-A536-233681BB8ED6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {EBD8DD35-EB0E-4648-A536-233681BB8ED6}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {EBD8DD35-EB0E-4648-A536-233681BB8ED6}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
23 | {EBD8DD35-EB0E-4648-A536-233681BB8ED6}.Release|Any CPU.ActiveCfg = Release|Any CPU
24 | {EBD8DD35-EB0E-4648-A536-233681BB8ED6}.Release|Any CPU.Build.0 = Release|Any CPU
25 | {EBD8DD35-EB0E-4648-A536-233681BB8ED6}.Release|Any CPU.Deploy.0 = Release|Any CPU
26 | {A082529D-EEC5-4103-A0C6-948B8C4D127A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {A082529D-EEC5-4103-A0C6-948B8C4D127A}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {A082529D-EEC5-4103-A0C6-948B8C4D127A}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {A082529D-EEC5-4103-A0C6-948B8C4D127A}.Release|Any CPU.Build.0 = Release|Any CPU
30 | {625DD3E0-6CB9-4F19-8037-8B95F8110236}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {625DD3E0-6CB9-4F19-8037-8B95F8110236}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {625DD3E0-6CB9-4F19-8037-8B95F8110236}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {625DD3E0-6CB9-4F19-8037-8B95F8110236}.Release|Any CPU.Build.0 = Release|Any CPU
34 | {FA02702D-8CC8-470B-835C-0C202F30B65B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {FA02702D-8CC8-470B-835C-0C202F30B65B}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {FA02702D-8CC8-470B-835C-0C202F30B65B}.Release|Any CPU.ActiveCfg = Release|Any CPU
37 | {FA02702D-8CC8-470B-835C-0C202F30B65B}.Release|Any CPU.Build.0 = Release|Any CPU
38 | EndGlobalSection
39 | GlobalSection(SolutionProperties) = preSolution
40 | HideSolutionNode = FALSE
41 | EndGlobalSection
42 | GlobalSection(ExtensibilityGlobals) = postSolution
43 | SolutionGuid = {61F7FB11-1E47-470C-91E2-47F8143E1572}
44 | EndGlobalSection
45 | EndGlobal
46 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Views/Pages/MainPageView.xaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
27 |
28 |
29 |
32 |
33 |
34 |
35 |
36 |
40 |
41 |
45 |
46 |
47 |
48 |
56 |
57 |
58 |
59 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/ViewModels/LoginPageViewModel.cs:
--------------------------------------------------------------------------------
1 | using FluentValidation;
2 | using FluentValidation.Results;
3 | using MAUI.CleanArchitecture.Application.Common.Interfaces;
4 | using MAUI.CleanArchitecture.Application.User.Commands.Login;
5 | using MAUI.CleanArchitecture.Domain;
6 | using MAUI.CleanArchitecture.ViewModels.Base;
7 | using MediatR;
8 | using Microsoft.Maui.Controls;
9 | using System;
10 | using System.Collections.Generic;
11 | using System.Collections.ObjectModel;
12 | using System.ComponentModel;
13 | using System.Linq;
14 | using System.Runtime.CompilerServices;
15 | using System.Text;
16 | using System.Threading.Tasks;
17 | using System.Windows.Input;
18 | using MAUI.CleanArchitecture.Application.Common.Exceptions;
19 | using MAUI.CleanArchitecture.Application.Common.Models;
20 | using System.Threading;
21 | using Microsoft.Extensions.DependencyInjection;
22 | using MAUI.CleanArchitecture.Utils;
23 | using MAUI.CleanArchitecture.Application.Common.Notificications;
24 |
25 | namespace MAUI.CleanArchitecture.ViewModels
26 | {
27 | public class LoginPageViewModel : ViewModelBase
28 | {
29 | private readonly IMediator _mediator;
30 | private readonly IServiceProvider _serviceProvider;
31 | private readonly IValidator _validator;
32 | private readonly IPageManager _pageManager;
33 | private LoginCommand _loginModel = new LoginCommand();
34 |
35 | public LoginPageViewModel(IServiceProvider serviceProvider, IValidator validator, IPageManager pageManager)
36 | {
37 | _serviceProvider = serviceProvider;
38 | _mediator = _serviceProvider.GetService();
39 | _validator = validator;
40 | _pageManager = pageManager;
41 | LoginCommand = new Command(() => LoginHandlerAsync(), () =>
42 | {
43 | var validationResult = _validator.Validate(_loginModel);
44 | Errors = validationResult.Errors;
45 | return validationResult.IsValid;
46 | });
47 |
48 | StartRegisterCommand = new Command(() => StartRegisterHandler());
49 | }
50 |
51 | private async void StartRegisterHandler()
52 | {
53 | // await _pageManager.PopPageAsync();
54 | await _pageManager.StartPageAsync();
55 | }
56 |
57 | public Command LoginCommand { get; private set; }
58 | public Command StartRegisterCommand { get; }
59 |
60 | public string Login
61 | {
62 | get { return _loginModel.Username; }
63 | set { _loginModel.Username = value; OnPropertyChanged(); LoginCommand.ChangeCanExecute(); }
64 | }
65 |
66 | public string Password
67 | {
68 | get { return _loginModel.Password; }
69 | set { _loginModel.Password = value; OnPropertyChanged(); LoginCommand.ChangeCanExecute(); }
70 | }
71 |
72 | private async void LoginHandlerAsync()
73 | {
74 | try
75 | {
76 | SigninNotification signinNotification = null;
77 | using (var scope = _serviceProvider.CreateScope())
78 | {
79 | var mediator = scope.ServiceProvider.GetService();
80 | signinNotification = await mediator.Send(_loginModel);
81 | }
82 |
83 | await _mediator.Publish(signinNotification);
84 | }
85 | catch (Application.Common.Exceptions.ValidationException ex)
86 | {
87 | CustomErrors = ex.ValidationErrors.Select(x => new ValidationFailure(x.Key, x.Value));
88 | }
89 | }
90 |
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Platforms/iOS/Resources/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
21 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Infrastructure/Services/AuthenticationService.cs:
--------------------------------------------------------------------------------
1 | // using AutoMapper;
2 | // using MAUI.CleanArchitecture.Application.Common.Exceptions;
3 | // using MAUI.CleanArchitecture.Application.Common.Interfaces;
4 | // using MAUI.CleanArchitecture.Application.User.Commands.Login;
5 | // using MAUI.CleanArchitecture.Application.User.Commands.Register;
6 | // using MAUI.CleanArchitecture.Domain.Entities;
7 | // using MAUI.CleanArchitecture.Infrastructure.Identity;
8 | // using Microsoft.AspNetCore.Http;
9 | // using Microsoft.AspNetCore.Identity;
10 | //
11 | // namespace MAUI.CleanArchitecture.Infrastructure.Services
12 | // {
13 | // public class AuthenticationService : IAuthentication
14 | // {
15 | // private readonly IServiceProvider _serviceProvider;
16 | // // readonly UserManager _userManager;
17 | // private readonly SignInManager _signInManager;
18 | // private readonly IMapper _mapper;
19 | //
20 | // public AuthenticationService(IServiceProvider serviceProvider,
21 | // // UserManager userManager,
22 | // // SignInManager signInManager,
23 | // IMapper mapper)
24 | // {
25 | // _serviceProvider = serviceProvider;
26 | // // _userManager = userManager;
27 | // // _signInManager = signInManager;
28 | // _mapper = mapper;
29 | // // _signInManager.Context = new DefaultHttpContext { RequestServices = _serviceProvider };
30 | // }
31 | //
32 | // public async Task CreateUser(RegisterCommand registerCommand)
33 | // {
34 | // var applicationUser = _mapper.Map(registerCommand);
35 | //
36 | // // var result = await _userManager.CreateAsync(applicationUser, registerCommand.Password);
37 | // // if (!result.Succeeded)
38 | // // {
39 | // // throw new ValidationException("Unable to create user") { ValidationErrors = result.Errors.ToDictionary(x => x.Code, x => x.Description) };
40 | // // }
41 | // //
42 | // // var loaded = await _userManager.FindByEmailAsync(registerCommand.Email);
43 | //
44 | // // return _mapper.Map(loaded);
45 | // return default;
46 | // }
47 | //
48 | // public async Task SignInAsync(LoginCommand loginCommand)
49 | // {
50 | // var result = await _signInManager.PasswordSignInAsync(loginCommand.Username, loginCommand.Password, false, true);
51 | // if (!result.Succeeded)
52 | // {
53 | // throw new ValidationException("Unable to create user") { ValidationErrors = result.IsLockedOut
54 | // ? new Dictionary { { "fail", "locked out"} }
55 | // : new Dictionary { { "fail", "wrong username or password" } }
56 | // };
57 | // }
58 | //
59 | // var loaded = await _userManager.FindByNameAsync(loginCommand.Username);
60 | // return _mapper.Map(loaded);
61 | // }
62 | //
63 | // public async Task UpdatePassword(string email, string oldPassword, string newPassword)
64 | // {
65 | // var loaded1 = await _userManager.FindByNameAsync(email);
66 | // if (loaded1 == null)
67 | // {
68 | // return null;
69 | // }
70 | //
71 | // var result = await _userManager.ChangePasswordAsync(loaded1, oldPassword, newPassword);
72 | // if (!result.Succeeded)
73 | // {
74 | // return null;
75 | // }
76 | //
77 | // var loaded = await _userManager.FindByNameAsync(email);
78 | // return _mapper.Map(loaded);
79 | // }
80 | //
81 | // public async Task CheckPassword(string email, string password)
82 | // {
83 | // var loaded1 = await _userManager.FindByNameAsync(email);
84 | // if (loaded1 == null)
85 | // {
86 | // return false;
87 | // }
88 | //
89 | // return await _userManager.CheckPasswordAsync(loaded1, password);
90 | // }
91 | // }
92 | // }
93 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/ViewModels/RegisterPageViewModel.cs:
--------------------------------------------------------------------------------
1 | using FluentValidation;
2 | using FluentValidation.Results;
3 | using MAUI.CleanArchitecture.Application.Common.Interfaces;
4 | using MAUI.CleanArchitecture.Application.User.Commands.Login;
5 | using MAUI.CleanArchitecture.Domain;
6 | using MAUI.CleanArchitecture.ViewModels.Base;
7 | using MediatR;
8 | using Microsoft.Maui.Controls;
9 | using System;
10 | using System.Collections.Generic;
11 | using System.Collections.ObjectModel;
12 | using System.ComponentModel;
13 | using System.Linq;
14 | using System.Runtime.CompilerServices;
15 | using System.Text;
16 | using System.Threading.Tasks;
17 | using System.Windows.Input;
18 | using MAUI.CleanArchitecture.Application.Common.Exceptions;
19 | using MAUI.CleanArchitecture.Application.User.Commands.Register;
20 | using MAUI.CleanArchitecture.Application.Common.Models;
21 | using MAUI.CleanArchitecture.Utils;
22 | using System.Threading;
23 | using MAUI.CleanArchitecture.Application.Common.Notificications;
24 | using Microsoft.Extensions.DependencyInjection;
25 |
26 | namespace MAUI.CleanArchitecture.ViewModels
27 | {
28 | public class RegisterPageViewModel : ViewModelBase
29 | {
30 | private readonly IMediator _mediator;
31 | private readonly IServiceProvider _serviceProvider;
32 | private readonly IValidator _validator;
33 | private readonly UserInfo _userInfo;
34 | private RegisterCommand _registerModel = new RegisterCommand();
35 | public RegisterPageViewModel(IServiceProvider serviceProvider, IValidator validator, UserInfo userInfo)
36 | {
37 | _serviceProvider = serviceProvider;
38 | _mediator = _serviceProvider.GetService();
39 | _validator = validator;
40 | _userInfo = userInfo;
41 | RegisterCommand = new Command(() => RegisterHandlerAsync(), () =>
42 | {
43 | var validationResult = _validator.Validate(_registerModel);
44 | Errors = validationResult.Errors;
45 | return validationResult.IsValid;
46 | });
47 | }
48 |
49 | public Command RegisterCommand { get; private set; }
50 |
51 | public string Username
52 | {
53 | get { return _registerModel.Username; }
54 | set
55 | {
56 | _registerModel.Username = value;
57 | OnPropertyChanged();
58 | RegisterCommand.ChangeCanExecute();
59 | }
60 | }
61 |
62 | public string Email
63 | {
64 | get { return _registerModel.Email; }
65 | set
66 | {
67 | _registerModel.Email = value;
68 | OnPropertyChanged();
69 | RegisterCommand.ChangeCanExecute();
70 | }
71 | }
72 |
73 | public string Password
74 | {
75 | get { return _registerModel.Password; }
76 | set
77 | {
78 | _registerModel.Password = value;
79 | OnPropertyChanged();
80 | RegisterCommand.ChangeCanExecute();
81 | }
82 | }
83 |
84 | public string FirstName
85 | {
86 | get { return _registerModel.FirstName; }
87 | set
88 | {
89 | _registerModel.FirstName = value;
90 | OnPropertyChanged();
91 | RegisterCommand.ChangeCanExecute();
92 | }
93 | }
94 |
95 | public string LastName
96 | {
97 | get { return _registerModel.LastName; }
98 | set
99 | {
100 | _registerModel.LastName = value;
101 | OnPropertyChanged();
102 | RegisterCommand.ChangeCanExecute();
103 | }
104 | }
105 |
106 |
107 | public Task Handle(UserInfo notification, CancellationToken cancellationToken)
108 | {
109 | return Task.CompletedTask;
110 | }
111 |
112 | private async void RegisterHandlerAsync()
113 | {
114 | try
115 | {
116 | SignupNotification signUpNotification = null;
117 | using (var scope = _serviceProvider.CreateScope())
118 | {
119 | var mediator = scope.ServiceProvider.GetService();
120 | signUpNotification = await mediator.Send(_registerModel);
121 | }
122 |
123 | await _mediator.Publish(signUpNotification);
124 | }
125 | catch (Application.Common.Exceptions.ValidationException ex)
126 | {
127 | CustomErrors = ex.ValidationErrors.Select(x => new ValidationFailure(x.Key, x.Value));
128 | }
129 | catch(Exception ex)
130 | {
131 |
132 | }
133 | }
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/ViewModels/MainPageViewModel.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Application.Card.Commands.CreateCardItem;
2 | using MAUI.CleanArchitecture.Application.Common.Models;
3 | using MAUI.CleanArchitecture.Application.Common.Notificications;
4 | using MAUI.CleanArchitecture.Application.Store.Queries;
5 | using MAUI.CleanArchitecture.Application.Store.Queries.GetStoreItemsQuery;
6 | using MAUI.CleanArchitecture.Domain.Entities;
7 | using MAUI.CleanArchitecture.Utils;
8 | using MAUI.CleanArchitecture.ViewModels.Base;
9 | using MediatR;
10 | using Microsoft.Extensions.DependencyInjection;
11 | using Microsoft.Maui.Controls;
12 | using System;
13 | using System.Collections.Generic;
14 | using System.ComponentModel;
15 | using System.Linq;
16 | using System.Threading;
17 | using System.Threading.Tasks;
18 | using System.Windows.Input;
19 |
20 | namespace MAUI.CleanArchitecture.ViewModels
21 | {
22 | public class MainPageViewModel : ViewModelBase,
23 | INotificationHandler,
24 | INotificationHandler,
25 | INotificationHandler
26 | {
27 | private readonly IServiceProvider _serviceProvider;
28 | private readonly IMediator _mediator;
29 | private readonly IPageManager _pageManager;
30 | private IList _cardItemViewModels;
31 |
32 | private string _toolbarItem1Text = "SignIn";
33 | private string _ToolbarItem1Logo = "login.png";
34 |
35 | public MainPageViewModel(IServiceProvider serviceProvider, IMediator mediator, IPageManager pageManager, UserInfo userInfo)
36 | {
37 | _serviceProvider = serviceProvider;
38 | _mediator = mediator;
39 | _pageManager = pageManager;
40 | UserInfo = userInfo;
41 | ToolbarItem1Command = new Command(LoginCommandHandler, (x) => UserInfo.IsSignedIn == false);
42 | LoadItems();
43 | }
44 |
45 | #region proeprties
46 | public Command ToolbarItem1Command { get; private set; }
47 | public UserInfo UserInfo { get; private set; }
48 |
49 | public string ToolbarItem1Text
50 | {
51 | get { return _toolbarItem1Text; }
52 | set { _toolbarItem1Text = value; OnPropertyChanged(); }
53 | }
54 |
55 | public string ToolbarItem1Logo
56 | {
57 | get { return _ToolbarItem1Logo; }
58 | set { _ToolbarItem1Logo = value; OnPropertyChanged(); }
59 | }
60 |
61 | public IList CardItemViewModels
62 | {
63 | get => _cardItemViewModels; private set
64 | {
65 | _cardItemViewModels = value;
66 | OnPropertyChanged();
67 | }
68 | }
69 | #endregion
70 |
71 | #region notifification handlers
72 | public Task Handle(SignupNotification notification, CancellationToken cancellationToken)
73 | {
74 | return ImplementSigninNotification(notification.UserInfo);
75 | }
76 |
77 | public Task Handle(SigninNotification notification, CancellationToken cancellationToken)
78 | {
79 | return ImplementSigninNotification(notification.UserInfo);
80 | }
81 |
82 | public Task Handle(AddCardItemNotification notification, CancellationToken cancellationToken)
83 | {
84 | //TODO: add to total for checkout
85 | return Task.CompletedTask;
86 | }
87 | #endregion
88 |
89 |
90 | private async void LoadItems()
91 | {
92 | using (var scope = _serviceProvider.CreateScope())
93 | {
94 | var mediator = scope.ServiceProvider.GetService();
95 | var storeItems = await _mediator.Send(new GetStoreItemsQuery());
96 | CardItemViewModels = storeItems.Select(x =>
97 | {
98 | var vm = _serviceProvider.GetService();
99 | vm.CardItem = new CardItem { StoreItem = x, SessionId = UserInfo.SessionId, UserId = UserInfo.IsSignedIn ? UserInfo.User.Id : null };
100 | return vm;
101 | }).ToList();
102 | }
103 | }
104 |
105 | private async void LoginCommandHandler(object obj)
106 | {
107 | if (UserInfo.IsSignedIn)
108 | {
109 | await _pageManager.StartPageAsync();
110 | }
111 | else
112 | {
113 | var loginPageRes = await _pageManager.StartPageAsync();
114 | ToolbarItem1Command.ChangeCanExecute();
115 | }
116 | }
117 |
118 | private async Task ImplementSigninNotification(UserInfo userInfo)
119 | {
120 | using (var scope = _serviceProvider.CreateScope())
121 | {
122 | var mediator = scope.ServiceProvider.GetService();
123 | //Update all carditems to logged in or registered user id
124 | await mediator.Send(new UpdateCardItemCommand { UserId = userInfo.User.Id, SessionId = userInfo.SessionId });
125 | }
126 |
127 | UserInfo = userInfo;
128 | OnPropertyChanged(nameof(UserInfo));
129 | await _pageManager.PopToRootPageAsync();
130 | ToolbarItem1Text = $"Welcome {userInfo.User.UserName}";
131 | ToolbarItem1Logo = "signup.png";
132 | }
133 |
134 | }
135 | }
136 |
137 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/MAUI.CleanArchitecture.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0-android;net6.0-ios;net6.0-maccatalyst
5 | $(TargetFrameworks);net6.0-windows10.0.19041.0
6 |
7 |
8 | Exe
9 | MAUI.CleanArchitecture
10 | true
11 | true
12 | enable
13 |
14 |
15 | MAUI.CleanArchitecture
16 |
17 |
18 |
19 | com.companyname.MAUI.CleanArchitecture
20 | 38e92730-f336-4c6d-8360-96e5c13fc93c
21 |
22 |
23 |
24 |
25 |
26 |
27 | 1.0
28 | 1
29 |
30 | 14.2
31 | 14.0
32 | 21.0
33 | 10.0.17763.0
34 | 10.0.17763.0
35 | 6.5
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | UserInfoPageView.xaml
92 |
93 |
94 | RegisterPageView.xaml
95 |
96 |
97 | LoginPageView.xaml
98 |
99 |
100 | CardItemView.xaml
101 |
102 |
103 |
104 |
105 |
106 | MSBuild:Compile
107 |
108 |
109 | MSBuild:Compile
110 |
111 |
112 | Designer
113 | MSBuild:Compile
114 |
115 |
116 | Designer
117 | MSBuild:Compile
118 |
119 |
120 | MSBuild:Compile
121 |
122 |
123 | MSBuild:Compile
124 |
125 |
126 |
127 |
131 |
132 |
133 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/ViewModels/Base/ViewModelLocator.cs:
--------------------------------------------------------------------------------
1 | using MAUI.CleanArchitecture.Application.Common.Models;
2 | using MAUI.CleanArchitecture.Views;
3 | using MediatR;
4 | using Microsoft.Extensions.DependencyInjection;
5 | using Microsoft.Maui.Controls;
6 | using Microsoft.Maui.Hosting;
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Diagnostics;
10 | using System.Linq;
11 | using System.Reflection;
12 | using System.Text;
13 | using System.Threading.Tasks;
14 |
15 | namespace MAUI.CleanArchitecture.ViewModels.Base
16 | {
17 | public static class ViewModelLocator
18 | {
19 | public static readonly BindableProperty AutoWireViewModelProperty =
20 | BindableProperty.CreateAttached("AutoWireViewModel", typeof(bool), typeof(ViewModelLocator), default(bool), propertyChanged: OnAutoWireViewModelChanged);
21 |
22 | internal static void Initialize(IServiceCollection services)
23 | {
24 | var watch = Stopwatch.StartNew();
25 | var viewsAndViewModels = Assembly.GetExecutingAssembly().GetTypes().Where(x => x.IsClass && x.GetInterface("INotifyPropertyChanged") != null).ToList();
26 | watch.Stop();
27 |
28 | Debug.WriteLine($"Execution Time: {watch.ElapsedMilliseconds} ms");
29 | var viewModels = viewsAndViewModels.Where(x => x.Name.EndsWith("ViewModel")).ToList();
30 | var views = viewsAndViewModels.Where(x => x.Name.EndsWith("View")).ToList();
31 |
32 | ViewToViewModelDict = Enumerable.Join>(views, viewModels, x => x.Name, y => y.Name, (view, viewModel) => (view, viewModel), new ViewToViewModelComparer()).ToDictionary(x => x.Item1, y => y.Item2);
33 | ViewModelToViewDict = ViewToViewModelDict.ToDictionary(x => x.Value, x => x.Key);
34 |
35 | foreach (Type vm in viewModels)
36 | {
37 | var notificationHandlers = vm.GetInterfaces().Where(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(INotificationHandler<>)).ToList();
38 |
39 | if (notificationHandlers.Any())
40 | {
41 | services.AddScoped(vm);
42 | }
43 | else
44 | {
45 | services.AddTransient(vm);
46 | }
47 |
48 | foreach (var notificationHandlerType in notificationHandlers)
49 | {
50 | services.AddScoped(notificationHandlerType, sp =>
51 | {
52 | return sp.GetRequiredService(vm);
53 | });
54 | }
55 | }
56 |
57 | ServiceProvider = services.BuildServiceProvider();
58 | ViewModelsRegistered = true;
59 | }
60 |
61 | #region Navigation
62 |
63 | internal static void InitializeNavigation(this INavigation navigation)
64 | {
65 | Navigation = navigation;
66 | }
67 |
68 | internal static async Task StartPageAsync(bool isModal = false)
69 | {
70 | var viewModelType = typeof(TViewModel);
71 |
72 | if (!viewModelType.Name.EndsWith("PageViewModel") || !ViewModelToViewDict.TryGetValue(viewModelType, out var viewType))
73 | {
74 | return default(TViewModel);
75 | }
76 |
77 | var viewInstance = Activator.CreateInstance(viewType);
78 |
79 | if (viewInstance is Page view)
80 | {
81 | if (isModal)
82 | {
83 | await Navigation.PushModalAsync(view);
84 | }
85 | else
86 | {
87 | await Navigation.PushAsync(view);
88 | }
89 | }
90 | else
91 | {
92 | return default(TViewModel);
93 | }
94 |
95 | return (TViewModel)view.BindingContext;
96 | }
97 |
98 | internal static async Task PopPageAsync()
99 | {
100 | await Navigation.PopAsync();
101 | }
102 |
103 | internal static async Task PopToRootPageAsync()
104 | {
105 | await Navigation.PopToRootAsync();
106 | }
107 |
108 | public static INavigation Navigation { get; private set; }
109 |
110 | #endregion
111 |
112 | private static bool ViewModelsRegistered = false;
113 |
114 | private static ServiceProvider ServiceProvider;
115 | private static Dictionary ViewToViewModelDict;
116 | private static Dictionary ViewModelToViewDict;
117 |
118 | public static bool GetAutoWireViewModel(BindableObject bindableObject)
119 | {
120 | return (bool)bindableObject.GetValue(AutoWireViewModelProperty);
121 | }
122 |
123 | public static void SetAutoWireViewModel(BindableObject bindableObject,bool value)
124 | {
125 | bindableObject.SetValue(AutoWireViewModelProperty, value);
126 | }
127 |
128 | private static void OnAutoWireViewModelChanged(BindableObject bindable, object oldValue, object newValue)
129 | {
130 | var view = bindable as Element;
131 | if (view is null) return;
132 |
133 | var viewType = view.GetType();
134 |
135 | if (!ViewToViewModelDict.TryGetValue(viewType, out var viewModelType))
136 | {
137 | return;
138 | }
139 |
140 | while (!ViewModelsRegistered)
141 | {
142 |
143 | }
144 |
145 | var viewModel = ServiceProvider.GetService(viewModelType);
146 |
147 | view.BindingContext = viewModel;
148 | }
149 |
150 | public class ViewToViewModelComparer : IEqualityComparer
151 | {
152 | public bool Equals(string l, string r)
153 | {
154 | return $"{l}Model" == r || $"{r}Model" == l;
155 | }
156 |
157 | public int GetHashCode(string obj)
158 | {
159 | return obj.EndsWith("Model") ? obj.Replace("Model", string.Empty).GetHashCode() : obj.GetHashCode();
160 | }
161 | }
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User specific
7 | .idea/**
8 | **/.idea/**/workspace.xml
9 | **/.idea/**/tasks.xml
10 | **/.idea/shelf/*
11 | **/.idea/dictionaries
12 | **/.idea/httpRequests/
13 |
14 | # Sensitive or high-churn files
15 | **/.idea/**/dataSources/
16 | **/.idea/**/dataSources.ids
17 | **/.idea/**/dataSources.xml
18 | **/.idea/**/dataSources.local.xml
19 | **/.idea/**/sqlDataSources.xml
20 | **/.idea/**/dynamic.xml
21 |
22 | # Rider
23 | # Rider auto-generates .iml files, and contentModel.xml
24 | **/.idea/**/*.iml
25 | **/.idea/**/contentModel.xml
26 | **/.idea/**/modules.xml
27 | # User-specific files
28 | *.rsuser
29 | *.suo
30 | *.user
31 | *.userosscache
32 | *.sln.docstates
33 |
34 | # User-specific files (MonoDevelop/Xamarin Studio)
35 | *.userprefs
36 |
37 | # Mono auto generated files
38 | mono_crash.*
39 |
40 | # Build results
41 | [Dd]ebug/
42 | [Dd]ebugPublic/
43 | [Rr]elease/
44 | [Rr]eleases/
45 | x64/
46 | x86/
47 | [Aa][Rr][Mm]/
48 | [Aa][Rr][Mm]64/
49 | bld/
50 | [Bb]in/
51 | [Oo]bj/
52 | [Ll]og/
53 | [Ll]ogs/
54 |
55 | # Visual Studio 2015/2017 cache/options directory
56 | .vs/
57 | # Uncomment if you have tasks that create the project's static files in wwwroot
58 | #wwwroot/
59 |
60 | # Visual Studio 2017 auto generated files
61 | Generated\ Files/
62 |
63 | # MSTest test Results
64 | [Tt]est[Rr]esult*/
65 | [Bb]uild[Ll]og.*
66 |
67 | # NUnit
68 | *.VisualState.xml
69 | TestResult.xml
70 | nunit-*.xml
71 |
72 | # Build Results of an ATL Project
73 | [Dd]ebugPS/
74 | [Rr]eleasePS/
75 | dlldata.c
76 |
77 | # Benchmark Results
78 | BenchmarkDotNet.Artifacts/
79 |
80 | # .NET Core
81 | project.lock.json
82 | project.fragment.lock.json
83 | artifacts/
84 |
85 | # StyleCop
86 | StyleCopReport.xml
87 |
88 | # Files built by Visual Studio
89 | *_i.c
90 | *_p.c
91 | *_h.h
92 | *.ilk
93 | *.meta
94 | *.obj
95 | *.iobj
96 | *.pch
97 | *.pdb
98 | *.ipdb
99 | *.pgc
100 | *.pgd
101 | *.rsp
102 | *.sbr
103 | *.tlb
104 | *.tli
105 | *.tlh
106 | *.tmp
107 | *.tmp_proj
108 | *_wpftmp.csproj
109 | *.log
110 | *.vspscc
111 | *.vssscc
112 | .builds
113 | *.pidb
114 | *.svclog
115 | *.scc
116 |
117 | # Chutzpah Test files
118 | _Chutzpah*
119 |
120 | # Visual C++ cache files
121 | ipch/
122 | *.aps
123 | *.ncb
124 | *.opendb
125 | *.opensdf
126 | *.sdf
127 | *.cachefile
128 | *.VC.db
129 | *.VC.VC.opendb
130 |
131 | # Visual Studio profiler
132 | *.psess
133 | *.vsp
134 | *.vspx
135 | *.sap
136 |
137 | # Visual Studio Trace Files
138 | *.e2e
139 |
140 | # TFS 2012 Local Workspace
141 | $tf/
142 |
143 | # Guidance Automation Toolkit
144 | *.gpState
145 |
146 | # ReSharper is a .NET coding add-in
147 | _ReSharper*/
148 | *.[Rr]e[Ss]harper
149 | *.DotSettings.user
150 |
151 | # TeamCity is a build add-in
152 | _TeamCity*
153 |
154 | # DotCover is a Code Coverage Tool
155 | *.dotCover
156 |
157 | # AxoCover is a Code Coverage Tool
158 | .axoCover/*
159 | !.axoCover/settings.json
160 |
161 | # Visual Studio code coverage results
162 | *.coverage
163 | *.coveragexml
164 |
165 | # NCrunch
166 | _NCrunch_*
167 | .*crunch*.local.xml
168 | nCrunchTemp_*
169 |
170 | # MightyMoose
171 | *.mm.*
172 | AutoTest.Net/
173 |
174 | # Web workbench (sass)
175 | .sass-cache/
176 |
177 | # Installshield output folder
178 | [Ee]xpress/
179 |
180 | # DocProject is a documentation generator add-in
181 | DocProject/buildhelp/
182 | DocProject/Help/*.HxT
183 | DocProject/Help/*.HxC
184 | DocProject/Help/*.hhc
185 | DocProject/Help/*.hhk
186 | DocProject/Help/*.hhp
187 | DocProject/Help/Html2
188 | DocProject/Help/html
189 |
190 | # Click-Once directory
191 | publish/
192 |
193 | # Publish Web Output
194 | *.[Pp]ublish.xml
195 | *.azurePubxml
196 | # Note: Comment the next line if you want to checkin your web deploy settings,
197 | # but database connection strings (with potential passwords) will be unencrypted
198 | *.pubxml
199 | *.publishproj
200 |
201 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
202 | # checkin your Azure Web App publish settings, but sensitive information contained
203 | # in these scripts will be unencrypted
204 | PublishScripts/
205 |
206 | # NuGet Packages
207 | *.nupkg
208 | # NuGet Symbol Packages
209 | *.snupkg
210 | # The packages folder can be ignored because of Package Restore
211 | **/[Pp]ackages/*
212 | # except build/, which is used as an MSBuild target.
213 | !**/[Pp]ackages/build/
214 | # Uncomment if necessary however generally it will be regenerated when needed
215 | #!**/[Pp]ackages/repositories.config
216 | # NuGet v3's project.json files produces more ignorable files
217 | *.nuget.props
218 | *.nuget.targets
219 |
220 | # Microsoft Azure Build Output
221 | csx/
222 | *.build.csdef
223 |
224 | # Microsoft Azure Emulator
225 | ecf/
226 | rcf/
227 |
228 | # Windows Store app package directories and files
229 | AppPackages/
230 | BundleArtifacts/
231 | Package.StoreAssociation.xml
232 | _pkginfo.txt
233 | *.appx
234 | *.appxbundle
235 | *.appxupload
236 |
237 | # Visual Studio cache files
238 | # files ending in .cache can be ignored
239 | *.[Cc]ache
240 | # but keep track of directories ending in .cache
241 | !?*.[Cc]ache/
242 |
243 | # Others
244 | ClientBin/
245 | ~$*
246 | *~
247 | *.dbmdl
248 | *.dbproj.schemaview
249 | *.jfm
250 | *.pfx
251 | *.publishsettings
252 | orleans.codegen.cs
253 |
254 | # Including strong name files can present a security risk
255 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
256 | #*.snk
257 |
258 | # Since there are multiple workflows, uncomment next line to ignore bower_components
259 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
260 | #bower_components/
261 |
262 | # RIA/Silverlight projects
263 | Generated_Code/
264 |
265 | # Backup & report files from converting an old project file
266 | # to a newer Visual Studio version. Backup files are not needed,
267 | # because we have git ;-)
268 | _UpgradeReport_Files/
269 | Backup*/
270 | UpgradeLog*.XML
271 | UpgradeLog*.htm
272 | ServiceFabricBackup/
273 | *.rptproj.bak
274 |
275 | # SQL Server files
276 | *.mdf
277 | *.ldf
278 | *.ndf
279 |
280 | # Business Intelligence projects
281 | *.rdl.data
282 | *.bim.layout
283 | *.bim_*.settings
284 | *.rptproj.rsuser
285 | *- [Bb]ackup.rdl
286 | *- [Bb]ackup ([0-9]).rdl
287 | *- [Bb]ackup ([0-9][0-9]).rdl
288 |
289 | # Microsoft Fakes
290 | FakesAssemblies/
291 |
292 | # GhostDoc plugin setting file
293 | *.GhostDoc.xml
294 |
295 | # Node.js Tools for Visual Studio
296 | .ntvs_analysis.dat
297 | node_modules/
298 |
299 | # Visual Studio 6 build log
300 | *.plg
301 |
302 | # Visual Studio 6 workspace options file
303 | *.opt
304 |
305 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
306 | *.vbw
307 |
308 | # Visual Studio LightSwitch build output
309 | **/*.HTMLClient/GeneratedArtifacts
310 | **/*.DesktopClient/GeneratedArtifacts
311 | **/*.DesktopClient/ModelManifest.xml
312 | **/*.Server/GeneratedArtifacts
313 | **/*.Server/ModelManifest.xml
314 | _Pvt_Extensions
315 |
316 | # Paket dependency manager
317 | .paket/paket.exe
318 | paket-files/
319 |
320 | # FAKE - F# Make
321 | .fake/
322 |
323 | # CodeRush personal settings
324 | .cr/personal
325 |
326 | # Python Tools for Visual Studio (PTVS)
327 | __pycache__/
328 | *.pyc
329 |
330 | # Cake - Uncomment if you are using it
331 | # tools/**
332 | # !tools/packages.config
333 |
334 | # Tabs Studio
335 | *.tss
336 |
337 | # Telerik's JustMock configuration file
338 | *.jmconfig
339 |
340 | # BizTalk build output
341 | *.btp.cs
342 | *.btm.cs
343 | *.odx.cs
344 | *.xsd.cs
345 |
346 | # OpenCover UI analysis results
347 | OpenCover/
348 |
349 | # Azure Stream Analytics local run output
350 | ASALocalRun/
351 |
352 | # MSBuild Binary and Structured Log
353 | *.binlog
354 |
355 | # NVidia Nsight GPU debugger configuration file
356 | *.nvuser
357 |
358 | # MFractors (Xamarin productivity tool) working folder
359 | .mfractor/
360 |
361 | # Local History for Visual Studio
362 | .localhistory/
363 |
364 | # BeatPulse healthcheck temp database
365 | healthchecksdb
366 |
367 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
368 | MigrationBackup/
369 |
370 | # Ionide (cross platform F# VS Code tools) working folder
371 | .ionide/
372 | **/.DS_Store
373 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture/Resources/Images/dotnet_bot.svg:
--------------------------------------------------------------------------------
1 |
94 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Infrastructure/Persistence/Migrations/20211214054413_InitialCreate.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.EntityFrameworkCore.Migrations;
3 |
4 | #nullable disable
5 |
6 | namespace MAUI.CleanArchitecture.Infrastructure.Persistence.Migrations
7 | {
8 | public partial class InitialCreate : Migration
9 | {
10 | protected override void Up(MigrationBuilder migrationBuilder)
11 | {
12 | migrationBuilder.CreateTable(
13 | name: "AspNetRoles",
14 | columns: table => new
15 | {
16 | Id = table.Column(type: "TEXT", nullable: false),
17 | Name = table.Column(type: "TEXT", maxLength: 256, nullable: true),
18 | NormalizedName = table.Column(type: "TEXT", maxLength: 256, nullable: true),
19 | ConcurrencyStamp = table.Column(type: "TEXT", nullable: true)
20 | },
21 | constraints: table =>
22 | {
23 | table.PrimaryKey("PK_AspNetRoles", x => x.Id);
24 | });
25 |
26 | migrationBuilder.CreateTable(
27 | name: "AspNetUsers",
28 | columns: table => new
29 | {
30 | Id = table.Column(type: "TEXT", nullable: false),
31 | FirstName = table.Column(type: "TEXT", nullable: false),
32 | LastName = table.Column(type: "TEXT", nullable: false),
33 | DateOfBirth = table.Column(type: "TEXT", nullable: false),
34 | UserName = table.Column(type: "TEXT", maxLength: 256, nullable: true),
35 | NormalizedUserName = table.Column(type: "TEXT", maxLength: 256, nullable: true),
36 | Email = table.Column(type: "TEXT", maxLength: 256, nullable: true),
37 | NormalizedEmail = table.Column(type: "TEXT", maxLength: 256, nullable: true),
38 | EmailConfirmed = table.Column(type: "INTEGER", nullable: false),
39 | PasswordHash = table.Column(type: "TEXT", nullable: true),
40 | SecurityStamp = table.Column(type: "TEXT", nullable: true),
41 | ConcurrencyStamp = table.Column(type: "TEXT", nullable: true),
42 | PhoneNumber = table.Column(type: "TEXT", nullable: true),
43 | PhoneNumberConfirmed = table.Column(type: "INTEGER", nullable: false),
44 | TwoFactorEnabled = table.Column(type: "INTEGER", nullable: false),
45 | LockoutEnd = table.Column(type: "TEXT", nullable: true),
46 | LockoutEnabled = table.Column(type: "INTEGER", nullable: false),
47 | AccessFailedCount = table.Column(type: "INTEGER", nullable: false)
48 | },
49 | constraints: table =>
50 | {
51 | table.PrimaryKey("PK_AspNetUsers", x => x.Id);
52 | });
53 |
54 | migrationBuilder.CreateTable(
55 | name: "CardItems",
56 | columns: table => new
57 | {
58 | StoreRef = table.Column(type: "INTEGER", nullable: false)
59 | .Annotation("Sqlite:Autoincrement", true),
60 | Quantity = table.Column(type: "INTEGER", nullable: false),
61 | UserId = table.Column(type: "TEXT", nullable: true),
62 | SessionId = table.Column(type: "TEXT", nullable: false)
63 | },
64 | constraints: table =>
65 | {
66 | table.PrimaryKey("PK_CardItems", x => x.StoreRef);
67 | });
68 |
69 | migrationBuilder.CreateTable(
70 | name: "AspNetRoleClaims",
71 | columns: table => new
72 | {
73 | Id = table.Column(type: "INTEGER", nullable: false)
74 | .Annotation("Sqlite:Autoincrement", true),
75 | RoleId = table.Column(type: "TEXT", nullable: false),
76 | ClaimType = table.Column(type: "TEXT", nullable: true),
77 | ClaimValue = table.Column(type: "TEXT", nullable: true)
78 | },
79 | constraints: table =>
80 | {
81 | table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
82 | table.ForeignKey(
83 | name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
84 | column: x => x.RoleId,
85 | principalTable: "AspNetRoles",
86 | principalColumn: "Id",
87 | onDelete: ReferentialAction.Cascade);
88 | });
89 |
90 | migrationBuilder.CreateTable(
91 | name: "AspNetUserClaims",
92 | columns: table => new
93 | {
94 | Id = table.Column(type: "INTEGER", nullable: false)
95 | .Annotation("Sqlite:Autoincrement", true),
96 | UserId = table.Column(type: "TEXT", nullable: false),
97 | ClaimType = table.Column(type: "TEXT", nullable: true),
98 | ClaimValue = table.Column(type: "TEXT", nullable: true)
99 | },
100 | constraints: table =>
101 | {
102 | table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
103 | table.ForeignKey(
104 | name: "FK_AspNetUserClaims_AspNetUsers_UserId",
105 | column: x => x.UserId,
106 | principalTable: "AspNetUsers",
107 | principalColumn: "Id",
108 | onDelete: ReferentialAction.Cascade);
109 | });
110 |
111 | migrationBuilder.CreateTable(
112 | name: "AspNetUserLogins",
113 | columns: table => new
114 | {
115 | LoginProvider = table.Column(type: "TEXT", nullable: false),
116 | ProviderKey = table.Column(type: "TEXT", nullable: false),
117 | ProviderDisplayName = table.Column(type: "TEXT", nullable: true),
118 | UserId = table.Column(type: "TEXT", nullable: false)
119 | },
120 | constraints: table =>
121 | {
122 | table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
123 | table.ForeignKey(
124 | name: "FK_AspNetUserLogins_AspNetUsers_UserId",
125 | column: x => x.UserId,
126 | principalTable: "AspNetUsers",
127 | principalColumn: "Id",
128 | onDelete: ReferentialAction.Cascade);
129 | });
130 |
131 | migrationBuilder.CreateTable(
132 | name: "AspNetUserRoles",
133 | columns: table => new
134 | {
135 | UserId = table.Column(type: "TEXT", nullable: false),
136 | RoleId = table.Column(type: "TEXT", nullable: false)
137 | },
138 | constraints: table =>
139 | {
140 | table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
141 | table.ForeignKey(
142 | name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
143 | column: x => x.RoleId,
144 | principalTable: "AspNetRoles",
145 | principalColumn: "Id",
146 | onDelete: ReferentialAction.Cascade);
147 | table.ForeignKey(
148 | name: "FK_AspNetUserRoles_AspNetUsers_UserId",
149 | column: x => x.UserId,
150 | principalTable: "AspNetUsers",
151 | principalColumn: "Id",
152 | onDelete: ReferentialAction.Cascade);
153 | });
154 |
155 | migrationBuilder.CreateTable(
156 | name: "AspNetUserTokens",
157 | columns: table => new
158 | {
159 | UserId = table.Column(type: "TEXT", nullable: false),
160 | LoginProvider = table.Column(type: "TEXT", nullable: false),
161 | Name = table.Column(type: "TEXT", nullable: false),
162 | Value = table.Column(type: "TEXT", nullable: true)
163 | },
164 | constraints: table =>
165 | {
166 | table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
167 | table.ForeignKey(
168 | name: "FK_AspNetUserTokens_AspNetUsers_UserId",
169 | column: x => x.UserId,
170 | principalTable: "AspNetUsers",
171 | principalColumn: "Id",
172 | onDelete: ReferentialAction.Cascade);
173 | });
174 |
175 | migrationBuilder.CreateTable(
176 | name: "StoreItems",
177 | columns: table => new
178 | {
179 | CardRef = table.Column(type: "INTEGER", nullable: false),
180 | Id = table.Column(type: "INTEGER", nullable: false),
181 | Title = table.Column(type: "TEXT", maxLength: 200, nullable: true),
182 | Price = table.Column(type: "TEXT", precision: 18, scale: 2, nullable: false),
183 | Description = table.Column(type: "TEXT", nullable: true),
184 | Category = table.Column(type: "TEXT", nullable: true),
185 | Image = table.Column(type: "TEXT", nullable: true)
186 | },
187 | constraints: table =>
188 | {
189 | table.PrimaryKey("PK_StoreItems", x => x.CardRef);
190 | table.ForeignKey(
191 | name: "FK_StoreItems_CardItems_CardRef",
192 | column: x => x.CardRef,
193 | principalTable: "CardItems",
194 | principalColumn: "StoreRef",
195 | onDelete: ReferentialAction.Cascade);
196 | });
197 |
198 | migrationBuilder.CreateTable(
199 | name: "Rating",
200 | columns: table => new
201 | {
202 | StoreRef = table.Column(type: "INTEGER", nullable: false),
203 | Rate = table.Column(type: "REAL", nullable: false),
204 | Count = table.Column(type: "INTEGER", nullable: false)
205 | },
206 | constraints: table =>
207 | {
208 | table.PrimaryKey("PK_Rating", x => x.StoreRef);
209 | table.ForeignKey(
210 | name: "FK_Rating_StoreItems_StoreRef",
211 | column: x => x.StoreRef,
212 | principalTable: "StoreItems",
213 | principalColumn: "CardRef",
214 | onDelete: ReferentialAction.Cascade);
215 | });
216 |
217 | migrationBuilder.CreateIndex(
218 | name: "IX_AspNetRoleClaims_RoleId",
219 | table: "AspNetRoleClaims",
220 | column: "RoleId");
221 |
222 | migrationBuilder.CreateIndex(
223 | name: "RoleNameIndex",
224 | table: "AspNetRoles",
225 | column: "NormalizedName",
226 | unique: true);
227 |
228 | migrationBuilder.CreateIndex(
229 | name: "IX_AspNetUserClaims_UserId",
230 | table: "AspNetUserClaims",
231 | column: "UserId");
232 |
233 | migrationBuilder.CreateIndex(
234 | name: "IX_AspNetUserLogins_UserId",
235 | table: "AspNetUserLogins",
236 | column: "UserId");
237 |
238 | migrationBuilder.CreateIndex(
239 | name: "IX_AspNetUserRoles_RoleId",
240 | table: "AspNetUserRoles",
241 | column: "RoleId");
242 |
243 | migrationBuilder.CreateIndex(
244 | name: "EmailIndex",
245 | table: "AspNetUsers",
246 | column: "NormalizedEmail");
247 |
248 | migrationBuilder.CreateIndex(
249 | name: "UserNameIndex",
250 | table: "AspNetUsers",
251 | column: "NormalizedUserName",
252 | unique: true);
253 | }
254 |
255 | protected override void Down(MigrationBuilder migrationBuilder)
256 | {
257 | migrationBuilder.DropTable(
258 | name: "AspNetRoleClaims");
259 |
260 | migrationBuilder.DropTable(
261 | name: "AspNetUserClaims");
262 |
263 | migrationBuilder.DropTable(
264 | name: "AspNetUserLogins");
265 |
266 | migrationBuilder.DropTable(
267 | name: "AspNetUserRoles");
268 |
269 | migrationBuilder.DropTable(
270 | name: "AspNetUserTokens");
271 |
272 | migrationBuilder.DropTable(
273 | name: "Rating");
274 |
275 | migrationBuilder.DropTable(
276 | name: "AspNetRoles");
277 |
278 | migrationBuilder.DropTable(
279 | name: "AspNetUsers");
280 |
281 | migrationBuilder.DropTable(
282 | name: "StoreItems");
283 |
284 | migrationBuilder.DropTable(
285 | name: "CardItems");
286 | }
287 | }
288 | }
289 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Infrastructure/Persistence/Migrations/StoreDbContextModelSnapshot.cs:
--------------------------------------------------------------------------------
1 | //
2 | using System;
3 | using MAUI.CleanArchitecture.Infrastructure.Persistence;
4 | using Microsoft.EntityFrameworkCore;
5 | using Microsoft.EntityFrameworkCore.Infrastructure;
6 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
7 |
8 | #nullable disable
9 |
10 | namespace MAUI.CleanArchitecture.Infrastructure.Persistence.Migrations
11 | {
12 | [DbContext(typeof(StoreDbContext))]
13 | partial class StoreDbContextModelSnapshot : ModelSnapshot
14 | {
15 | protected override void BuildModel(ModelBuilder modelBuilder)
16 | {
17 | #pragma warning disable 612, 618
18 | modelBuilder.HasAnnotation("ProductVersion", "6.0.0");
19 |
20 | modelBuilder.Entity("MAUI.CleanArchitecture.Domain.Entities.CardItem", b =>
21 | {
22 | b.Property("StoreRef")
23 | .ValueGeneratedOnAdd()
24 | .HasColumnType("INTEGER");
25 |
26 | b.Property("Quantity")
27 | .HasColumnType("INTEGER");
28 |
29 | b.Property("SessionId")
30 | .HasColumnType("TEXT");
31 |
32 | b.Property("UserId")
33 | .HasColumnType("TEXT");
34 |
35 | b.HasKey("StoreRef");
36 |
37 | b.ToTable("CardItems");
38 | });
39 |
40 | modelBuilder.Entity("MAUI.CleanArchitecture.Domain.Entities.Rating", b =>
41 | {
42 | b.Property("StoreRef")
43 | .HasColumnType("INTEGER");
44 |
45 | b.Property("Count")
46 | .HasColumnType("INTEGER");
47 |
48 | b.Property("Rate")
49 | .HasColumnType("REAL");
50 |
51 | b.HasKey("StoreRef");
52 |
53 | b.ToTable("Rating");
54 | });
55 |
56 | modelBuilder.Entity("MAUI.CleanArchitecture.Domain.Entities.StoreItem", b =>
57 | {
58 | b.Property("CardRef")
59 | .HasColumnType("INTEGER");
60 |
61 | b.Property("Category")
62 | .HasColumnType("TEXT");
63 |
64 | b.Property("Description")
65 | .HasColumnType("TEXT");
66 |
67 | b.Property("Id")
68 | .IsUnicode(true)
69 | .HasColumnType("INTEGER");
70 |
71 | b.Property("Image")
72 | .HasColumnType("TEXT");
73 |
74 | b.Property("Price")
75 | .HasPrecision(18, 2)
76 | .HasColumnType("TEXT");
77 |
78 | b.Property("Title")
79 | .HasMaxLength(200)
80 | .HasColumnType("TEXT");
81 |
82 | b.HasKey("CardRef");
83 |
84 | b.ToTable("StoreItems");
85 | });
86 |
87 | modelBuilder.Entity("MAUI.CleanArchitecture.Infrastructure.Identity.ApplicationUser", b =>
88 | {
89 | b.Property("Id")
90 | .HasColumnType("TEXT");
91 |
92 | b.Property("AccessFailedCount")
93 | .HasColumnType("INTEGER");
94 |
95 | b.Property("ConcurrencyStamp")
96 | .IsConcurrencyToken()
97 | .HasColumnType("TEXT");
98 |
99 | b.Property("DateOfBirth")
100 | .HasColumnType("TEXT");
101 |
102 | b.Property("Email")
103 | .HasMaxLength(256)
104 | .HasColumnType("TEXT");
105 |
106 | b.Property("EmailConfirmed")
107 | .HasColumnType("INTEGER");
108 |
109 | b.Property("FirstName")
110 | .IsRequired()
111 | .HasColumnType("TEXT");
112 |
113 | b.Property("LastName")
114 | .IsRequired()
115 | .HasColumnType("TEXT");
116 |
117 | b.Property("LockoutEnabled")
118 | .HasColumnType("INTEGER");
119 |
120 | b.Property("LockoutEnd")
121 | .HasColumnType("TEXT");
122 |
123 | b.Property("NormalizedEmail")
124 | .HasMaxLength(256)
125 | .HasColumnType("TEXT");
126 |
127 | b.Property("NormalizedUserName")
128 | .HasMaxLength(256)
129 | .HasColumnType("TEXT");
130 |
131 | b.Property("PasswordHash")
132 | .HasColumnType("TEXT");
133 |
134 | b.Property("PhoneNumber")
135 | .HasColumnType("TEXT");
136 |
137 | b.Property("PhoneNumberConfirmed")
138 | .HasColumnType("INTEGER");
139 |
140 | b.Property("SecurityStamp")
141 | .HasColumnType("TEXT");
142 |
143 | b.Property("TwoFactorEnabled")
144 | .HasColumnType("INTEGER");
145 |
146 | b.Property("UserName")
147 | .HasMaxLength(256)
148 | .HasColumnType("TEXT");
149 |
150 | b.HasKey("Id");
151 |
152 | b.HasIndex("NormalizedEmail")
153 | .HasDatabaseName("EmailIndex");
154 |
155 | b.HasIndex("NormalizedUserName")
156 | .IsUnique()
157 | .HasDatabaseName("UserNameIndex");
158 |
159 | b.ToTable("AspNetUsers", (string)null);
160 | });
161 |
162 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
163 | {
164 | b.Property("Id")
165 | .HasColumnType("TEXT");
166 |
167 | b.Property("ConcurrencyStamp")
168 | .IsConcurrencyToken()
169 | .HasColumnType("TEXT");
170 |
171 | b.Property("Name")
172 | .HasMaxLength(256)
173 | .HasColumnType("TEXT");
174 |
175 | b.Property("NormalizedName")
176 | .HasMaxLength(256)
177 | .HasColumnType("TEXT");
178 |
179 | b.HasKey("Id");
180 |
181 | b.HasIndex("NormalizedName")
182 | .IsUnique()
183 | .HasDatabaseName("RoleNameIndex");
184 |
185 | b.ToTable("AspNetRoles", (string)null);
186 | });
187 |
188 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b =>
189 | {
190 | b.Property("Id")
191 | .ValueGeneratedOnAdd()
192 | .HasColumnType("INTEGER");
193 |
194 | b.Property("ClaimType")
195 | .HasColumnType("TEXT");
196 |
197 | b.Property("ClaimValue")
198 | .HasColumnType("TEXT");
199 |
200 | b.Property("RoleId")
201 | .IsRequired()
202 | .HasColumnType("TEXT");
203 |
204 | b.HasKey("Id");
205 |
206 | b.HasIndex("RoleId");
207 |
208 | b.ToTable("AspNetRoleClaims", (string)null);
209 | });
210 |
211 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
212 | {
213 | b.Property("Id")
214 | .ValueGeneratedOnAdd()
215 | .HasColumnType("INTEGER");
216 |
217 | b.Property("ClaimType")
218 | .HasColumnType("TEXT");
219 |
220 | b.Property("ClaimValue")
221 | .HasColumnType("TEXT");
222 |
223 | b.Property("UserId")
224 | .IsRequired()
225 | .HasColumnType("TEXT");
226 |
227 | b.HasKey("Id");
228 |
229 | b.HasIndex("UserId");
230 |
231 | b.ToTable("AspNetUserClaims", (string)null);
232 | });
233 |
234 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b =>
235 | {
236 | b.Property("LoginProvider")
237 | .HasColumnType("TEXT");
238 |
239 | b.Property("ProviderKey")
240 | .HasColumnType("TEXT");
241 |
242 | b.Property("ProviderDisplayName")
243 | .HasColumnType("TEXT");
244 |
245 | b.Property("UserId")
246 | .IsRequired()
247 | .HasColumnType("TEXT");
248 |
249 | b.HasKey("LoginProvider", "ProviderKey");
250 |
251 | b.HasIndex("UserId");
252 |
253 | b.ToTable("AspNetUserLogins", (string)null);
254 | });
255 |
256 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b =>
257 | {
258 | b.Property("UserId")
259 | .HasColumnType("TEXT");
260 |
261 | b.Property("RoleId")
262 | .HasColumnType("TEXT");
263 |
264 | b.HasKey("UserId", "RoleId");
265 |
266 | b.HasIndex("RoleId");
267 |
268 | b.ToTable("AspNetUserRoles", (string)null);
269 | });
270 |
271 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b =>
272 | {
273 | b.Property("UserId")
274 | .HasColumnType("TEXT");
275 |
276 | b.Property("LoginProvider")
277 | .HasColumnType("TEXT");
278 |
279 | b.Property("Name")
280 | .HasColumnType("TEXT");
281 |
282 | b.Property("Value")
283 | .HasColumnType("TEXT");
284 |
285 | b.HasKey("UserId", "LoginProvider", "Name");
286 |
287 | b.ToTable("AspNetUserTokens", (string)null);
288 | });
289 |
290 | modelBuilder.Entity("MAUI.CleanArchitecture.Domain.Entities.Rating", b =>
291 | {
292 | b.HasOne("MAUI.CleanArchitecture.Domain.Entities.StoreItem", null)
293 | .WithOne("Rating")
294 | .HasForeignKey("MAUI.CleanArchitecture.Domain.Entities.Rating", "StoreRef")
295 | .OnDelete(DeleteBehavior.Cascade)
296 | .IsRequired();
297 | });
298 |
299 | modelBuilder.Entity("MAUI.CleanArchitecture.Domain.Entities.StoreItem", b =>
300 | {
301 | b.HasOne("MAUI.CleanArchitecture.Domain.Entities.CardItem", null)
302 | .WithOne("StoreItem")
303 | .HasForeignKey("MAUI.CleanArchitecture.Domain.Entities.StoreItem", "CardRef")
304 | .OnDelete(DeleteBehavior.Cascade)
305 | .IsRequired();
306 | });
307 |
308 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b =>
309 | {
310 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
311 | .WithMany()
312 | .HasForeignKey("RoleId")
313 | .OnDelete(DeleteBehavior.Cascade)
314 | .IsRequired();
315 | });
316 |
317 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
318 | {
319 | b.HasOne("MAUI.CleanArchitecture.Infrastructure.Identity.ApplicationUser", null)
320 | .WithMany()
321 | .HasForeignKey("UserId")
322 | .OnDelete(DeleteBehavior.Cascade)
323 | .IsRequired();
324 | });
325 |
326 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b =>
327 | {
328 | b.HasOne("MAUI.CleanArchitecture.Infrastructure.Identity.ApplicationUser", null)
329 | .WithMany()
330 | .HasForeignKey("UserId")
331 | .OnDelete(DeleteBehavior.Cascade)
332 | .IsRequired();
333 | });
334 |
335 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b =>
336 | {
337 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
338 | .WithMany()
339 | .HasForeignKey("RoleId")
340 | .OnDelete(DeleteBehavior.Cascade)
341 | .IsRequired();
342 |
343 | b.HasOne("MAUI.CleanArchitecture.Infrastructure.Identity.ApplicationUser", null)
344 | .WithMany()
345 | .HasForeignKey("UserId")
346 | .OnDelete(DeleteBehavior.Cascade)
347 | .IsRequired();
348 | });
349 |
350 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b =>
351 | {
352 | b.HasOne("MAUI.CleanArchitecture.Infrastructure.Identity.ApplicationUser", null)
353 | .WithMany()
354 | .HasForeignKey("UserId")
355 | .OnDelete(DeleteBehavior.Cascade)
356 | .IsRequired();
357 | });
358 |
359 | modelBuilder.Entity("MAUI.CleanArchitecture.Domain.Entities.CardItem", b =>
360 | {
361 | b.Navigation("StoreItem")
362 | .IsRequired();
363 | });
364 |
365 | modelBuilder.Entity("MAUI.CleanArchitecture.Domain.Entities.StoreItem", b =>
366 | {
367 | b.Navigation("Rating")
368 | .IsRequired();
369 | });
370 | #pragma warning restore 612, 618
371 | }
372 | }
373 | }
374 |
--------------------------------------------------------------------------------
/MAUI.CleanArchitecture.Infrastructure/Persistence/Migrations/20211214054413_InitialCreate.Designer.cs:
--------------------------------------------------------------------------------
1 | //
2 | using System;
3 | using MAUI.CleanArchitecture.Infrastructure.Persistence;
4 | using Microsoft.EntityFrameworkCore;
5 | using Microsoft.EntityFrameworkCore.Infrastructure;
6 | using Microsoft.EntityFrameworkCore.Migrations;
7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
8 |
9 | #nullable disable
10 |
11 | namespace MAUI.CleanArchitecture.Infrastructure.Persistence.Migrations
12 | {
13 | [DbContext(typeof(StoreDbContext))]
14 | [Migration("20211214054413_InitialCreate")]
15 | partial class InitialCreate
16 | {
17 | protected override void BuildTargetModel(ModelBuilder modelBuilder)
18 | {
19 | #pragma warning disable 612, 618
20 | modelBuilder.HasAnnotation("ProductVersion", "6.0.0");
21 |
22 | modelBuilder.Entity("MAUI.CleanArchitecture.Domain.Entities.CardItem", b =>
23 | {
24 | b.Property("StoreRef")
25 | .ValueGeneratedOnAdd()
26 | .HasColumnType("INTEGER");
27 |
28 | b.Property("Quantity")
29 | .HasColumnType("INTEGER");
30 |
31 | b.Property("SessionId")
32 | .HasColumnType("TEXT");
33 |
34 | b.Property("UserId")
35 | .HasColumnType("TEXT");
36 |
37 | b.HasKey("StoreRef");
38 |
39 | b.ToTable("CardItems");
40 | });
41 |
42 | modelBuilder.Entity("MAUI.CleanArchitecture.Domain.Entities.Rating", b =>
43 | {
44 | b.Property("StoreRef")
45 | .HasColumnType("INTEGER");
46 |
47 | b.Property("Count")
48 | .HasColumnType("INTEGER");
49 |
50 | b.Property("Rate")
51 | .HasColumnType("REAL");
52 |
53 | b.HasKey("StoreRef");
54 |
55 | b.ToTable("Rating");
56 | });
57 |
58 | modelBuilder.Entity("MAUI.CleanArchitecture.Domain.Entities.StoreItem", b =>
59 | {
60 | b.Property("CardRef")
61 | .HasColumnType("INTEGER");
62 |
63 | b.Property("Category")
64 | .HasColumnType("TEXT");
65 |
66 | b.Property("Description")
67 | .HasColumnType("TEXT");
68 |
69 | b.Property("Id")
70 | .IsUnicode(true)
71 | .HasColumnType("INTEGER");
72 |
73 | b.Property("Image")
74 | .HasColumnType("TEXT");
75 |
76 | b.Property("Price")
77 | .HasPrecision(18, 2)
78 | .HasColumnType("TEXT");
79 |
80 | b.Property("Title")
81 | .HasMaxLength(200)
82 | .HasColumnType("TEXT");
83 |
84 | b.HasKey("CardRef");
85 |
86 | b.ToTable("StoreItems");
87 | });
88 |
89 | modelBuilder.Entity("MAUI.CleanArchitecture.Infrastructure.Identity.ApplicationUser", b =>
90 | {
91 | b.Property("Id")
92 | .HasColumnType("TEXT");
93 |
94 | b.Property("AccessFailedCount")
95 | .HasColumnType("INTEGER");
96 |
97 | b.Property("ConcurrencyStamp")
98 | .IsConcurrencyToken()
99 | .HasColumnType("TEXT");
100 |
101 | b.Property("DateOfBirth")
102 | .HasColumnType("TEXT");
103 |
104 | b.Property("Email")
105 | .HasMaxLength(256)
106 | .HasColumnType("TEXT");
107 |
108 | b.Property("EmailConfirmed")
109 | .HasColumnType("INTEGER");
110 |
111 | b.Property("FirstName")
112 | .IsRequired()
113 | .HasColumnType("TEXT");
114 |
115 | b.Property("LastName")
116 | .IsRequired()
117 | .HasColumnType("TEXT");
118 |
119 | b.Property("LockoutEnabled")
120 | .HasColumnType("INTEGER");
121 |
122 | b.Property("LockoutEnd")
123 | .HasColumnType("TEXT");
124 |
125 | b.Property