feat(commerce): Use uno.reactive in commerce demo app
This commit is contained in:
Родитель
9c206b26c1
Коммит
cea931728c
|
@ -232,3 +232,9 @@ dotnet_diagnostic.IDE0022.severity = none
|
|||
|
||||
# CS1998: This async method lacks 'await' operators and will run synchronously.
|
||||
dotnet_diagnostic.CS1998.severity = none
|
||||
|
||||
# SA1101: Prefix local calls with this
|
||||
dotnet_diagnostic.SA1101.severity = none
|
||||
|
||||
# SA1309: Field names should not begin with underscore
|
||||
dotnet_diagnostic.SA1309.severity = none
|
||||
|
|
|
@ -71,6 +71,7 @@
|
|||
<PackageReference Include="Uno.UniversalImageLoader" Version="1.9.33" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||
<PackageReference Include="System.Linq.Async" Version="4.0.0" />
|
||||
<PackageReference Include="Xamarin.AndroidX.AppCompat.AppCompatResources">
|
||||
<Version>1.2.0.5</Version>
|
||||
</PackageReference>
|
||||
|
@ -143,6 +144,14 @@
|
|||
<Project>{5123670c-9756-4c9e-9844-f4a9c0aee633}</Project>
|
||||
<Name>Uno.Extensions.Serialization</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\src\Uno.Extensions.Reactive\Uno.Extensions.Reactive.csproj">
|
||||
<Project>{74D93A0B-42F9-45A6-8AC3-684DAE9659A8}</Project>
|
||||
<Name>Uno.Extensions.Reactive</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\src\Uno.Extensions.Reactive.View\Uno.Extensions.Reactive.View.csproj">
|
||||
<Project>{7516C1F2-6CCB-4B59-91B7-E6D4B4EA5835}</Project>
|
||||
<Name>Uno.Extensions.Reactive.View</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="..\Commerce.Shared\Commerce.Shared.projitems" Label="Shared" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
||||
|
@ -154,4 +163,4 @@
|
|||
<Compile Remove="$(_AndroidResourceDesignerFile)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
<ToolkitResources xmlns="using:Uno.UI.ToolkitLib" />
|
||||
<!--<MaterialToolkitResources xmlns="using:Uno.Toolkit.Material" />-->
|
||||
|
||||
<ResourceDictionary Source="ms-appx:///Styles/FeedView.xaml" />
|
||||
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
</ResourceDictionary>
|
||||
|
|
|
@ -74,9 +74,9 @@ namespace Commerce
|
|||
.AddSingleton<INavigationBindingHandler, NavigationViewItemNavigationBindingHandler>()
|
||||
|
||||
.AddTransient<LoginViewModel>()
|
||||
.AddTransient<ProductsViewModel>()
|
||||
.AddTransient<ProductsViewModel.BindableProductsViewModel>()
|
||||
.AddTransient<FilterViewModel>()
|
||||
.AddTransient<ProductDetailsViewModel>()
|
||||
.AddTransient<ProductDetailsViewModel.BindableProductDetailsViewModel>()
|
||||
.AddViewModelData<Product>()
|
||||
.AddTransient<DealsViewModel>()
|
||||
.AddSingleton<IProductService>(sp => new ProductService("products.json"));
|
||||
|
@ -86,11 +86,13 @@ namespace Commerce
|
|||
.EnableUnoLogging();
|
||||
|
||||
var mapping = Host.Services.GetService<IRouteMappings>();
|
||||
mapping.Register(new RouteMap("Login", typeof(LoginPage), typeof(LoginViewModel.BindableLoginViewModel)));
|
||||
mapping.Register(new RouteMap(typeof(CommerceHomePage).Name, typeof(CommerceHomePage),
|
||||
RegionInitialization: (region, nav) => nav.Route.Next().IsEmpty() ?
|
||||
nav with { Route = nav.Route.Append(Route.NestedRoute("Products")) } :
|
||||
nav));
|
||||
mapping.Register(new RouteMap("Products", typeof(FrameView),
|
||||
ViewModel: typeof(ProductsViewModel.BindableProductsViewModel),
|
||||
RegionInitialization: (region, nav) => nav.Route.Next().IsEmpty() ?
|
||||
nav with { Route = nav.Route.AppendPage<ProductsPage>() } : nav with
|
||||
{
|
||||
|
@ -104,7 +106,8 @@ namespace Commerce
|
|||
nav with { Route = nav.Route with { Path = "+DealsPage/HotDeals" } }));
|
||||
mapping.Register(new RouteMap("ProductDetails",
|
||||
typeof(ProductDetailsPage),
|
||||
typeof(ProductDetailsViewModel), typeof(Product),
|
||||
typeof(ProductDetailsViewModel.BindableProductDetailsViewModel),
|
||||
typeof(Product),
|
||||
BuildQueryParameters: entity => new Dictionary<string, string> { { "ProductId", (entity as Product)?.ProductId + "" } }));
|
||||
mapping.Register(new RouteMap(typeof(CartDialog).Name, typeof(CartDialog),
|
||||
RegionInitialization: (region, nav) => nav.Route.Next().IsEmpty() ?
|
||||
|
@ -183,7 +186,7 @@ namespace Commerce
|
|||
});
|
||||
|
||||
var nav = Host.Services.GetService<INavigator>();
|
||||
var navResult = nav.NavigateToViewAsync<LoginPage>(this);
|
||||
var navResult = nav.NavigateToRouteAsync(this, "Login");
|
||||
//var navResult = nav.NavigateToRouteAsync(this, "/CommerceHomePage/Products/ProductDetails?ProductId=3");
|
||||
}
|
||||
|
||||
|
|
|
@ -30,8 +30,11 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\DealsViewModel.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\FilterViewModel.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\LoginViewModel.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\LoginViewModel.g.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\ProductDetailsViewModel.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\ProductDetailsViewModel.g.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\ProductsViewModel.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\ProductsViewModel.g.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Views\CartDialog.xaml.cs">
|
||||
<DependentUpon>CartDialog.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
@ -71,6 +74,10 @@
|
|||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="$(MSBuildThisFileDirectory)Styles\FeedView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="$(MSBuildThisFileDirectory)Views\CartDialog.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Storage;
|
||||
|
||||
|
@ -50,67 +52,23 @@ public class ProductService : JsonDataService<Product>, IProductService
|
|||
|
||||
}
|
||||
|
||||
public Task<Product[]> GetProducts()
|
||||
public async Task<IEnumerable<Product>> GetProducts(string? term, CancellationToken ct)
|
||||
{
|
||||
return base.GetEntities();
|
||||
//return new List<Product>
|
||||
//{
|
||||
// new Product{ProductId=1, Name="ProMaster headphones", Category="Technology", FullPrice="$130",Price="$99", Discount="Save 25%", Photo="ms-appx:///Assets/Photos/stockphoto1.png"},
|
||||
// new Product{ProductId=2, Name="Ray-gen sunglasses", Category="Accessories", FullPrice="$130",Price="$99", Discount="Save 25%", Photo="ms-appx:///Assets/Photos/stockphoto2.png"},
|
||||
// new Product{
|
||||
// ProductId=3,
|
||||
// Name="Jeffords sneakers",
|
||||
// Category="Men's shoes",
|
||||
// FullPrice="$130",
|
||||
// Price="$99",
|
||||
// Discount="Save 25%",
|
||||
// Photo="ms-appx:///Assets/Photos/stockphoto3.png",
|
||||
// Description="The classic low top silhouette is reinvented with a water-resistant feature. The perfect go-to pair to sport on light rainy days!",
|
||||
// Reviews= new[]{
|
||||
// new Review { Name = "Jean-Ralphio", Message = "Really good shoes. Love them" },
|
||||
// new Review{Name="Eric", Message="Instant buy, instant classic"},
|
||||
// new Review{Name="Lisa Kudrow", Message="I feel like walking on clouds with these shoes. Never experienced somthing simliar"}
|
||||
// }
|
||||
// },
|
||||
// new Product{ProductId=4, Name="Wheel watch 2019", Category="Watches", FullPrice="$130",Price="$99", Discount="Save 25%", Photo="ms-appx:///Assets/Photos/stockphoto4.png"},
|
||||
// new Product{ProductId=1, Name="ProMaster headphones", Category="Technology",FullPrice="$130",Price="$99", Discount="Save 25%", Photo="ms-appx:///Assets/Photos/stockphoto1.png"},
|
||||
// new Product{ProductId=2, Name="Ray-gen sunglasses", Category="Accessories", FullPrice="$130",Price="$99", Discount="Save 25%", Photo="ms-appx:///Assets/Photos/stockphoto2.png"},
|
||||
// new Product{ProductId=3, Name="Jeffords sneakers", Category="Men's shoes",FullPrice="$130",Price="$99", Discount="Save 25%", Photo="ms-appx:///Assets/Photos/stockphoto3.png"},
|
||||
// new Product{ProductId=4, Name="Wheel watch 2019", Category="Watches", FullPrice="$130",Price="$99", Discount="Save 25%", Photo="ms-appx:///Assets/Photos/stockphoto4.png"},
|
||||
// new Product{ProductId=1, Name="ProMaster headphones", Category="Technology",FullPrice="$130",Price="$99", Discount="Save 25%", Photo="ms-appx:///Assets/Photos/stockphoto1.png"},
|
||||
// new Product{ProductId=2, Name="Ray-gen sunglasses", Category="Accessories", FullPrice="$130",Price="$99", Discount="Save 25%", Photo="ms-appx:///Assets/Photos/stockphoto2.png"},
|
||||
// new Product{ProductId=3, Name="Jeffords sneakers", Category="Men's shoes",FullPrice="$130",Price="$99", Discount="Save 25%", Photo="ms-appx:///Assets/Photos/stockphoto3.png"},
|
||||
// new Product{ProductId=4, Name="Wheel watch 2019", Category="Watches", FullPrice="$130",Price="$99", Discount="Save 25%", Photo="ms-appx:///Assets/Photos/stockphoto4.png"},
|
||||
// new Product{ProductId=1, Name="ProMaster headphones", Category="Technology",FullPrice="$130",Price="$99", Discount="Save 25%", Photo="ms-appx:///Assets/Photos/stockphoto1.png"},
|
||||
// new Product{ProductId=2, Name="Ray-gen sunglasses", Category="Accessories", FullPrice="$130",Price="$99", Discount="Save 25%", Photo="ms-appx:///Assets/Photos/stockphoto2.png"},
|
||||
// new Product{ProductId=3, Name="Jeffords sneakers", Category="Men's shoes",FullPrice="$130",Price="$99", Discount="Save 25%", Photo="ms-appx:///Assets/Photos/stockphoto3.png"},
|
||||
// new Product{ProductId=4, Name="Wheel watch 2019", Category="Watches", FullPrice="$130",Price="$99", Discount="Save 25%", Photo="ms-appx:///Assets/Photos/stockphoto4.png"},
|
||||
// new Product{ProductId=1, Name="ProMaster headphones", Category="Technology",FullPrice="$130",Price="$99", Discount="Save 25%", Photo="ms-appx:///Assets/Photos/stockphoto1.png"},
|
||||
// new Product{ProductId=2, Name="Ray-gen sunglasses", Category="Accessories", FullPrice="$130",Price="$99", Discount="Save 25%", Photo="ms-appx:///Assets/Photos/stockphoto2.png"},
|
||||
// new Product{
|
||||
// ProductId=3,
|
||||
// Name="Jeffords sneakers",
|
||||
// Category="Men's shoes",
|
||||
// FullPrice="$130",
|
||||
// Price="$99",
|
||||
// Discount="Save 25%",
|
||||
// Photo="ms-appx:///Assets/Photos/stockphoto3.png",
|
||||
// Description="The classic low top silhouette is reinvented with a water-resistant feature. The perfect go-to pair to sport on light rainy days!",
|
||||
// Reviews= new[]{
|
||||
// new Review { Name = "Jean-Ralphio", Message = "Really good shoes. Love them" },
|
||||
// new Review{Name="Eric", Message="Instant buy, instant classic"},
|
||||
// new Review{Name="Lisa Kudrow", Message="I feel like walking on clouds with these shoes. Never experienced somthing simliar"}
|
||||
// }
|
||||
// },
|
||||
// new Product{ProductId=4, Name="Wheel watch 2019", Category="Watches", FullPrice="$130",Price="$99", Discount="Save 25%", Photo="ms-appx:///Assets/Photos/stockphoto4.png"},
|
||||
await Task.Delay(new Random(DateTime.Now.Millisecond).Next(100, 1000), ct);
|
||||
|
||||
//};
|
||||
var products = (await GetEntities()).AsEnumerable();
|
||||
if (term is not null)
|
||||
{
|
||||
products = products.Where(p => p.Name.Contains(term));
|
||||
}
|
||||
|
||||
return products;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IProductService
|
||||
{
|
||||
Task<Product[]> GetProducts();
|
||||
Task<IEnumerable<Product>> GetProducts(string? term, CancellationToken ct);
|
||||
}
|
||||
|
||||
public class Product
|
||||
|
|
|
@ -0,0 +1,294 @@
|
|||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:reactive="using:Uno.Extensions.Reactive">
|
||||
|
||||
<Style TargetType="reactive:FeedView">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="reactive:FeedView">
|
||||
<Grid>
|
||||
<VisualStateManager.CustomVisualStateManager>
|
||||
<reactive:SmoothVisualStateManager>
|
||||
<reactive:SmoothVisualStateRule MinDuration="0:0:0.500" />
|
||||
<reactive:SmoothVisualStateRule Group="ProgressGroup" To="Indeterminate" Delay="0:0:0.250" />
|
||||
</reactive:SmoothVisualStateManager>
|
||||
</VisualStateManager.CustomVisualStateManager>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="DataGroup">
|
||||
<VisualState x:Name="Undefined" />
|
||||
<VisualState x:Name="None">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="UndefinedPresenter.Visibility" Value="Collapsed" />
|
||||
<Setter Target="NonePresenter.Visibility" Value="Visible" />
|
||||
<Setter Target="SomePresenter.Visibility" Value="Collapsed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Some">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="UndefinedPresenter.Visibility" Value="Collapsed" />
|
||||
<Setter Target="NonePresenter.Visibility" Value="Collapsed" />
|
||||
<Setter Target="SomePresenter.Visibility" Value="Visible" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="ErrorGroup">
|
||||
<VisualStateGroup.Transitions>
|
||||
<VisualTransition To="Error">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames
|
||||
Storyboard.TargetName="ErrorPresenter"
|
||||
Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame
|
||||
KeyTime="0:0:0"
|
||||
Value="Visible"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetName="ErrorPresenterTransform"
|
||||
Storyboard.TargetProperty="Y"
|
||||
From="-50"
|
||||
To="0"
|
||||
Duration="0:0:.5"/>
|
||||
</Storyboard>
|
||||
</VisualTransition>
|
||||
<VisualTransition From="Error">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames
|
||||
Storyboard.TargetName="ErrorPresenter"
|
||||
Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame
|
||||
KeyTime="0:0:0"
|
||||
Value="Visible"/>
|
||||
<DiscreteObjectKeyFrame
|
||||
KeyTime="0:0:0.5"
|
||||
Value="Collapsed"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetName="ErrorPresenterTransform"
|
||||
Storyboard.TargetProperty="Y"
|
||||
To="-50"
|
||||
Duration="0:0:.5"/>
|
||||
</Storyboard>
|
||||
</VisualTransition>
|
||||
</VisualStateGroup.Transitions>
|
||||
<VisualState x:Name="NoError" />
|
||||
<VisualState x:Name="Error">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ErrorPresenter.Visibility" Value="Visible" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="ProgressGroup">
|
||||
<VisualState x:Name="Final" />
|
||||
<VisualState x:Name="Indeterminate">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="LoadingPresenter.Visibility" Value="Visible" />
|
||||
</VisualState.Setters>
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetName="LoadingPresenter"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
From=".5"
|
||||
To=".8"
|
||||
Duration="0:0:0.250"
|
||||
AutoReverse="True"
|
||||
RepeatBehavior="Forever"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
|
||||
<ContentPresenter
|
||||
x:Name="UndefinedPresenter"
|
||||
Content="{TemplateBinding Undefined}"
|
||||
ContentTemplate="{TemplateBinding UndefinedTemplate}"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
Visibility="Visible" />
|
||||
<ContentPresenter
|
||||
x:Name="NonePresenter"
|
||||
Content="{TemplateBinding None}"
|
||||
ContentTemplate="{TemplateBinding NoneTemplate}"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
Visibility="Collapsed" />
|
||||
<ContentPresenter
|
||||
x:Name="SomePresenter"
|
||||
Content="{TemplateBinding State}"
|
||||
ContentTemplate="{TemplateBinding ValueTemplate}"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
Visibility="Collapsed" />
|
||||
|
||||
<Border
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Top"
|
||||
Background="Red"
|
||||
x:Name="ErrorPresenter"
|
||||
Visibility="Collapsed"
|
||||
Height="50">
|
||||
<Border.RenderTransform>
|
||||
<TranslateTransform x:Name="ErrorPresenterTransform" />
|
||||
</Border.RenderTransform>
|
||||
<ContentPresenter Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=State.Error}" />
|
||||
</Border>
|
||||
|
||||
<Border
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Background="Orange"
|
||||
x:Name="LoadingPresenter"
|
||||
Visibility="Collapsed"
|
||||
Opacity="0">
|
||||
<TextBlock Text="Loading" />
|
||||
</Border>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
|
||||
<Style TargetType="reactive:FeedView" x:Key="SingleStateFeedView">
|
||||
<Setter Property="VerticalAlignment" Value="Stretch" />
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Stretch" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="reactive:FeedView">
|
||||
<Grid
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}">
|
||||
<VisualStateManager.CustomVisualStateManager>
|
||||
<reactive:SmoothVisualStateManager>
|
||||
<reactive:SmoothVisualStateRule MinDuration="0:0:0.500" />
|
||||
<reactive:SmoothVisualStateRule Group="ProgressGroup" To="Indeterminate" Delay="0:0:0.250" />
|
||||
</reactive:SmoothVisualStateManager>
|
||||
</VisualStateManager.CustomVisualStateManager>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="DataGroup">
|
||||
<VisualState x:Name="Undefined" />
|
||||
<VisualState x:Name="None">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="UndefinedPresenter.Visibility" Value="Collapsed" />
|
||||
<Setter Target="NonePresenter.Visibility" Value="Visible" />
|
||||
<Setter Target="SomePresenter.Visibility" Value="Collapsed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Some">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="UndefinedPresenter.Visibility" Value="Collapsed" />
|
||||
<Setter Target="NonePresenter.Visibility" Value="Collapsed" />
|
||||
<Setter Target="SomePresenter.Visibility" Value="Visible" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="ErrorGroup">
|
||||
<VisualState x:Name="NoError" />
|
||||
<VisualState x:Name="Error">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ErrorPresenter.Visibility" Value="Visible" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="ProgressGroup">
|
||||
<VisualStateGroup.Transitions>
|
||||
<VisualTransition To="Indeterminate">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames
|
||||
Storyboard.TargetName="LoadingWheel"
|
||||
Storyboard.TargetProperty="IsActive">
|
||||
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="True" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetName="LoadingPresenter"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
From="0"
|
||||
To="1"
|
||||
Duration="0:0:0.100" />
|
||||
</Storyboard>
|
||||
</VisualTransition>
|
||||
<VisualTransition From="Indeterminate">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetName="LoadingPresenter"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
From="1"
|
||||
To="0"
|
||||
Duration="0:0:0.100" />
|
||||
</Storyboard>
|
||||
</VisualTransition>
|
||||
</VisualStateGroup.Transitions>
|
||||
<VisualState x:Name="Final" />
|
||||
<VisualState x:Name="Indeterminate">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="LoadingPresenter.Visibility" Value="Visible" />
|
||||
<Setter Target="LoadingPresenter.Opacity" Value="1" />
|
||||
<Setter Target="LoadingWheel.IsActive" Value="True" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
|
||||
<ContentPresenter
|
||||
x:Name="UndefinedPresenter"
|
||||
Content="{TemplateBinding Undefined}"
|
||||
ContentTemplate="{TemplateBinding UndefinedTemplate}"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
Visibility="Visible" />
|
||||
<ContentPresenter
|
||||
x:Name="NonePresenter"
|
||||
Content="{TemplateBinding None}"
|
||||
ContentTemplate="{TemplateBinding NoneTemplate}"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
Visibility="Collapsed" />
|
||||
<ContentPresenter
|
||||
x:Name="SomePresenter"
|
||||
Content="{TemplateBinding State}"
|
||||
ContentTemplate="{TemplateBinding ValueTemplate}"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
Visibility="Collapsed" />
|
||||
|
||||
<ContentPresenter
|
||||
x:Name="ErrorPresenter"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
Visibility="Collapsed"
|
||||
Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=State.Error}" />
|
||||
|
||||
<Border
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
x:Name="LoadingPresenter"
|
||||
Visibility="Collapsed"
|
||||
Opacity="0">
|
||||
<ProgressRing
|
||||
x:Name="LoadingWheel"
|
||||
IsActive="False"
|
||||
Width="50"
|
||||
Height="50" />
|
||||
</Border>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
|
@ -2,6 +2,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Commerce.Services;
|
||||
using Uno.Extensions;
|
||||
|
@ -21,7 +22,7 @@ public class DealsViewModel
|
|||
|
||||
private async Task Load(IProductService products)
|
||||
{
|
||||
var productItems = await products.GetProducts();
|
||||
var productItems = await products.GetProducts(null, CancellationToken.None);
|
||||
productItems.ForEach(p =>
|
||||
{
|
||||
HotDeals.Add(p);
|
||||
|
|
|
@ -1,15 +1,48 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Commerce.Services;
|
||||
using Uno.Extensions.Navigation;
|
||||
using Uno.Extensions.Reactive;
|
||||
using Windows.ApplicationModel.Core;
|
||||
|
||||
namespace Commerce.ViewModels
|
||||
namespace Commerce.ViewModels;
|
||||
|
||||
public partial class LoginViewModel
|
||||
{
|
||||
public class LoginViewModel
|
||||
private readonly INavigator _navigator;
|
||||
private readonly IState<string> _error;
|
||||
|
||||
private LoginViewModel(
|
||||
INavigator navigator,
|
||||
IFeed<string> userName,
|
||||
IFeed<string> password,
|
||||
IState<string> error,
|
||||
ICommandBuilder login)
|
||||
{
|
||||
public LoginViewModel()
|
||||
_navigator = navigator;
|
||||
_error = error;
|
||||
|
||||
login
|
||||
.Given(Feed.Combine(userName, password))
|
||||
.When(CanLogin)
|
||||
.Then(Login);
|
||||
}
|
||||
|
||||
private bool CanLogin((string userName, string password) values)
|
||||
=> values is { userName.Length: > 0 } and { password.Length: > 0 };
|
||||
|
||||
private async ValueTask Login((string userName, string password) values, CancellationToken ct)
|
||||
{
|
||||
if (values is { userName.Length: >= 3 } and { password.Length: >= 3 })
|
||||
{
|
||||
await _error.Set(default, ct);
|
||||
await Task.Delay(1000, ct);
|
||||
|
||||
CoreApplication.MainView?.DispatcherQueue.TryEnqueue(() => _navigator.NavigateToRouteAsync(this, "/-/CommerceHomePage", cancellation: ct));
|
||||
}
|
||||
else
|
||||
{
|
||||
await _error.Set("Login and password must be at least 3 characters long.", ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using Uno.Extensions.Navigation;
|
||||
using Uno.Extensions.Reactive;
|
||||
|
||||
namespace Commerce.ViewModels;
|
||||
|
||||
public partial class LoginViewModel : IAsyncDisposable
|
||||
{
|
||||
public class BindableLoginViewModel : BindableViewModelBase
|
||||
{
|
||||
private readonly Bindable<string> _userName;
|
||||
private readonly Bindable<string> _password;
|
||||
private readonly Bindable<string> _error;
|
||||
|
||||
public BindableLoginViewModel(
|
||||
INavigator navigator,
|
||||
string? defaultUserName = default,
|
||||
string? defaultPassword = default,
|
||||
string? defaultError = default)
|
||||
{
|
||||
_userName = new Bindable<string>(Property<string>(nameof(UserName), defaultUserName, out var userNameSubject));
|
||||
_password = new Bindable<string>(Property<string>(nameof(Password), defaultPassword, out var passwordSubject));
|
||||
_error = new Bindable<string>(Property<string>(nameof(Error), defaultError, out var errorSubject));
|
||||
|
||||
var login = new CommandBuilder<object?>(nameof(Login));
|
||||
|
||||
var vm = new LoginViewModel(navigator, userNameSubject, passwordSubject, errorSubject, login);
|
||||
var ctx = SourceContext.GetOrCreate(vm);
|
||||
SourceContext.Set(this, ctx);
|
||||
RegisterDisposable(vm);
|
||||
|
||||
Model = vm;
|
||||
Login = login.Build(ctx);
|
||||
}
|
||||
|
||||
public LoginViewModel Model { get; }
|
||||
|
||||
public string UserName
|
||||
{
|
||||
get => _userName.GetValue();
|
||||
set => _userName.SetValue(value);
|
||||
}
|
||||
|
||||
public string Password
|
||||
{
|
||||
get => _password.GetValue();
|
||||
set => _password.SetValue(value);
|
||||
}
|
||||
|
||||
public string Error
|
||||
{
|
||||
get => _error.GetValue();
|
||||
set => _error.SetValue(value);
|
||||
}
|
||||
|
||||
public IAsyncCommand Login { get; }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ValueTask DisposeAsync()
|
||||
=> SourceContext.Find(this)?.DisposeAsync() ?? default;
|
||||
}
|
|
@ -2,36 +2,47 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Commerce.Services;
|
||||
using System.Threading.Tasks;
|
||||
using Uno.Extensions.Reactive;
|
||||
|
||||
namespace Commerce.ViewModels;
|
||||
|
||||
public class ProductDetailsViewModel : ObservableObject
|
||||
public partial class ProductDetailsViewModel
|
||||
{
|
||||
private Product _product;
|
||||
private readonly IProductService _products;
|
||||
private readonly Product _product;
|
||||
private readonly IDictionary<string, object> _parameters;
|
||||
|
||||
public Product Product { get => _product; set => SetProperty(ref _product, value); }
|
||||
|
||||
public ProductDetailsViewModel(IProductService products, Product p, IDictionary<string, object> parameters)
|
||||
{
|
||||
Load(products, p, parameters);
|
||||
}
|
||||
|
||||
private async Task Load(IProductService products, Product p, IDictionary<string, object> parameters)
|
||||
public ProductDetailsViewModel(
|
||||
IProductService products,
|
||||
Product product,
|
||||
IDictionary<string, object> parameters)
|
||||
{
|
||||
_products = products;
|
||||
_product = product;
|
||||
_parameters = parameters;
|
||||
}
|
||||
|
||||
if (p is not null)
|
||||
public IFeed<Product> Product => Feed.Async(Load);
|
||||
|
||||
private async ValueTask<Option<Product>> Load(CancellationToken ct)
|
||||
{
|
||||
await Task.Delay(5000);
|
||||
|
||||
if (_product is not null)
|
||||
{
|
||||
Product = p;
|
||||
return _product;
|
||||
}
|
||||
else if(_parameters.TryGetValue("ProductId", out var id))
|
||||
{
|
||||
return (await _products.GetProducts(null, CancellationToken.None)).FirstOrDefault(x => x.ProductId + "" == id.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (parameters.TryGetValue("ProductId", out var id))
|
||||
{
|
||||
Product = (await products.GetProducts()).FirstOrDefault(x => x.ProductId + "" == id.ToString());
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Commerce.Services;
|
||||
using Uno.Extensions.Reactive;
|
||||
|
||||
namespace Commerce.ViewModels;
|
||||
|
||||
partial class ProductDetailsViewModel : IAsyncDisposable
|
||||
{
|
||||
public class BindableProductDetailsViewModel : BindableViewModelBase
|
||||
{
|
||||
public BindableProductDetailsViewModel(
|
||||
IProductService service,
|
||||
Product product,
|
||||
IDictionary<string, object> parameters)
|
||||
{
|
||||
var vm = new ProductDetailsViewModel(service, product, parameters);
|
||||
var ctx = SourceContext.GetOrCreate(vm);
|
||||
SourceContext.Set(this, ctx);
|
||||
RegisterDisposable(vm);
|
||||
|
||||
Model = vm;
|
||||
Product = ctx.GetOrCreateState(vm.Product);
|
||||
}
|
||||
|
||||
public ProductDetailsViewModel Model { get; }
|
||||
|
||||
public IFeed<Product> Product { get; }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ValueTask DisposeAsync()
|
||||
=> SourceContext.Find(this)?.DisposeAsync() ?? default;
|
||||
}
|
|
@ -1,35 +1,43 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Commerce.Services;
|
||||
using Uno.Extensions;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Commerce.Services;
|
||||
using Uno.Extensions.Reactive;
|
||||
|
||||
namespace Commerce.ViewModels;
|
||||
|
||||
public class ProductsViewModel : ObservableObject
|
||||
public partial class ProductsViewModel
|
||||
{
|
||||
private string _filterQuery;
|
||||
private readonly IProductService _products;
|
||||
private readonly IFeed<string> _searchTerm;
|
||||
private readonly IState<string> _filterQuery;
|
||||
|
||||
public string FilterQuery { get => _filterQuery; set => SetProperty(ref _filterQuery,value); }
|
||||
public ObservableCollection<Product> Products { get; } = new ObservableCollection<Product>();
|
||||
|
||||
public ProductsViewModel(IProductService products)
|
||||
{
|
||||
Load(products);
|
||||
}
|
||||
|
||||
private async Task Load(IProductService products)
|
||||
private ProductsViewModel(
|
||||
IProductService products,
|
||||
[DefaultValue("")] IFeed<string> searchTerm,
|
||||
[DefaultValue("")] IState<string> filterQuery)
|
||||
{
|
||||
var productItems = await products.GetProducts();
|
||||
productItems.ForEach(p => Products.Add(p));
|
||||
|
||||
FilterQuery = "Query-" + DateTime.Now.ToString("HH:mm:ss:ffff");
|
||||
|
||||
_products = products;
|
||||
_searchTerm = searchTerm;
|
||||
_filterQuery = filterQuery;
|
||||
}
|
||||
|
||||
public IFeed<Product[]> Items => Feed
|
||||
.Combine(_searchTerm.SelectAsync(Load), _filterQuery)
|
||||
.Select(FilterProducts);
|
||||
|
||||
private async ValueTask<Product[]> Load(string searchTerm, CancellationToken ct)
|
||||
{
|
||||
var products = await _products.GetProducts(searchTerm, ct);
|
||||
|
||||
return products.ToArray();
|
||||
}
|
||||
|
||||
private Product[] FilterProducts((Product[] products, string filterQuery) inputs)
|
||||
{
|
||||
// TODO: Apply filter here
|
||||
return inputs.products;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Commerce.Services;
|
||||
using Uno.Extensions.Reactive;
|
||||
|
||||
namespace Commerce.ViewModels;
|
||||
|
||||
public partial class ProductsViewModel : IAsyncDisposable
|
||||
{
|
||||
public class BindableProductsViewModel : BindableViewModelBase
|
||||
{
|
||||
private readonly Bindable<string> _searchTerm;
|
||||
private readonly Bindable<string> _filterQuery;
|
||||
|
||||
public BindableProductsViewModel(
|
||||
IProductService products,
|
||||
string? defaultSearchTerm = "",
|
||||
string? defaultFilterQuery = "")
|
||||
{
|
||||
_searchTerm = new Bindable<string>(Property(nameof(SearchTerm), defaultSearchTerm, out var searchTermSubject));
|
||||
_filterQuery = new Bindable<string>(Property(nameof(FilterQuery), defaultFilterQuery, out var filterQuerySubject));
|
||||
|
||||
var vm = new ProductsViewModel(products, searchTermSubject, filterQuerySubject);
|
||||
var ctx = SourceContext.GetOrCreate(vm);
|
||||
SourceContext.Set(this, ctx);
|
||||
RegisterDisposable(vm);
|
||||
|
||||
Model = vm;
|
||||
Items = ctx.GetOrCreateState(vm.Items);
|
||||
}
|
||||
|
||||
public ProductsViewModel Model { get; }
|
||||
|
||||
public IFeed<Product[]> Items { get; }
|
||||
|
||||
public string SearchTerm
|
||||
{
|
||||
get => _searchTerm.GetValue();
|
||||
set => _searchTerm.SetValue(value);
|
||||
}
|
||||
|
||||
public string FilterQuery
|
||||
{
|
||||
get => _filterQuery.GetValue();
|
||||
set => _filterQuery.SetValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ValueTask DisposeAsync()
|
||||
=> SourceContext.Find(this)?.DisposeAsync() ?? default;
|
||||
}
|
|
@ -39,25 +39,28 @@
|
|||
<TextBox PlaceholderText="Email"
|
||||
Margin="0,8"
|
||||
MinWidth="200"
|
||||
Name="UsernameText" />
|
||||
Name="UsernameText"
|
||||
Text="{x:Bind VM.UserName, Mode=TwoWay}"/>
|
||||
<PasswordBox Margin="0,8"
|
||||
PlaceholderText="Password"
|
||||
MinWidth="200" />
|
||||
MinWidth="200"
|
||||
Password="{x:Bind VM.Password, Mode=TwoWay}" />
|
||||
<HyperlinkButton Content="Forgot password?" />
|
||||
<Button Content="LOGIN"
|
||||
<TextBlock Text="{Binding Error}" Foreground="DarkRed" HorizontalAlignment="Center" />
|
||||
<Button Content="LOGIN"
|
||||
HorizontalAlignment="Stretch"
|
||||
Margin="0,8"
|
||||
nav:Navigation.Request="/-/CommerceHomePage" />
|
||||
<TextBlock Text="Legal mentions" HorizontalAlignment="Center" />
|
||||
</StackPanel>
|
||||
Command="{Binding Login}" />
|
||||
<TextBlock Text="Legal mentions" HorizontalAlignment="Center" />
|
||||
</StackPanel>
|
||||
<Grid x:Name="ProgressOverlay"
|
||||
Visibility="Collapsed">
|
||||
Visibility="{Binding Login.IsExecuting}">
|
||||
<Border Background="White"
|
||||
Opacity="0.7"/>
|
||||
<ProgressRing x:Name="Progress"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
IsActive="False" />
|
||||
IsActive="{Binding Login.IsExecuting}" />
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
|
|
@ -16,6 +16,7 @@ using Windows.UI.Xaml.Data;
|
|||
using Windows.UI.Xaml.Input;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
using Commerce.ViewModels;
|
||||
|
||||
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
|
||||
|
||||
|
@ -29,13 +30,16 @@ namespace Commerce
|
|||
public LoginPage()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
}
|
||||
|
||||
private INavigator navigator;
|
||||
public void Inject(INavigator entity)
|
||||
{
|
||||
navigator = entity;
|
||||
}
|
||||
DataContext = VM = new LoginViewModel.BindableLoginViewModel(navigator);
|
||||
}
|
||||
|
||||
public LoginViewModel.BindableLoginViewModel VM { get; private set; }
|
||||
|
||||
public async Task<bool> Stop(NavigationRequest request)
|
||||
{
|
||||
|
|
|
@ -1,75 +1,79 @@
|
|||
<Page x:Class="Commerce.ProductDetailsPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Commerce"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:fake="using:Commerce.DesignTime"
|
||||
xmlns:controls="using:Microsoft.UI.Xaml.Controls"
|
||||
xmlns:nav="using:Uno.Extensions.Navigation.Controls"
|
||||
xmlns:toolkit="using:Uno.UI.ToolkitLib"
|
||||
mc:Ignorable="d fake"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Commerce"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:fake="using:Commerce.DesignTime"
|
||||
xmlns:controls="using:Microsoft.UI.Xaml.Controls"
|
||||
xmlns:nav="using:Uno.Extensions.Navigation.Controls"
|
||||
xmlns:toolkit="using:Uno.UI.ToolkitLib"
|
||||
xmlns:reactive="using:Uno.Extensions.Reactive"
|
||||
mc:Ignorable="d fake"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<Grid d:DataContext="{d:DesignInstance fake:FakeProducts, IsDesignTimeCreatable=True}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<toolkit:NavigationBar Content="Products" />
|
||||
<Grid d:DataContext="{d:DesignInstance fake:FakeProducts, IsDesignTimeCreatable=True}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<toolkit:NavigationBar Content="Products" />
|
||||
|
||||
<ScrollViewer d:DataContext="{Binding Products[2]}"
|
||||
DataContext="{Binding Product}" Grid.Row="1">
|
||||
<StackPanel Margin="12">
|
||||
<Border Height="300">
|
||||
<Image Source="{Binding Photo}" HorizontalAlignment="Center" VerticalAlignment="Center" Stretch="UniformToFill" />
|
||||
</Border>
|
||||
|
||||
<TextBlock Text="{Binding Name}" FontSize="32" FontWeight="Bold" Margin="12"/>
|
||||
<Grid>
|
||||
<TextBlock Text="{Binding Category}" />
|
||||
<TextBlock Text="{Binding Price}" HorizontalAlignment="Right" Foreground="Red" />
|
||||
</Grid>
|
||||
<reactive:FeedView
|
||||
Source="{Binding Product}"
|
||||
Style="{StaticResource SingleStateFeedView}"
|
||||
Grid.Row="1">
|
||||
<DataTemplate>
|
||||
<ScrollViewer
|
||||
d:DataContext="{Binding Products[2]}"
|
||||
DataContext="{Binding Data}">
|
||||
<StackPanel Margin="12">
|
||||
<Border Height="300">
|
||||
<Image Source="{Binding Photo}" HorizontalAlignment="Center" VerticalAlignment="Center" Stretch="UniformToFill" />
|
||||
</Border>
|
||||
|
||||
<Border Height="1"
|
||||
Background="DarkGray" />
|
||||
<TextBlock Text="{Binding Name}" FontSize="32" FontWeight="Bold" Margin="12"/>
|
||||
<Grid>
|
||||
<TextBlock Text="{Binding Category}" />
|
||||
<TextBlock Text="{Binding Price}" HorizontalAlignment="Right" Foreground="Red" />
|
||||
</Grid>
|
||||
|
||||
<Button Content="ADD TO CART"
|
||||
HorizontalAlignment="Stretch" />
|
||||
<Border Height="1" Background="DarkGray" />
|
||||
|
||||
<Button Content="SAVE TO FAVORITES"
|
||||
HorizontalAlignment="Stretch" />
|
||||
<Button Content="ADD TO CART" HorizontalAlignment="Stretch" />
|
||||
|
||||
<Border Height="1"
|
||||
Background="DarkGray" />
|
||||
<Button Content="SAVE TO FAVORITES" HorizontalAlignment="Stretch" />
|
||||
|
||||
<TextBlock Text="Product details"
|
||||
FontWeight="Bold" />
|
||||
<TextBlock Text="{Binding Description}" />
|
||||
<Border Height="1" Background="DarkGray" />
|
||||
|
||||
<TextBlock Text="Reviews"
|
||||
FontWeight="Bold" />
|
||||
<TextBlock Text="Product details" FontWeight="Bold" />
|
||||
<TextBlock Text="{Binding Description}" />
|
||||
|
||||
<controls:ItemsRepeater ItemsSource="{Binding Reviews}">
|
||||
<controls:ItemsRepeater.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Margin="4" Height="50">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="50" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Ellipse Margin="4" Fill="DarkGray" HorizontalAlignment="Left" VerticalAlignment="Center" Height="40" Width="40"/>
|
||||
<StackPanel Grid.Column="1" VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding Name}" FontWeight="Bold" />
|
||||
<TextBlock Text="{Binding Message}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
</DataTemplate>
|
||||
</controls:ItemsRepeater.ItemTemplate>
|
||||
</controls:ItemsRepeater>
|
||||
<TextBlock Text="Reviews" FontWeight="Bold" />
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
<controls:ItemsRepeater ItemsSource="{Binding Reviews}">
|
||||
<controls:ItemsRepeater.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Margin="4" Height="50">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="50" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Ellipse Margin="4" Fill="DarkGray" HorizontalAlignment="Left" VerticalAlignment="Center" Height="40" Width="40"/>
|
||||
<StackPanel Grid.Column="1" VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding Name}" FontWeight="Bold" />
|
||||
<TextBlock Text="{Binding Message}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
</DataTemplate>
|
||||
</controls:ItemsRepeater.ItemTemplate>
|
||||
</controls:ItemsRepeater>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</DataTemplate>
|
||||
</reactive:FeedView>
|
||||
|
||||
</Grid>
|
||||
</Page>
|
||||
|
|
|
@ -1,70 +1,99 @@
|
|||
<Page x:Class="Commerce.ProductsPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Commerce"
|
||||
xmlns:fake="using:Commerce.DesignTime"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:services="using:Commerce.Services"
|
||||
xmlns:nav="using:Uno.Extensions.Navigation.Controls"
|
||||
xmlns:toolkit="using:Uno.UI.ToolkitLib"
|
||||
mc:Ignorable="d fake"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Commerce"
|
||||
xmlns:fake="using:Commerce.DesignTime"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:services="using:Commerce.Services"
|
||||
xmlns:nav="using:Uno.Extensions.Navigation.Controls"
|
||||
xmlns:toolkit="using:Uno.UI.ToolkitLib"
|
||||
xmlns:reactive="using:Uno.Extensions.Reactive"
|
||||
mc:Ignorable="d fake"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<Grid d:DataContext="{d:DesignInstance fake:FakeProducts, IsDesignTimeCreatable=True}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid d:DataContext="{d:DesignInstance fake:FakeProducts, IsDesignTimeCreatable=True}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<toolkit:NavigationBar Content="Products" />
|
||||
<StackPanel Grid.Row="1">
|
||||
<TextBox PlaceholderText="Search" />
|
||||
<Grid>
|
||||
<TextBlock Text="5254 Products"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="32" />
|
||||
<StackPanel Orientation="Horizontal"
|
||||
HorizontalAlignment="Right">
|
||||
<TextBlock Text="{Binding FilterQuery}" />
|
||||
<HyperlinkButton Content="Filter"
|
||||
nav:Navigation.Request="!FilterPopup"
|
||||
nav:Navigation.Data="{Binding FilterQuery, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
<ListView nav:Navigation.Request="ProductDetails"
|
||||
ItemsSource="{Binding Products}"
|
||||
Grid.Row="2"
|
||||
IsItemClickEnabled="True"
|
||||
>
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Margin="8"
|
||||
Height="100">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="100" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border>
|
||||
<Image Source="{Binding Photo}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Stretch="UniformToFill" />
|
||||
</Border>
|
||||
<StackPanel Grid.Column="1"
|
||||
Margin="8">
|
||||
<TextBlock Text="{Binding Name}"
|
||||
FontSize="24"
|
||||
FontWeight="Bold" />
|
||||
<TextBlock Text="{Binding Price}"
|
||||
FontSize="18" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</Grid>
|
||||
<toolkit:NavigationBar Content="Products" />
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBox
|
||||
Grid.Row="0"
|
||||
PlaceholderText="Search"
|
||||
Text="{Binding SearchTerm, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
|
||||
|
||||
<reactive:FeedView
|
||||
Grid.Row="1"
|
||||
Undefined="Type some text to search products."
|
||||
None="No products found."
|
||||
Source="{Binding Items}">
|
||||
<DataTemplate>
|
||||
<ListView
|
||||
nav:Navigation.Request="ProductDetails"
|
||||
ItemsSource="{Binding Data}"
|
||||
Grid.Row="2"
|
||||
IsItemClickEnabled="True">
|
||||
<ListView.Header>
|
||||
<Grid>
|
||||
<TextBlock
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="32" >
|
||||
<Run Text="{Binding Data.Length}" />
|
||||
<Run Text=" Products" />
|
||||
</TextBlock>
|
||||
<StackPanel
|
||||
Orientation="Horizontal"
|
||||
HorizontalAlignment="Right">
|
||||
<TextBlock Text="{Binding Parent.FilterQuery}" />
|
||||
<HyperlinkButton
|
||||
Content="Filter"
|
||||
nav:Navigation.Request="!FilterPopup"
|
||||
nav:Navigation.Data="{Binding Parent.FilterQuery, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ListView.Header>
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid
|
||||
Margin="8"
|
||||
Height="100">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="100" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border>
|
||||
<Image
|
||||
Source="{Binding Photo}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Stretch="UniformToFill" />
|
||||
</Border>
|
||||
<StackPanel
|
||||
Grid.Column="1"
|
||||
Margin="8">
|
||||
<TextBlock
|
||||
Text="{Binding Name}"
|
||||
FontSize="24"
|
||||
FontWeight="Bold" />
|
||||
<TextBlock
|
||||
Text="{Binding Price}"
|
||||
FontSize="18" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</DataTemplate>
|
||||
</reactive:FeedView>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="6.0.0" />
|
||||
<PackageReference Include="System.Linq.Async" Version="4.0.0" />
|
||||
<PackageReference Include="Uno.UI.Toolkit" Version="0.1.0-dev.71" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
|
@ -177,6 +178,14 @@
|
|||
<Project>{5123670c-9756-4c9e-9844-f4a9c0aee633}</Project>
|
||||
<Name>Uno.Extensions.Serialization</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\src\Uno.Extensions.Reactive\Uno.Extensions.Reactive.csproj">
|
||||
<Project>{74D93A0B-42F9-45A6-8AC3-684DAE9659A8}</Project>
|
||||
<Name>Uno.Extensions.Reactive</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\src\Uno.Extensions.Reactive.View\Uno.Extensions.Reactive.View.csproj">
|
||||
<Project>{7516C1F2-6CCB-4B59-91B7-E6D4B4EA5835}</Project>
|
||||
<Name>Uno.Extensions.Reactive.View</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
|
@ -196,6 +205,7 @@
|
|||
<Content Include="Assets\Wide310x150Logo.scale-200.png" />
|
||||
<Content Include="Properties\Default.rd.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="..\Commerce.Shared\Commerce.Shared.projitems" Label="Shared" />
|
||||
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' < '14.0' ">
|
||||
<VisualStudioVersion>14.0</VisualStudioVersion>
|
||||
|
@ -208,4 +218,4 @@
|
|||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
|
@ -55,6 +55,7 @@
|
|||
<PackageReference Include="Uno.UI.RemoteControl" Version="4.0.0-dev.5489" Condition="'$(Configuration)'=='Debug'" />
|
||||
<PackageReference Include="Uno.Wasm.Bootstrap" Version="3.0.0" />
|
||||
<PackageReference Include="Uno.Wasm.Bootstrap.DevServer" Version="3.0.0" />
|
||||
<PackageReference Include="System.Linq.Async" Version="4.0.0" />
|
||||
<PackageReference Include="Uno.UI.Toolkit">
|
||||
<Version>0.1.0-dev.71</Version>
|
||||
</PackageReference>
|
||||
|
@ -74,6 +75,14 @@
|
|||
<ProjectReference Include="..\..\..\src\Uno.Extensions.Logging.Wasm\Uno.Extensions.Logging.Wasm.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Uno.Extensions.Navigation\Uno.Extensions.Navigation.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Uno.Extensions.Serialization\Uno.Extensions.Serialization.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Uno.Extensions.Reactive\Uno.Extensions.Reactive.csproj">
|
||||
<Project>{74D93A0B-42F9-45A6-8AC3-684DAE9659A8}</Project>
|
||||
<Name>Uno.Extensions.Reactive</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\src\Uno.Extensions.Reactive.View\Uno.Extensions.Reactive.View.csproj">
|
||||
<Project>{7516C1F2-6CCB-4B59-91B7-E6D4B4EA5835}</Project>
|
||||
<Name>Uno.Extensions.Reactive.View</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="..\Commerce.Shared\Commerce.Shared.projitems" Label="Shared" Condition="Exists('..\Commerce.Shared\Commerce.Shared.projitems')" />
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -127,6 +127,7 @@
|
|||
<!--<PackageReference Include="Uno.UI.RemoteControl" Version="4.0.0-dev.5441" Condition="'$(Configuration)'=='Debug'" />-->
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||
<PackageReference Include="Uno.Extensions.Logging.OSLog " Version="1.3.0-dev.1" />
|
||||
<PackageReference Include="System.Linq.Async" Version="4.0.0" />
|
||||
<PackageReference Include="Uno.UI.Toolkit" Version="0.1.0-dev.71" />
|
||||
<PackageReference Include="Uno.Material" Version="1.1.0-dev.5" />
|
||||
</ItemGroup>
|
||||
|
@ -219,6 +220,14 @@
|
|||
<Project>{5123670c-9756-4c9e-9844-f4a9c0aee633}</Project>
|
||||
<Name>Uno.Extensions.Serialization</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\src\Uno.Extensions.Reactive\Uno.Extensions.Reactive.csproj">
|
||||
<Project>{74D93A0B-42F9-45A6-8AC3-684DAE9659A8}</Project>
|
||||
<Name>Uno.Extensions.Reactive</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\src\Uno.Extensions.Reactive.View\Uno.Extensions.Reactive.View.csproj">
|
||||
<Project>{7516C1F2-6CCB-4B59-91B7-E6D4B4EA5835}</Project>
|
||||
<Name>Uno.Extensions.Reactive.View</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="XamarinForms.targets" Condition="'$(Configuration)'=='Debug'" />
|
||||
<Import Project="..\Commerce.Shared\Commerce.Shared.projitems" Label="Shared" />
|
||||
|
@ -228,4 +237,4 @@
|
|||
<UserProperties XamarinHotReloadDebuggerTimeoutExceptionCommerceiOSHideInfoBar="True" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
Загрузка…
Ссылка в новой задаче