Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: ReactiveUI.Maui On IOS and Android Binding is not working #3520

Open
RAMESHKUMAR502 opened this issue Apr 13, 2023 · 3 comments
Open
Labels

Comments

@RAMESHKUMAR502
Copy link

RAMESHKUMAR502 commented Apr 13, 2023

Describe the bug 🐞

ReactiveUI.Maui On IOS and Android we are not able receive the command or Binding getting executed.
Below is the code Sinpet when i press login Button the command is not getting trigged once we port from xamarin to MAUI.

 public partial class LoginPage : ContentPage, IViewFor<LoginViewModel>
{
    /// <inheritdoc/>
    public LoginViewModel ViewModel { get; set; }

    /// <inheritdoc/>
    object IViewFor.ViewModel { get => this.ViewModel; set { this.ViewModel = (LoginViewModel)value; } }
    List<string> backimage = new List<string>();
    int pickedIndex = 0;

    /// <summary>
    /// Initializes a new instance of the <see cref="LoginPage"/> class.
    /// </summary>
    public LoginPage()
    {
        backimage.Add("portalui_1");
        backimage.Add("portalui_2_v2");
        backimage.Add("portalui_3_v2");
        backimage.Add("portalui_4_v2");
        backimage.Add("portalui_5_v2");
        backimage.Add("portalui_6_v2");
        backimage.Add("portalui_7");
        backimage.Add("portalui_8");
        Random random = new Random();
        pickedIndex = random.Next(backimage.Count);
        this.InitializeComponent();
        this.BindingContext = ViewModel;
        if (pickedIndex >= 0)
            this.BackgroundImageSource = backimage[pickedIndex];

        if (Device.RuntimePlatform == Device.Android)
            FaceID.Source = "fingerprint.svg";

        this.WhenActivated(disposables =>
        {
             this.BindCommand(
                    this.ViewModel,
                    vm => vm.LoginCommand,
                    v => v.LoginButton,
                    nameof(this.LoginButton.Clicked))
                .DisposeWith(disposables);

            this.Bind(
                    this.ViewModel,
                    vm => vm.EmailAddress,
                    v => v.EmailAddress.Text)
                .DisposeWith(disposables);

            this.Bind(
                   this.ViewModel,
                   vm => vm.Versionumber,
                   v => v.version.Text)
               .DisposeWith(disposables);

            this.Bind(
               this.ViewModel,
               vm => vm.IsFaceEnabledChecked,
               v => v.FaceEnableChecked.IsToggled)
           .DisposeWith(disposables);


            this.Bind(
               this.ViewModel,
               vm => vm.IsFaceSaved,
               v => v.FaceID.IsVisible)
           .DisposeWith(disposables);

            this.BindCommand(
                this.ViewModel,
                vm => vm.FaceClickCommand,
                v => v.FaceGesture)
            .DisposeWith(disposables);



            this.BindCommand(
                  this.ViewModel,
                  vm => vm.RestPasswordClickCommand,
                  v => v.RestPasswordGesture)
              .DisposeWith(disposables);

            this.BindCommand(
                this.ViewModel,
                vm => vm.ConcatusClickCommand,
                v => v.ContactUsGesture)
            .DisposeWith(disposables);



            this.BindCommand(
                  this.ViewModel,
                  vm => vm.ForgotUsernameClickCommand,
                  v => v.ForgotUsernameGesture)
              .DisposeWith(disposables);

            this.Bind(
                    this.ViewModel,
                    vm => vm.Enablefacemess,
                    v => v.EnbaleFace.Text)
                .DisposeWith(disposables);

            this.Bind(
                    this.ViewModel,
                    vm => vm.Password,
                    v => v.Password.Text)
                .DisposeWith(disposables);
        });
    }

    /// <inheritdoc/>
    protected override async void OnAppearing()
    {
        base.OnAppearing();
        if (this.Logo.IsVisible == false)
        {
            this.Logo.Opacity = 0;
            this.Logo.IsVisible = true;

            this.FormContainer.Opacity = 0;
            this.FormContainer.IsVisible = true;

            this.Logo.TranslationY = this.Logo.TranslationY + 200;
            await this.Logo.FadeTo(1, 700, Easing.CubicInOut);
            await this.Logo.TranslateTo(this.Logo.TranslationX, this.Logo.TranslationY - 200, 500, Easing.CubicInOut);
            await this.FormContainer.FadeTo(1, 700, Easing.CubicInOut);
        }
        try
        {
            if (this.ViewModel != null && Device.RuntimePlatform == Device.iOS)
            {
                await this.ViewModel.CheckForFingerprintAuthentication();
            }
#if TODOMAUI
            string latestVersionNumber = await CrossLatestVersion.Current.GetLatestVersionNumber();
            string installedVersionNumber = CrossLatestVersion.Current.InstalledVersionNumber;
            bool isupgradereq = false;
            if (Device.RuntimePlatform == Device.iOS)
            {

                if (Convert.ToInt32(installedVersionNumber) < Convert.ToInt32(latestVersionNumber))
                {
                    isupgradereq = true;
                }
            }
            else
            {
                if (Convert.ToDecimal(installedVersionNumber) < Convert.ToDecimal(latestVersionNumber))
                {
                    isupgradereq = true;
                }
            }

            if (isupgradereq == true)
            {
                await DisplayAlert("New Version", "There is a new version of this app available. Would you like to update now?", "Update");

                await CrossLatestVersion.Current.OpenAppInStore();
            }
#endif
        }
        catch (Exception ex)
        {

        }
    }

    void FaceEnableChecked_Toggled(System.Object sender, ToggledEventArgs e)
    {
        try
        {
            if (e.Value == false)
            {
                Preferences.Set("IsFaceEnabledChecked", e.Value.ToString());
            }
        }
        catch (Exception ex)
        {

        }
    }
}

 public class LoginViewModel : ReactiveObject, IEnableLogger, IRoutableViewModel
    {
        /// <inheritdoc/>
        public string UrlPathSegment => "Login";

        /// <inheritdoc/>
        public IScreen HostScreen { get; }

        private IAuthenticationService Service { get; }

        private string emailAddress;

        public string EmailAddress
        {
            get => emailAddress;
            set => this.RaiseAndSetIfChanged(ref emailAddress, value);
        }

        private string password;

        public string Password
        {
            get => password;
            set => this.RaiseAndSetIfChanged(ref password, value);
        }

        private string enablefacemess;

        public string Enablefacemess
        {
            get => enablefacemess;
            set => this.RaiseAndSetIfChanged(ref enablefacemess, value);
        }

        private string versionumber;

        public string Versionumber
        {
            get => versionumber;
            set => this.RaiseAndSetIfChanged(ref versionumber, value);
        }

        private bool isFaceEnabledChecked = true;

        public bool IsFaceEnabledChecked
        {
            get => isFaceEnabledChecked;
            set => this.RaiseAndSetIfChanged(ref isFaceEnabledChecked, value);
        }

        private bool isFaceSaved;

        public bool IsFaceSaved
        {
            get => isFaceSaved;
            set => this.RaiseAndSetIfChanged(ref isFaceSaved, value);
        }


        public ReactiveCommand<Unit, Unit> LoginCommand { get; }

        public ICommand RestPasswordClickCommand { get; set; }

        public ICommand FaceClickCommand { get; set; }

        public ICommand ConcatusClickCommand { get; set; }

        public ICommand ForgotUsernameClickCommand { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="LoginViewModel"/> class.
        /// </summary>
        /// <param name="hostScreen"></param>
        /// <param name="service"></param>
        public LoginViewModel(IScreen hostScreen, IAuthenticationService service = null)
        {
            this.HostScreen = hostScreen;
            this.Service = service ?? Locator.Current.GetService<IAuthenticationService>();
            Versionumber = "Version " + VersionTracking.CurrentVersion;
            if (Preferences.ContainsKey("IsFaceEnabledChecked"))
            {
                string IsFaceEnabled = Preferences.Get("IsFaceEnabledChecked", string.Empty);
                this.IsFaceEnabledChecked = Convert.ToBoolean(Preferences.Get("IsFaceEnabledChecked", string.Empty));
            }


            string EmailAdd = Preferences.Get("EmailAddress", string.Empty);
            string Passwd = Preferences.Get("Password", string.Empty);
            bool IsFaceChecked = false;
            if (Preferences.ContainsKey("IsFaceEnabledChecked"))
                IsFaceChecked = Convert.ToBoolean(Preferences.Get("IsFaceEnabledChecked", string.Empty));

            if (IsFaceChecked == true && !string.IsNullOrEmpty(EmailAdd) && !string.IsNullOrEmpty(Passwd))
                IsFaceSaved = true;


            this.RestPasswordClickCommand = ReactiveCommand.Create(() => this.RestPassword());
            this.ConcatusClickCommand = ReactiveCommand.Create(() => this.ConcatUS());
            this.ForgotUsernameClickCommand = ReactiveCommand.Create(() => this.ForgotUsername());

            this.FaceClickCommand = ReactiveCommand.Create(() => this.CheckForFingerprintAuthentication());

            var canLogin = this.WhenAnyValue(
                vm => vm.EmailAddress,
                vm => vm.Password,
                (emailAddress, password) => !string.IsNullOrEmpty(emailAddress) && !string.IsNullOrEmpty(password));
            this.LoginCommand = ReactiveCommand
                .Create(
                    () =>
                    {
                        Loginasync(this.EmailAddress, this.Password, true);
                    }, canLogin);

            this.LoginCommand
                .ThrownExceptions
                .Subscribe(ex =>
                {
                    UserDialogs.Instance.Alert(ex.Message, "Error");
                });

            if (Device.RuntimePlatform == Device.Android)
            {
                CheckForFingerprintAuthentication();
            }
        }

        private async Task Loginasync(string emailid, string password, bool isFirsttime = false)
        {
            try
            {
                var payload = new SignInPayload();
                payload.RememberMe = true;
                payload.UserName = emailid;
                payload.Password = password;

                UserDialogs.Instance.ShowLoading();

                this.Service
                    .SignIn(payload)
                    .SubscribeOn(RxApp.TaskpoolScheduler)
                    .ObserveOn(RxApp.MainThreadScheduler)
                    .Finally(() => UserDialogs.Instance.HideLoading())
                    .Subscribe(
                        content =>
                        {
                            Observable.FromAsync<string>(() => content.Content.ReadAsStringAsync())
                            .SubscribeOn(RxApp.TaskpoolScheduler)
                            .ObserveOn(RxApp.MainThreadScheduler)
                            .Subscribe(
                                async stringContent =>
                                {
                                    if (content.IsSuccessStatusCode)
                                    {
                                        IEnumerable<string> values;
                                        if (content.Headers.TryGetValues("Set-Cookie", out values))
                                        {
                                            App.cookiestring.Add(values);
                                        }

                                        Preferences.Set("EmailAddress", this.EmailAddress);
                                        Preferences.Set("Password", password);

                                        Preferences.Set("IsFaceEnabledChecked", this.IsFaceEnabledChecked.ToString());

                                        if (isFirsttime == true)
                                            await EnableFingerprintAuthentication();
#if TODOMAUI
                                        this.HostScreen.Router.NavigateAndReset.Execute(new HomeViewModel(this.HostScreen)).Subscribe();
#endif
                                    }
                                    else
                                    {
                                        UserDialogs.Instance.Alert(stringContent, "Error");
                                    }
                                },
                                e =>
                                {
                                    var apiException = (ApiException)e;
                                    UserDialogs.Instance.Alert(apiException.Content, "Error");
                                });
                        },
                        e =>
                        {
                            if (e is ApiException)
                            {
                                var apiException = (ApiException)e;
                                UserDialogs.Instance.Alert(apiException.Content, "Error");
                            }
                            else
                            {
                                UserDialogs.Instance.Alert(e.Message, "Error");
                            }
                        });
            }
            catch (Exception ex)
            {

            }
        }

        private async Task EnableFingerprintAuthentication()
        {
            if (this.IsFaceEnabledChecked == true)
            {
                var isFingerprintAvailable = await CrossFingerprint.Current.IsAvailableAsync(true);
                var authenticationType = await CrossFingerprint.Current.GetAuthenticationTypeAsync();

                string authenticationFailureMessage = authenticationType == Plugin.Fingerprint.Abstractions.AuthenticationType.Face ? "No Face ID Recognized." : "There are no fingerprints available.";
                if (isFingerprintAvailable)
                {
                    AuthenticationRequestConfiguration conf =
                    new AuthenticationRequestConfiguration("Authentication",
                                    "Authenticate access to your personal data");
                    var result = await CrossFingerprint.Current.AuthenticateAsync(conf);
                    if (result.Authenticated == false)
                    {

                    }
                }
            }


        }


        /// <summary>
        /// Checks for Finger Print Authentication
        /// </summary>
        /// <returns></returns>
        public async Task CheckForFingerprintAuthentication()
        {
            this.EmailAddress = Preferences.Get("EmailAddress", string.Empty);
            string Pwd = Preferences.Get("Password", string.Empty);

            var authenticationType = await CrossFingerprint.Current.GetAuthenticationTypeAsync();

            this.Enablefacemess = "Biometric ";



            this.IsFaceEnabledChecked = Convert.ToBoolean(Preferences.Get("IsFaceEnabledChecked", string.Empty));

            if (IsFaceEnabledChecked == true && !string.IsNullOrEmpty(this.EmailAddress) && !string.IsNullOrEmpty(Pwd))
            {
                var isFingerprintAvailable = await CrossFingerprint.Current.IsAvailableAsync(true);


                string authenticationFailureMessage = authenticationType == Plugin.Fingerprint.Abstractions.AuthenticationType.Face ? "No Face ID Recognized." : "There are no fingerprints available.";



                try
                {

                    if (isFingerprintAvailable)
                    {
                        AuthenticationRequestConfiguration conf =
                        new AuthenticationRequestConfiguration("Authentication",
                                        "Authenticate access to your personal data");
                        var result = await CrossFingerprint.Current.AuthenticateAsync(conf);


                        if (result.Authenticated)
                        {
                            this.EmailAddress = Preferences.Get("EmailAddress", string.Empty);
                            Pwd = Preferences.Get("Password", string.Empty);

                            if (!string.IsNullOrEmpty(this.EmailAddress) && !string.IsNullOrEmpty(Pwd))
                            {

                                await Loginasync(this.EmailAddress, Pwd, false); ;
                            }
                        }
                        else
                        {
                            UserDialogs.Instance.Alert("Unable to Access Biometric", "Error");
                        }
                    }
                    else
                    {
                        UserDialogs.Instance.Alert("Biometric is Not Supported", "Error");
                    }

                }
                catch (Exception exception)
                {
                    Debug.WriteLine("FingerPrint Exception" + exception);
                }
            }
        }

        private void ForgotUsername()
        {
#if TODOMAUI
            this.HostScreen.Router.NavigateAndReset.Execute(new ForgotusernameViewModel(this.HostScreen)).Subscribe();
#endif
        }

        private void RestPassword()
        {
#if TODOMAUI
            this.HostScreen.Router.NavigateAndReset.Execute(new ResetPasswordViewModel(this.HostScreen)).Subscribe();
#endif
        }

        private void ConcatUS()
        {
            //Webview
            //this.HostScreen.Router.NavigateAndReset.Execute(new ContactUSViewModel(this.HostScreen,false)).Subscribe();
            PhoneDialer.Open("8665903550");
        }
    }

Step to reproduce

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Reproduction repository

https://github.com/reactiveui/ReactiveUI

Expected behavior

This should happen...

Screenshots 🖼️

No response

IDE

No response

Operating system

Apple

Version

No response

Device

IOS

ReactiveUI Version

18.4.26

Additional information ℹ️

No response

@ChrisPulman
Copy link
Member

@RAMESHKUMAR502 Is this still an issue in the latest release 19.4.1?
Could it have been caused by the Navigation issues crashing the process in other areas?

@RAMESHKUMAR502
Copy link
Author

@ChrisPulman no there is issue with 19.4.1

@ChrisPulman
Copy link
Member

Is there any chance that you have a repo to share demonstrating the issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants