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
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
Post a Comment