LoginView.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. using System.Reactive.Disposables;
  2. using System.Reactive.Linq;
  3. using NStack;
  4. using ReactiveUI;
  5. using Terminal.Gui;
  6. using ReactiveMarbles.ObservableEvents;
  7. namespace ReactiveExample {
  8. public class LoginView : Window, IViewFor<LoginViewModel> {
  9. readonly CompositeDisposable _disposable = new CompositeDisposable();
  10. public LoginView (LoginViewModel viewModel) : base("Reactive Extensions Example") {
  11. ViewModel = viewModel;
  12. var title = TitleLabel ();
  13. var usernameLengthLabel = UsernameLengthLabel (title);
  14. var usernameInput = UsernameInput (usernameLengthLabel);
  15. var passwordLengthLabel = PasswordLengthLabel (usernameInput);
  16. var passwordInput = PasswordInput (passwordLengthLabel);
  17. var validationLabel = ValidationLabel (passwordInput);
  18. var loginButton = LoginButton (validationLabel);
  19. var clearButton = ClearButton (loginButton);
  20. LoginProgressLabel (clearButton);
  21. }
  22. public LoginViewModel ViewModel { get; set; }
  23. protected override void Dispose (bool disposing) {
  24. _disposable.Dispose ();
  25. base.Dispose (disposing);
  26. }
  27. Label TitleLabel () {
  28. var label = new Label("Login Form");
  29. Add (label);
  30. return label;
  31. }
  32. TextField UsernameInput (View previous) {
  33. var usernameInput = new TextField (ViewModel.Username) {
  34. X = Pos.Left(previous),
  35. Y = Pos.Top(previous) + 1,
  36. Width = 40
  37. };
  38. ViewModel
  39. .WhenAnyValue (x => x.Username)
  40. .BindTo (usernameInput, x => x.Text)
  41. .DisposeWith (_disposable);
  42. usernameInput
  43. .Events ()
  44. .TextChanged
  45. .Select (old => usernameInput.Text)
  46. .DistinctUntilChanged ()
  47. .BindTo (ViewModel, x => x.Username)
  48. .DisposeWith (_disposable);
  49. Add (usernameInput);
  50. return usernameInput;
  51. }
  52. Label UsernameLengthLabel (View previous) {
  53. var usernameLengthLabel = new Label {
  54. X = Pos.Left(previous),
  55. Y = Pos.Top(previous) + 1,
  56. Width = 40
  57. };
  58. ViewModel
  59. .WhenAnyValue (x => x.UsernameLength)
  60. .Select (length => ustring.Make ($"Username ({length} characters)"))
  61. .BindTo (usernameLengthLabel, x => x.Text)
  62. .DisposeWith (_disposable);
  63. Add (usernameLengthLabel);
  64. return usernameLengthLabel;
  65. }
  66. TextField PasswordInput (View previous) {
  67. var passwordInput = new TextField (ViewModel.Password) {
  68. X = Pos.Left(previous),
  69. Y = Pos.Top(previous) + 1,
  70. Width = 40
  71. };
  72. ViewModel
  73. .WhenAnyValue (x => x.Password)
  74. .BindTo (passwordInput, x => x.Text)
  75. .DisposeWith (_disposable);
  76. passwordInput
  77. .Events ()
  78. .TextChanged
  79. .Select (old => passwordInput.Text)
  80. .DistinctUntilChanged ()
  81. .BindTo (ViewModel, x => x.Password)
  82. .DisposeWith (_disposable);
  83. Add (passwordInput);
  84. return passwordInput;
  85. }
  86. Label PasswordLengthLabel (View previous) {
  87. var passwordLengthLabel = new Label {
  88. X = Pos.Left(previous),
  89. Y = Pos.Top(previous) + 1,
  90. Width = 40
  91. };
  92. ViewModel
  93. .WhenAnyValue (x => x.PasswordLength)
  94. .Select (length => ustring.Make ($"Password ({length} characters)"))
  95. .BindTo (passwordLengthLabel, x => x.Text)
  96. .DisposeWith (_disposable);
  97. Add (passwordLengthLabel);
  98. return passwordLengthLabel;
  99. }
  100. Label ValidationLabel (View previous) {
  101. var error = ustring.Make("Please, enter user name and password.");
  102. var success = ustring.Make("The input is valid!");
  103. var validationLabel = new Label(error) {
  104. X = Pos.Left(previous),
  105. Y = Pos.Top(previous) + 1,
  106. Width = 40
  107. };
  108. ViewModel
  109. .WhenAnyValue (x => x.IsValid)
  110. .Select (valid => valid ? success : error)
  111. .BindTo (validationLabel, x => x.Text)
  112. .DisposeWith (_disposable);
  113. ViewModel
  114. .WhenAnyValue (x => x.IsValid)
  115. .Select (valid => valid ? Colors.Base : Colors.Error)
  116. .BindTo (validationLabel, x => x.ColorScheme)
  117. .DisposeWith (_disposable);
  118. Add (validationLabel);
  119. return validationLabel;
  120. }
  121. Label LoginProgressLabel (View previous) {
  122. var progress = ustring.Make ("Logging in...");
  123. var idle = ustring.Make ("Press 'Login' to log in.");
  124. var loginProgressLabel = new Label(idle) {
  125. X = Pos.Left(previous),
  126. Y = Pos.Top(previous) + 1,
  127. Width = 40
  128. };
  129. ViewModel
  130. .WhenAnyObservable (x => x.Login.IsExecuting)
  131. .Select (executing => executing ? progress : idle)
  132. .ObserveOn (RxApp.MainThreadScheduler)
  133. .BindTo (loginProgressLabel, x => x.Text)
  134. .DisposeWith (_disposable);
  135. Add (loginProgressLabel);
  136. return loginProgressLabel;
  137. }
  138. Button LoginButton (View previous) {
  139. var loginButton = new Button ("Login") {
  140. X = Pos.Left(previous),
  141. Y = Pos.Top(previous) + 1,
  142. Width = 40
  143. };
  144. loginButton
  145. .Events ()
  146. .Clicked
  147. .InvokeCommand (ViewModel, x => x.Login)
  148. .DisposeWith (_disposable);
  149. Add (loginButton);
  150. return loginButton;
  151. }
  152. Button ClearButton (View previous) {
  153. var clearButton = new Button("Clear") {
  154. X = Pos.Left(previous),
  155. Y = Pos.Top(previous) + 1,
  156. Width = 40
  157. };
  158. clearButton
  159. .Events ()
  160. .Clicked
  161. .InvokeCommand (ViewModel, x => x.Clear)
  162. .DisposeWith (_disposable);
  163. Add (clearButton);
  164. return clearButton;
  165. }
  166. object IViewFor.ViewModel {
  167. get => ViewModel;
  168. set => ViewModel = (LoginViewModel) value;
  169. }
  170. }
  171. }