14

Uber Clone App using State Machine in Xamarin Forms

 2 years ago
source link: https://www.xamboy.com/2022/01/28/uber-clone-app-using-state-machine-in-xamarin-forms/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Uber Clone App using State Machine in Xamarin Forms

Screen-Shot-2022-01-12-at-4.30.04-PM.png?fit=1818%2C1122&ssl=1

For the last few months, I have been writing about State Machine. As the final article of this series and the first article of the year, I’ll show you how to implement State Machine in a real-life scenario, using as an example an Uber Clone App. 

A few years ago, I did this sample of an Uber Clone app, so I’ll take this sample and modify it to use a State Machine. 

Let’s start

As I mentioned in a previous article, the first step when working with State Machines is to define the states that will be handled.

These states can be represented using an Enum:

Create another Enum to define the triggers for each state:

Let’s code

After installing the Stateless package, we create the State machine and configure the initial state:

public class MapPageViewModel : INotifyPropertyChanged { public MapPageViewModel() { var _stateMachine = new StateMachine<XUberState, XUberTrigger>(XUberState.Initial);

_stateMachine.Configure(XUberState.Initial) .OnEntry(Initialize) .OnExit(() => { Places = new ObservableCollection<GooglePlaceAutoCompletePrediction>(RecentPlaces); }) .OnActivateAsync(GetActualUserLocation) .Permit(XUberTrigger.ChooseDestination, XUberState.SearchingDestination) .Permit(XUberTrigger.CalculateRoute, XUberState.CalculatingRoute);

... } }

To connect the State with the UI, we expose a State property that will represent the current state:

namespace UberClone.ViewModels { public class MapPageViewModel : INotifyPropertyChanged { public XUberState State { get; private set; }

public ICommand FireTriggerCommand { get; } private readonly StateMachine<XUberState, XUberTrigger> _stateMachine;

public MapPageViewModel() { var _stateMachine = new StateMachine<XUberState, XUberTrigger>(XUberState.Initial); ... FireTriggerCommand = new Command<XUberTrigger>((trigger) => { if(_stateMachine.CanFire(trigger)) { _stateMachine.Fire(trigger); State = _stateMachine.State; } }); } } }

<?xml version="1.0" encoding="UTF-8"?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="UberClone.Views.MapPage" > <Grid RowSpacing="0" x:Name="layout" VerticalOptions="FillAndExpand" RowDefinitions="Auto, *"> ... <local:SearchContentView IsVisible="false" Grid.Row="1" x:Name="searchContentView"> <local:SearchContentView.Triggers> <DataTrigger TargetType="local:SearchContentView" Binding="{Binding State}" Value="{x:Static helpers:XUberState.SearchingDestination}"> <Setter Property="IsVisible" Value="True"/> </DataTrigger> </local:SearchContentView.Triggers> </local:SearchContentView> </Grid> </ContentPage>

Now that we have the UI + ViewModel connected, we can define the rest of our states:

namespace UberClone.ViewModels { public class MapPageViewModel : INotifyPropertyChanged { ... public MapPageViewModel() { var _stateMachine = new StateMachine<XUberState, XUberTrigger>(XUberState.Initial);

CalculateRouteTrigger = _stateMachine.SetTriggerParameters<GooglePlaceAutoCompletePrediction>(XUberTrigger.CalculateRoute);

_stateMachine.Configure(XUberState.Initial) .OnEntry(Initialize) .OnExit(() => { Places = new ObservableCollection<GooglePlaceAutoCompletePrediction>(RecentPlaces); }) .OnActivateAsync(GetActualUserLocation) .Permit(XUberTrigger.ChooseDestination, XUberState.SearchingDestination) .Permit(XUberTrigger.CalculateRoute, XUberState.CalculatingRoute);

_stateMachine .Configure(XUberState.SearchingOrigin) .Permit(XUberTrigger.Cancel, XUberState.Initial) .Permit(XUberTrigger.ChooseDestination, XUberState.SearchingDestination);

_stateMachine .Configure(XUberState.SearchingDestination) .Permit(XUberTrigger.Cancel, XUberState.Initial) .Permit(XUberTrigger.ChooseOrigin, XUberState.SearchingOrigin) .PermitIf(XUberTrigger.CalculateRoute, XUberState.CalculatingRoute, () => OriginCoordinates != null);

_stateMachine .Configure(XUberState.CalculatingRoute) .OnEntryFromAsync(CalculateRouteTrigger, GetPlacesDetail) .Permit(XUberTrigger.ChooseRide, XUberState.ChoosingRide) .Permit(XUberTrigger.Cancel, XUberState.Initial);

_stateMachine .Configure(XUberState.ChoosingRide) .Permit(XUberTrigger.Cancel, XUberState.Initial) .Permit(XUberTrigger.ChooseDestination, XUberState.SearchingDestination) .Permit(XUberTrigger.ConfirmPickUp, XUberState.ConfirmingPickUp);

_stateMachine .Configure(XUberState.ConfirmingPickUp) .Permit(XUberTrigger.ChooseRide, XUberState.ChoosingRide) .Permit(XUberTrigger.ShowXUberPass, XUberState.ShowingXUberPass);

_stateMachine .Configure(XUberState.ShowingXUberPass) .Permit(XUberTrigger.ConfirmPickUp, XUberState.ConfirmingPickUp) .Permit(XUberTrigger.WaitForDriver, XUberState.WaitingForDriver);

_stateMachine .Configure(XUberState.WaitingForDriver) .Permit(XUberTrigger.CancelTrip, XUberState.Initial) .Permit(XUberTrigger.StartTrip, XUberState.TripInProgress); State = _stateMachine.State;

_stateMachine.ActivateAsync(); }

private void Initialize() { CleanPolylineCommand.Execute(null); DestinationLocation = string.Empty; }

private async Task GetActualUserLocation() { try { await Task.Yield(); var request = new GeolocationRequest(GeolocationAccuracy.High,TimeSpan.FromSeconds(5000)); var location = await Geolocation.GetLocationAsync(request);

if (location != null) { OriginCoordinates = location; CenterMapCommand.Execute(location); GetLocationNameCommand.Execute(new Position(location.Latitude, location.Longitude)); } } catch (Exception) { await UserDialogs.Instance.AlertAsync("Error", "Unable to get actual location", "Ok"); } } ... } }

Result:

That’s all for now.

Check the full source code here.

NOTE: This code has a lot of room for improvement, I made this quick sample just to show the concept.

Happy Stateless.

Be First to Comment

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Comment

Name*

Email*

Website

Notify me of follow-up comments by email.

Notify me of new posts by email.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK