2
0
Эх сурвалжийг харах

Add Community Toolkit example

John Baughman 1 жил өмнө
parent
commit
12adcf3bf4

+ 19 - 0
CommunityToolkitExample/CommunityToolkitExample.csproj

@@ -0,0 +1,19 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net8.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
+    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\Terminal.Gui\Terminal.Gui.csproj" />
+  </ItemGroup>
+
+</Project>

+ 7 - 0
CommunityToolkitExample/LoginAction.cs

@@ -0,0 +1,7 @@
+namespace CommunityToolkitExample;
+
+internal enum LoginAction
+{
+    Validation,
+    LoginProgress
+}

+ 62 - 0
CommunityToolkitExample/LoginView.Designer.cs

@@ -0,0 +1,62 @@
+using Terminal.Gui;
+
+namespace CommunityToolkitExample;
+
+internal partial class LoginView : Window
+{
+    private Label titleLabel;
+    private Label usernameLengthLabel;
+    private TextField usernameInput;
+    private Label passwordLengthLabel;
+    private TextField passwordInput;
+    private Label validationLabel;
+    private Button loginButton;
+    private Button clearButton;
+    private Label loginProgressLabel;
+
+    private void InitializeComponent ()
+    {
+        titleLabel = new Label ();
+        titleLabel.Text = "Login Form";
+        Add (titleLabel);
+        usernameLengthLabel = new Label ();
+        usernameLengthLabel.X = Pos.Left (titleLabel);
+        usernameLengthLabel.Y = Pos.Top (titleLabel) + 1;
+        Add (usernameLengthLabel);
+        usernameInput = new TextField ();
+        usernameInput.X = Pos.Right (usernameLengthLabel) + 1;
+        usernameInput.Y = Pos.Top (usernameLengthLabel);
+        usernameInput.Width = 40;
+        Add (usernameInput);
+        passwordLengthLabel = new Label ();
+        passwordLengthLabel.X = Pos.Left (usernameLengthLabel);
+        passwordLengthLabel.Y = Pos.Top (usernameLengthLabel) + 1;
+        Add (passwordLengthLabel);
+        passwordInput = new TextField ();
+        passwordInput.X = Pos.Right (passwordLengthLabel) + 1;
+        passwordInput.Y = Pos.Top (passwordLengthLabel);
+        passwordInput.Width = 40;
+        passwordInput.Secret = true;
+        Add (passwordInput);
+        validationLabel = new Label ();
+        validationLabel.X = Pos.Left (passwordInput);
+        validationLabel.Y = Pos.Top (passwordInput) + 1;
+        Add (validationLabel);
+        loginButton = new Button ();
+        loginButton.X = Pos.Left (validationLabel);
+        loginButton.Y = Pos.Top (validationLabel) + 1;
+        loginButton.Text = "_Login";
+        Add (loginButton);
+        clearButton = new Button ();
+        clearButton.X = Pos.Left (loginButton);
+        clearButton.Y = Pos.Top (loginButton) + 1;
+        clearButton.Text = "_Clear";
+        Add (clearButton);
+        loginProgressLabel = new Label ();
+        loginProgressLabel.X = Pos.Left (clearButton);
+        loginProgressLabel.Y = Pos.Top (clearButton) + 1;
+        loginProgressLabel.Width = 40;
+        loginProgressLabel.Height = 1;
+        Add (loginProgressLabel);
+    }
+}

+ 68 - 0
CommunityToolkitExample/LoginView.cs

@@ -0,0 +1,68 @@
+using CommunityToolkit.Mvvm.Messaging;
+using Terminal.Gui;
+
+namespace CommunityToolkitExample;
+
+internal partial class LoginView : IRecipient<Message<LoginAction>>
+{
+    public LoginView (LoginViewModel viewModel)
+    {
+        WeakReferenceMessenger.Default.Register (this);
+        Title = $"Community Toolkit MVVM Example - {Application.QuitKey} to Exit";
+        ViewModel = viewModel;
+        InitializeComponent ();
+        usernameInput.TextChanged += (_, _) =>
+                                     {
+                                         ViewModel.Username = usernameInput.Text;
+                                         SetText ();
+                                     };
+        passwordInput.TextChanged += (_, _) =>
+                                     {
+                                         ViewModel.Password = passwordInput.Text;
+                                         SetText ();
+                                     };
+        loginButton.Accept += (_, _) =>
+                              {
+                                  if (!ViewModel.CanLogin) { return; }
+                                  ViewModel.LoginCommand.Execute (null);
+                              };
+
+        clearButton.Accept += (_, _) =>
+                              {
+                                  ViewModel.ClearCommand.Execute (null);
+                                  SetText ();
+                              };
+
+        Initialized += (_, _) => { ViewModel.Initialized (); };
+    }
+
+    public LoginViewModel ViewModel { get; set; }
+
+    public void Receive (Message<LoginAction> message)
+    {
+        switch (message.Value)
+        {
+            case LoginAction.LoginProgress:
+                {
+                    loginProgressLabel.Text = ViewModel.LoginProgressMessage;
+                    break;
+                }
+            case LoginAction.Validation:
+                {
+                    validationLabel.Text = ViewModel.ValidationMessage;
+                    validationLabel.ColorScheme = ViewModel.ValidationColorScheme;
+                    break;
+                }
+        }
+        SetText();
+        Application.Refresh ();
+    }
+
+    private void SetText ()
+    {
+        usernameInput.Text = ViewModel.Username;
+        usernameLengthLabel.Text = ViewModel.UsernameLengthMessage;
+        passwordInput.Text = ViewModel.Password;
+        passwordLengthLabel.Text = ViewModel.PasswordLengthMessage;
+    }
+}

+ 118 - 0
CommunityToolkitExample/LoginViewModel.cs

@@ -0,0 +1,118 @@
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using CommunityToolkit.Mvvm.Messaging;
+using Terminal.Gui;
+
+namespace CommunityToolkitExample;
+
+internal partial class LoginViewModel : ObservableObject
+{
+    private const string DEFAULT_LOGIN_PROGRESS_MESSAGE = "Press 'Login' to log in.";
+    private const string LOGGING_IN_PROGRESS_MESSAGE = "Logging in...";
+    private const string VALID_LOGIN_MESSAGE = "The input is valid!";
+    private const string INVALID_LOGIN_MESSAGE = "Please enter a valid user name and password.";
+
+    [ObservableProperty]
+    private bool _canLogin;
+
+    private string _password;
+
+    [ObservableProperty]
+    private string _passwordLengthMessage;
+
+    private string _username;
+
+    [ObservableProperty]
+    private string _usernameLengthMessage;
+
+    [ObservableProperty]
+    private string _loginProgressMessage;
+
+    [ObservableProperty]
+    private string _validationMessage;
+
+    [ObservableProperty]
+    private ColorScheme? _validationColorScheme;
+
+    public LoginViewModel ()
+    {
+        Username = string.Empty;
+        Password = string.Empty;
+
+        ClearCommand = new (Clear);
+        LoginCommand = new (Execute);
+
+        Clear ();
+
+        return;
+
+        async void Execute () { await Login (); }
+    }
+
+    public RelayCommand ClearCommand { get; }
+
+    public RelayCommand LoginCommand { get; }
+
+    public string Password
+    {
+        get => _password;
+        set
+        {
+            SetProperty (ref _password, value);
+            PasswordLengthMessage = $"_Password ({_password.Length} characters):";
+            ValidateLogin ();
+        }
+    }
+
+    private void ValidateLogin ()
+    {
+        CanLogin = !string.IsNullOrEmpty (Username) && !string.IsNullOrEmpty (Password);
+        SendMessage (LoginAction.Validation);
+    }
+
+    public string Username
+    {
+        get => _username;
+        set
+        {
+            SetProperty (ref _username, value);
+            UsernameLengthMessage = $"_Username ({_username.Length} characters):";
+            ValidateLogin ();
+        }
+    }
+
+    private void Clear ()
+    {
+        Username = string.Empty;
+        Password = string.Empty;
+        SendMessage (LoginAction.Validation);
+        SendMessage (LoginAction.LoginProgress, DEFAULT_LOGIN_PROGRESS_MESSAGE);
+    }
+
+    private async Task Login ()
+    {
+        SendMessage (LoginAction.LoginProgress, LOGGING_IN_PROGRESS_MESSAGE);
+        await Task.Delay (TimeSpan.FromSeconds (1));
+        Clear ();
+    }
+
+    private void SendMessage (LoginAction loginAction, string message = "")
+    {
+        switch (loginAction)
+        {
+            case LoginAction.LoginProgress:
+                LoginProgressMessage = message;
+                break;
+            case LoginAction.Validation:
+                ValidationMessage = CanLogin ? VALID_LOGIN_MESSAGE : INVALID_LOGIN_MESSAGE;
+                ValidationColorScheme = CanLogin ? Colors.ColorSchemes ["Base"] : Colors.ColorSchemes ["Error"];
+                break;
+        }
+        WeakReferenceMessenger.Default.Send (new Message<LoginAction> { Value = loginAction });
+    }
+
+    public void Initialized ()
+    {
+        Clear ();
+    }
+}

+ 6 - 0
CommunityToolkitExample/Message.cs

@@ -0,0 +1,6 @@
+namespace CommunityToolkitExample;
+
+internal class Message<T>
+{
+    public T Value { get; set; }
+}

+ 25 - 0
CommunityToolkitExample/Program.cs

@@ -0,0 +1,25 @@
+using Microsoft.Extensions.DependencyInjection;
+using Terminal.Gui;
+
+namespace CommunityToolkitExample;
+
+public static class Program
+{
+    public static IServiceProvider Services { get; private set; }
+
+    private static void Main (string [] args)
+    {
+        Services = ConfigureServices ();
+        Application.Init ();
+        Application.Run (Services.GetRequiredService<LoginView> ());
+        Application.Shutdown ();
+    }
+
+    private static IServiceProvider ConfigureServices ()
+    {
+        var services = new ServiceCollection ();
+        services.AddTransient<LoginView> ();
+        services.AddTransient<LoginViewModel> ();
+        return services.BuildServiceProvider ();
+    }
+}

+ 19 - 13
Terminal.sln

@@ -38,12 +38,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Terminal.Gui.Analyzers.Inte
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Terminal.Gui.Analyzers.Internal.Debugging", "Analyzers\Terminal.Gui.Analyzers.Internal.Debugging\Terminal.Gui.Analyzers.Internal.Debugging.csproj", "{C2AD09BD-D579-45A7-ACA3-E4EF3BC027D2}"
 EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CommunityToolkitExample", "CommunityToolkitExample\CommunityToolkitExample.csproj", "{58FDCA8F-08F7-4D80-9DA3-6A9AED01E163}"
+EndProject
 Global
-	GlobalSection(NestedProjects) = preSolution
-		{5DE91722-8765-4E2B-97E4-2A18010B5CED} = {CCADA0BC-61CF-4B4B-96BA-A3B0C0A7F54D}
-		{715DB4BA-F989-4DF6-B46F-5ED26A32B2DD} = {CCADA0BC-61CF-4B4B-96BA-A3B0C0A7F54D}
-		{C2AD09BD-D579-45A7-ACA3-E4EF3BC027D2} = {CCADA0BC-61CF-4B4B-96BA-A3B0C0A7F54D}
-	EndGlobalSection
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
 		Release|Any CPU = Release|Any CPU
@@ -53,14 +50,6 @@ Global
 		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Release|Any CPU.Build.0 = Release|Any CPU
-		{5DE91722-8765-4E2B-97E4-2A18010B5CED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{5DE91722-8765-4E2B-97E4-2A18010B5CED}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{5DE91722-8765-4E2B-97E4-2A18010B5CED}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{5DE91722-8765-4E2B-97E4-2A18010B5CED}.Release|Any CPU.Build.0 = Release|Any CPU
-		{715DB4BA-F989-4DF6-B46F-5ED26A32B2DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{715DB4BA-F989-4DF6-B46F-5ED26A32B2DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{715DB4BA-F989-4DF6-B46F-5ED26A32B2DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{715DB4BA-F989-4DF6-B46F-5ED26A32B2DD}.Release|Any CPU.Build.0 = Release|Any CPU
 		{88979F89-9A42-448F-AE3E-3060145F6375}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{88979F89-9A42-448F-AE3E-3060145F6375}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{88979F89-9A42-448F-AE3E-3060145F6375}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -77,14 +66,31 @@ Global
 		{B0A602CD-E176-449D-8663-64238D54F857}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{B0A602CD-E176-449D-8663-64238D54F857}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{B0A602CD-E176-449D-8663-64238D54F857}.Release|Any CPU.Build.0 = Release|Any CPU
+		{5DE91722-8765-4E2B-97E4-2A18010B5CED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{5DE91722-8765-4E2B-97E4-2A18010B5CED}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{5DE91722-8765-4E2B-97E4-2A18010B5CED}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{5DE91722-8765-4E2B-97E4-2A18010B5CED}.Release|Any CPU.Build.0 = Release|Any CPU
+		{715DB4BA-F989-4DF6-B46F-5ED26A32B2DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{715DB4BA-F989-4DF6-B46F-5ED26A32B2DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{715DB4BA-F989-4DF6-B46F-5ED26A32B2DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{715DB4BA-F989-4DF6-B46F-5ED26A32B2DD}.Release|Any CPU.Build.0 = Release|Any CPU
 		{C2AD09BD-D579-45A7-ACA3-E4EF3BC027D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{C2AD09BD-D579-45A7-ACA3-E4EF3BC027D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{C2AD09BD-D579-45A7-ACA3-E4EF3BC027D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{C2AD09BD-D579-45A7-ACA3-E4EF3BC027D2}.Release|Any CPU.Build.0 = Release|Any CPU
+		{58FDCA8F-08F7-4D80-9DA3-6A9AED01E163}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{58FDCA8F-08F7-4D80-9DA3-6A9AED01E163}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{58FDCA8F-08F7-4D80-9DA3-6A9AED01E163}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{58FDCA8F-08F7-4D80-9DA3-6A9AED01E163}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 	EndGlobalSection
+	GlobalSection(NestedProjects) = preSolution
+		{5DE91722-8765-4E2B-97E4-2A18010B5CED} = {CCADA0BC-61CF-4B4B-96BA-A3B0C0A7F54D}
+		{715DB4BA-F989-4DF6-B46F-5ED26A32B2DD} = {CCADA0BC-61CF-4B4B-96BA-A3B0C0A7F54D}
+		{C2AD09BD-D579-45A7-ACA3-E4EF3BC027D2} = {CCADA0BC-61CF-4B4B-96BA-A3B0C0A7F54D}
+	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {9F8F8A4D-7B8D-4C2A-AC5E-CD7117F74C03}
 	EndGlobalSection