Home Page - Food Delivery App in Maui

 

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

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

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

School UI Design using xamarin form