├── .github
└── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── .gitignore
├── CraftUI.sln
├── README.md
├── global.json
└── src
├── CraftUI.Demo.Application
├── Cities
│ └── CityVm.cs
├── Common
│ ├── Interfaces
│ │ ├── Infrastructure
│ │ │ ├── IDisplayService.cs
│ │ │ ├── INavigationService.cs
│ │ │ └── IToastService.cs
│ │ └── Services
│ │ │ ├── ICityService.cs
│ │ │ └── ICountryService.cs
│ └── LinkMenuItem.cs
├── Countries
│ └── CountryVm.cs
└── CraftUI.Demo.Application.csproj
├── CraftUI.Demo.Infrastructure
├── CraftUI.Demo.Infrastructure.csproj
├── DependencyInjection.cs
├── Displays
│ └── DisplayService.cs
├── Navigation
│ └── NavigationService.cs
└── Toasts
│ └── ToastService.cs
├── CraftUI.Demo.Services
├── Cities
│ └── CityService.cs
├── Countries
│ └── CountryService.cs
├── CraftUI.Demo.Services.csproj
└── DependencyInjection.cs
├── CraftUI.Demo
├── App.xaml
├── App.xaml.cs
├── AppShell.xaml
├── AppShell.xaml.cs
├── CraftUI.Demo.csproj
├── MauiProgram.cs
├── Platforms
│ ├── Android
│ │ ├── AndroidManifest.xml
│ │ ├── MainActivity.cs
│ │ ├── MainApplication.cs
│ │ └── Resources
│ │ │ └── values
│ │ │ └── colors.xml
│ ├── MacCatalyst
│ │ ├── AppDelegate.cs
│ │ ├── Entitlements.plist
│ │ ├── Info.plist
│ │ └── Program.cs
│ ├── Windows
│ │ ├── App.xaml
│ │ ├── App.xaml.cs
│ │ ├── Package.appxmanifest
│ │ └── app.manifest
│ └── iOS
│ │ ├── AppDelegate.cs
│ │ ├── Info.plist
│ │ └── Program.cs
├── Presentation
│ ├── Common
│ │ ├── ContentPageBase.cs
│ │ ├── RouteConstants.cs
│ │ └── ViewModelBase.cs
│ └── Pages
│ │ ├── Controls
│ │ ├── Buttons
│ │ │ ├── ButtonPage.xaml
│ │ │ ├── ButtonPage.xaml.cs
│ │ │ └── ButtonPageViewModel.cs
│ │ ├── ControlsList.xaml
│ │ ├── ControlsList.xaml.cs
│ │ ├── ControlsListViewModel.cs
│ │ ├── DatePickers
│ │ │ ├── DatePickerPage.xaml
│ │ │ ├── DatePickerPage.xaml.cs
│ │ │ └── DatePickerPageViewModel.cs
│ │ ├── Entries
│ │ │ ├── EntryPage.xaml
│ │ │ ├── EntryPage.xaml.cs
│ │ │ ├── EntryPageViewModel.cs
│ │ │ └── EntryPageViewModelValidator.cs
│ │ ├── Pickers
│ │ │ ├── MultiPickerPopupPage.xaml
│ │ │ ├── MultiPickerPopupPage.xaml.cs
│ │ │ ├── PickerPage.xaml
│ │ │ ├── PickerPage.xaml.cs
│ │ │ ├── PickerPageViewModel.cs
│ │ │ ├── PickerPopupPage.xaml
│ │ │ └── PickerPopupPage.xaml.cs
│ │ └── ProgressBars
│ │ │ ├── ProgressBarPage.xaml
│ │ │ ├── ProgressBarPage.xaml.cs
│ │ │ └── ProgressBarPageViewModel.cs
│ │ ├── Settings
│ │ ├── SettingsPage.xaml
│ │ ├── SettingsPage.xaml.cs
│ │ └── SettingsPageViewModel.cs
│ │ └── UseCases
│ │ ├── UseCasesList.xaml
│ │ ├── UseCasesList.xaml.cs
│ │ └── UseCasesListViewModel.cs
├── Properties
│ └── launchSettings.json
└── Resources
│ ├── AppIcon
│ ├── appicon.svg
│ └── appiconfg.svg
│ ├── Fonts
│ ├── OpenSans-Regular.ttf
│ └── OpenSans-Semibold.ttf
│ ├── Images
│ ├── chevron_bottom.svg
│ ├── close.svg
│ ├── demo_code.svg
│ ├── demo_cog.svg
│ ├── demo_date_picker.svg
│ ├── demo_hand_click.svg
│ ├── demo_info.svg
│ ├── demo_input.svg
│ ├── demo_new_window.svg
│ ├── demo_picker.svg
│ ├── demo_progress_bar.svg
│ ├── demo_use_cases.svg
│ └── demo_work_in_progress.svg
│ ├── Raw
│ └── AboutAssets.txt
│ ├── Splash
│ └── splash.svg
│ └── Styles
│ ├── Buttons.xaml
│ ├── Colors.xaml
│ ├── CustomControls.xaml
│ ├── Layouts.xaml
│ └── Styles.xaml
└── CraftUI.Library.Maui
├── Common
├── Extensions
│ ├── BaseLabelExtension.cs
│ └── ObjectExtension.cs
├── Helpers
│ ├── ResourceHelper.cs
│ └── ViewHelper.cs
├── LabelBase.xaml
├── LabelBase.xaml.cs
└── Resources
│ └── ColorResources.cs
├── Controls
├── CfButton.xaml
├── CfButton.xaml.cs
├── CfDatePicker.xaml
├── CfDatePicker.xaml.cs
├── CfDatePickerInternal.cs
├── CfEntry.xaml
├── CfEntry.xaml.cs
├── CfMultiPickerPopup.xaml
├── CfMultiPickerPopup.xaml.cs
├── CfPicker.xaml
├── CfPicker.xaml.cs
├── CfPickerPopup.xaml
├── CfPickerPopup.xaml.cs
├── Popups
│ ├── CfCollectionMultiSelectionPopup.xaml
│ ├── CfCollectionMultiSelectionPopup.xaml.cs
│ ├── CfCollectionSingleSelectionPopup.xaml
│ └── CfCollectionSingleSelectionPopup.xaml.cs
└── ProgressBars
│ ├── CfProgressBar.cs
│ └── CfProgressBarHandler.cs
├── Converters
├── SelectedItemsContainsConverter.cs
└── ShowErrorConverter.cs
├── CraftUI.Library.Maui.csproj
├── DependencyInjection.cs
└── MarkupExtensions
└── GutterMarkupExtension.cs
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/CraftUI.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CraftUI.Demo", "src\CraftUI.Demo\CraftUI.Demo.csproj", "{350C190D-BE1F-4998-B849-47C79B8407E4}"
4 | EndProject
5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CraftUI.Library.Maui", "src\CraftUI.Library.Maui\CraftUI.Library.Maui.csproj", "{050FEBD3-B53F-414B-9AFC-5E5C2F202858}"
6 | EndProject
7 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CraftUI.Demo.Application", "src\CraftUI.Demo.Application\CraftUI.Demo.Application.csproj", "{91F72502-ADC1-499A-B8C4-712FA1E3D726}"
8 | EndProject
9 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CraftUI.Demo.Infrastructure", "src\CraftUI.Demo.Infrastructure\CraftUI.Demo.Infrastructure.csproj", "{E542540F-7368-41DA-AD64-C1AA5568ECED}"
10 | EndProject
11 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CraftUI.Demo.Services", "src\CraftUI.Demo.Services\CraftUI.Demo.Services.csproj", "{21809B72-515E-40C7-B850-B43FB95B397F}"
12 | EndProject
13 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{94BD610A-F683-4377-AEB4-5434EFB981A5}"
14 | EndProject
15 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "demo", "demo", "{FA8E676E-4901-48EB-A97F-57B761D60841}"
16 | EndProject
17 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "library", "library", "{62919E63-BA59-40EC-ABA2-42D6BA079954}"
18 | EndProject
19 | Global
20 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
21 | Debug|Any CPU = Debug|Any CPU
22 | Release|Any CPU = Release|Any CPU
23 | EndGlobalSection
24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
25 | {350C190D-BE1F-4998-B849-47C79B8407E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26 | {350C190D-BE1F-4998-B849-47C79B8407E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
27 | {350C190D-BE1F-4998-B849-47C79B8407E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
28 | {350C190D-BE1F-4998-B849-47C79B8407E4}.Release|Any CPU.Build.0 = Release|Any CPU
29 | {350C190D-BE1F-4998-B849-47C79B8407E4}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
30 | {050FEBD3-B53F-414B-9AFC-5E5C2F202858}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {050FEBD3-B53F-414B-9AFC-5E5C2F202858}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {050FEBD3-B53F-414B-9AFC-5E5C2F202858}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {050FEBD3-B53F-414B-9AFC-5E5C2F202858}.Release|Any CPU.Build.0 = Release|Any CPU
34 | {91F72502-ADC1-499A-B8C4-712FA1E3D726}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {91F72502-ADC1-499A-B8C4-712FA1E3D726}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {91F72502-ADC1-499A-B8C4-712FA1E3D726}.Release|Any CPU.ActiveCfg = Release|Any CPU
37 | {91F72502-ADC1-499A-B8C4-712FA1E3D726}.Release|Any CPU.Build.0 = Release|Any CPU
38 | {E542540F-7368-41DA-AD64-C1AA5568ECED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 | {E542540F-7368-41DA-AD64-C1AA5568ECED}.Debug|Any CPU.Build.0 = Debug|Any CPU
40 | {E542540F-7368-41DA-AD64-C1AA5568ECED}.Release|Any CPU.ActiveCfg = Release|Any CPU
41 | {E542540F-7368-41DA-AD64-C1AA5568ECED}.Release|Any CPU.Build.0 = Release|Any CPU
42 | {21809B72-515E-40C7-B850-B43FB95B397F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
43 | {21809B72-515E-40C7-B850-B43FB95B397F}.Debug|Any CPU.Build.0 = Debug|Any CPU
44 | {21809B72-515E-40C7-B850-B43FB95B397F}.Release|Any CPU.ActiveCfg = Release|Any CPU
45 | {21809B72-515E-40C7-B850-B43FB95B397F}.Release|Any CPU.Build.0 = Release|Any CPU
46 | EndGlobalSection
47 | GlobalSection(NestedProjects) = preSolution
48 | {FA8E676E-4901-48EB-A97F-57B761D60841} = {94BD610A-F683-4377-AEB4-5434EFB981A5}
49 | {62919E63-BA59-40EC-ABA2-42D6BA079954} = {94BD610A-F683-4377-AEB4-5434EFB981A5}
50 | {350C190D-BE1F-4998-B849-47C79B8407E4} = {FA8E676E-4901-48EB-A97F-57B761D60841}
51 | {91F72502-ADC1-499A-B8C4-712FA1E3D726} = {FA8E676E-4901-48EB-A97F-57B761D60841}
52 | {E542540F-7368-41DA-AD64-C1AA5568ECED} = {FA8E676E-4901-48EB-A97F-57B761D60841}
53 | {21809B72-515E-40C7-B850-B43FB95B397F} = {FA8E676E-4901-48EB-A97F-57B761D60841}
54 | {050FEBD3-B53F-414B-9AFC-5E5C2F202858} = {62919E63-BA59-40EC-ABA2-42D6BA079954}
55 | EndGlobalSection
56 | EndGlobal
57 |
--------------------------------------------------------------------------------
/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "sdk": {
3 | "version": "9.0.0",
4 | "rollForward": "latestMajor",
5 | "allowPrerelease": true
6 | }
7 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo.Application/Cities/CityVm.cs:
--------------------------------------------------------------------------------
1 | namespace CraftUI.Demo.Application.Cities;
2 |
3 | public record CityVm(int Id, int CountryId, string Name);
4 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo.Application/Common/Interfaces/Infrastructure/IDisplayService.cs:
--------------------------------------------------------------------------------
1 | namespace CraftUI.Demo.Application.Common.Interfaces.Infrastructure;
2 |
3 | public interface IDisplayService
4 | {
5 | Task ShowPopupAsync(string title, string message, string accept = "OK");
6 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo.Application/Common/Interfaces/Infrastructure/INavigationService.cs:
--------------------------------------------------------------------------------
1 | namespace CraftUI.Demo.Application.Common.Interfaces.Infrastructure;
2 |
3 | public interface INavigationService
4 | {
5 | ///
6 | /// Performs hierarchical navigation to a specific page using a registered navigation route.
7 | /// Can optionally pass named route parameters to be used for processing in the destination page.
8 | ///
9 | /// Name of the page
10 | /// Dictionary of parameters
11 | Task NavigateToAsync(string route, IDictionary? routeParameters = null);
12 |
13 | ///
14 | /// Returns to the previous page in the navigation stack.
15 | ///
16 | Task GoBackAsync();
17 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo.Application/Common/Interfaces/Infrastructure/IToastService.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Maui.Core;
2 |
3 | namespace CraftUI.Demo.Application.Common.Interfaces.Infrastructure;
4 |
5 | public interface IToastService
6 | {
7 | Task ShowAsync(string message, ToastDuration duration = ToastDuration.Short, double textSize = 14.0);
8 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo.Application/Common/Interfaces/Services/ICityService.cs:
--------------------------------------------------------------------------------
1 | using CraftUI.Demo.Application.Cities;
2 |
3 | namespace CraftUI.Demo.Application.Common.Interfaces.Services;
4 |
5 | public interface ICityService
6 | {
7 | Task> GetAllCitiesAsync(CancellationToken cancellationToken = default);
8 | Task> GetCitiesAsync(int countryId, CancellationToken cancellationToken = default);
9 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo.Application/Common/Interfaces/Services/ICountryService.cs:
--------------------------------------------------------------------------------
1 | using CraftUI.Demo.Application.Countries;
2 |
3 | namespace CraftUI.Demo.Application.Common.Interfaces.Services;
4 |
5 | public interface ICountryService
6 | {
7 | Task> GetAllCountriesAsync(CancellationToken cancellationToken = default);
8 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo.Application/Common/LinkMenuItem.cs:
--------------------------------------------------------------------------------
1 | namespace CraftUI.Demo.Application.Common;
2 |
3 | public record LinkMenuItem(string Title, string Image, string RoutePage);
--------------------------------------------------------------------------------
/src/CraftUI.Demo.Application/Countries/CountryVm.cs:
--------------------------------------------------------------------------------
1 | namespace CraftUI.Demo.Application.Countries;
2 |
3 | public record CountryVm(int Id, string Name);
--------------------------------------------------------------------------------
/src/CraftUI.Demo.Application/CraftUI.Demo.Application.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo.Infrastructure/CraftUI.Demo.Infrastructure.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo.Infrastructure/DependencyInjection.cs:
--------------------------------------------------------------------------------
1 | using CraftUI.Demo.Application.Common.Interfaces.Infrastructure;
2 | using CraftUI.Demo.Infrastructure.Displays;
3 | using CraftUI.Demo.Infrastructure.Navigation;
4 | using CraftUI.Demo.Infrastructure.Toasts;
5 | using Microsoft.Extensions.DependencyInjection;
6 |
7 | namespace CraftUI.Demo.Infrastructure;
8 |
9 | public static class DependencyInjection
10 | {
11 | public static IServiceCollection AddInfrastructure(this IServiceCollection services)
12 | {
13 | services.AddSingleton();
14 | services.AddSingleton();
15 | services.AddSingleton();
16 |
17 | return services;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo.Infrastructure/Displays/DisplayService.cs:
--------------------------------------------------------------------------------
1 | using CraftUI.Demo.Application.Common.Interfaces.Infrastructure;
2 |
3 | namespace CraftUI.Demo.Infrastructure.Displays;
4 |
5 | public class DisplayService : IDisplayService
6 | {
7 | public Task ShowPopupAsync(string title, string message, string accept = "OK")
8 | {
9 | return Microsoft.Maui.Controls.Application.Current!.Windows[0].Page!.DisplayAlert(title, message, accept);
10 | }
11 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo.Infrastructure/Navigation/NavigationService.cs:
--------------------------------------------------------------------------------
1 | using CraftUI.Demo.Application.Common.Interfaces.Infrastructure;
2 |
3 | namespace CraftUI.Demo.Infrastructure.Navigation;
4 |
5 | // Read more about navigation : https://learn.microsoft.com/fr-fr/dotnet/architecture/maui/navigation
6 |
7 | public class NavigationService : INavigationService
8 | {
9 | public Task NavigateToAsync(string route, IDictionary? routeParameters = null)
10 | {
11 | return routeParameters != null
12 | ? Shell.Current.GoToAsync(route, routeParameters)
13 | : Shell.Current.GoToAsync(route);
14 | }
15 |
16 | public Task GoBackAsync()
17 | {
18 | return Shell.Current.GoToAsync("..");
19 | }
20 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo.Infrastructure/Toasts/ToastService.cs:
--------------------------------------------------------------------------------
1 | using CraftUI.Demo.Application.Common.Interfaces.Infrastructure;
2 | using CommunityToolkit.Maui.Alerts;
3 | using CommunityToolkit.Maui.Core;
4 |
5 | namespace CraftUI.Demo.Infrastructure.Toasts;
6 |
7 | public class ToastService : IToastService
8 | {
9 | public Task ShowAsync(string message, ToastDuration duration = ToastDuration.Short, double textSize = 14.0)
10 | {
11 | return Toast.Make(message, duration, textSize).Show();
12 | }
13 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo.Services/Countries/CountryService.cs:
--------------------------------------------------------------------------------
1 | using CraftUI.Demo.Application.Common.Interfaces.Services;
2 | using CraftUI.Demo.Application.Countries;
3 |
4 | namespace CraftUI.Demo.Services.Countries;
5 |
6 | public class CountryService : ICountryService
7 | {
8 | public async Task> GetAllCountriesAsync(CancellationToken cancellationToken = default)
9 | {
10 | var countries = new List
11 | {
12 | new (1, "France"),
13 | new (2, "United States"),
14 | new (3, "Japan"),
15 | new (4, "United Kingdom"),
16 | new (5, "Australia"),
17 | new (6, "Canada"),
18 | new (7, "Germany"),
19 | new (8, "Italy"),
20 | new (9, "Spain"),
21 | new (10, "Brazil"),
22 | new (11, "China"),
23 | new (12, "India"),
24 | new (13, "Mexico"),
25 | new (14, "Russia"),
26 | new (15, "South Korea"),
27 | new (16, "Netherlands"),
28 | new (17, "Sweden"),
29 | new (18, "Norway"),
30 | new (19, "Denmark"),
31 | new (20, "Finland"),
32 | new (21, "Argentina"),
33 | new (22, "Belgium"),
34 | new (23, "Chile"),
35 | new (24, "Colombia"),
36 | new (25, "New Zealand"),
37 | new (26, "South Africa"),
38 | new (27, "Ireland"),
39 | new (28, "Portugal"),
40 | new (29, "Greece"),
41 | new (30, "Turkey"),
42 | new (31, "Saudi Arabia"),
43 | new (32, "Israel"),
44 | new (33, "Poland"),
45 | new (34, "Switzerland"),
46 | new (35, "Austria"),
47 | new (36, "Hungary"),
48 | new (37, "Czech Republic"),
49 | new (38, "Ukraine"),
50 | new (39, "Vietnam"),
51 | new (40, "Thailand"),
52 | new (41, "Malaysia"),
53 | new (42, "Philippines"),
54 | new (43, "Indonesia"),
55 | new (44, "Singapore"),
56 | new (45, "Pakistan"),
57 | new (46, "Bangladesh"),
58 | new (47, "Sri Lanka"),
59 | new (48, "Nepal"),
60 | new (49, "Afghanistan"),
61 | new (50, "Kazakhstan"),
62 | new (51, "Uzbekistan"),
63 | new (52, "Azerbaijan"),
64 | new (53, "Armenia"),
65 | new (54, "Georgia"),
66 | new (55, "Morocco"),
67 | new (56, "Tunisia"),
68 | new (57, "Egypt"),
69 | new (58, "Kenya"),
70 | new (59, "Nigeria"),
71 | new (60, "Ghana"),
72 | new (61, "Ivory Coast"),
73 | new (62, "Senegal"),
74 | new (63, "Uganda"),
75 | new (64, "Ethiopia"),
76 | new (65, "Tanzania"),
77 | new (66, "Zambia"),
78 | new (67, "Zimbabwe"),
79 | new (68, "Algeria"),
80 | new (69, "Libya"),
81 | new (70, "Sudan"),
82 | new (71, "Angola"),
83 | new (72, "Mozambique"),
84 | new (73, "Botswana"),
85 | new (74, "Namibia"),
86 | new (75, "Madagascar"),
87 | new (76, "Mauritius"),
88 | new (77, "Seychelles"),
89 | new (78, "Malawi"),
90 | new (79, "Rwanda"),
91 | new (80, "Burundi"),
92 | new (81, "Mali"),
93 | new (82, "Niger"),
94 | new (83, "Chad"),
95 | new (84, "Central African Republic"),
96 | new (85, "Democratic Republic of the Congo"),
97 | new (86, "Republic of the Congo"),
98 | new (87, "Gabon"),
99 | new (88, "Equatorial Guinea"),
100 | new (89, "Sao Tome and Principe"),
101 | new (90, "Togo"),
102 | new (91, "Benin"),
103 | new (92, "Sierra Leone"),
104 | new (93, "Liberia"),
105 | new (94, "Cameroon"),
106 | new (95, "Burkina Faso"),
107 | new (96, "Lesotho"),
108 | new (97, "Eswatini"),
109 | new (98, "Somalia"),
110 | new (99, "Djibouti"),
111 | new (100, "Eritrea")
112 | };
113 |
114 | await Task.Delay(2000, cancellationToken);
115 |
116 | return countries.AsReadOnly();
117 | }
118 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo.Services/CraftUI.Demo.Services.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo.Services/DependencyInjection.cs:
--------------------------------------------------------------------------------
1 | using CraftUI.Demo.Application.Common.Interfaces.Services;
2 | using CraftUI.Demo.Services.Cities;
3 | using CraftUI.Demo.Services.Countries;
4 | using Microsoft.Extensions.DependencyInjection;
5 |
6 | namespace CraftUI.Demo.Services;
7 |
8 | public static class DependencyInjection
9 | {
10 | public static IServiceCollection AddServices(this IServiceCollection services)
11 | {
12 | services.AddSingleton();
13 | services.AddSingleton();
14 |
15 | return services;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/App.xaml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/App.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace CraftUI.Demo;
2 |
3 | public partial class App
4 | {
5 | public App()
6 | {
7 | InitializeComponent();
8 | }
9 |
10 | protected override Window CreateWindow(IActivationState? activationState)
11 | {
12 | return new Window(new AppShell());
13 | }
14 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/AppShell.xaml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
17 |
18 |
19 |
23 |
24 |
25 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/AppShell.xaml.cs:
--------------------------------------------------------------------------------
1 | using CraftUI.Library.Maui.Common.Helpers;
2 |
3 | namespace CraftUI.Demo;
4 |
5 | public partial class AppShell
6 | {
7 | public AppShell()
8 | {
9 | InitializeComponent();
10 | SetBackgroundColor(this, ResourceHelper.GetResource("Primary"));
11 | SetTitleColor(this, ResourceHelper.GetResource("White"));
12 | }
13 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/CraftUI.Demo.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0-android;net9.0-ios;net9.0-maccatalyst
5 | $(TargetFrameworks);net9.0-windows10.0.19041.0
6 |
7 |
8 |
9 |
14 |
15 |
16 | Exe
17 | true
18 | true
19 | enable
20 | enable
21 |
22 |
23 | CraftUI Demo
24 |
25 |
26 | com.stephanarnas.blog_maui_components
27 |
28 |
29 | 1.0
30 | 1
31 |
32 | 15.0
33 | 15.0
34 | 21.0
35 | 10.0.17763.0
36 | 10.0.17763.0
37 |
38 |
39 |
40 | SdkOnly
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | Designer
73 |
74 |
75 | Designer
76 |
77 |
78 | Designer
79 |
80 |
81 | Designer
82 |
83 |
84 | Designer
85 |
86 |
87 | Designer
88 |
89 |
90 | Designer
91 |
92 |
93 |
94 |
95 |
96 | EntryLabel.xaml
97 | Code
98 |
99 |
100 | EntryLabelBacis.xaml
101 | Code
102 |
103 |
104 | LabelBase.xaml
105 | Code
106 |
107 |
108 | CitySearchPage.xaml
109 | Code
110 |
111 |
112 | CountrySearchPage.xaml
113 | Code
114 |
115 |
116 | UseCasesList.xaml
117 | Code
118 |
119 |
120 | MultiPickerPopupPage.xaml
121 | Code
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/MauiProgram.cs:
--------------------------------------------------------------------------------
1 | using CraftUI.Demo.Infrastructure;
2 | using CraftUI.Library.Maui;
3 | using CraftUI.Demo.Services;
4 | using CommunityToolkit.Maui;
5 | using Microsoft.Extensions.Logging;
6 | using Microsoft.Maui.Handlers;
7 | using CraftUI.Demo.Presentation.Common;
8 | using CraftUI.Demo.Presentation.Pages.Controls;
9 | using CraftUI.Demo.Presentation.Pages.Controls.Buttons;
10 | using CraftUI.Demo.Presentation.Pages.Controls.DatePickers;
11 | using CraftUI.Demo.Presentation.Pages.Controls.Entries;
12 | using CraftUI.Demo.Presentation.Pages.Controls.Pickers;
13 | using CraftUI.Demo.Presentation.Pages.Controls.ProgressBars;
14 | using CraftUI.Demo.Presentation.Pages.Settings;
15 | using CraftUI.Demo.Presentation.Pages.UseCases;
16 |
17 | namespace CraftUI.Demo;
18 |
19 | public static class MauiProgram
20 | {
21 | public static MauiApp CreateMauiApp()
22 | {
23 | var builder = MauiApp.CreateBuilder();
24 | builder
25 | .UseMauiApp()
26 | .AddBlogComponents()
27 | .UseMauiCommunityToolkit()
28 | .ConfigureFonts(fonts =>
29 | {
30 | fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
31 | fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
32 | });
33 |
34 | #if DEBUG
35 | builder.Logging.AddDebug();
36 | #endif
37 |
38 | builder.Services.AddInfrastructure();
39 | builder.Services.AddServices();
40 |
41 | ApplyStyleCustomization();
42 |
43 | // Register your pages.
44 | builder.Services.AddTransient();
45 | builder.Services.AddTransientWithShellRoute(RouteConstants.ButtonPage);
46 | builder.Services.AddTransientWithShellRoute(RouteConstants.EntryPage);
47 | builder.Services.AddTransientWithShellRoute(RouteConstants.DatePickerPage);
48 | builder.Services.AddTransientWithShellRoute(RouteConstants.PickerPage);
49 | builder.Services.AddTransientWithShellRoute(RouteConstants.PickerPopupPage);
50 | builder.Services.AddTransientWithShellRoute(RouteConstants.MultiPickerPopupPage);
51 | builder.Services.AddTransientWithShellRoute(RouteConstants.ProgressBarPage);
52 |
53 | builder.Services.AddTransient();
54 | builder.Services.AddTransient();
55 |
56 | return builder.Build();
57 | }
58 |
59 | private static void ApplyStyleCustomization()
60 | {
61 | EntryHandler.Mapper.AppendToMapping("NoUnderline", (handler, view) =>
62 | {
63 | #if ANDROID
64 | // Remove the underline from the EditText
65 | handler.PlatformView.SetBackgroundColor(Android.Graphics.Color.Transparent);
66 | #endif
67 | });
68 |
69 | EntryHandler.Mapper.AppendToMapping("SetUpEntry", (handler, _) =>
70 | {
71 | #if ANDROID
72 |
73 | #elif IOS || MACCATALYST
74 | // Remove outline from the UITextField
75 | handler.PlatformView.BorderStyle = UIKit.UITextBorderStyle.None;
76 | #elif WINDOWS
77 |
78 | #endif
79 | });
80 |
81 | PickerHandler.Mapper.AppendToMapping("NoUnderline", (handler, _) =>
82 | {
83 | #if ANDROID
84 | // Remove the underline from the Spinner (Picker)
85 | handler.PlatformView.Background = null;
86 | #endif
87 | });
88 |
89 | PickerHandler.Mapper.AppendToMapping("SetUpPicker", (handler, _) =>
90 | {
91 | #if ANDROID
92 | // Set the background to transparent
93 | handler.PlatformView.Background = null;
94 | #elif IOS || MACCATALYST
95 | // Remove border for the UITextField (Picker)
96 | if (handler.PlatformView is UIKit.UITextField textField)
97 | {
98 | textField.BorderStyle = UIKit.UITextBorderStyle.None;
99 | }
100 | #elif WINDOWS
101 |
102 | #endif
103 | });
104 |
105 | DatePickerHandler.Mapper.AppendToMapping("Borderless", (handler, view) =>
106 | {
107 | #if ANDROID
108 | handler.PlatformView.Background = null;
109 | #elif IOS || MACCATALYST
110 | handler.PlatformView.BackgroundColor = UIKit.UIColor.Clear;
111 | handler.PlatformView.Layer.BorderWidth = 0;
112 | handler.PlatformView.BorderStyle = UIKit.UITextBorderStyle.None;
113 | #endif
114 | });
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Platforms/Android/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Platforms/Android/MainActivity.cs:
--------------------------------------------------------------------------------
1 | using Android.App;
2 | using Android.Content.PM;
3 | using Android.OS;
4 |
5 | namespace CraftUI.Demo;
6 |
7 | [Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true,
8 | ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode |
9 | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
10 | public class MainActivity : MauiAppCompatActivity
11 | {
12 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Platforms/Android/MainApplication.cs:
--------------------------------------------------------------------------------
1 | using Android.App;
2 | using Android.Runtime;
3 |
4 | namespace CraftUI.Demo;
5 |
6 | [Application]
7 | public class MainApplication : MauiApplication
8 | {
9 | public MainApplication(IntPtr handle, JniHandleOwnership ownership)
10 | : base(handle, ownership)
11 | {
12 | }
13 |
14 | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
15 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Platforms/Android/Resources/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #512BD4
4 | #2B0B98
5 | #2B0B98
6 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Platforms/MacCatalyst/AppDelegate.cs:
--------------------------------------------------------------------------------
1 | using Foundation;
2 |
3 | namespace CraftUI.Demo;
4 |
5 | [Register("AppDelegate")]
6 | public class AppDelegate : MauiUIApplicationDelegate
7 | {
8 | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
9 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Platforms/MacCatalyst/Entitlements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | com.apple.security.app-sandbox
8 |
9 |
10 | com.apple.security.network.client
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Platforms/MacCatalyst/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | UIDeviceFamily
15 |
16 | 2
17 |
18 | UIRequiredDeviceCapabilities
19 |
20 | arm64
21 |
22 | UISupportedInterfaceOrientations
23 |
24 | UIInterfaceOrientationPortrait
25 | UIInterfaceOrientationLandscapeLeft
26 | UIInterfaceOrientationLandscapeRight
27 |
28 | UISupportedInterfaceOrientations~ipad
29 |
30 | UIInterfaceOrientationPortrait
31 | UIInterfaceOrientationPortraitUpsideDown
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | XSAppIconAssets
36 | Assets.xcassets/appicon.appiconset
37 |
38 |
39 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Platforms/MacCatalyst/Program.cs:
--------------------------------------------------------------------------------
1 | using ObjCRuntime;
2 | using UIKit;
3 |
4 | namespace CraftUI.Demo;
5 |
6 | public class Program
7 | {
8 | // This is the main entry point of the application.
9 | static void Main(string[] args)
10 | {
11 | // if you want to use a different Application Delegate class from "AppDelegate"
12 | // you can specify it here.
13 | UIApplication.Main(args, null, typeof(AppDelegate));
14 | }
15 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Platforms/Windows/App.xaml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Platforms/Windows/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.UI.Xaml;
2 |
3 | // To learn more about WinUI, the WinUI project structure,
4 | // and more about our project templates, see: http://aka.ms/winui-project-info.
5 |
6 | namespace StephanArnas.Controls.WinUI;
7 |
8 | ///
9 | /// Provides application-specific behavior to supplement the default Application class.
10 | ///
11 | public partial class App : MauiWinUIApplication
12 | {
13 | ///
14 | /// Initializes the singleton application object. This is the first line of authored code
15 | /// executed, and as such is the logical equivalent of main() or WinMain().
16 | ///
17 | public App()
18 | {
19 | this.InitializeComponent();
20 | }
21 |
22 | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
23 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Platforms/Windows/Package.appxmanifest:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | $placeholder$
15 | User Name
16 | $placeholder$.png
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Platforms/Windows/app.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 | true/PM
12 | PerMonitorV2, PerMonitor
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Platforms/iOS/AppDelegate.cs:
--------------------------------------------------------------------------------
1 | using Foundation;
2 |
3 | namespace CraftUI.Demo;
4 |
5 | [Register("AppDelegate")]
6 | public class AppDelegate : MauiUIApplicationDelegate
7 | {
8 | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
9 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/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 |
32 |
33 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Platforms/iOS/Program.cs:
--------------------------------------------------------------------------------
1 | using UIKit;
2 |
3 | namespace CraftUI.Demo;
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 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Common/ContentPageBase.cs:
--------------------------------------------------------------------------------
1 | namespace CraftUI.Demo.Presentation.Common;
2 |
3 | public class ContentPageBase : ContentPage
4 | {
5 | protected override void OnAppearing()
6 | {
7 | base.OnAppearing();
8 |
9 | ((ViewModelBase) BindingContext)?.OnAppearing();
10 | }
11 |
12 | protected override void OnDisappearing()
13 | {
14 | base.OnDisappearing();
15 |
16 | ((ViewModelBase) BindingContext)?.OnDisappearing();
17 | }
18 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Common/RouteConstants.cs:
--------------------------------------------------------------------------------
1 | namespace CraftUI.Demo.Presentation.Common;
2 |
3 | public static class RouteConstants
4 | {
5 | public const string ControlsListPage = "ControlsListPage";
6 | public const string ButtonPage = "ButtonPage";
7 | public const string EntryPage = "EntryPage";
8 | public const string DatePickerPage = "DatePickerPage";
9 | public const string PickerPage = "PikerPage";
10 | public const string PickerPopupPage = "PickerPopupPage";
11 | public const string MultiPickerPopupPage = "MultiPickerPopupPage";
12 | public const string ProgressBarPage = "ProgressBarPage";
13 |
14 | public const string UseCasesListPage = "UseCasesListPage";
15 | public const string SettingsPage = "SettingsPage";
16 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Common/ViewModelBase.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 |
3 | namespace CraftUI.Demo.Presentation.Common;
4 |
5 | public abstract class ViewModelBase : ObservableObject, IQueryAttributable
6 | {
7 | protected bool IsAppearingFromDetailPage;
8 |
9 | protected ViewModelBase() { }
10 |
11 | public virtual void ApplyQueryAttributes(IDictionary query)
12 | {
13 | query.Clear();
14 | }
15 |
16 | public virtual void OnAppearing()
17 | {
18 | IsAppearingFromDetailPage = false;
19 | }
20 |
21 | public virtual void OnDisappearing() { }
22 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/Controls/Buttons/ButtonPage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
14 |
17 |
18 |
22 |
23 |
25 |
26 |
29 |
30 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/Controls/Buttons/ButtonPage.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace CraftUI.Demo.Presentation.Pages.Controls.Buttons;
2 |
3 | public partial class ButtonPage
4 | {
5 | public ButtonPage(ButtonPageViewModel viewModel)
6 | {
7 | InitializeComponent();
8 | BindingContext = viewModel;
9 | }
10 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/Controls/Buttons/ButtonPageViewModel.cs:
--------------------------------------------------------------------------------
1 | using CraftUI.Demo.Presentation.Common;
2 | using Microsoft.Extensions.Logging;
3 | using Sharpnado.TaskLoaderView;
4 |
5 | namespace CraftUI.Demo.Presentation.Pages.Controls.Buttons;
6 |
7 | public class ButtonPageViewModel : ViewModelBase
8 | {
9 | private readonly ILogger _logger;
10 |
11 | public TaskLoaderCommand DemoOneCommand { get; }
12 |
13 | public ButtonPageViewModel(
14 | ILogger logger)
15 | {
16 | _logger = logger;
17 |
18 | DemoOneCommand = new TaskLoaderCommand(DemoOneAsync);
19 |
20 | _logger.LogInformation("Building ButtonPageViewModel");
21 | }
22 |
23 | private async Task DemoOneAsync()
24 | {
25 | _logger.LogInformation("DemoOne()");
26 |
27 | await Task.Delay(5000);
28 | }
29 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/Controls/ControlsList.xaml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
18 |
19 |
20 |
21 |
25 |
26 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/Controls/ControlsList.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace CraftUI.Demo.Presentation.Pages.Controls;
2 |
3 | public partial class ControlsList
4 | {
5 | public ControlsList(ControlsListViewModel viewModel)
6 | {
7 | InitializeComponent();
8 | BindingContext = viewModel;
9 | }
10 |
11 | protected override void OnAppearing()
12 | {
13 | ItemsCollectionView.SelectedItem = null;
14 | base.OnAppearing();
15 | }
16 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/Controls/ControlsListViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.ObjectModel;
2 | using CommunityToolkit.Mvvm.ComponentModel;
3 | using CommunityToolkit.Mvvm.Input;
4 | using CraftUI.Demo.Application.Common;
5 | using CraftUI.Demo.Application.Common.Interfaces.Infrastructure;
6 | using CraftUI.Demo.Presentation.Common;
7 | using CraftUI.Demo.Presentation.Pages.Controls.Pickers;
8 | using Microsoft.Extensions.Logging;
9 |
10 | namespace CraftUI.Demo.Presentation.Pages.Controls;
11 |
12 | public partial class ControlsListViewModel : ViewModelBase
13 | {
14 | private readonly ILogger _logger;
15 | private readonly INavigationService _navigationService;
16 |
17 | [ObservableProperty]
18 | private ObservableCollection _items;
19 |
20 | public ControlsListViewModel(
21 | ILogger logger,
22 | INavigationService navigationService)
23 | {
24 | _logger = logger;
25 | _navigationService = navigationService;
26 |
27 | InitializeItems();
28 |
29 | _logger.LogInformation("Building ControlsListViewModel");
30 | }
31 |
32 | public override void ApplyQueryAttributes(IDictionary query)
33 | {
34 | _logger.LogInformation("ApplyQueryAttributes( query: {Query} )", query);
35 |
36 | base.ApplyQueryAttributes(query);
37 | }
38 |
39 | public override void OnAppearing()
40 | {
41 | _logger.LogInformation("OnAppearing()");
42 |
43 | base.OnAppearing();
44 | }
45 |
46 | public override void OnDisappearing()
47 | {
48 | _logger.LogInformation("OnDisappearing()");
49 |
50 | base.OnDisappearing();
51 | }
52 |
53 | [RelayCommand]
54 | private async Task NavigateToPage(LinkMenuItem? item)
55 | {
56 | _logger.LogInformation("NavigateToPage( item: {Item} )", item);
57 |
58 | if (item is not null)
59 | {
60 | await _navigationService.NavigateToAsync(item.RoutePage);
61 | }
62 | }
63 |
64 | private void InitializeItems()
65 | {
66 | Items =
67 | [
68 | new LinkMenuItem("Button", "demo_hand_click.png", RouteConstants.ButtonPage),
69 | new LinkMenuItem("Entry", "demo_input.png", RouteConstants.EntryPage),
70 | new LinkMenuItem("Date Picker", "demo_date_picker.png", RouteConstants.DatePickerPage),
71 | new LinkMenuItem("Native Picker", "demo_picker.png", RouteConstants.PickerPage),
72 | new LinkMenuItem("Popup Picker", "demo_picker.png", RouteConstants.PickerPopupPage),
73 | new LinkMenuItem("Mutli Popup Picker", "demo_picker.png", RouteConstants.MultiPickerPopupPage),
74 | new LinkMenuItem("Progress Bar", "demo_progress_bar.png", RouteConstants.ProgressBarPage)
75 | ];
76 | }
77 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/Controls/DatePickers/DatePickerPage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
14 |
15 |
18 |
19 |
23 |
24 |
28 |
29 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/Controls/DatePickers/DatePickerPage.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace CraftUI.Demo.Presentation.Pages.Controls.DatePickers;
2 |
3 | public partial class DatePickerPage
4 | {
5 | public DatePickerPage(DatePickerPageViewModel viewModel)
6 | {
7 | InitializeComponent();
8 | BindingContext = viewModel;
9 | }
10 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/Controls/DatePickers/DatePickerPageViewModel.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 | using CraftUI.Demo.Presentation.Common;
3 | using Microsoft.Extensions.Logging;
4 |
5 | namespace CraftUI.Demo.Presentation.Pages.Controls.DatePickers;
6 |
7 | public partial class DatePickerPageViewModel : ViewModelBase
8 | {
9 | private readonly ILogger _logger;
10 |
11 | [ObservableProperty]
12 | private DateTime _date;
13 |
14 | [ObservableProperty]
15 | private DateTime? _dateNullable;
16 |
17 | [ObservableProperty]
18 | private DateTime? _rangeDateNullable;
19 |
20 | [ObservableProperty]
21 | private DateTime _minimumDate;
22 |
23 | [ObservableProperty]
24 | private DateTime _maximumDate;
25 |
26 | public DatePickerPageViewModel(
27 | ILogger logger)
28 | {
29 | _logger = logger;
30 |
31 | MinimumDate = DateTime.Now.AddDays(-1);
32 | MaximumDate = DateTime.Now.AddDays(30);
33 |
34 | _logger.LogInformation("Building DatePickerPageViewModel");
35 | }
36 |
37 | public override void OnAppearing()
38 | {
39 | _logger.LogInformation("OnAppearing()");
40 |
41 | Date = DateTime.Now;
42 | DateNullable = null;
43 | RangeDateNullable = null;
44 |
45 | base.OnAppearing();
46 | }
47 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/Controls/Entries/EntryPage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
14 |
15 |
18 |
19 |
29 |
30 |
40 |
41 |
48 |
49 |
53 |
54 |
55 |
56 |
57 |
58 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/Controls/Entries/EntryPage.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace CraftUI.Demo.Presentation.Pages.Controls.Entries;
2 |
3 | public partial class EntryPage
4 | {
5 | public EntryPage(EntryPageViewModel viewModel)
6 | {
7 | InitializeComponent();
8 | BindingContext = viewModel;
9 | }
10 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/Controls/Entries/EntryPageViewModel.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 | using CommunityToolkit.Mvvm.Input;
3 | using CraftUI.Demo.Application.Common.Interfaces.Infrastructure;
4 | using CraftUI.Demo.Presentation.Common;
5 | using FluentValidation.Results;
6 | using Microsoft.Extensions.Logging;
7 | using Sharpnado.TaskLoaderView;
8 |
9 | namespace CraftUI.Demo.Presentation.Pages.Controls.Entries;
10 |
11 | public partial class EntryPageViewModel : ViewModelBase
12 | {
13 | private readonly ILogger _logger;
14 | private readonly IToastService _toastService;
15 | private readonly IDisplayService _displayService;
16 |
17 | [ObservableProperty]
18 | private string? _fullName;
19 |
20 | [ObservableProperty]
21 | private string? _email;
22 |
23 | [ObservableProperty]
24 | private string? _website;
25 |
26 | [ObservableProperty]
27 | private ValidationResult? _validationResult;
28 |
29 | public TaskLoaderNotifier WebsiteLoader { get; }
30 |
31 | public EntryPageViewModel(
32 | ILogger logger,
33 | IToastService toastService,
34 | IDisplayService displayService)
35 | {
36 | _logger = logger;
37 | _toastService = toastService;
38 | _displayService = displayService;
39 |
40 | WebsiteLoader = new TaskLoaderNotifier();
41 |
42 | _logger.LogInformation("Building EntryPageViewModel");
43 | }
44 |
45 | public override void ApplyQueryAttributes(IDictionary query)
46 | {
47 | _logger.LogInformation("ApplyQueryAttributes( query: {Query} )", query);
48 | }
49 |
50 | public override void OnAppearing()
51 | {
52 | _logger.LogInformation("OnAppearing()");
53 |
54 | if (WebsiteLoader.IsNotStarted)
55 | {
56 | WebsiteLoader.Load(_ => LoadWebsiteAsync());
57 | }
58 |
59 | base.OnAppearing();
60 | }
61 |
62 | public override void OnDisappearing()
63 | {
64 | _logger.LogInformation("OnDisappearing()");
65 |
66 | base.OnDisappearing();
67 | }
68 |
69 | private async Task LoadWebsiteAsync()
70 | {
71 | _logger.LogInformation("LoadAsync()");
72 |
73 | await Task.Delay(4000);
74 |
75 | return "https://www.stephanarnas.com/";
76 | }
77 |
78 | [RelayCommand]
79 | private async Task Save()
80 | {
81 | _logger.LogInformation("Save()");
82 |
83 | var validator = new EntryPageViewModelValidator();
84 | ValidationResult = await validator.ValidateAsync(this);
85 | if (!ValidationResult.IsValid)
86 | {
87 | return;
88 | }
89 |
90 | await _toastService.ShowAsync("Saved !!");
91 | }
92 |
93 | [RelayCommand]
94 | private async Task FullnameInfo()
95 | {
96 | _logger.LogInformation("FullnameInfo()");
97 |
98 | await _displayService.ShowPopupAsync("Full name", "Your first name and last name are used for communication purpose.");
99 | }
100 |
101 | [RelayCommand]
102 | private async Task OpenWebsite()
103 | {
104 | _logger.LogInformation("OpenWebsite()");
105 |
106 | if (WebsiteLoader.ShowResult)
107 | {
108 | await Launcher.OpenAsync(uri: new Uri(WebsiteLoader.Result));
109 | }
110 | }
111 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/Controls/Entries/EntryPageViewModelValidator.cs:
--------------------------------------------------------------------------------
1 | using FluentValidation;
2 |
3 | namespace CraftUI.Demo.Presentation.Pages.Controls.Entries;
4 |
5 | public class EntryPageViewModelValidator : AbstractValidator
6 | {
7 | public static string FullNameProperty => nameof(EntryPageViewModel.FullName);
8 | public static string EmailProperty => nameof(EntryPageViewModel.Email);
9 |
10 | public EntryPageViewModelValidator()
11 | {
12 | RuleFor(x => x.FullName)
13 | .NotNull()
14 | .NotEmpty();
15 |
16 | RuleFor(x => x.Email)
17 | .NotNull()
18 | .NotEmpty()
19 | .EmailAddress();
20 | }
21 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/Controls/Pickers/MultiPickerPopupPage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
14 |
15 |
18 |
19 |
25 |
26 |
27 |
28 |
29 |
30 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/Controls/Pickers/MultiPickerPopupPage.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace CraftUI.Demo.Presentation.Pages.Controls.Pickers;
2 |
3 | public partial class MultiPickerPopupPage
4 | {
5 | public MultiPickerPopupPage(PickerPageViewModel viewModel)
6 | {
7 | InitializeComponent();
8 | BindingContext = viewModel;
9 | }
10 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/Controls/Pickers/PickerPage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
14 |
15 |
18 |
19 |
26 |
27 |
33 |
34 |
35 |
36 |
37 |
38 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/Controls/Pickers/PickerPage.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace CraftUI.Demo.Presentation.Pages.Controls.Pickers;
2 |
3 | public partial class PickerPage
4 | {
5 | public PickerPage(PickerPageViewModel viewModel)
6 | {
7 | InitializeComponent();
8 | BindingContext = viewModel;
9 | }
10 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/Controls/Pickers/PickerPageViewModel.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 | using CommunityToolkit.Mvvm.Input;
3 | using CraftUI.Demo.Application.Cities;
4 | using CraftUI.Demo.Application.Common.Interfaces.Services;
5 | using CraftUI.Demo.Application.Countries;
6 | using CraftUI.Demo.Presentation.Common;
7 | using Microsoft.Extensions.Logging;
8 | using Sharpnado.TaskLoaderView;
9 |
10 | namespace CraftUI.Demo.Presentation.Pages.Controls.Pickers;
11 |
12 | public partial class PickerPageViewModel : ViewModelBase
13 | {
14 | private readonly ILogger _logger;
15 | private readonly ICityService _cityService;
16 | private readonly ICountryService _countryService;
17 |
18 | [ObservableProperty]
19 | private CountryVm? _country;
20 |
21 | [ObservableProperty]
22 | private List? _countries;
23 |
24 | [ObservableProperty]
25 | private CityVm? _city;
26 |
27 | public static string CountryDisplayProperty => nameof(CountryVm.Name);
28 | public static string CityDisplayProperty => nameof(CityVm.Name);
29 |
30 | public TaskLoaderNotifier> CountriesLoader { get; } = new();
31 | public TaskLoaderNotifier> CitiesLoader { get; } = new();
32 |
33 | public PickerPageViewModel(
34 | ILogger logger,
35 | ICityService cityService,
36 | ICountryService countryService)
37 | {
38 | _logger = logger;
39 | _cityService = cityService;
40 | _countryService = countryService;
41 |
42 | _logger.LogInformation("Building LabelPageViewModel");
43 | }
44 |
45 | public override void ApplyQueryAttributes(IDictionary query)
46 | {
47 | _logger.LogInformation("ApplyQueryAttributes( query: {Query} )", query);
48 |
49 | base.ApplyQueryAttributes(query);
50 | }
51 |
52 | public override void OnAppearing()
53 | {
54 | _logger.LogInformation("OnAppearing()");
55 |
56 | if (CountriesLoader.IsNotStarted)
57 | {
58 | CountriesLoader.Load(_ => LoadCountriesAsync());
59 | }
60 |
61 | base.OnAppearing();
62 | }
63 |
64 | public override void OnDisappearing()
65 | {
66 | _logger.LogInformation("OnDisappearing()");
67 |
68 | base.OnDisappearing();
69 | }
70 |
71 | private async Task> LoadCountriesAsync(CancellationToken cancellationToken = default)
72 | {
73 | _logger.LogInformation("LoadCountriesAsync()");
74 |
75 | var domainResult = await _countryService.GetAllCountriesAsync(cancellationToken);
76 | _logger.LogInformation("Items loaded: {Count}", domainResult.Count);
77 |
78 | return domainResult;
79 | }
80 |
81 | private async Task> LoadCitiesByCountry(CancellationToken cancellationToken = default)
82 | {
83 | _logger.LogInformation("LoadCitiesByCountry()");
84 |
85 | if (Country is null)
86 | {
87 | // Add a toast to enhance the user experience.
88 | return Array.Empty();
89 | }
90 |
91 | var domainResult = await _cityService.GetCitiesAsync(Country.Id, cancellationToken);
92 | _logger.LogInformation("Items loaded: {Count}", domainResult.Count);
93 |
94 | return domainResult;
95 | }
96 |
97 | [RelayCommand]
98 | private Task CountrySelected()
99 | {
100 | _logger.LogInformation("CountrySelected()");
101 |
102 | City = null;
103 | CitiesLoader.Reset();
104 | CitiesLoader.Load(_ => LoadCitiesByCountry());
105 |
106 | return Task.CompletedTask;
107 | }
108 |
109 | [RelayCommand]
110 | private Task Reset()
111 | {
112 | _logger.LogInformation("Reset()");
113 |
114 | Country = null;
115 | City = null;
116 | CitiesLoader.Reset();
117 |
118 | return Task.CompletedTask;
119 | }
120 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/Controls/Pickers/PickerPopupPage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
14 |
15 |
18 |
19 |
27 |
28 |
34 |
35 |
36 |
37 |
38 |
39 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/Controls/Pickers/PickerPopupPage.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace CraftUI.Demo.Presentation.Pages.Controls.Pickers;
2 |
3 | public partial class PickerPopupPage
4 | {
5 | public PickerPopupPage(PickerPageViewModel viewModel)
6 | {
7 | InitializeComponent();
8 | BindingContext = viewModel;
9 | }
10 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/Controls/ProgressBars/ProgressBarPage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
19 |
22 |
23 |
24 |
25 |
26 |
28 |
29 |
32 |
36 |
37 |
40 |
46 |
47 |
50 |
58 |
59 |
62 |
72 |
73 |
76 |
84 |
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/Controls/ProgressBars/ProgressBarPage.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace CraftUI.Demo.Presentation.Pages.Controls.ProgressBars;
2 |
3 | public partial class ProgressBarPage
4 | {
5 | public ProgressBarPage(ProgressBarPageViewModel viewModel)
6 | {
7 | InitializeComponent();
8 | BindingContext = viewModel;
9 | }
10 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/Controls/ProgressBars/ProgressBarPageViewModel.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 | using CraftUI.Demo.Presentation.Common;
3 | using Microsoft.Extensions.Logging;
4 |
5 | namespace CraftUI.Demo.Presentation.Pages.Controls.ProgressBars;
6 |
7 | public partial class ProgressBarPageViewModel : ViewModelBase
8 | {
9 | private readonly ILogger _logger;
10 | private bool _isAnimating;
11 | private double _angle;
12 | private IDispatcherTimer? _timer;
13 | private readonly Random _random = new();
14 |
15 | [ObservableProperty]
16 | private float _currentProgress;
17 |
18 | [ObservableProperty]
19 | private float _basicProgress;
20 |
21 | [ObservableProperty]
22 | private float _wavyProgress;
23 |
24 | [ObservableProperty]
25 | private float _pulsatingProgress;
26 |
27 | [ObservableProperty]
28 | private float _stepProgress;
29 |
30 |
31 | public ProgressBarPageViewModel(
32 | ILogger logger)
33 | {
34 | _logger = logger;
35 |
36 | _logger.LogInformation("Building ProgressBarPageViewModel");
37 | }
38 |
39 | public override void ApplyQueryAttributes(IDictionary query)
40 | {
41 | _logger.LogInformation("ApplyQueryAttributes( query: {Query} )", query);
42 |
43 | base.ApplyQueryAttributes(query);
44 | }
45 |
46 | public override void OnAppearing()
47 | {
48 | _logger.LogInformation("OnAppearing()");
49 |
50 | InitializeProgressValues();
51 | StartAnimation();
52 |
53 | base.OnAppearing();
54 | }
55 |
56 | public override void OnDisappearing()
57 | {
58 | _logger.LogInformation("OnDisappearing()");
59 |
60 | StopAnimation();
61 |
62 | base.OnDisappearing();
63 | }
64 |
65 | private void InitializeProgressValues()
66 | {
67 | CurrentProgress = 0.0f;
68 | BasicProgress = 0.0f;
69 | WavyProgress = 0.5f;
70 | PulsatingProgress = 0.75f;
71 | StepProgress = 0.0f;
72 | _angle = 0;
73 | }
74 |
75 | private void StartAnimation()
76 | {
77 | if (_isAnimating)
78 | {
79 | return;
80 | }
81 |
82 | _isAnimating = true;
83 | _timer = Dispatcher.GetForCurrentThread()!.CreateTimer();
84 | _timer.Interval = TimeSpan.FromMilliseconds(16); // ~60fps
85 | _timer.Tick += OnTimerTick;
86 | _timer.Start();
87 | }
88 |
89 | private void StopAnimation()
90 | {
91 | if (!_isAnimating)
92 | {
93 | return;
94 | }
95 |
96 | if (_timer is not null)
97 | {
98 | _timer.Stop();
99 | _timer = null;
100 | }
101 | _isAnimating = false;
102 | }
103 |
104 | private void OnTimerTick(object? sender, EventArgs e)
105 | {
106 | // Linear progress animation
107 | CurrentProgress += 0.005f;
108 | if (CurrentProgress > 1.0f)
109 | {
110 | CurrentProgress = 0.0f;
111 | }
112 |
113 | // Smooth basic progress animation
114 | BasicProgress += 0.003f;
115 | if (BasicProgress > 1.0f)
116 | {
117 | BasicProgress = 0.0f;
118 | }
119 |
120 | // Sine wave animation
121 | _angle += 0.02;
122 | WavyProgress = 0.5f + 0.5f * (float)Math.Sin(_angle);
123 |
124 | // Pulsating animation (breathe effect)
125 | PulsatingProgress = 0.5f + 0.25f * (float)Math.Sin(_angle * 0.5);
126 |
127 | // Step progress animation
128 | if (_random.NextDouble() < 0.01) // Randomly increment
129 | {
130 | StepProgress = Math.Min(1.0f, StepProgress + _random.Next(1, 5) * 0.05f);
131 | }
132 |
133 | if (StepProgress >= 1.0f && _random.NextDouble() < 0.05) // Reset if full
134 | {
135 | StepProgress = 0.0f;
136 | }
137 | }
138 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/Settings/SettingsPage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
12 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/Settings/SettingsPage.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace CraftUI.Demo.Presentation.Pages.Settings;
2 |
3 | public partial class SettingsPage
4 | {
5 | public SettingsPage(SettingsPageViewModel viewModel)
6 | {
7 | InitializeComponent();
8 | BindingContext = viewModel;
9 | }
10 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/Settings/SettingsPageViewModel.cs:
--------------------------------------------------------------------------------
1 | using CraftUI.Demo.Presentation.Common;
2 | using Microsoft.Extensions.Logging;
3 |
4 | namespace CraftUI.Demo.Presentation.Pages.Settings;
5 |
6 | public class SettingsPageViewModel : ViewModelBase
7 | {
8 | private readonly ILogger _logger;
9 |
10 | public SettingsPageViewModel(
11 | ILogger logger)
12 | {
13 | _logger = logger;
14 |
15 | _logger.LogInformation("Building SettingsPageViewModel");
16 | }
17 |
18 | public override void ApplyQueryAttributes(IDictionary query)
19 | {
20 | _logger.LogInformation("ApplyQueryAttributes( query: {Query} )", query);
21 |
22 | base.ApplyQueryAttributes(query);
23 | }
24 |
25 | public override void OnAppearing()
26 | {
27 | _logger.LogInformation("OnAppearing()");
28 |
29 | base.OnAppearing();
30 | }
31 |
32 | public override void OnDisappearing()
33 | {
34 | _logger.LogInformation("OnDisappearing()");
35 |
36 | base.OnDisappearing();
37 | }
38 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/UseCases/UseCasesList.xaml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
12 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/UseCases/UseCasesList.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace CraftUI.Demo.Presentation.Pages.UseCases;
2 |
3 | public partial class UseCasesList
4 | {
5 | public UseCasesList(UseCasesListViewModel viewModel)
6 | {
7 | InitializeComponent();
8 | BindingContext = viewModel;
9 | }
10 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Presentation/Pages/UseCases/UseCasesListViewModel.cs:
--------------------------------------------------------------------------------
1 | using CraftUI.Demo.Application.Common.Interfaces.Infrastructure;
2 | using CraftUI.Demo.Presentation.Common;
3 | using Microsoft.Extensions.Logging;
4 |
5 | namespace CraftUI.Demo.Presentation.Pages.UseCases;
6 |
7 | public partial class UseCasesListViewModel : ViewModelBase
8 | {
9 | private readonly ILogger _logger;
10 | private readonly INavigationService _navigationService;
11 |
12 | public UseCasesListViewModel(
13 | ILogger logger,
14 | INavigationService navigationService)
15 | {
16 | _logger = logger;
17 | _navigationService = navigationService;
18 |
19 | _logger.LogInformation("Building MainPageViewModel");
20 | }
21 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "Windows Machine": {
4 | "commandName": "MsixPackage",
5 | "nativeDebugging": false
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Resources/AppIcon/appicon.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Resources/Fonts/OpenSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StephanArnas/CraftUI/aaea85d1b073e5e0f0401783c17fc9b7738d0652/src/CraftUI.Demo/Resources/Fonts/OpenSans-Regular.ttf
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Resources/Fonts/OpenSans-Semibold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StephanArnas/CraftUI/aaea85d1b073e5e0f0401783c17fc9b7738d0652/src/CraftUI.Demo/Resources/Fonts/OpenSans-Semibold.ttf
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Resources/Images/chevron_bottom.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Resources/Images/close.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Resources/Images/demo_code.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Resources/Images/demo_cog.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Resources/Images/demo_date_picker.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Resources/Images/demo_hand_click.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Resources/Images/demo_info.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Resources/Images/demo_input.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Resources/Images/demo_new_window.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Resources/Images/demo_picker.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Resources/Images/demo_progress_bar.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Resources/Images/demo_use_cases.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Resources/Images/demo_work_in_progress.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/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 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Resources/Splash/splash.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Resources/Styles/Buttons.xaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
13 |
14 |
18 |
19 |
23 |
24 |
28 |
29 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Resources/Styles/Colors.xaml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 | #4F46E5
10 | #818CF8
11 | #9333EA
12 | #C084FC
13 |
14 | #E00034
15 | #528922
16 | #DD732D
17 |
18 | White
19 | Black
20 | #D600AA
21 | #190649
22 | #1f1f1f
23 |
24 | #F8FAFC
25 | #0e0e0e
26 | White
27 | Black
28 |
29 | #E1E1E1
30 | #C8C8C8
31 | #ACACAC
32 | #919191
33 | #6E6E6E
34 | #404040
35 | #212121
36 | #141414
37 |
38 |
39 | #EEF2FF
40 | #E0E7FF
41 | #C7D2FE
42 | #A5B4FC
43 | #818CF8
44 | #6366F1
45 | #4F46E5
46 | #4338CA
47 | #3730A3
48 | #312E81
49 | #1E1B4B
50 |
51 | #FAF5FF
52 | #F3E8FF
53 | #E9D5FF
54 | #D8B4FE
55 | #C084FC
56 | #A855F7
57 | #9333EA
58 | #7E22CE
59 | #6D28D9
60 | #581C87
61 | #3B0764
62 |
63 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Resources/Styles/CustomControls.xaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
25 |
26 |
--------------------------------------------------------------------------------
/src/CraftUI.Demo/Resources/Styles/Layouts.xaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
8 |
9 |
15 |
16 |
31 |
32 |
--------------------------------------------------------------------------------
/src/CraftUI.Library.Maui/Common/Extensions/BaseLabelExtension.cs:
--------------------------------------------------------------------------------
1 | namespace CraftUI.Library.Maui.Common.Extensions;
2 |
3 | public static class BaseLabelExtension
4 | {
5 | public static void SetVisualElementBinding(this VisualElement visualElement)
6 | {
7 | visualElement.SetBinding(VisualElement.IsEnabledProperty, "IsEnabled", BindingMode.TwoWay);
8 | visualElement.SetBinding(VisualElement.IsVisibleProperty, "IsVisible", BindingMode.TwoWay);
9 | }
10 | }
--------------------------------------------------------------------------------
/src/CraftUI.Library.Maui/Common/Extensions/ObjectExtension.cs:
--------------------------------------------------------------------------------
1 | namespace CraftUI.Library.Maui.Common.Extensions;
2 |
3 | public static class ObjectExtension
4 | {
5 | public static T GetPropertyValue(this object? item, string? propertyName)
6 | {
7 | ArgumentNullException.ThrowIfNull(item);
8 |
9 | if (string.IsNullOrEmpty(propertyName))
10 | {
11 | throw new ArgumentNullException(nameof(propertyName));
12 | }
13 |
14 | var type = item.GetType();
15 | var propertyInfo = type.GetProperty(propertyName);
16 |
17 | if (propertyInfo == null)
18 | {
19 | throw new ArgumentException($"Property {propertyName} was not found in the object {type.Name}");
20 | }
21 |
22 | return (T)propertyInfo.GetValue(item)!;
23 | }
24 |
25 | public static string? GetDisplayString(this object? item, string? propertyName)
26 | {
27 | if (item == null || string.IsNullOrEmpty(propertyName))
28 | {
29 | return item?.ToString();
30 | }
31 |
32 | var prop = item.GetType().GetProperty(propertyName);
33 | return prop?.GetValue(item)?.ToString();
34 | }
35 | }
--------------------------------------------------------------------------------
/src/CraftUI.Library.Maui/Common/Helpers/ResourceHelper.cs:
--------------------------------------------------------------------------------
1 | namespace CraftUI.Library.Maui.Common.Helpers;
2 |
3 | public static class ResourceHelper
4 | {
5 | public static T GetResource(string key)
6 | {
7 | if (Application.Current!.Resources.TryGetValue(key, out var value))
8 | {
9 | return (T)value;
10 | }
11 |
12 | throw new InvalidOperationException($"key {key} not found in the resource dictionary");
13 | }
14 |
15 | public static Color GetThemeColor(string lightKey, string darkKey)
16 | {
17 | return Application.Current!.RequestedTheme switch
18 | {
19 | AppTheme.Dark => GetResource(darkKey),
20 | AppTheme.Light => GetResource(lightKey),
21 | _ => GetResource(lightKey)
22 | };
23 | }
24 | }
--------------------------------------------------------------------------------
/src/CraftUI.Library.Maui/Common/Helpers/ViewHelper.cs:
--------------------------------------------------------------------------------
1 | namespace CraftUI.Library.Maui.Common.Helpers;
2 |
3 | public static class ViewHelper
4 | {
5 | public static bool ValidateCustomView(BindableObject bindable, object value)
6 | {
7 | if (value is not View)
8 | {
9 | throw new InvalidOperationException("Only View allowed");
10 | }
11 |
12 | return true;
13 | }
14 | }
--------------------------------------------------------------------------------
/src/CraftUI.Library.Maui/Common/LabelBase.xaml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
18 |
26 |
30 |
36 |
37 |
38 |
39 |
42 |
43 |
45 |
46 |
47 |
49 |
50 |
52 |
53 |
57 |
58 |
62 |
63 |
75 |
76 |
84 |
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/src/CraftUI.Library.Maui/Common/LabelBase.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Input;
2 | using SkiaSharp;
3 | using SkiaSharp.Views.Maui;
4 | using CraftUI.Library.Maui.Common.Helpers;
5 |
6 | namespace CraftUI.Library.Maui.Common;
7 |
8 | public partial class LabelBase
9 | {
10 | public static readonly BindableProperty ViewProperty = BindableProperty.Create(nameof(View), typeof(View), typeof(LabelBase), defaultValue: null, BindingMode.OneWay, ViewHelper.ValidateCustomView, ElementChanged);
11 | public static readonly BindableProperty IsRequiredProperty = BindableProperty.Create(nameof(IsRequired), typeof(bool), typeof(LabelBase), defaultValue: false, propertyChanged: IsRequiredChanged);
12 | public static readonly BindableProperty LabelProperty = BindableProperty.Create(nameof(Label), typeof(string), typeof(LabelBase), propertyChanged: LabelChanged);
13 | public static readonly BindableProperty InfoProperty = BindableProperty.Create(nameof(Info), typeof(string), typeof(LabelBase), propertyChanged: InfoChanged);
14 | public static readonly BindableProperty ErrorProperty = BindableProperty.Create(nameof(Error), typeof(string), typeof(LabelBase), propertyChanged: ErrorChanged);
15 | public static readonly BindableProperty IsLoadingProperty = BindableProperty.Create(nameof(IsLoading), typeof(bool), typeof(LabelBase), defaultValue: false, propertyChanged: IsLoadingChanged);
16 | public static readonly BindableProperty ActionIconSourceProperty = BindableProperty.Create(nameof(ActionIconSource), typeof(ImageSource), typeof(LabelBase), defaultValue: null, propertyChanged: ActionIconSourceChanged);
17 | public static readonly BindableProperty ActionIconCommandProperty = BindableProperty.Create(nameof(ActionIconCommand), typeof(ICommand), typeof(LabelBase), defaultValue: null);
18 |
19 | public View View
20 | {
21 | get => (View)GetValue(ViewProperty);
22 | set => SetValue(ViewProperty, value);
23 | }
24 |
25 | public bool IsRequired
26 | {
27 | get => (bool)GetValue(IsRequiredProperty);
28 | set => SetValue(IsRequiredProperty, value);
29 | }
30 |
31 | public string Label
32 | {
33 | get => (string)GetValue(LabelProperty);
34 | set => SetValue(LabelProperty, value);
35 | }
36 |
37 | public string Info
38 | {
39 | get => (string)GetValue(InfoProperty);
40 | set => SetValue(InfoProperty, value);
41 | }
42 |
43 | public string Error
44 | {
45 | get => (string)GetValue(ErrorProperty);
46 | set => SetValue(ErrorProperty, value);
47 | }
48 |
49 | public bool IsLoading
50 | {
51 | get => (bool)GetValue(IsLoadingProperty);
52 | set => SetValue(IsLoadingProperty, value);
53 | }
54 |
55 | public ImageSource? ActionIconSource
56 | {
57 | get => (ImageSource?)GetValue(ActionIconSourceProperty);
58 | set => SetValue(ActionIconSourceProperty, value);
59 | }
60 |
61 | public ICommand? ActionIconCommand
62 | {
63 | get => (ICommand?)GetValue(ActionIconCommandProperty);
64 | set => SetValue(ActionIconCommandProperty, value);
65 | }
66 |
67 | public LabelBase()
68 | {
69 | InitializeComponent();
70 | }
71 |
72 | private static void ElementChanged(BindableObject bindable, object oldValue, object newValue) => ((LabelBase)bindable).UpdateElementView();
73 | private static void IsRequiredChanged(BindableObject bindable, object oldValue, object newValue) => ((LabelBase)bindable).UpdateIsRequiredView();
74 | private static void LabelChanged(BindableObject bindable, object oldValue, object newValue) => ((LabelBase)bindable).UpdateLabelView();
75 | private static void InfoChanged(BindableObject bindable, object oldValue, object newValue) => ((LabelBase)bindable).UpdateInfoView();
76 | private static void ErrorChanged(BindableObject bindable, object oldValue, object newValue) => ((LabelBase)bindable).UpdateErrorView();
77 | private static void IsLoadingChanged(BindableObject bindable, object oldValue, object newValue) => ((LabelBase)bindable).UpdateIsLoadingView();
78 | private static void ActionIconSourceChanged(BindableObject bindable, object oldValue, object newValue) => ((LabelBase)bindable).UpdateActionIconSourceView();
79 |
80 | private void UpdateElementView()
81 | {
82 | BorderLabel.Content = View;
83 | UpdateIsRequiredView();
84 | }
85 |
86 | private void UpdateIsRequiredView()
87 | {
88 | RequiredLabel.IsVisible = IsRequired;
89 | }
90 |
91 | private void UpdateLabelView()
92 | {
93 | LabelLabel.Text = Label;
94 | LabelLabel.IsVisible = !string.IsNullOrEmpty(Label);
95 | }
96 |
97 | private void UpdateInfoView()
98 | {
99 | InfoLabel.Text = Info;
100 | InfoLabel.IsVisible = !string.IsNullOrEmpty(Info);
101 | }
102 |
103 | private void UpdateErrorView()
104 | {
105 | ErrorLabel.Text = Error;
106 | ErrorLabel.IsVisible = !string.IsNullOrEmpty(Error);
107 | InvalidateSurfaceForCanvasView();
108 | }
109 |
110 | private void UpdateIsLoadingView()
111 | {
112 | LoaderActivityIndicator.IsVisible = IsLoading;
113 | LoaderActivityIndicator.IsRunning = IsLoading;
114 |
115 | if (ActionIconSource is not null)
116 | {
117 | ActionIconButton.IsVisible = !IsLoading;
118 | }
119 | }
120 |
121 | private void UpdateActionIconSourceView()
122 | {
123 | ActionIconButton.IsVisible = ActionIconSource is not null;
124 | ActionIconButton.Source = ActionIconSource;
125 | }
126 |
127 | private void OnActionIconTapped(object sender, EventArgs e)
128 | {
129 | if (ActionIconCommand?.CanExecute(null) == true)
130 | {
131 | ActionIconCommand.Execute(null);
132 | }
133 | }
134 |
135 | protected override void OnBindingContextChanged()
136 | {
137 | base.OnBindingContextChanged();
138 | InvalidateSurfaceForCanvasView();
139 | }
140 |
141 | protected void PlatformSizeChangedCanvasView()
142 | {
143 | BorderCanvasView.InvalidateMeasure();
144 | BorderCanvasView.PlatformSizeChanged();
145 | }
146 |
147 | protected void InvalidateSurfaceForCanvasView()
148 | {
149 | BorderCanvasView.InvalidateSurface();
150 | }
151 |
152 | private void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs e)
153 | {
154 | // System.Diagnostics.Debug.WriteLine($"SKCanvasView: {BorderCanvasView.Width}x{BorderCanvasView.Height}, SKInfo: {e.Info.Width}x{e.Info.Height}");
155 |
156 | var canvas = e.Surface.Canvas;
157 | canvas.Clear(); // Clear the canvas
158 |
159 | var paint = new SKPaint
160 | {
161 | Style = SKPaintStyle.Stroke,
162 | StrokeWidth = 3,
163 | IsAntialias = true // Smooth edges
164 | };
165 |
166 | paint.Color = !string.IsNullOrEmpty(Error)
167 | ? ResourceHelper.GetResource("Danger").ToSKColor()
168 | : ResourceHelper.GetThemeColor("Gray900", "Gray100").ToSKColor();
169 |
170 | const float radius = 20f; // Corner radius
171 | const float labelExtraSpace = 8; // Fixed length for the segment
172 | float borderThickness = paint.StrokeWidth / 2;
173 |
174 | // Define the full rectangle based on the canvas size
175 | var rect = new SKRect(
176 | borderThickness,
177 | borderThickness,
178 | e.Info.Width - borderThickness,
179 | e.Info.Height - borderThickness
180 | );
181 |
182 | // Measure the Label's width
183 | float labelWidth = (float)LabelLabel.Width * e.Info.Width / (float)BorderCanvasView.Width;
184 |
185 | // Measure the RequiredLabel's width
186 | float isRequiredWidth = RequiredLabel.IsVisible ? (float)RequiredLabel.Width * e.Info.Width / (float)BorderCanvasView.Width : 0;
187 |
188 | // Calculate endX correctly
189 | float topLineRightSegmentStartX =
190 | rect.Left + radius + labelExtraSpace + isRequiredWidth + labelWidth + labelExtraSpace;
191 |
192 | // Draw the top-left arc
193 | canvas.DrawArc(new SKRect(rect.Left, rect.Top, rect.Left + 2 * radius, rect.Top + 2 * radius), startAngle: 180, sweepAngle: 90, useCenter: false, paint);
194 |
195 | // Draw the top-right arc
196 | canvas.DrawArc(new SKRect(rect.Right - 2 * radius, rect.Top, rect.Right, rect.Top + 2 * radius), startAngle: 270, sweepAngle: 90, useCenter: false, paint);
197 |
198 | // Draw the bottom-right arc
199 | canvas.DrawArc(new SKRect(rect.Right - 2 * radius, rect.Bottom - 2 * radius, rect.Right, rect.Bottom), startAngle: 0, sweepAngle: 90, useCenter: false, paint);
200 |
201 | // Draw the bottom-left arc
202 | canvas.DrawArc(new SKRect(rect.Left, rect.Bottom - 2 * radius, rect.Left + 2 * radius, rect.Bottom), startAngle: 90, sweepAngle: 90, useCenter: false, paint);
203 |
204 | // Draw the left segment of the top line with a fixed length of 10 units
205 | canvas.DrawLine(rect.Left + radius, rect.Top, rect.Left + radius + labelExtraSpace, rect.Top, paint);
206 |
207 | // Draw the right segment of the top line from the end of the label to the top-right arc
208 | canvas.DrawLine(topLineRightSegmentStartX, rect.Top, rect.Right - radius, rect.Top, paint);
209 |
210 | // Draw the right line between the top-right and bottom-right arcs
211 | canvas.DrawLine(rect.Right, rect.Top + radius, rect.Right, rect.Bottom - radius, paint);
212 |
213 | // Draw the bottom line between the bottom-right and bottom-left arcs
214 | canvas.DrawLine(rect.Left + radius, rect.Bottom, rect.Right - radius, rect.Bottom, paint);
215 |
216 | // Draw the left line between the bottom-left and top-left arcs
217 | canvas.DrawLine(rect.Left, rect.Top + radius, rect.Left, rect.Bottom - radius, paint);
218 | }
219 | }
--------------------------------------------------------------------------------
/src/CraftUI.Library.Maui/Common/Resources/ColorResources.cs:
--------------------------------------------------------------------------------
1 | namespace CraftUI.Library.Maui.Common.Resources;
2 |
3 | public static class ColorResources
4 | {
5 | public const string Primary50 = "Primary50";
6 | public const string Primary100 = "Primary100";
7 | public const string Primary200 = "Primary200";
8 | public const string Primary300 = "Primary300";
9 | public const string Primary400 = "Primary400";
10 | public const string Primary500 = "Primary500";
11 | public const string Primary600 = "Primary600";
12 | public const string Primary700 = "Primary700";
13 | public const string Primary800 = "Primary800";
14 | public const string Primary900 = "Primary900";
15 | public const string Primary950 = "Primary950";
16 | }
--------------------------------------------------------------------------------
/src/CraftUI.Library.Maui/Controls/CfButton.xaml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
13 |
14 |
22 |
23 |
--------------------------------------------------------------------------------
/src/CraftUI.Library.Maui/Controls/CfButton.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Input;
2 |
3 | namespace CraftUI.Library.Maui.Controls;
4 |
5 | public partial class CfButton
6 | {
7 | private const string LowerKey = "lower";
8 | private const string UpperKey = "upper";
9 |
10 | private readonly Animation _lowerAnimation;
11 | private readonly Animation _upperAnimation;
12 |
13 | public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(CfButton), defaultBindingMode: BindingMode.OneWay);
14 | public static readonly BindableProperty IsLoadingProperty = BindableProperty.Create(nameof(IsLoading), typeof(bool), typeof(CfButton), defaultBindingMode: BindingMode.OneWay, propertyChanged: IsLoadingChanged);
15 | public static readonly BindableProperty CommandProperty = BindableProperty.Create(nameof(Command), typeof(ICommand), typeof(CfButton));
16 | public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create(nameof(CommandParameter), typeof(object), typeof(CfButton));
17 | public static readonly BindableProperty TextColorProperty = BindableProperty.Create(nameof(TextColor), typeof(object), typeof(CfButton));
18 |
19 | public string Text
20 | {
21 | get => (string)GetValue(TextProperty);
22 | set => SetValue(TextProperty, value);
23 | }
24 |
25 | public bool IsLoading
26 | {
27 | get => (bool)GetValue(IsLoadingProperty);
28 | set => SetValue(IsLoadingProperty, value);
29 | }
30 |
31 | public ICommand? Command
32 | {
33 | get => (ICommand?)GetValue(CommandProperty);
34 | set => SetValue(CommandProperty, value);
35 | }
36 |
37 | public object? CommandParameter
38 | {
39 | get => GetValue(CommandParameterProperty);
40 | set => SetValue(CommandParameterProperty, value);
41 | }
42 |
43 | public Color TextColor
44 | {
45 | get => (Color)GetValue(TextColorProperty);
46 | set => SetValue(TextColorProperty, value);
47 | }
48 |
49 | public CfButton()
50 | {
51 | InitializeComponent();
52 |
53 | _lowerAnimation = new Animation(v => AnimatedProgressBar.LowerRangeValue = (float)v, start: -0.4, end: 1.0);
54 | _upperAnimation = new Animation(v => AnimatedProgressBar.UpperRangeValue = (float)v, start: 0.0, end: 1.4);
55 | }
56 |
57 | protected override void OnPropertyChanged(string? propertyName = null)
58 | {
59 | base.OnPropertyChanged(propertyName);
60 |
61 | if (propertyName == IsEnabledProperty.PropertyName)
62 | {
63 | Button.IsEnabled = IsEnabled;
64 | }
65 | else if (propertyName == BackgroundColorProperty.PropertyName)
66 | {
67 | Button.BackgroundColor = BackgroundColor;
68 | }
69 | else if (propertyName == TextColorProperty.PropertyName)
70 | {
71 | AnimatedProgressBar.ProgressColor = TextColor;
72 | Button.TextColor = TextColor;
73 | }
74 | else if (propertyName == TextProperty.PropertyName)
75 | {
76 | Button.Text = Text;
77 | }
78 | }
79 |
80 | private static void IsLoadingChanged(BindableObject bindable, object oldValue, object newValue) => ((CfButton)bindable).UpdateIsLoadingView();
81 |
82 | private void Button_OnClicked(object? sender, EventArgs e)
83 | {
84 | if (Command != null && Command.CanExecute(CommandParameter))
85 | {
86 | Command.Execute(CommandParameter);
87 | }
88 | }
89 |
90 | private void UpdateIsLoadingView()
91 | {
92 | Button.IsEnabled = !IsLoading;
93 | AnimatedProgressBar.IsVisible = IsLoading;
94 |
95 | if (IsLoading)
96 | {
97 | _lowerAnimation.Commit(owner: this, name: LowerKey, length: 1000, easing: Easing.CubicInOut, repeat: () => true);
98 | _upperAnimation.Commit(owner: this, name: UpperKey, length: 1000, easing: Easing.CubicInOut, repeat: () => true);
99 | }
100 | else
101 | {
102 | this.AbortAnimation(handle: LowerKey);
103 | this.AbortAnimation(handle: UpperKey);
104 | }
105 | }
106 | }
--------------------------------------------------------------------------------
/src/CraftUI.Library.Maui/Controls/CfDatePicker.xaml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 |
16 |
17 |
18 |
19 |
20 |
21 |
23 |
24 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/CraftUI.Library.Maui/Controls/CfDatePicker.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace CraftUI.Library.Maui.Controls;
2 |
3 | public partial class CfDatePicker
4 | {
5 | public static readonly BindableProperty PlaceHolderProperty = BindableProperty.Create(nameof(PlaceHolder), typeof(string), typeof(CfDatePicker), defaultValue: "/ . / . /");
6 | public static readonly BindableProperty NullableDateProperty = BindableProperty.Create(nameof(NullableDate), typeof(DateTime?), typeof(CfDatePicker), defaultValue: null, defaultBindingMode: BindingMode.TwoWay);
7 | public static readonly BindableProperty FormatProperty = BindableProperty.Create(nameof(Format), typeof(string), typeof(CfDatePicker), defaultValue: "d", propertyChanged: OnFormatChanged);
8 | public static readonly BindableProperty MinimumDateProperty = BindableProperty.Create(nameof(MinimumDate), typeof(DateTime), typeof(CfDatePicker), propertyChanged: OnMinimumDateChanged);
9 | public static readonly BindableProperty MaximumDateProperty = BindableProperty.Create(nameof(MaximumDate), typeof(DateTime), typeof(CfDatePicker), propertyChanged: OnMaximumDateChanged);
10 | public static readonly BindableProperty ShowClearButtonProperty = BindableProperty.Create(nameof(ShowClearButton), typeof(bool), typeof(CfDatePicker), defaultValue: true, propertyChanged: OnShowClearButtonChanged);
11 |
12 | public string PlaceHolder
13 | {
14 | get => (string)GetValue(PlaceHolderProperty);
15 | set => SetValue(PlaceHolderProperty, value);
16 | }
17 |
18 | public DateTime? NullableDate
19 | {
20 | get => (DateTime?)GetValue(NullableDateProperty);
21 | set => SetValue(NullableDateProperty, value);
22 | }
23 |
24 | public string Format
25 | {
26 | get => (string)GetValue(FormatProperty);
27 | set => SetValue(FormatProperty, value);
28 | }
29 |
30 | public DateTime MinimumDate
31 | {
32 | get => (DateTime)GetValue(MinimumDateProperty);
33 | set => SetValue(MinimumDateProperty, value);
34 | }
35 |
36 | public DateTime MaximumDate
37 | {
38 | get => (DateTime)GetValue(MaximumDateProperty);
39 | set => SetValue(MaximumDateProperty, value);
40 | }
41 |
42 | public bool ShowClearButton
43 | {
44 | get => (bool)GetValue(ShowClearButtonProperty);
45 | set => SetValue(ShowClearButtonProperty, value);
46 | }
47 |
48 | public CfDatePicker()
49 | {
50 | InitializeComponent();
51 | Element.DateSelected += OnDateSelected;
52 |
53 | var tapped = new TapGestureRecognizer();
54 | tapped.Tapped += (_, _) =>
55 | {
56 | Element.Date = DateTime.Today;
57 | NullableDate = null;
58 | };
59 | CloseImage.GestureRecognizers.Add(tapped);
60 | }
61 |
62 | private static void OnFormatChanged(BindableObject bindable, object oldValue, object newValue) => ((CfDatePicker)bindable).OnFormatChanged();
63 | private static void OnMinimumDateChanged(BindableObject bindable, object oldValue, object newValue) => ((CfDatePicker)bindable).OnMinimumDateChanged();
64 | private static void OnMaximumDateChanged(BindableObject bindable, object oldValue, object newValue) => ((CfDatePicker)bindable).OnMaximumDateChanged();
65 | private static void OnShowClearButtonChanged(BindableObject bindable, object oldValue, object newValue) => ((CfDatePicker)bindable).UpdateClearButtonVisibility();
66 |
67 | private void OnDateSelected(object? sender, DateChangedEventArgs e)
68 | {
69 | NullableDate = e.NewDate;
70 | }
71 |
72 | protected override void OnBindingContextChanged()
73 | {
74 | base.OnBindingContextChanged();
75 |
76 | if (BindingContext != null)
77 | {
78 | Element.Format = PlaceHolder;
79 | }
80 | }
81 |
82 | protected override void OnPropertyChanged(string? propertyName = null)
83 | {
84 | base.OnPropertyChanged(propertyName);
85 |
86 | if (propertyName == NullableDateProperty.PropertyName)
87 | {
88 | if (NullableDate.HasValue)
89 | {
90 | Element.Date = NullableDate.Value;
91 | }
92 |
93 | UpdateDateView();
94 | }
95 | }
96 |
97 | public void OnFormatChanged()
98 | {
99 | Element.Format = Format;
100 | UpdateDateView();
101 | }
102 |
103 | public void OnMinimumDateChanged()
104 | {
105 | Element.MinimumDate = MinimumDate;
106 | }
107 |
108 | public void OnMaximumDateChanged()
109 | {
110 | Element.MaximumDate = MaximumDate;
111 | }
112 |
113 | private void UpdateClearButtonVisibility()
114 | {
115 | CloseImage.IsVisible = ShowClearButton;
116 | }
117 |
118 | private void UpdateDateView()
119 | {
120 | if (NullableDate.HasValue)
121 | {
122 | Element.Date = NullableDate.Value;
123 | Element.Format = Format;
124 | }
125 | else
126 | {
127 | Element.Format = PlaceHolder;
128 | }
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/src/CraftUI.Library.Maui/Controls/CfDatePickerInternal.cs:
--------------------------------------------------------------------------------
1 | namespace CraftUI.Library.Maui.Controls;
2 |
3 | ///
4 | /// This control exists to avoid the issue of DatePicker setting the date today when the date is set today.
5 | /// Source: https://github.com/dotnet/maui/issues/13156
6 | ///
7 | public class CfDatePickerInternal : DatePicker, IDatePicker
8 | {
9 | DateTime IDatePicker.Date
10 | {
11 | get => Date;
12 | set
13 | {
14 | if (value.Equals(DateTime.Today.Date))
15 | {
16 | Date = value.AddDays(-1);
17 | }
18 |
19 | Date = value;
20 | OnPropertyChanged();
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/src/CraftUI.Library.Maui/Controls/CfEntry.xaml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/CraftUI.Library.Maui/Controls/CfEntry.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Input;
2 | using CraftUI.Library.Maui.Common.Extensions;
3 |
4 | namespace CraftUI.Library.Maui.Controls;
5 |
6 | public partial class CfEntry
7 | {
8 | public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(CfEntry), propertyChanged: TextChanged, defaultBindingMode: BindingMode.TwoWay);
9 | public static readonly BindableProperty PlaceholderProperty = BindableProperty.Create(nameof(Placeholder), typeof(string), typeof(CfEntry), propertyChanged: PlaceholderChanged);
10 | public static readonly BindableProperty KeyboardProperty = BindableProperty.Create(nameof(Keyboard), typeof(Keyboard), typeof(CfEntry), defaultValue: Keyboard.Plain, propertyChanged: KeyboardChanged);
11 | public static readonly BindableProperty ReturnTypeProperty = BindableProperty.Create(nameof(ReturnType), typeof(ReturnType), typeof(CfEntry), defaultValue: ReturnType.Done, propertyChanged: ReturnTypeChanged);
12 | public static readonly BindableProperty ReturnCommandProperty = BindableProperty.Create(nameof(ReturnCommand), typeof(ICommand), typeof(CfEntry), defaultValue: null, propertyChanged: ReturnCommandChanged);
13 | public static readonly BindableProperty TextTransformProperty = BindableProperty.Create(nameof(TextTransform), typeof(TextTransform), typeof(CfEntry), defaultValue: TextTransform.Default, propertyChanged: TextTransformChanged);
14 | public static readonly BindableProperty IsReadOnlyProperty = BindableProperty.Create(nameof(IsReadOnly), typeof(bool), typeof(CfEntry), false, propertyChanged: IsReadOnlyChanged);
15 |
16 | public string Text
17 | {
18 | get => (string)GetValue(TextProperty);
19 | set => SetValue(TextProperty, value);
20 | }
21 |
22 | public string Placeholder
23 | {
24 | get => (string)GetValue(PlaceholderProperty);
25 | set => SetValue(PlaceholderProperty, value);
26 | }
27 |
28 | public Keyboard Keyboard
29 | {
30 | get => (Keyboard)GetValue(KeyboardProperty);
31 | set => SetValue(KeyboardProperty, value);
32 | }
33 |
34 | public ReturnType ReturnType
35 | {
36 | get => (ReturnType)GetValue(ReturnTypeProperty);
37 | set => SetValue(ReturnTypeProperty, value);
38 | }
39 |
40 | public ICommand ReturnCommand
41 | {
42 | get => (ICommand)GetValue(ReturnCommandProperty);
43 | set => SetValue(ReturnCommandProperty, value);
44 | }
45 |
46 | public TextTransform TextTransform
47 | {
48 | get => (TextTransform)GetValue(TextTransformProperty);
49 | set => SetValue(TextTransformProperty, value);
50 | }
51 |
52 | public bool IsReadOnly
53 | {
54 | get => (bool)GetValue(IsReadOnlyProperty);
55 | set => SetValue(IsReadOnlyProperty, value);
56 | }
57 |
58 | public CfEntry()
59 | {
60 | InitializeComponent();
61 |
62 | Element.SetVisualElementBinding();
63 | Element.SetBinding(Entry.TextProperty, nameof(Text), BindingMode.TwoWay);
64 | Element.BindingContext = this;
65 | }
66 |
67 | protected override void OnPropertyChanged(string? propertyName = null)
68 | {
69 | if (propertyName == IsEnabledProperty.PropertyName)
70 | {
71 | Element.IsEnabled = IsEnabled;
72 | }
73 | }
74 |
75 | private static void TextChanged(BindableObject bindable, object oldValue, object newValue) => ((CfEntry)bindable).UpdateTextView();
76 | private static void PlaceholderChanged(BindableObject bindable, object oldValue, object newValue) => ((CfEntry)bindable).UpdatePlaceholderView();
77 | private static void KeyboardChanged(BindableObject bindable, object oldValue, object newValue) => ((CfEntry)bindable).UpdateKeyboardView();
78 | private static void ReturnTypeChanged(BindableObject bindable, object oldValue, object newValue) => ((CfEntry)bindable).UpdateReturnTypeView();
79 | private static void ReturnCommandChanged(BindableObject bindable, object oldValue, object newValue) => ((CfEntry)bindable).UpdateReturnCommandView();
80 | private static void TextTransformChanged(BindableObject bindable, object oldValue, object newValue) => ((CfEntry)bindable).UpdateTextTransformView();
81 | private static void IsReadOnlyChanged(BindableObject bindable, object oldValue, object newValue) => ((CfEntry)bindable).UpdateIsReadOnlyView();
82 |
83 | private void UpdateTextView()
84 | {
85 | if (Keyboard == Keyboard.Numeric)
86 | {
87 | if (string.IsNullOrEmpty(Text))
88 | {
89 | Element.Text = Text;
90 | return;
91 | }
92 |
93 | Element.Text = int.TryParse(Text, out var number)
94 | ? number.ToString()
95 | : Text[..^1];
96 | }
97 | else
98 | {
99 | Element.Text = Text;
100 | }
101 | }
102 |
103 | private void UpdatePlaceholderView() => Element.Placeholder = Placeholder;
104 | private void UpdateKeyboardView() => Element.Keyboard = Keyboard;
105 | private void UpdateReturnTypeView() => Element.ReturnType = ReturnType;
106 | private void UpdateReturnCommandView() => Element.ReturnCommand = ReturnCommand;
107 | private void UpdateTextTransformView() => Element.TextTransform = TextTransform;
108 | private void UpdateIsReadOnlyView() => Element.IsReadOnly = IsReadOnly;
109 | }
--------------------------------------------------------------------------------
/src/CraftUI.Library.Maui/Controls/CfMultiPickerPopup.xaml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 |
19 |
20 |
21 |
22 |
31 |
32 |
33 |
39 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/src/CraftUI.Library.Maui/Controls/CfMultiPickerPopup.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.ObjectModel;
3 | using System.Collections.Specialized;
4 | using CommunityToolkit.Maui.Views;
5 | using CraftUI.Library.Maui.Common.Extensions;
6 | using CraftUI.Library.Maui.Controls.Popups;
7 |
8 | namespace CraftUI.Library.Maui.Controls;
9 |
10 | public partial class CfMultiPickerPopup
11 | {
12 | private CfCollectionMultiSelectionPopup? _collectionPopup;
13 | private readonly TapGestureRecognizer _tapGestureRecognizer;
14 |
15 | public static readonly BindableProperty TitleProperty = BindableProperty.Create(nameof(Title), typeof(string), typeof(CfMultiPickerPopup));
16 | public static readonly BindableProperty SelectedItemsProperty = BindableProperty.Create(nameof(SelectedItems), typeof(ObservableCollection