Show / Hide Table of Contents

    Tips and Tricks

    Empty View

    In order to centralize the state of the application when there is no data, we made template view

    <templates:EmptyView Message="{ext:Translate accountdata_empty}" Kind="Transactions" IsVisible="{Binding ShowEmptyView}" />
    

    It’s not particularly smart; at the moment it only shows a message centered on the screen

    <ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 x:Class="AssecoSEE.DEM.Components.Templates.EmptyView"
                 HeightRequest="1000000" 
                 x:Name="emptyViewTamplate">
      <ContentView.Content>
            <StackLayout VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
                <Label Text="{Binding Message, Source={x:Reference emptyViewTamplate}}" 
                       VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" 
                       HorizontalTextAlignment="Center" VerticalTextAlignment="Center" />
            </StackLayout>
      </ContentView.Content>
    </ContentView>
    

    But based on Kind, special appearances (ControlTemplates) in the theme can be made in the future when implementation is made regardless of the product and, at the same time, they can adapt to some specific usage. I changed in the application the part where the special code for that part from above was.

    Lottie animations

    We added animations when initiating the application on Android and making payments

    Demo video

    <ctrl:AAnimationView x:Name="DoneAnimation" Animation="_DEM_done.json" AutoPlay="True" Loop="False" WidthRequest="80" HeightRequest="80" Margin="10" />
    

    More info at https://lottiefiles.com/featured

    Timer Service

    A new service InActivityService was added which after certain time of inactivity logs out the user.

            public InActivityService(IConfiguration config, IDebugService debug)
            {
                this.debug = debug;
    
                timeoutInMinutes = config.FactoryConfig_InActivity_Logout_In_Minutes;
    
                timer = new TimerService(debug, TimeSpan.FromMinutes(timeoutInMinutes), async () => { await CallBack(); });
            }
    

    Temporarily it’s only connected to navigation, so if you don’t navigate anywhere in 4 minutes, the application logs you out; here, for example, timer gets reset

    internal async Task<NavigationResult> PushPage(IUsecasePage page, bool? useModalNavigation, bool animated = true)
            {
                InActivityService?.Reset();
    

    And on pop

            protected virtual void NavigationPage_Popped(object sender, NavigationEventArgs e)
            {
                InActivityService?.Reset();
    

    We knew that more or less, but what is important here is that the service uses this class. Now you can use it if you want to perform something for a certain time period, from time to time or just once etc. Basically, I added this method to Device service because the class is internal and so we could have better control.

            /// <summary>
            ///     Starts a recurring timer using the timer class.
            /// </summary>
            /// <param name="name">Represent name of the timer </param>
            /// <param name="interval">The interval between invocations of the callback </param>
            /// <param name="callBack">Action to run when the timer elapses</param>
            /// <param name="repeat">Sets execution of action only once (false) or repeatedly (true). Default value is true</param>
            public ITimerService StartTimer(string name, TimeSpan interval, Action callBack, bool repeat = true)
            {
                return new TimerService(name, debug, interval, callBack, repeat);
            }
    

    This is how I initialize something that is being performed every 5 minutes in the background

        refreshMailboxSummary = device.StartTimer("refreshMailboxSummary", TimeSpan.FromMinutes(5), async () =>
        {
            await  RefershData<MailboxSummary>();
         }); 
    

    And this is how I start

        refreshMailboxSummary.Start();
    

    And during logout, sleep etc. we put stop or dispose;

        refreshMailboxSummary?.Stop();
    

    In this way we can control what is centralized, what is set from the timer, what is being made in the background etc.

    Inline error / warning control

    We added new method in base view model ShowInlineMassage for showing messages on every screen:

    For example

        public override async Task<bool> Start()
        {
                if (!CheckIsConnected())
                {
      ShowInlineMassage(new Message(MessageType.Error, "foundation_connection_error"));
                    return false;
                }
    

    Page Tasks

    PageViewModel task list for data retrieval is added and it can be expanded on a specific ViewModel.

            private readonly List<Func<Task<bool>>> pageTasks = new List<Func<Task<bool>>>();
    
            public void AddPageTask(Func<Task<bool>> pageTask)
            {
                pageTasks.Add(pageTask);
            }
    
            public async Task<bool> ExexuteAllPageTasks()
            {
                try
                {
                    await Task.WhenAll(pageTasks.Select(x => x()));
    
                    return true;
                }
                catch(Exception)
                {
                    return false;
                }
            }
    

    For example, in the AccountDetailsViewModel we can add task:

            public AccountDetailsViewModel()
            {
                DataSource = new ListDataSource<Transaction, TransactionDataOptions, TransactionsGetListUriParams, ITransactionsManager>(
                    App.ResolveService<IApiClient>(), App.Cache)
                {
                    ResultPropertyName = "Transactions"
                };
    
                Transform = TransformTransaction;
    
                AddPageTask(() => App.ResolveService<IAccountService>().GetData(
                    navigationParams.AccountNumber, navigationParams.Data, (account) => {
                        Account = account;
                    }));
            }
    

    and execute it on Start:

            public async override Task<bool> Start()
            {
                if (navigationParams==null)
                {
                    return false;
                }
    
                await ExexuteAllPageTasks();
    
                return Account.HasValue();
            }
    

    In the future, when someone wants to expand the details that need to be shown here, s/he will simply override this view model and add the new task. This approach is different than overriding the methods themselves as the main functionality is not killed but expanded and all the existing mechanisms of the main functionality can be used. Nevertheless, there is an option to override the main functionality if required.

    Push message

    We got integrated with firebase through initial scenario and we showed a message that remains like a Toast at the bottom of the screen. The only thing left is to push it through our APIs in order to support the user, links, etc.

    DeepLinking and RedirectUri

    We also pushed through DeepLinking, in order to get URIs through, for example, push messages or advertisements that can then be opened with our app. Then we implemented support for RedirectUri similar to Web to link the user first to the login page and afterwards, when the user gets access to the system, to go to the requested page from DeepLink instead to the initial one, i.e. Dashboard. There is still work to do, to check if it's pre login or post login; if the page doesn’t exist, to go to 404 Not found, etc. but the basic scenario is closed.

    Translation text with comma

    If you want to use a comma within your translation text, you should wrap the whole sentence in "", like this:

    Resource,en-US,ro
    core_payments,"Payments, 2, with comma","Payments, ro, with comma"
    

    Resorce.designer.cs

    Every time I checkout on another branch a new change is automatically applied to Resorce.designer.cs. Does this issue seem familiar to you?

    Try adding

    <AndroidUseIntermediateDesignerFile>True</AndroidUseIntermediateDesignerFile>
    

    to the Android head's .csproj - this should make the designer file autogenerate in the obj folder and you can then just delete the designer file from the project

    TranslateConverter

    Sometimes it's convenient to use data bindings to display the string representation of an object or value with translation.

    The most powerful tool is the converter: TranslateConverter.

     <Label Text="{Binding TotalNumber, Converter={StaticResource TranslateConverter}, ConverterParameter='($accountdata_total) {0}'}"  />
    

    Notice that the formatting string is delimited is specifiend with ConverterParameter by single-quote (apostrophe) characters to help the XAML parser avoid treating the curly braces as another XAML markup extension.

    Uppercase

    Just add $! before translation key in translate extension, and your translation will display in uppercase.

     <Button Text="{ext:Translate ($!accountdata_change_nickname)}" />
    
    Back to top Copyright 2020 Asseco SEE