Forum Xamarin.Forms

Integrating login page in Master Detail Page Xmarin.Forms example

veso266veso266 Member ✭✭
edited January 2020 in Xamarin.Forms

Hi there
I created Master-Detail example app when creating new Xmarin.Forms project

but then I wanted to integrate this login screen: mallibone.com/post/creating-a-login-screen-with-xamarinforms

Now He is using A simple Navigation Service for Xamarin.Forms: mallibone.com/post/a-simple-navigation-service-for-xamarinforms
to show login page and navigate

now the problem is I cannot seem to integrate this into my app

now in the xmarin.forms master-detail page example, main page(app.xaml.cs) it started like this: MainPage = new MainPage();

but the SimpleNavigationService requires the page to be started like this:

_navigationService.Configure(PageNames.LoginPage, typeof(Views.LoginPage));
_navigationService.Configure(PageNames.MainPage, typeof(Views.MainPage));
MainPage = _navigationService.SetRootPage(nameof(Views.MainPage));

if I do that then Hambuger menu navigation doesn't work (I get System.NullReferenceException: 'Object reference not set to an instance of an object.', but it doesn't show where) any more and app looks weird (cannot post picture, but there are 2 hambuerger menu icons it looks like MainPage in MainPage)

Hopefully someone can tell me how I can use A simple Navigation Service for Xamarin.Forms with Master-Detail page (cuz it looks like a neat library)

Thanks for Anwsering and Best Regards

Answers

  • aga913aga913 Member ✭✭✭

    hi,
    i'm sorry but i don't really understand what are you trying to do here
    you want to push the login page when the app starts ?
    you want to make the MainPage in the app the Login Page then if he enters valid information you want to change it again ?
    you are just asking about how to use the library ?

  • veso266veso266 Member ✭✭

    I would like to first display the login page and if the user is logged in, then I would like to show the rest (Main, page, hamburger menu, etc)

    as he is using this library I would like to do this with this library as well

  • Dinesh_OfficialDinesh_Official Member ✭✭✭
    edited January 2020

    @veso266 ,

    If you want to show login page at Start, Follow the below steps.

    Initially, Set the App.MainPage as your Login Page.

    If user logined, set the App.MainPage = new NavigationPage(new MainPage/MasterDetailPage());
    else
    show error.

    Simple :). Correct me if am wrong in understanding the requirement.

  • veso266veso266 Member ✭✭
    edited January 2020
    Isnt this what SetRootPage method is supposed to do?

    Because he does the same thing: github.com/mallibone/LoginViewSample/blob/master/LoginViewSample.Core/App.xaml.cs

    And it works fine in his example
    Why it doesnt work for me?
  • WendyZangWendyZang Member, Xamarin Team Xamurai

    The SetRootPage is used for MainPage, do the same thing.

    You could try the way Dinesh_Official suggested. It is simple and works well.

  • veso266veso266 Member ✭✭

    oh
    this is hard, as that was the example Master-Detail page app, I decided to scrap it all and instead try the new aproach: https://devblogs.microsoft.com/xamarin/shell-xamarin-forms-4-0-getting-started/

    so I created a New Shell example app(Visual Studio 2019 xmarin.forms template) and decided to add login page to there instead

    my App.xaml.cs constructor looks like this

    public App()
    {
        InitializeComponent();
        DependencyService.Register<MockDataStore>();
        MainPage = new Views.LoginPage();
    }
    

    so my AppShell.xaml looks like that

    <?xml version="1.0" encoding="UTF-8"?>
    <Shell xmlns="http://xamarin.com/schemas/2014/forms" 
           xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
           xmlns:d="http://xamarin.com/schemas/2014/forms/design"
           xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
           mc:Ignorable="d"
           xmlns:local="clr-namespace:MyApp.Views"
           Title="MyApp"
           x:Class="MyApp.AppShell">
    
        <!-- 
            Styles and Resources 
        -->
        <Shell.Resources>
            <ResourceDictionary>
                <Color x:Key="NavigationPrimary">#2196F3</Color>
                <Style x:Key="BaseStyle" TargetType="Element">
                    <Setter Property="Shell.BackgroundColor" Value="{StaticResource NavigationPrimary}" />
                    <Setter Property="Shell.ForegroundColor" Value="White" />
                    <Setter Property="Shell.TitleColor" Value="White" />
                    <Setter Property="Shell.DisabledColor" Value="#B4FFFFFF" />
                    <Setter Property="Shell.UnselectedColor" Value="#95FFFFFF" />
                    <Setter Property="Shell.TabBarBackgroundColor" Value="{StaticResource NavigationPrimary}" />
                    <Setter Property="Shell.TabBarForegroundColor" Value="White"/>
                    <Setter Property="Shell.TabBarUnselectedColor" Value="#95FFFFFF"/>
                    <Setter Property="Shell.TabBarTitleColor" Value="White"/>
                </Style>
                <Style TargetType="TabBar" BasedOn="{StaticResource BaseStyle}" />
            </ResourceDictionary>
        </Shell.Resources>
    
        <!-- Your Pages -->
        <FlyoutItem Title="Browse" Icon="tab_feed.png">
            <ShellContent ContentTemplate="{DataTemplate local:ItemsPage}" />
        </FlyoutItem>
        <FlyoutItem Title="About" Icon="tab_about.png">
            <ShellContent ContentTemplate="{DataTemplate local:AboutPage}" />
        </FlyoutItem>
    
    </Shell>
    
    

    my LoginPage.xaml

    <?xml version="1.0" encoding="utf-8" ?>
    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 xmlns:d="http://xamarin.com/schemas/2014/forms/design"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                 mc:Ignorable="d"
                 x:Class="MyApp.Views.LoginPage">
        <ContentPage.Content>
            <Grid Margin="16">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="*"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <StackLayout Grid.Row="0">
                    <Label Text="Please enter your credentials" />
                    <Entry Text="{Binding Username}"
                           Placeholder="Username" />
                    <Entry Text="{Binding Password}"
                           Placeholder="Password"
                           IsPassword="True" />
                    <Label Text="Invalid credentials entered" 
                           IsVisible="{Binding AreCredentialsInvalid}" 
                           TextColor="Red" />
                </StackLayout>
                <Button Grid.Row="2" Text="Authenticate" Command="{Binding AuthenticateCommand}" />
            </Grid>
        </ContentPage.Content>
    </ContentPage>
    

    and my LoginPageModel.cs looks like this

    using System.ComponentModel;
    using System.Windows.Input;
    using Xamarin.Forms;
    
    using MyApp.Services;
    using MyApp.Interface;
    
    namespace MyApp.ViewModels
    {
        public class LoginViewModel : INotifyPropertyChanged
        {
            private string _username;
            private string _password;
            private bool _areCredentialsInvalid;
    
            public LoginViewModel(INavigationService navigationService)
            {
                AuthenticateCommand = new Command(() =>
                {
                    AreCredentialsInvalid = !UserAuthenticated(Username, Password);
                    if (AreCredentialsInvalid) return;
    
                    App.Current.MainPage = new NavigationPage(new AppShell());
                });
    
                AreCredentialsInvalid = false;
            }
    
            private bool UserAuthenticated(string username, string password)
            {
                if (string.IsNullOrEmpty(username)
                    || string.IsNullOrEmpty(password))
                {
                    return false;
                }
    
                return username.ToLowerInvariant() == "joe"
                    && password.ToLowerInvariant() == "secret";
            }
    
            public string Username
            {
                get => _username;
                set
                {
                    if (value == _username) return;
                    _username = value;
                    OnPropertyChanged(nameof(Username));
                }
            }
    
            public string Password
            {
                get => _password;
                set
                {
                    if (value == _password) return;
                    _password = value;
                    OnPropertyChanged(nameof(Password));
                }
            }
    
            public ICommand AuthenticateCommand { get; set; }
    
            public bool AreCredentialsInvalid
            {
                get => _areCredentialsInvalid;
                set
                {
                    if (value == _areCredentialsInvalid) return;
                    _areCredentialsInvalid = value;
                    OnPropertyChanged(nameof(AreCredentialsInvalid));
                }
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected virtual void OnPropertyChanged(string propertyName = null)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
    
    

    now this should all work, but it doesn't
    although app first launches login page, no matter what I do (even if I enter correct credentials) and cannot get past it
    and when setting breakpoint on any of this methods, the breakpoints are never hit, so I must be doing something wrong

    not sure how did you guys implemented loginPage on Shell Apps? (specialy ones that connect to REST api and get a token back which should then be used in all subsequent api requests?)

    I am realy new to xmarin so thats why this simple tasks are giving me a lot of problems

  • WendyZangWendyZang Member, Xamarin Team Xamurai

    It seems you open the login page first. But i do not make sure how do you navigate to the shell page. You could make a login button to check the username and password, if it matches, navigate to the shell page.

  • veso266veso266 Member ✭✭
    edited February 2020

    I am a moron :smile:
    I didn't set the login page to bind to anything

        <ContentPage.BindingContext>
            <vm:LoginViewModel />
        </ContentPage.BindingContext>
    

    and don't forget to tell LoginPage where ViewModels are located

    xmlns:vm="clr-namespace:Calimero.ViewModels"
    

    that was the reason my ViewModel was never called :smile:

  • veso266veso266 Member ✭✭

    right yea I can do that (although I had to do it like this: App.Current.MainPage.DisplayAlert(e.message); to make it work (I have a static class))

    but I cannot seem to cath exeption (catch (Exeption e): CS0246 The type or namespace name 'Exeption' could not be found (are you missing a using directive or an assembly reference?)

    I(my library) am trowing them like so: throw new Exception(err.code);

    also if you remember I made my login page working: https://forums.xamarin.com/discussion/comment/401812#Comment_401812

    but now when I call my DoLogin method my ui freezes up while data is fetch

    so if I have method in my library like so

    public bool Login(string TENANTID, string username, string password, string platform)
            {
                bool isLoggedIn = false;
    
                this.TENANT_ID = TENANTID;
                this.BASE_URL = Regex.Replace(this.BASE_URL, "{.*?}", this.TENANT_ID);
    
                client = new RestClient(BASE_URL); //Construct new HTTP Client with request URL
                RestRequest request = new RestRequest(RestSharp.Method.POST); //Tell RestSharp we are doing POST requests
    
                string method = "mobileapi/auth/loginpass"; //Tell it on which method to connect to
                request.Resource = method; //Tell it on which method to connect to
    
                request.RequestFormat = DataFormat.Json; //Tell it that POST data is RAW JSON
    
                User user = new User(username, password, platform); //Construct USER Object (used later)
                request.AddJsonBody(user); //Construct USER Object (used later)
    
                var response = client.Execute(request); //Connect and get the response back
    
                if ((response.StatusCode == HttpStatusCode.OK) || (response.StatusCode == HttpStatusCode.Created)) //If login is successful 200 is returned
                {
                    API_TOKEN = JsonConvert.DeserializeObject<APIToken>(response.Content); //We have our API Key
                    isLoggedIn = true; //We are logged in
                }
                return isLoggedIn;
            }
    

    how could I change it so I won't lock the UI while it fetches data?
    I am calling it like so in my LoginViewModel

            public LoginViewModel()
            {
                AuthenticateCommand = new Command(() =>
                {
                    AreCredentialsInvalid = !UserAuthenticated(Username, Password);
                    if (AreCredentialsInvalid) return;
    
                    App.Current.MainPage = new MainPage();
                });
    
                AreCredentialsInvalid = false;
            }
    
            private bool UserAuthenticated(string username, string password)
            {
                bool loggedIn = false;
                if (string.IsNullOrEmpty(username)
                    || string.IsNullOrEmpty(password))
                {
                    return false;
                }
                loggedIn = App.api.Login("dxing", username, password, Device.RuntimePlatform.ToString());
                if (loggedIn)
                    App.IsUserLoggedIn = true;
                else
                    App.IsUserLoggedIn = false;
    
                return loggedIn;
            }
    

    how could I change and call my method so it won't lock the UI while it gets data?

  • veso266veso266 Member ✭✭

    damm I can't move this post into other section :disappointed:
    so I double posted here: https://forums.xamarin.com/discussion/comment/402139#Comment_402139

Sign In or Register to comment.