LoginView.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. using System.Reactive.Disposables;
  2. using System.Reactive.Linq;
  3. using ReactiveMarbles.ObservableEvents;
  4. using ReactiveUI;
  5. using Terminal.Gui.Configuration;
  6. using Terminal.Gui.Views;
  7. using Terminal.Gui.App;
  8. using Terminal.Gui.ViewBase;
  9. namespace ReactiveExample;
  10. public class LoginView : Window, IViewFor<LoginViewModel>
  11. {
  12. private const string SuccessMessage = "The input is valid!";
  13. private const string ErrorMessage = "Please enter a valid user name and password.";
  14. private const string ProgressMessage = "Logging in...";
  15. private const string IdleMessage = "Press 'Login' to log in.";
  16. private readonly CompositeDisposable _disposable = [];
  17. public LoginView (LoginViewModel viewModel)
  18. {
  19. Title = $"Reactive Extensions Example - {Application.QuitKey} to Exit";
  20. ViewModel = viewModel;
  21. var title = this.AddControl<Label> (x => x.Text = "Login Form");
  22. var unLengthLabel = title.AddControlAfter<Label> ((previous, unLength) =>
  23. {
  24. unLength.X = Pos.Left (previous);
  25. unLength.Y = Pos.Top (previous) + 1;
  26. ViewModel
  27. .WhenAnyValue (x => x.UsernameLength)
  28. .Select (length => $"_Username ({length} characters):")
  29. .BindTo (unLength, x => x.Text)
  30. .DisposeWith (_disposable);
  31. });
  32. unLengthLabel.AddControlAfter<TextField> ((previous, unInput) =>
  33. {
  34. unInput.X = Pos.Right (previous) + 1;
  35. unInput.Y = Pos.Top (previous);
  36. unInput.Width = 40;
  37. unInput.Text = ViewModel.Username;
  38. ViewModel
  39. .WhenAnyValue (x => x.Username)
  40. .BindTo (unInput, x => x.Text)
  41. .DisposeWith (_disposable);
  42. unInput
  43. .Events ()
  44. .TextChanged
  45. .Select (_ => unInput.Text)
  46. .DistinctUntilChanged ()
  47. .BindTo (ViewModel, x => x.Username)
  48. .DisposeWith (_disposable);
  49. });
  50. unLengthLabel.AddControlAfter<Label> ((previous, pwLength) =>
  51. {
  52. pwLength.X = Pos.Left (previous);
  53. pwLength.Y = Pos.Top (previous) + 1;
  54. ViewModel
  55. .WhenAnyValue (x => x.PasswordLength)
  56. .Select (length => $"_Password ({length} characters):")
  57. .BindTo (pwLength, x => x.Text)
  58. .DisposeWith (_disposable);
  59. })
  60. .AddControlAfter<TextField> ((previous, pwInput) =>
  61. {
  62. pwInput.X = Pos.Right (previous) + 1;
  63. pwInput.Y = Pos.Top (previous);
  64. pwInput.Width = 40;
  65. pwInput.Text = ViewModel.Password;
  66. ViewModel
  67. .WhenAnyValue (x => x.Password)
  68. .BindTo (pwInput, x => x.Text)
  69. .DisposeWith (_disposable);
  70. pwInput
  71. .Events ()
  72. .TextChanged
  73. .Select (_ => pwInput.Text)
  74. .DistinctUntilChanged ()
  75. .BindTo (ViewModel, x => x.Password)
  76. .DisposeWith (_disposable);
  77. })
  78. .AddControlAfter<Label> ((previous, validation) =>
  79. {
  80. validation.X = Pos.Left (previous);
  81. validation.Y = Pos.Top (previous) + 1;
  82. validation.Text = ErrorMessage;
  83. ViewModel
  84. .WhenAnyValue (x => x.IsValid)
  85. .Select (valid => valid ? SuccessMessage : ErrorMessage)
  86. .BindTo (validation, x => x.Text)
  87. .DisposeWith (_disposable);
  88. ViewModel
  89. .WhenAnyValue (x => x.IsValid)
  90. .Select (valid => valid ? SchemeManager.GetScheme ("Base") : SchemeManager.GetScheme ("Error"))
  91. .BindTo (validation, x => x.GetScheme ())
  92. .DisposeWith (_disposable);
  93. })
  94. .AddControlAfter<Button> ((previous, login) =>
  95. {
  96. login.X = Pos.Left (previous);
  97. login.Y = Pos.Top (previous) + 1;
  98. login.Text = "_Login";
  99. login
  100. .Events ()
  101. .Accepting
  102. .InvokeCommand (ViewModel, x => x.Login)
  103. .DisposeWith (_disposable);
  104. })
  105. .AddControlAfter<Button> ((previous, clear) =>
  106. {
  107. clear.X = Pos.Left (previous);
  108. clear.Y = Pos.Top (previous) + 1;
  109. clear.Text = "_Clear";
  110. clear
  111. .Events ()
  112. .Accepting
  113. .InvokeCommand (ViewModel, x => x.ClearCommand)
  114. .DisposeWith (_disposable);
  115. })
  116. .AddControlAfter<Label> ((previous, progress) =>
  117. {
  118. progress.X = Pos.Left (previous);
  119. progress.Y = Pos.Top (previous) + 1;
  120. progress.Width = 40;
  121. progress.Height = 1;
  122. progress.Text = IdleMessage;
  123. ViewModel
  124. .WhenAnyObservable (x => x.Login.IsExecuting)
  125. .Select (executing => executing ? ProgressMessage : IdleMessage)
  126. .ObserveOn (RxApp.MainThreadScheduler)
  127. .BindTo (progress, x => x.Text)
  128. .DisposeWith (_disposable);
  129. });
  130. }
  131. public LoginViewModel ViewModel { get; set; }
  132. object IViewFor.ViewModel
  133. {
  134. get => ViewModel;
  135. set => ViewModel = (LoginViewModel)value;
  136. }
  137. protected override void Dispose (bool disposing)
  138. {
  139. _disposable.Dispose ();
  140. base.Dispose (disposing);
  141. }
  142. }