Home Page - Food Delivery App in Maui

 

Home Page - Food Delivery App in MAUI
Home Page - Food Delivery App in MAUI

Please, support my blog by clicking on our sponsors ad!

Follow basic setup from here
You will get all page of this app from FoodDeliveryApp Menu on top.

Let's Create Model

MenuModel

    public class MenuModel
    {
        public string Name { get; set; }
        public decimal Price { get; set; }
        public string Description { get; set; }
        public ImageSource Image { get; set; }
    }  

RestaurantModel

   public class RestaurantModel
    {
        public string Name { get; set; }
        public string Description { get; set; }
        public string Rating { get; set; }
        public ImageSource Image { get; set; }

        public List<MenuModel> Menus { get; set; } = new List<MenuModel>();

    }  

BannerModel

   public class BannerModel 
    {
        public ImageSource Image { get; set; }
    }  

BaseViewModel

    public class BaseViewModel : INotifyPropertyChanged
    {
        bool isBusy = false;
        public bool IsBusy
        {
            get { return isBusy; }
            set { SetProperty(ref isBusy, value); }
        }

        protected bool SetProperty<T>(ref T backingStore, T value,
            [CallerMemberName] string propertyName = "",
            Action onChanged = null)
        {
            if (EqualityComparer<T>.Default.Equals(backingStore, value))
                return false;

            backingStore = value;
            onChanged?.Invoke();
            OnPropertyChanged(propertyName);
            return true;
        }

        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            var changed = PropertyChanged;
            if (changed == null)
                return;

            changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion
    }  

MainViewModel

    public class MainViewModel
    {
        public List<BannerModel> BannerModel { get; set; } = new List<BannerModel>();
        public List<RestaurantModel> Restaurants { get; set; } = new List<RestaurantModel>();
        public List<RestaurantModel> FirstSlotRestaurants { get; set; } = new List<RestaurantModel>();
        public List<RestaurantModel> SecondSlotRestaurants { get; set; } = new List<RestaurantModel>();
        public List<MenuModel> Menus { get; set; } = new List<MenuModel>();
    }  

HomeViewModel

    public class HomeViewModel : BaseViewModel
    {

        public Command LoadBannerCommand { get; set; }
        private List<MainViewModel> bannerVM;
        public HomeViewModel()
        {
            LoadBannerCommand = new Command(async () => await ExecuteLoadBannerCommand());
        }

        public List<MainViewModel> vm
        {
            get
            {
                return bannerVM;
            }
            set
            {
                SetProperty(ref bannerVM, value);
            }
        }

        public async Task ExecuteLoadBannerCommand()
        {
            try
            {
                IsBusy = true;
                vm = new List<MainViewModel>();
                vm.Add(new MainViewModel { BannerModel = new List<BannerModel>() });
                List<BannerModel> list = new List<BannerModel>();
                list.Add(new BannerModel { Image = "https://cdn.grabon.in/gograbon/images/web-images/uploads/1658919135375/swiggy-coupons.jpg" });
                list.Add(new BannerModel { Image = "https://www.dealsshutter.com/uploads/social_images/stores/swiggy-coupons-social-image-final-1621831150.jpg" });
                list.Add(new BannerModel { Image = "https://www.couponmoto.com/boards/wp-content/uploads/2019/02/Swiggy-Banner.png" });
                list.Add(new BannerModel { Image = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR8CF6zXRURcFjGNS4twbPJefG596hzaydN1d_oC4Xtx391t_BOIxqLXsfUgv4RlK0V2JY" });
                list.Add(new BannerModel { Image = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR9-SipuwkwtNCQCBbr47cU0-tWqYfO4QJLJQ" });


                List<MenuModel> menus = new List<MenuModel>();
                menus.Add(new MenuModel { Name = "Locho", Description = "Locho", Price = 25, Image = "https://cdn-bkdna.nitrocdn.com/byIcNObNLXVFaYWLstICKAkCMytzVoyD/assets/static/optimized/rev-02ea418/wp-content/uploads/2021/03/LOCHO.jpg" });
                menus.Add(new MenuModel { Name = "Pani Puri", Description = "Locho", Price = 25, Image = "https://akm-img-a-in.tosshub.com/indiatoday/images/story/201708/dish-story_647_081417052301.jpg" });
                menus.Add(new MenuModel { Name = "Chole Bhature", Description = "Chole Bhature", Price = 25, Image = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRXh5LCoOMSM_9pmgcOROJRd4If-6ciXX_bkw" });
                menus.Add(new MenuModel { Name = "Lithi Chokha", Description = "Locho", Price = 25, Image = "https://img.traveltriangle.com/blog/wp-content/uploads/2018/01/shutterstock_4148348021.jpg" });
                menus.Add(new MenuModel { Name = "Indian Food", Description = "Indian Food", Price = 25, Image = "https://t3.ftcdn.net/jpg/01/43/83/08/360_F_143830808_V7n31HxcS8duJIVr3opWzG4FCkDQZK4v.jpg" });


                List<RestaurantModel> restaurants = new List<RestaurantModel>();
                restaurants.Add(new RestaurantModel
                {
                    Name = "Table 101",
                    Description = "Good Option",
                    Rating = "4.0 (10k)",
                    Image = "https://hips.hearstapps.com/hmg-prod/images/img-6171-jpg-1516034404.jpg",
                    Menus = menus
                });

                restaurants.Add(new RestaurantModel
                {
                    Name = "Foina",
                    Description = "Good Option",
                    Rating = "4.0 (10k)",
                    Image = "https://im1.dineout.co.in/images/uploads/restaurant/sharpen/4/l/h/p4185-164156150261d83d9ec6ca8.jpg",
                    Menus = menus
                });

                restaurants.Add(new RestaurantModel
                {
                    Name = "Kabab and Kurries",
                    Description = "Good Option",
                    Rating = "4.0 (10k)",
                    Image = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTx0hX-qswrn0vA1ZGogh05cd6dbRiJqbG-ww",
                    Menus = menus
                });

                restaurants.Add(new RestaurantModel
                {
                    Name = "Rasoi Kitchen",
                    Description = "Good Option",
                    Rating = "4.0 (10k)",
                    Image = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTO5nlpGTbABZretJas2xH6RDnWIhTbiRoIOA",
                    Menus = menus
                });

                restaurants.Add(new RestaurantModel
                {
                    Name = "Mabruk",
                    Description = "Good Option",
                    Rating = "4.0 (10k)",
                    Image = "https://threebestrated.in/images/MahalaxmiFastFoodandJuiceCorner-Surat-GJ.jpeg",
                    Menus = menus
                });

                restaurants.Add(new RestaurantModel
                {
                    Name = "Saptami",
                    Description = "Good Option",
                    Rating = "4.0 (10k)",
                    Image = "https://i0.wp.com/swadishta.de/wp-content/uploads/2021/01/Thali.jpg",
                    Menus = menus
                });

                restaurants.Add(new RestaurantModel
                {
                    Name = "Yeda Republic",
                    Description = "Good Option",
                    Rating = "4.0 (10k)",
                    Image = "https://i0.wp.com/indiacurrents.com/wp-content/uploads/2022/09/pesarratu.jpg",
                    Menus = menus
                });

                restaurants.Add(new RestaurantModel
                {
                    Name = "Peshawari",
                    Description = "Good Option",
                    Rating = "4.0 (10k)",
                    Image = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSCAOb9b2dUqUFuUbzbYlMWu4qLwrxjRs_2Dg",
                    Menus = menus
                });

                restaurants.Add(new RestaurantModel
                {
                    Name = "Solitare Restaurant",
                    Description = "Good Option",
                    Rating = "4.0 (10k)",
                    Image = "https://static.toiimg.com/thumb/56624568/308796_287027921321520_585680932_n.jpg",
                    Menus = menus
                });

                restaurants.Add(new RestaurantModel
                {
                    Name = "Gallery Cafe",
                    Description = "Good Option",
                    Rating = "4.0 (10k)",
                    Image = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQsuxe-gEy1j2uKXJG9pUWdx-ZGalqtGCDStw",
                    Menus = menus
                });

                vm[0].BannerModel = list;
                bannerVM[0].Restaurants = restaurants;
                bannerVM[0].FirstSlotRestaurants = restaurants.Take(3).ToList();
                bannerVM[0].SecondSlotRestaurants = restaurants.Reverse<RestaurantModel>().Take(7).ToList();
                bannerVM[0].Menus = menus;
            }
            catch (Exception ex)
            {
                await App.Current.MainPage.DisplayAlert("", ex.Message, "OK");
            }
            IsBusy = false;
        }

        public void OnAppearing()
        {
            IsBusy = true;
        }


    }  
Let's Create a Control

ProductHomeControl.xaml
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="FoodDeliveryApp.Controls.ProductHomeControl"
             xmlns:fontAwesome="clr-namespace:FoodDeliveryApp.Utilities">
    <Grid ColumnDefinitions="Auto,Auto,*,Auto" RowDefinitions="Auto,Auto" ColumnSpacing="5" RowSpacing="5">
        <Label Grid.Column="0" Grid.Row="0" Text="{x:Static fontAwesome:FontAwesomeSolid.Shopping_Bag}" 
               FontSize="15"  TextColor="{x:StaticResource Primary}" FontFamily="FontAwesome" ></Label>
        <Label Grid.Column="1" Grid.Row="0" Text="Work" TextColor="{x:StaticResource Secondary}" 
               FontAttributes="Bold" ></Label>
        <Label Grid.Column="2" Grid.Row="0" Text="{x:Static fontAwesome:FontAwesomeSolid.Angle_Down}"
               VerticalOptions="End" FontSize="20" TextColor="{x:StaticResource Gray}" FontFamily="FontAwesome" >
            
        </Label>
        <Label Grid.Column="3" Grid.Row="0" Grid.RowSpan="2" Text="{x:Static fontAwesome:FontAwesomeSolid.User_Circle}" 
               FontSize="30" TextColor="{x:StaticResource Gray}" FontFamily="FontAwesome" ></Label>
        <Label Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="1" Text="1600 Amphitheatre Parkway 
               Mountain View, CA 94043, USA." TextColor="{x:StaticResource Gray}"></Label>
    </Grid>
</ContentView>
RoundCornerImage.Xaml
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="FoodDeliveryApp.Controls.RoundCornerImage">
    <Grid RowDefinitions="Auto,Auto" Padding="5">
        <Frame Grid.Row="0" Padding="0" CornerRadius="20">
            <Image x:Name="img" HeightRequest="80" Aspect="AspectFill"></Image>
        </Frame>
        <Label Grid.Row="1" x:Name="lbl" TextColor="{x:StaticResource Gray}" HorizontalOptions="Center" Margin="0,8,0,0"></Label>
    </Grid>
</ContentView>
RoundCornerImage.Xaml.cs
public partial class RoundCornerImage : ContentView
{
    public RoundCornerImage()
    {
        InitializeComponent();
    }

    public ImageSource Image { get => img.Source; set => img.Source = value; }
    public bool IsAnimation { get => img.IsAnimationPlaying; set => img.IsAnimationPlaying = value; }
    public string Title { get => lbl.Text; set => lbl.Text = value; }
}

Let's Create Template

BannerTemplate.Xaml

 <ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="FoodDeliveryApp.Pages.Products.Template.BannerTemplate"
             xmlns:model="clr-namespace:FoodDeliveryApp.Models">
    <StackLayout Padding="5">
        <Frame x:DataType="model:BannerModel" Padding="0" CornerRadius="10">
            <Image Source="{Binding Image}" HeightRequest="150" Aspect="AspectFill"></Image>
        </Frame>
    </StackLayout>
</ContentView>  

ProductTemplate.xaml

  <ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="FoodDeliveryApp.Pages.Products.Template.ProductTemplate">
    <Grid Padding="5" ColumnSpacing="10" RowDefinitions="Auto" RowSpacing="0" ColumnDefinitions="150,*">
        <Frame  Padding="0" CornerRadius="10" Grid.Row="0" Grid.Column="0" Grid.RowSpan="4">
            <Image Source="{Binding Image}" HeightRequest="150" Aspect="AspectFill"></Image>
        </Frame>
        <StackLayout Grid.Row="0" Grid.Column="1" VerticalOptions="CenterAndExpand">
            <Label  Text="{Binding Name}" TextColor="{x:StaticResource Gray}" VerticalOptions="Start" FontAttributes="Bold"></Label>
            <Label Text="{Binding Rating}" TextColor="{x:StaticResource Gray}" FontAttributes="Bold"></Label>
            <Label Text="{Binding Description}" TextColor="{x:StaticResource Gray}" ></Label>
            <Label Text="Gopipura . 15km" TextColor="{x:StaticResource Gray}" ></Label>
        </StackLayout>
    </Grid>
</ContentView> 

Let's Create Home Page

   <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="FoodDeliveryApp.Pages.Products.Home"
             xmlns:control="clr-namespace:FoodDeliveryApp.Controls"
             xmlns:fontAwesome="clr-namespace:FoodDeliveryApp.Utilities"
             xmlns:vm="clr-namespace:FoodDeliveryApp.ViewModels"
             xmlns:model="clr-namespace:FoodDeliveryApp.Models"
             xmlns:template="clr-namespace:FoodDeliveryApp.Pages.Products.Template"
             Title="Home"
             Shell.NavBarIsVisible="False">
    <RefreshView x:Name="refreshView" x:DataType="vm:HomeViewModel" Command="{Binding LoadBannerCommand}" 
                 IsRefreshing="{Binding IsBusy, Mode=TwoWay}">
        <Grid RowDefinitions="Auto,Auto,*" Padding="10" RowSpacing="10" x:DataType="vm:HomeViewModel" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
            <control:ProductHomeControl Grid.Row="0"></control:ProductHomeControl>
            <Frame Padding="12" Grid.Row="1" BackgroundColor="#f8f8f8" BorderColor="#f8f8f8" HasShadow="True">
                <Grid ColumnDefinitions="*,Auto,Auto,Auto" ColumnSpacing="10">
                    <Label Grid.Column="0" Text="Search,Order,Enjoy,Repeat" TextColor="{x:StaticResource Gray}"></Label>
                    <Label Grid.Column="1" Text="{x:Static fontAwesome:FontAwesomeSolid.Search}" TextColor="{x:StaticResource Gray}" FontSize="20" FontFamily="FontAwesome"></Label>
                    <BoxView Grid.Column="2" BackgroundColor="{x:StaticResource Gray}" HeightRequest="20" WidthRequest="1"></BoxView>
                    <Label Grid.Column="3" Text="{x:Static fontAwesome:FontAwesomeSolid.Microphone}" FontSize="20" TextColor="{x:StaticResource Secondary}" FontFamily="FontAwesome">

                    </Label>
                </Grid>
            </Frame>

            <ListView x:DataType="vm:HomeViewModel" x:Name="listView" ItemsSource="{Binding vm}" Grid.Row="2" HasUnevenRows="True" SeparatorVisibility="None">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <Grid x:DataType="vm:MainViewModel" RowSpacing="10" RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">

                                <Grid ColumnDefinitions="*,*,*" Grid.Row="0">
                                    <control:RoundCornerImage Grid.Column="0" x:Name="img1" Image="https://img95.lovepik.com/photo/40104/9102.gif_wh300.gif" IsAnimation="True" Title="Tasty"></control:RoundCornerImage>
                                    <control:RoundCornerImage Grid.Column="1" x:Name="img2" Image="https://i.pinimg.com/736x/a9/e7/b9/a9e7b9c4a3e6d2a260d68bd6fd019dc7.jpg"  Title="Ofer Zone"></control:RoundCornerImage>
                                    <control:RoundCornerImage Grid.Column="2" x:Name="img3" Image="https://media4.giphy.com/media/v1.Y2lkPTc5MGI3NjExMHpwbHdiMTFiaTBoY3kyZTNueTk4bXA4eGNjcWxzOGNmaTgzaDU4ZCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/Yuy61Bd6K8STS/giphy.gif" IsAnimation="True" Title="Gourmet"></control:RoundCornerImage>
                                </Grid>
                                <StackLayout Grid.Row="1">
                                    <!-- Other content for the list item -->
                                    <CarouselView IndicatorView="indicatorView" Grid.Row="1"  ItemsSource="{Binding BannerModel}" PeekAreaInsets="15">
                                        <CarouselView.ItemsLayout>
                                            <LinearItemsLayout ItemSpacing="0" Orientation="Horizontal" SnapPointsAlignment="Center" SnapPointsType="MandatorySingle"></LinearItemsLayout>
                                        </CarouselView.ItemsLayout>
                                        <CarouselView.ItemTemplate>
                                            <DataTemplate>
                                                <template:BannerTemplate></template:BannerTemplate>
                                            </DataTemplate>
                                        </CarouselView.ItemTemplate>
                                    </CarouselView>
                                    <IndicatorView x:Name="indicatorView"
                   IndicatorColor="LightGray"
                   SelectedIndicatorColor="DarkGray"
                   HorizontalOptions="Center" />
                                </StackLayout>


                                <Label Text="Your trusted picks" Grid.Row="2" TextColor="{x:StaticResource Gray}" FontAttributes="Bold"></Label>
                                <Frame CornerRadius="20" HorizontalOptions="Start" Padding="0" Grid.Row="3" BackgroundColor="{x:StaticResource Gray}">
                                    <Label Text="Reorder" TextColor="white" FontAttributes="Bold" Margin="10" ></Label>
                                </Frame>

                                <Grid Grid.Row="4" ColumnDefinitions="*,*,*" RowDefinitions="Auto,Auto">
                                    <control:RoundCornerImage Grid.Row="0" Grid.Column="0"  Image="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQsuxe-gEy1j2uKXJG9pUWdx-ZGalqtGCDStw" IsAnimation="True" Title="Thali"></control:RoundCornerImage>
                                    <control:RoundCornerImage Grid.Row="0" Grid.Column="1"  Image="https://static.toiimg.com/thumb/56624568/308796_287027921321520_585680932_n.jpg"  Title="Ofer Zone"></control:RoundCornerImage>
                                    <control:RoundCornerImage Grid.Row="0" Grid.Column="2"  Image="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSCAOb9b2dUqUFuUbzbYlMWu4qLwrxjRs_2Dg" IsAnimation="True" Title="South Indian"></control:RoundCornerImage>

                                    <control:RoundCornerImage Grid.Row="1" Grid.Column="0"  Image="https://i0.wp.com/indiacurrents.com/wp-content/uploads/2022/09/pesarratu.jpg" IsAnimation="True" Title="Roll"></control:RoundCornerImage>
                                    <control:RoundCornerImage Grid.Row="1" Grid.Column="1"  Image="https://i0.wp.com/swadishta.de/wp-content/uploads/2021/01/Thali.jpg"  Title="Full Thali"></control:RoundCornerImage>
                                    <control:RoundCornerImage Grid.Row="1" Grid.Column="2"  Image="https://threebestrated.in/images/MahalaxmiFastFoodandJuiceCorner-Surat-GJ.jpeg" IsAnimation="True" Title="Sandwich"></control:RoundCornerImage>
                                </Grid>

                                <Image Grid.Row="5" Source="https://media.tenor.com/K67T2j90c-cAAAAC/fruits-web-banner.gif" Aspect="AspectFill" IsAnimationPlaying="True"></Image>



                                <ListView HasUnevenRows="True" Grid.Row="6" ItemsSource="{Binding FirstSlotRestaurants}" SeparatorVisibility="None">
                                    <ListView.ItemTemplate>
                                        <DataTemplate>
                                            <ViewCell>
                                                <template:ProductTemplate></template:ProductTemplate>
                                            </ViewCell>
                                        </DataTemplate>
                                    </ListView.ItemTemplate>
                                </ListView>

                                <StackLayout BackgroundColor="{x:StaticResource LightGray}" Grid.Row="7" Spacing="10" Padding="10">
                                    <Label Text="Popular Restaurant" TextColor="{x:StaticResource Gray}" FontAttributes="Bold"></Label>
                                    <CarouselView    ItemsSource="{Binding Restaurants}" >
                                        <CarouselView.ItemsLayout>
                                            <LinearItemsLayout ItemSpacing="0" Orientation="Horizontal" SnapPointsAlignment="Center" SnapPointsType="MandatorySingle"></LinearItemsLayout>
                                        </CarouselView.ItemsLayout>
                                        <CarouselView.ItemTemplate>
                                            <DataTemplate>
                                                <template:ProductTemplate></template:ProductTemplate>
                                            </DataTemplate>
                                        </CarouselView.ItemTemplate>
                                    </CarouselView>
                                </StackLayout>

                                <ListView HasUnevenRows="True" Grid.Row="8" ItemsSource="{Binding SecondSlotRestaurants}" SeparatorVisibility="None">
                                    <ListView.ItemTemplate>
                                        <DataTemplate>
                                            <ViewCell>
                                                <template:ProductTemplate></template:ProductTemplate>
                                            </ViewCell>
                                        </DataTemplate>
                                    </ListView.ItemTemplate>
                                </ListView>

                                <StackLayout BackgroundColor="{x:StaticResource LightGray}" Grid.Row="9" Spacing="10" Padding="10">
                                    <Label Text="Popular Menu" TextColor="{x:StaticResource Gray}" FontAttributes="Bold"></Label>
                                    <CarouselView    ItemsSource="{Binding Menus}" >
                                        <CarouselView.ItemsLayout>
                                            <LinearItemsLayout ItemSpacing="0" Orientation="Horizontal" SnapPointsAlignment="Center" SnapPointsType="MandatorySingle"></LinearItemsLayout>
                                        </CarouselView.ItemsLayout>
                                        <CarouselView.ItemTemplate>
                                            <DataTemplate>
                                                <template:ProductTemplate></template:ProductTemplate>
                                            </DataTemplate>
                                        </CarouselView.ItemTemplate>
                                    </CarouselView>
                                </StackLayout>


                            </Grid>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </Grid>
    </RefreshView>
</ContentPage>  

HomePage.xaml.cs

public partial class Home : ContentPage
{
    HomeViewModel _viewModel;
	public Home()
	{
		InitializeComponent();
        BindingContext = _viewModel = new HomeViewModel();
	}

    protected override async void OnAppearing()
    {
        base.OnAppearing();
        _viewModel.OnAppearing();
    }
}  

Hope this is helpfull to you. please share your feedback in comment section.

Comments

Popular posts from this blog

Push Notifications in .NET MAUI: A Comprehensive Guide

Explore the UI libraries available for .NET MAUI at no cost.

Push Notification using Firebase in xamarin form (Android and IOS)