This commit is contained in:
Ramón Tomás 2017-03-31 11:04:03 +02:00
commit 2e50097c65
49 changed files with 440 additions and 401 deletions

View File

@ -44,6 +44,7 @@ services:
- ASPNETCORE_URLS=http://0.0.0.0:5102 - ASPNETCORE_URLS=http://0.0.0.0:5102
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word - ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word
- identityUrl=http://identity.api:5105 #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105. - identityUrl=http://identity.api:5105 #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
- BasketUrl=http://basket.api:5103
- EventBusConnection=rabbitmq - EventBusConnection=rabbitmq
ports: ports:
- "5102:5102" - "5102:5102"

View File

@ -19,6 +19,7 @@ services:
- ASPNETCORE_URLS=http://0.0.0.0:5103 - ASPNETCORE_URLS=http://0.0.0.0:5103
- ConnectionString=basket.data - ConnectionString=basket.data
- identityUrl=http://identity.api:5105 #Local: You need to open your host's firewall at range 5100-5105. at range 5100-5105. - identityUrl=http://identity.api:5105 #Local: You need to open your host's firewall at range 5100-5105. at range 5100-5105.
- EventBusConnection=rabbitmq
ports: ports:
- "5103:5103" - "5103:5103"
@ -28,6 +29,7 @@ services:
- ASPNETCORE_URLS=http://0.0.0.0:5101 - ASPNETCORE_URLS=http://0.0.0.0:5101
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word - ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word
- ExternalCatalogBaseUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5101 #Local: You need to open your host's firewall at range 5100-5105. at range 5100-5105. - ExternalCatalogBaseUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5101 #Local: You need to open your host's firewall at range 5100-5105. at range 5100-5105.
- EventBusConnection=rabbitmq
ports: ports:
- "5101:5101" - "5101:5101"
@ -47,6 +49,8 @@ services:
- ASPNETCORE_URLS=http://0.0.0.0:5102 - ASPNETCORE_URLS=http://0.0.0.0:5102
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word - ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word
- identityUrl=http://identity.api:5105 #Local: You need to open your host's firewall at range 5100-5105. at range 5100-5105. - identityUrl=http://identity.api:5105 #Local: You need to open your host's firewall at range 5100-5105. at range 5100-5105.
- BasketUrl=http://basket.api:5103
- EventBusConnection=rabbitmq
ports: ports:
- "5102:5102" - "5102:5102"
@ -81,10 +85,13 @@ services:
webstatus: webstatus:
environment: environment:
- ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://0.0.0.0:5107
- CatalogUrl=http://catalog.api:5101/hc - CatalogUrl=http://catalog.api:5101/hc
- OrderingUrl=http://ordering.api:5102/hc - OrderingUrl=http://ordering.api:5102/hc
- BasketUrl=http://basket.api:5103/hc - BasketUrl=http://basket.api:5103/hc
- IdentityUrl=http://10.0.75.1:5105/hc - mvc=http://webmvc:5100/hc
- spa=http://webspa:5104/hc
- IdentityUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105 #Local: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}, if using external IP or DNS name from browser.
ports: ports:
- "5107:5107" - "5107:5107"

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:light="clr-namespace:Xamarin.Forms.Themes;assembly=Xamarin.Forms.Theme.Light" xmlns:light="clr-namespace:Xamarin.Forms.Themes;assembly=Xamarin.Forms.Theme.Light"
xmlns:converters="clr-namespace:eShopOnContainers.Core.Converters;assembly=eShopOnContainers.Core" xmlns:converters="clr-namespace:eShopOnContainers.Core.Converters;assembly=eShopOnContainers.Core"
xmlns:effects="clr-namespace:eShopOnContainers.Core.Effects;assembly=eShopOnContainers.Core" xmlns:behaviors="clr-namespace:eShopOnContainers.Core.Behaviors;assembly=eShopOnContainers.Core"
x:Class="eShopOnContainers.App"> x:Class="eShopOnContainers.App">
<Application.Resources> <Application.Resources>
<ResourceDictionary MergedWith="light:LightThemeResources"> <ResourceDictionary MergedWith="light:LightThemeResources">
@ -17,6 +17,7 @@
<Color x:Key="GreenColor">#00A69C</Color> <Color x:Key="GreenColor">#00A69C</Color>
<Color x:Key="DarkGreenColor">#00857D</Color> <Color x:Key="DarkGreenColor">#00857D</Color>
<Color x:Key="GrayColor">#e2e2e2</Color> <Color x:Key="GrayColor">#e2e2e2</Color>
<Color x:Key="ErrorColor">#ff5252</Color>
<!-- FONTS --> <!-- FONTS -->
<OnPlatform <OnPlatform
@ -100,6 +101,7 @@
<!-- CONVERTERS --> <!-- CONVERTERS -->
<converters:CountToBoolConverter x:Key="CountToBoolConverter" /> <converters:CountToBoolConverter x:Key="CountToBoolConverter" />
<converters:DatetimeConverter x:Key="DatetimeConverter" /> <converters:DatetimeConverter x:Key="DatetimeConverter" />
<converters:FirstValidationErrorConverter x:Key="FirstValidationErrorConverter" />
<converters:ImageConverter x:Key="ImageConverter" /> <converters:ImageConverter x:Key="ImageConverter" />
<converters:ItemTappedEventArgsConverter x:Key="ItemTappedEventArgsConverter" /> <converters:ItemTappedEventArgsConverter x:Key="ItemTappedEventArgsConverter" />
<converters:InverseCountToBoolConverter x:Key="InverseCountToBoolConverter" /> <converters:InverseCountToBoolConverter x:Key="InverseCountToBoolConverter" />
@ -109,6 +111,14 @@
<converters:WebNavigatingEventArgsConverter x:Key="WebNavigatingEventArgsConverter" /> <converters:WebNavigatingEventArgsConverter x:Key="WebNavigatingEventArgsConverter" />
<!-- STYLES --> <!-- STYLES -->
<Style x:Key="ValidationErrorLabelStyle"
TargetType="{x:Type Label}">
<Setter Property="TextColor"
Value="{StaticResource ErrorColor}" />
<Setter Property="FontSize"
Value="{StaticResource LittleSize}" />
</Style>
<Style x:Key="EntryStyle" <Style x:Key="EntryStyle"
TargetType="{x:Type Entry}"> TargetType="{x:Type Entry}">
<Setter Property="FontFamily" <Setter Property="FontFamily"
@ -125,9 +135,9 @@
Value="Bold" /> Value="Bold" />
<Setter Property="Opacity" <Setter Property="Opacity"
Value="0.6" /> Value="0.6" />
<Setter Property="effects:LineColorEffect.ApplyLineColor" <Setter Property="behaviors:LineColorBehavior.ApplyLineColor"
Value="True" /> Value="True" />
<Setter Property="effects:LineColorEffect.LineColor" <Setter Property="behaviors:LineColorBehavior.LineColor"
Value="{StaticResource BlackColor}" /> Value="{StaticResource BlackColor}" />
<Style.Triggers> <Style.Triggers>
<Trigger TargetType="Entry" <Trigger TargetType="Entry"
@ -156,16 +166,16 @@
Value="Transparent" /> Value="Transparent" />
<Setter Property="Opacity" <Setter Property="Opacity"
Value="0.6" /> Value="0.6" />
<Setter Property="effects:LineColorEffect.ApplyLineColor" <Setter Property="behaviors:LineColorBehavior.ApplyLineColor"
Value="True" /> Value="True" />
<Setter Property="effects:LineColorEffect.LineColor" <Setter Property="behaviors:LineColorBehavior.LineColor"
Value="Gray" /> Value="Gray" />
<Style.Triggers> <Style.Triggers>
<Trigger TargetType="Entry" <Trigger TargetType="Entry"
Property="IsFocused" Property="IsFocused"
Value="True"> Value="True">
<Setter Property="Opacity" Value="1" /> <Setter Property="Opacity" Value="1" />
<Setter Property="effects:LineColorEffect.LineColor" <Setter Property="behaviors:LineColorBehavior.LineColor"
Value="{StaticResource GreenColor}" /> Value="{StaticResource GreenColor}" />
</Trigger> </Trigger>
</Style.Triggers> </Style.Triggers>

View File

@ -1,6 +1,6 @@
using eShopOnContainers.Core.Helpers; using eShopOnContainers.Core.Helpers;
using eShopOnContainers.Services; using eShopOnContainers.Services;
using eShopOnContainers.ViewModels.Base; using eShopOnContainers.Core.ViewModels.Base;
using System.Threading.Tasks; using System.Threading.Tasks;
using Xamarin.Forms; using Xamarin.Forms;
using Xamarin.Forms.Xaml; using Xamarin.Forms.Xaml;
@ -27,13 +27,13 @@ namespace eShopOnContainers
private void InitApp() private void InitApp()
{ {
UseMockServices = Settings.UseMocks; UseMockServices = Settings.UseMocks;
ViewModelLocator.Initialize();
ViewModelLocator.Instance.UpdateDependencies(UseMockServices); ViewModelLocator.UpdateDependencies(UseMockServices);
} }
private Task InitNavigation() private Task InitNavigation()
{ {
var navigationService = ViewModelLocator.Instance.Resolve<INavigationService>(); var navigationService = ViewModelLocator.Resolve<INavigationService>();
return navigationService.InitializeAsync(); return navigationService.InitializeAsync();
} }

View File

@ -1,14 +1,18 @@
using System.Linq; using System.Linq;
using Xamarin.Forms; using Xamarin.Forms;
using eShopOnContainers.Core.Effects;
namespace eShopOnContainers.Core.Effects namespace eShopOnContainers.Core.Behaviors
{ {
public static class LineColorEffect public static class LineColorBehavior
{ {
public static readonly BindableProperty ApplyLineColorProperty = public static readonly BindableProperty ApplyLineColorProperty =
BindableProperty.CreateAttached("ApplyLineColor", typeof(bool), typeof(LineColorEffect), false, BindableProperty.CreateAttached("ApplyLineColor", typeof(bool), typeof(LineColorBehavior), false,
propertyChanged: OnApplyLineColorChanged); propertyChanged: OnApplyLineColorChanged);
public static readonly BindableProperty LineColorProperty =
BindableProperty.CreateAttached("LineColor", typeof(Color), typeof(LineColorBehavior), Color.Default);
public static bool GetApplyLineColor(BindableObject view) public static bool GetApplyLineColor(BindableObject view)
{ {
return (bool)view.GetValue(ApplyLineColorProperty); return (bool)view.GetValue(ApplyLineColorProperty);
@ -19,6 +23,16 @@ namespace eShopOnContainers.Core.Effects
view.SetValue(ApplyLineColorProperty, value); view.SetValue(ApplyLineColorProperty, value);
} }
public static Color GetLineColor(BindableObject view)
{
return (Color)view.GetValue(LineColorProperty);
}
public static void SetLineColor(BindableObject view, Color value)
{
view.SetValue(LineColorProperty, value);
}
private static void OnApplyLineColorChanged(BindableObject bindable, object oldValue, object newValue) private static void OnApplyLineColorChanged(BindableObject bindable, object oldValue, object newValue)
{ {
var view = bindable as View; var view = bindable as View;
@ -28,9 +42,9 @@ namespace eShopOnContainers.Core.Effects
return; return;
} }
bool hasShadow = (bool)newValue; bool hasLine = (bool)newValue;
if (hasShadow) if (hasLine)
{ {
view.Effects.Add(new EntryLineColorEffect()); view.Effects.Add(new EntryLineColorEffect());
} }
@ -43,25 +57,5 @@ namespace eShopOnContainers.Core.Effects
} }
} }
} }
public static readonly BindableProperty LineColorProperty =
BindableProperty.CreateAttached("LineColor", typeof(Color), typeof(LineColorEffect), Color.Default);
public static Color GetLineColor(BindableObject view)
{
return (Color)view.GetValue(LineColorProperty);
}
public static void SetLineColor(BindableObject view, Color value)
{
view.SetValue(LineColorProperty, value);
}
class EntryLineColorEffect : RoutingEffect
{
public EntryLineColorEffect() : base("eShopOnContainers.EntryLineColorEffect")
{
}
}
} }
} }

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Xamarin.Forms;
namespace eShopOnContainers.Core.Converters
{
public class FirstValidationErrorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
ICollection<string> errors = value as ICollection<string>;
return errors != null && errors.Count > 0 ? errors.ElementAt(0) : null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,11 @@
using Xamarin.Forms;
namespace eShopOnContainers.Core.Effects
{
public class EntryLineColorEffect : RoutingEffect
{
public EntryLineColorEffect() : base("eShopOnContainers.EntryLineColorEffect")
{
}
}
}

View File

@ -1,18 +0,0 @@
using eShopOnContainers.Core.Animations.Base;
using System;
using Xamarin.Forms;
namespace eShopOnContainers.Core.Extensions
{
public static class AnimationExtension
{
public static async void Animate(this VisualElement visualElement, AnimationBase animation, Action onFinishedCallback = null)
{
animation.Target = visualElement;
await animation.Begin();
onFinishedCallback?.Invoke();
}
}
}

View File

@ -1,6 +1,6 @@
using eShopOnContainers.Core.Models.Basket; using eShopOnContainers.Core.Models.Basket;
using eShopOnContainers.Core.Models.Catalog; using eShopOnContainers.Core.Models.Catalog;
using eShopOnContainers.ViewModels.Base; using eShopOnContainers.Core.ViewModels.Base;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
@ -21,7 +21,7 @@ namespace eShopOnContainers.Core.Helpers
try try
{ {
if (!ViewModelLocator.Instance.UseMockService if (!ViewModelLocator.UseMockService
&& Settings.UrlBase != GlobalSetting.DefaultEndpoint) && Settings.UrlBase != GlobalSetting.DefaultEndpoint)
{ {
foreach (var catalogItem in catalogItems) foreach (var catalogItem in catalogItems)
@ -54,7 +54,7 @@ namespace eShopOnContainers.Core.Helpers
try try
{ {
if (!ViewModelLocator.Instance.UseMockService if (!ViewModelLocator.UseMockService
&& Settings.UrlBase != GlobalSetting.DefaultEndpoint) && Settings.UrlBase != GlobalSetting.DefaultEndpoint)
{ {
foreach (var basketItem in basketItems) foreach (var basketItem in basketItems)

View File

@ -1,4 +1,4 @@
using eShopOnContainers.ViewModels.Base; using eShopOnContainers.Core.ViewModels.Base;
using Plugin.Settings; using Plugin.Settings;
using Plugin.Settings.Abstractions; using Plugin.Settings.Abstractions;
@ -27,7 +27,7 @@ namespace eShopOnContainers.Core.Helpers
private const string IdUrlBase = "url_base"; private const string IdUrlBase = "url_base";
private static readonly string AccessTokenDefault = string.Empty; private static readonly string AccessTokenDefault = string.Empty;
private static readonly string IdTokenDefault = string.Empty; private static readonly string IdTokenDefault = string.Empty;
private static readonly bool UseMocksDefault = ViewModelLocator.Instance.UseMockService; private static readonly bool UseMocksDefault = true;
private static readonly string UrlBaseDefault = GlobalSetting.Instance.BaseEndpoint; private static readonly string UrlBaseDefault = GlobalSetting.Instance.BaseEndpoint;
#endregion #endregion

View File

@ -1,5 +1,4 @@
using eShopOnContainers.ViewModels.Base; using eShopOnContainers.Core.ViewModels.Base;
using System;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace eShopOnContainers.Services namespace eShopOnContainers.Services
@ -12,12 +11,6 @@ namespace eShopOnContainers.Services
Task NavigateToAsync<TViewModel>(object parameter) where TViewModel : ViewModelBase; Task NavigateToAsync<TViewModel>(object parameter) where TViewModel : ViewModelBase;
Task NavigateToAsync(Type viewModelType);
Task NavigateToAsync(Type viewModelType, object parameter);
Task NavigateBackAsync();
Task RemoveLastFromBackStackAsync(); Task RemoveLastFromBackStackAsync();
Task RemoveBackStackAsync(); Task RemoveBackStackAsync();

View File

@ -1,9 +1,10 @@
using eShopOnContainers.Core.Helpers; using eShopOnContainers.Core.Helpers;
using eShopOnContainers.Core.ViewModels; using eShopOnContainers.Core.ViewModels;
using eShopOnContainers.Core.Views; using eShopOnContainers.Core.Views;
using eShopOnContainers.ViewModels.Base; using eShopOnContainers.Core.ViewModels.Base;
using System; using System;
using System.Collections.Generic; using System.Globalization;
using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using Xamarin.Forms; using Xamarin.Forms;
@ -11,23 +12,6 @@ namespace eShopOnContainers.Services
{ {
public class NavigationService : INavigationService public class NavigationService : INavigationService
{ {
protected readonly Dictionary<Type, Type> _mappings;
protected Application CurrentApplication
{
get
{
return Application.Current;
}
}
public NavigationService()
{
_mappings = new Dictionary<Type, Type>();
CreatePageViewModelMappings();
}
public Task InitializeAsync() public Task InitializeAsync()
{ {
if(string.IsNullOrEmpty(Settings.AuthAccessToken)) if(string.IsNullOrEmpty(Settings.AuthAccessToken))
@ -46,32 +30,9 @@ namespace eShopOnContainers.Services
return InternalNavigateToAsync(typeof(TViewModel), parameter); return InternalNavigateToAsync(typeof(TViewModel), parameter);
} }
public Task NavigateToAsync(Type viewModelType) public Task RemoveLastFromBackStackAsync()
{ {
return InternalNavigateToAsync(viewModelType, null); var mainPage = Application.Current.MainPage as CustomNavigationView;
}
public Task NavigateToAsync(Type viewModelType, object parameter)
{
return InternalNavigateToAsync(viewModelType, parameter);
}
public async Task NavigateBackAsync()
{
if (CurrentApplication.MainPage is CatalogView)
{
var mainPage = CurrentApplication.MainPage as CatalogView;
await mainPage.Navigation.PopAsync();
}
else if (CurrentApplication.MainPage != null)
{
await CurrentApplication.MainPage.Navigation.PopAsync();
}
}
public virtual Task RemoveLastFromBackStackAsync()
{
var mainPage = CurrentApplication.MainPage as CustomNavigationView;
if (mainPage != null) if (mainPage != null)
{ {
@ -82,9 +43,9 @@ namespace eShopOnContainers.Services
return Task.FromResult(true); return Task.FromResult(true);
} }
public virtual Task RemoveBackStackAsync() public Task RemoveBackStackAsync()
{ {
var mainPage = CurrentApplication.MainPage as CustomNavigationView; var mainPage = Application.Current.MainPage as CustomNavigationView;
if (mainPage != null) if (mainPage != null)
{ {
@ -98,67 +59,49 @@ namespace eShopOnContainers.Services
return Task.FromResult(true); return Task.FromResult(true);
} }
protected virtual async Task InternalNavigateToAsync(Type viewModelType, object parameter) private async Task InternalNavigateToAsync(Type viewModelType, object parameter)
{ {
Page page = CreateAndBindPage(viewModelType, parameter); Page page = CreatePage(viewModelType, parameter);
if (page is LoginView) if (page is LoginView)
{ {
CurrentApplication.MainPage = new CustomNavigationView(page); Application.Current.MainPage = new CustomNavigationView(page);
} }
else else
{ {
var navigationPage = CurrentApplication.MainPage as CustomNavigationView; var navigationPage = Application.Current.MainPage as CustomNavigationView;
if (navigationPage != null) if (navigationPage != null)
{ {
await navigationPage.PushAsync(page); await navigationPage.PushAsync(page);
} }
else else
{ {
CurrentApplication.MainPage = new CustomNavigationView(page); Application.Current.MainPage = new CustomNavigationView(page);
} }
} }
await (page.BindingContext as ViewModelBase).InitializeAsync(parameter); await (page.BindingContext as ViewModelBase).InitializeAsync(parameter);
} }
protected Type GetPageTypeForViewModel(Type viewModelType) private Type GetPageTypeForViewModel(Type viewModelType)
{ {
if (!_mappings.ContainsKey(viewModelType)) var viewName = viewModelType.FullName.Replace("Model", string.Empty);
{ var viewModelAssemblyName = viewModelType.GetTypeInfo().Assembly.FullName;
throw new KeyNotFoundException($"No map for ${viewModelType} was found on navigation mappings"); var viewAssemblyName = string.Format(CultureInfo.InvariantCulture, "{0}, {1}", viewName, viewModelAssemblyName);
} var viewType = Type.GetType(viewAssemblyName);
return viewType;
}
return _mappings[viewModelType]; private Page CreatePage(Type viewModelType, object parameter)
} {
Type pageType = GetPageTypeForViewModel(viewModelType);
if (pageType == null)
{
throw new Exception($"Cannot locate page type for {viewModelType}");
}
protected Page CreateAndBindPage(Type viewModelType, object parameter) Page page = Activator.CreateInstance(pageType) as Page;
{ return page;
Type pageType = GetPageTypeForViewModel(viewModelType); }
if (pageType == null)
{
throw new Exception($"Mapping type for {viewModelType} is not a page");
}
Page page = Activator.CreateInstance(pageType) as Page;
ViewModelBase viewModel = ViewModelLocator.Instance.Resolve(viewModelType) as ViewModelBase;
page.BindingContext = viewModel;
return page;
}
private void CreatePageViewModelMappings()
{
_mappings.Add(typeof(BasketViewModel), typeof(BasketView));
_mappings.Add(typeof(CatalogViewModel), typeof(CatalogView));
_mappings.Add(typeof(CheckoutViewModel), typeof(CheckoutView));
_mappings.Add(typeof(LoginViewModel), typeof(LoginView));
_mappings.Add(typeof(MainViewModel), typeof(MainView));
_mappings.Add(typeof(OrderDetailViewModel), typeof(OrderDetailView));
_mappings.Add(typeof(ProfileViewModel), typeof(ProfileView));
_mappings.Add(typeof(SettingsViewModel), typeof(SettingsView));
}
} }
} }

View File

@ -1,6 +1,5 @@
using eShopOnContainers.ViewModels.Base; using eShopOnContainers.Core.ViewModels.Base;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
namespace eShopOnContainers.Core.Validations namespace eShopOnContainers.Core.Validations
@ -8,13 +7,24 @@ namespace eShopOnContainers.Core.Validations
public class ValidatableObject<T> : ExtendedBindableObject, IValidity public class ValidatableObject<T> : ExtendedBindableObject, IValidity
{ {
private readonly List<IValidationRule<T>> _validations; private readonly List<IValidationRule<T>> _validations;
private readonly ObservableCollection<string> _errors; private List<string> _errors;
private T _value; private T _value;
private bool _isValid; private bool _isValid;
public List<IValidationRule<T>> Validations => _validations; public List<IValidationRule<T>> Validations => _validations;
public ObservableCollection<string> Errors => _errors; public List<string> Errors
{
get
{
return _errors;
}
set
{
_errors = value;
RaisePropertyChanged(() => Errors);
}
}
public T Value public T Value
{ {
@ -22,7 +32,6 @@ namespace eShopOnContainers.Core.Validations
{ {
return _value; return _value;
} }
set set
{ {
_value = value; _value = value;
@ -36,11 +45,9 @@ namespace eShopOnContainers.Core.Validations
{ {
return _isValid; return _isValid;
} }
set set
{ {
_isValid = value; _isValid = value;
_errors.Clear();
RaisePropertyChanged(() => IsValid); RaisePropertyChanged(() => IsValid);
} }
} }
@ -48,7 +55,7 @@ namespace eShopOnContainers.Core.Validations
public ValidatableObject() public ValidatableObject()
{ {
_isValid = true; _isValid = true;
_errors = new ObservableCollection<string>(); _errors = new List<string>();
_validations = new List<IValidationRule<T>>(); _validations = new List<IValidationRule<T>>();
} }
@ -59,11 +66,7 @@ namespace eShopOnContainers.Core.Validations
IEnumerable<string> errors = _validations.Where(v => !v.Check(Value)) IEnumerable<string> errors = _validations.Where(v => !v.Check(Value))
.Select(v => v.ValidationMessage); .Select(v => v.ValidationMessage);
foreach (var error in errors) Errors = errors.ToList();
{
Errors.Add(error);
}
IsValid = !Errors.Any(); IsValid = !Errors.Any();
return this.IsValid; return this.IsValid;

View File

@ -3,7 +3,7 @@ using System.Linq.Expressions;
using System.Reflection; using System.Reflection;
using Xamarin.Forms; using Xamarin.Forms;
namespace eShopOnContainers.ViewModels.Base namespace eShopOnContainers.Core.ViewModels.Base
{ {
public abstract class ExtendedBindableObject : BindableObject public abstract class ExtendedBindableObject : BindableObject
{ {

View File

@ -1,6 +1,6 @@
namespace eShopOnContainers.Core.ViewModels.Base namespace eShopOnContainers.Core.ViewModels.Base
{ {
public class MessengerKeys public class MessageKeys
{ {
// Add product to basket // Add product to basket
public const string AddProduct = "AddProduct"; public const string AddProduct = "AddProduct";

View File

@ -1,9 +1,8 @@
using eShopOnContainers.Core; using eShopOnContainers.Core.Helpers;
using eShopOnContainers.Core.Helpers;
using eShopOnContainers.Services; using eShopOnContainers.Services;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace eShopOnContainers.ViewModels.Base namespace eShopOnContainers.Core.ViewModels.Base
{ {
public abstract class ViewModelBase : ExtendedBindableObject public abstract class ViewModelBase : ExtendedBindableObject
{ {
@ -28,8 +27,8 @@ namespace eShopOnContainers.ViewModels.Base
public ViewModelBase() public ViewModelBase()
{ {
DialogService = ViewModelLocator.Instance.Resolve<IDialogService>(); DialogService = ViewModelLocator.Resolve<IDialogService>();
NavigationService = ViewModelLocator.Instance.Resolve<INavigationService>(); NavigationService = ViewModelLocator.Resolve<INavigationService>();
GlobalSetting.Instance.BaseEndpoint = Settings.UrlBase; GlobalSetting.Instance.BaseEndpoint = Settings.UrlBase;
} }

View File

@ -1,7 +1,8 @@
using Microsoft.Practices.Unity; using Microsoft.Practices.Unity;
using eShopOnContainers.Core.ViewModels;
using eShopOnContainers.Services; using eShopOnContainers.Services;
using System; using System;
using System.Globalization;
using System.Reflection;
using eShopOnContainers.Core.Services.Catalog; using eShopOnContainers.Core.Services.Catalog;
using eShopOnContainers.Core.Services.OpenUrl; using eShopOnContainers.Core.Services.OpenUrl;
using eShopOnContainers.Core.Services.RequestProvider; using eShopOnContainers.Core.Services.RequestProvider;
@ -9,100 +10,101 @@ using eShopOnContainers.Core.Services.Basket;
using eShopOnContainers.Core.Services.Identity; using eShopOnContainers.Core.Services.Identity;
using eShopOnContainers.Core.Services.Order; using eShopOnContainers.Core.Services.Order;
using eShopOnContainers.Core.Services.User; using eShopOnContainers.Core.Services.User;
using Xamarin.Forms;
namespace eShopOnContainers.ViewModels.Base namespace eShopOnContainers.Core.ViewModels.Base
{ {
public class ViewModelLocator public static class ViewModelLocator
{ {
private bool _useMockService; private static readonly IUnityContainer _unityContainer = new UnityContainer();
private readonly IUnityContainer _unityContainer;
private static readonly ViewModelLocator _instance = new ViewModelLocator(); public static readonly BindableProperty AutoWireViewModelProperty =
BindableProperty.CreateAttached("AutoWireViewModel", typeof(bool), typeof(ViewModelLocator), default(bool), propertyChanged: OnAutoWireViewModelChanged);
public static ViewModelLocator Instance public static bool GetAutoWireViewModel(BindableObject bindable)
{ {
get { return _instance; } return (bool)bindable.GetValue(ViewModelLocator.AutoWireViewModelProperty);
} }
public bool UseMockService public static void SetAutoWireViewModel(BindableObject bindable, bool value)
{ {
get { return _useMockService; } bindable.SetValue(ViewModelLocator.AutoWireViewModelProperty, value);
set { _useMockService = value; ; } }
}
protected ViewModelLocator() public static bool UseMockService { get; set; }
{
_unityContainer = new UnityContainer();
// Services public static void Initialize()
_unityContainer.RegisterType<IDialogService, DialogService>(); {
RegisterSingleton<INavigationService, NavigationService>(); // Services
_unityContainer.RegisterType<IOpenUrlService, OpenUrlService>(); _unityContainer.RegisterType<IDialogService, DialogService>();
_unityContainer.RegisterType<IRequestProvider, RequestProvider>(); _unityContainer.RegisterType<INavigationService, NavigationService>(new ContainerControlledLifetimeManager());
_unityContainer.RegisterType<IIdentityService, IdentityService>(); _unityContainer.RegisterType<IOpenUrlService, OpenUrlService>();
_unityContainer.RegisterType<IRequestProvider, RequestProvider>();
_unityContainer.RegisterType<IIdentityService, IdentityService>();
_unityContainer.RegisterType<ICatalogService, CatalogMockService>();
_unityContainer.RegisterType<IBasketService, BasketMockService>();
_unityContainer.RegisterType<IUserService, UserMockService>();
_unityContainer.RegisterType<ICatalogService, CatalogMockService>(); // View models
_unityContainer.RegisterType<IBasketService, BasketMockService>(); _unityContainer.RegisterType<BasketViewModel>();
_unityContainer.RegisterType<IUserService, UserMockService>(); _unityContainer.RegisterType<CatalogViewModel>();
_unityContainer.RegisterType<CheckoutViewModel>();
_unityContainer.RegisterType<LoginViewModel>();
_unityContainer.RegisterType<MainViewModel>();
_unityContainer.RegisterType<OrderDetailViewModel>();
_unityContainer.RegisterType<ProfileViewModel>();
_unityContainer.RegisterType<SettingsViewModel>();
}
// View models public static void UpdateDependencies(bool useMockServices)
_unityContainer.RegisterType<BasketViewModel>(); {
_unityContainer.RegisterType<CatalogViewModel>(); // Change injected dependencies
_unityContainer.RegisterType<CheckoutViewModel>(); if (useMockServices)
_unityContainer.RegisterType<LoginViewModel>(); {
_unityContainer.RegisterType<MainViewModel>(); _unityContainer.RegisterInstance<ICatalogService>(new CatalogMockService());
_unityContainer.RegisterType<OrderDetailViewModel>(); _unityContainer.RegisterInstance<IBasketService>(new BasketMockService());
_unityContainer.RegisterType<ProfileViewModel>(); _unityContainer.RegisterInstance<IOrderService>(new OrderMockService());
_unityContainer.RegisterType<SettingsViewModel>(); _unityContainer.RegisterInstance<IUserService>(new UserMockService());
}
public void UpdateDependencies(bool useMockServices) UseMockService = true;
{ }
// Change injected dependencies else
if (useMockServices) {
{ var requestProvider = Resolve<IRequestProvider>();
_unityContainer.RegisterInstance<ICatalogService>(new CatalogMockService()); _unityContainer.RegisterInstance<ICatalogService>(new CatalogService(requestProvider));
_unityContainer.RegisterInstance<IBasketService>(new BasketMockService()); _unityContainer.RegisterInstance<IBasketService>(new BasketService(requestProvider));
_unityContainer.RegisterInstance<IOrderService>(new OrderMockService()); _unityContainer.RegisterInstance<IOrderService>(new OrderService(requestProvider));
_unityContainer.RegisterInstance<IUserService>(new UserMockService()); _unityContainer.RegisterInstance<IUserService>(new UserService(requestProvider));
UseMockService = true; UseMockService = false;
} }
else }
{
var requestProvider = Resolve<IRequestProvider>();
_unityContainer.RegisterInstance<ICatalogService>(new CatalogService(requestProvider));
_unityContainer.RegisterInstance<IBasketService>(new BasketService(requestProvider));
_unityContainer.RegisterInstance<IOrderService>(new OrderService(requestProvider));
_unityContainer.RegisterInstance<IUserService>(new UserService(requestProvider));
UseMockService = false; public static T Resolve<T>()
} {
} return _unityContainer.Resolve<T>();
}
public T Resolve<T>()
{
return _unityContainer.Resolve<T>();
}
public object Resolve(Type type) private static void OnAutoWireViewModelChanged(BindableObject bindable, object oldValue, object newValue)
{ {
return _unityContainer.Resolve(type); var view = bindable as Element;
} if (view == null)
{
return;
}
public void Register<T>(T instance) var viewType = view.GetType();
{ var viewName = viewType.FullName.Replace(".Views.", ".ViewModels.");
_unityContainer.RegisterInstance<T>(instance); var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
} var viewModelName = string.Format(CultureInfo.InvariantCulture, "{0}Model, {1}", viewName, viewAssemblyName);
public void Register<TInterface, T>() where T : TInterface var viewModelType = Type.GetType(viewModelName);
{ if (viewModelType == null)
_unityContainer.RegisterType<TInterface, T>(); {
} return;
}
public void RegisterSingleton<TInterface, T>() where T : TInterface var viewModel = _unityContainer.Resolve(viewModelType);
{ view.BindingContext = viewModel;
_unityContainer.RegisterType<TInterface, T>(new ContainerControlledLifetimeManager()); }
} }
}
} }

View File

@ -4,8 +4,6 @@ using eShopOnContainers.Core.Models.Catalog;
using eShopOnContainers.Core.Services.Basket; using eShopOnContainers.Core.Services.Basket;
using eShopOnContainers.Core.Services.User; using eShopOnContainers.Core.Services.User;
using eShopOnContainers.Core.ViewModels.Base; using eShopOnContainers.Core.ViewModels.Base;
using eShopOnContainers.ViewModels.Base;
using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -61,7 +59,7 @@ namespace eShopOnContainers.Core.ViewModels
} }
} }
public ICommand AddCommand => new Command<BasketItem>(AddItem); public ICommand AddCommand => new Command<BasketItem>(async (item) => await AddItemAsync(item));
public ICommand CheckoutCommand => new Command(async () => await CheckoutAsync()); public ICommand CheckoutCommand => new Command(async () => await CheckoutAsync());
@ -82,22 +80,22 @@ namespace eShopOnContainers.Core.ViewModels
foreach (var basketItem in basket.Items) foreach (var basketItem in basket.Items)
{ {
BadgeCount += basketItem.Quantity; BadgeCount += basketItem.Quantity;
AddBasketItem(basketItem); await AddBasketItemAsync(basketItem);
} }
} }
MessagingCenter.Unsubscribe<CatalogViewModel, CatalogItem>(this, MessengerKeys.AddProduct); MessagingCenter.Unsubscribe<CatalogViewModel, CatalogItem>(this, MessageKeys.AddProduct);
MessagingCenter.Subscribe<CatalogViewModel, CatalogItem>(this, MessengerKeys.AddProduct, (sender, arg) => MessagingCenter.Subscribe<CatalogViewModel, CatalogItem>(this, MessageKeys.AddProduct, async (sender, arg) =>
{ {
BadgeCount++; BadgeCount++;
AddCatalogItem(arg); await AddCatalogItemAsync(arg);
}); });
await base.InitializeAsync(navigationData); await base.InitializeAsync(navigationData);
} }
private void AddCatalogItem(CatalogItem item) private async Task AddCatalogItemAsync(CatalogItem item)
{ {
BasketItems.Add(new BasketItem BasketItems.Add(new BasketItem
{ {
@ -108,26 +106,26 @@ namespace eShopOnContainers.Core.ViewModels
Quantity = 1 Quantity = 1
}); });
ReCalculateTotal(); await ReCalculateTotalAsync();
} }
private void AddItem(BasketItem item) private async Task AddItemAsync(BasketItem item)
{ {
BadgeCount++; BadgeCount++;
AddBasketItem(item); await AddBasketItemAsync(item);
RaisePropertyChanged(() => BasketItems); RaisePropertyChanged(() => BasketItems);
} }
private void AddBasketItem(BasketItem item) private async Task AddBasketItemAsync(BasketItem item)
{ {
BasketItems.Add(item); BasketItems.Add(item);
ReCalculateTotal(); await ReCalculateTotalAsync();
} }
private async void ReCalculateTotal() private async Task ReCalculateTotalAsync()
{ {
Total = 0; Total = 0;

View File

@ -1,14 +1,11 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using eShopOnContainers.ViewModels.Base; using eShopOnContainers.Core.ViewModels.Base;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using Xamarin.Forms; using Xamarin.Forms;
using eShopOnContainers.Core.ViewModels.Base;
using eShopOnContainers.Core.Models.Catalog; using eShopOnContainers.Core.Models.Catalog;
using eShopOnContainers.Core.Services.Catalog; using eShopOnContainers.Core.Services.Catalog;
using System.Windows.Input; using System.Windows.Input;
using System.Linq;
using eShopOnContainers.Core.Services.Basket; using eShopOnContainers.Core.Services.Basket;
using eShopOnContainers.Core.Helpers;
using eShopOnContainers.Core.Services.User; using eShopOnContainers.Core.Services.User;
namespace eShopOnContainers.Core.ViewModels namespace eShopOnContainers.Core.ViewModels
@ -20,19 +17,11 @@ namespace eShopOnContainers.Core.ViewModels
private CatalogBrand _brand; private CatalogBrand _brand;
private ObservableCollection<CatalogType> _types; private ObservableCollection<CatalogType> _types;
private CatalogType _type; private CatalogType _type;
private IBasketService _basketService;
private ICatalogService _productsService; private ICatalogService _productsService;
private IUserService _userService;
public CatalogViewModel( public CatalogViewModel(ICatalogService productsService)
IBasketService basketService,
ICatalogService productsService,
IUserService userService)
{ {
_basketService = basketService;
_productsService = productsService; _productsService = productsService;
_userService = userService;
} }
public ObservableCollection<CatalogItem> Products public ObservableCollection<CatalogItem> Products
@ -91,9 +80,9 @@ namespace eShopOnContainers.Core.ViewModels
public ICommand AddCatalogItemCommand => new Command<CatalogItem>(AddCatalogItem); public ICommand AddCatalogItemCommand => new Command<CatalogItem>(AddCatalogItem);
public ICommand FilterCommand => new Command(Filter); public ICommand FilterCommand => new Command(async () => await FilterAsync());
public ICommand ClearFilterCommand => new Command(ClearFilter); public ICommand ClearFilterCommand => new Command(async () => await ClearFilterAsync());
public override async Task InitializeAsync(object navigationData) public override async Task InitializeAsync(object navigationData)
{ {
@ -110,10 +99,10 @@ namespace eShopOnContainers.Core.ViewModels
private void AddCatalogItem(CatalogItem catalogItem) private void AddCatalogItem(CatalogItem catalogItem)
{ {
// Add new item to Basket // Add new item to Basket
MessagingCenter.Send(this, MessengerKeys.AddProduct, catalogItem); MessagingCenter.Send(this, MessageKeys.AddProduct, catalogItem);
} }
private async void Filter() private async Task FilterAsync()
{ {
if (Brand == null && Type == null) if (Brand == null && Type == null)
{ {
@ -123,13 +112,13 @@ namespace eShopOnContainers.Core.ViewModels
IsBusy = true; IsBusy = true;
// Filter catalog products // Filter catalog products
MessagingCenter.Send(this, MessengerKeys.Filter); MessagingCenter.Send(this, MessageKeys.Filter);
Products = await _productsService.FilterAsync(Brand.Id, Type.Id); Products = await _productsService.FilterAsync(Brand.Id, Type.Id);
IsBusy = false; IsBusy = false;
} }
private async void ClearFilter() private async Task ClearFilterAsync()
{ {
IsBusy = true; IsBusy = true;

View File

@ -1,5 +1,5 @@
using eShopOnContainers.Core.Models.Navigation; using eShopOnContainers.Core.Models.Navigation;
using eShopOnContainers.ViewModels.Base; using eShopOnContainers.Core.ViewModels.Base;
using System.Windows.Input; using System.Windows.Input;
using Xamarin.Forms; using Xamarin.Forms;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -138,7 +138,7 @@ namespace eShopOnContainers.Core.ViewModels
await _basketService.ClearBasketAsync(_shippingAddress.Id.ToString(), authToken); await _basketService.ClearBasketAsync(_shippingAddress.Id.ToString(), authToken);
// Reset Basket badge // Reset Basket badge
var basketViewModel = ViewModelLocator.Instance.Resolve<BasketViewModel>(); var basketViewModel = ViewModelLocator.Resolve<BasketViewModel>();
basketViewModel.BadgeCount = 0; basketViewModel.BadgeCount = 0;
// Navigate to Orders // Navigate to Orders

View File

@ -2,9 +2,8 @@
using eShopOnContainers.Core.Models.User; using eShopOnContainers.Core.Models.User;
using eShopOnContainers.Core.Services.Identity; using eShopOnContainers.Core.Services.Identity;
using eShopOnContainers.Core.Services.OpenUrl; using eShopOnContainers.Core.Services.OpenUrl;
using eShopOnContainers.Core.Services.User;
using eShopOnContainers.Core.Validations; using eShopOnContainers.Core.Validations;
using eShopOnContainers.ViewModels.Base; using eShopOnContainers.Core.ViewModels.Base;
using IdentityModel.Client; using IdentityModel.Client;
using System; using System;
using System.Diagnostics; using System.Diagnostics;
@ -25,16 +24,13 @@ namespace eShopOnContainers.Core.ViewModels
private IOpenUrlService _openUrlService; private IOpenUrlService _openUrlService;
private IIdentityService _identityService; private IIdentityService _identityService;
private IUserService _userService;
public LoginViewModel( public LoginViewModel(
IOpenUrlService openUrlService, IOpenUrlService openUrlService,
IIdentityService identityService, IIdentityService identityService)
IUserService userService)
{ {
_openUrlService = openUrlService; _openUrlService = openUrlService;
_identityService = identityService; _identityService = identityService;
_userService = userService;
_userName = new ValidatableObject<string>(); _userName = new ValidatableObject<string>();
_password = new ValidatableObject<string>(); _password = new ValidatableObject<string>();
@ -131,6 +127,10 @@ namespace eShopOnContainers.Core.ViewModels
public ICommand SettingsCommand => new Command(async () => await SettingsAsync()); public ICommand SettingsCommand => new Command(async () => await SettingsAsync());
public ICommand ValidateUserNameCommand => new Command(() => ValidateUserName());
public ICommand ValidatePasswordCommand => new Command(() => ValidatePassword());
public override Task InitializeAsync(object navigationData) public override Task InitializeAsync(object navigationData)
{ {
if(navigationData is LogoutParameter) if(navigationData is LogoutParameter)
@ -253,16 +253,26 @@ namespace eShopOnContainers.Core.ViewModels
private bool Validate() private bool Validate()
{ {
bool isValidUser = _userName.Validate(); bool isValidUser = ValidateUserName();
bool isValidPassword = _password.Validate(); bool isValidPassword = ValidatePassword();
return isValidUser && isValidPassword; return isValidUser && isValidPassword;
} }
private bool ValidateUserName()
{
return _userName.Validate();
}
private bool ValidatePassword()
{
return _password.Validate();
}
private void AddValidations() private void AddValidations()
{ {
_userName.Validations.Add(new IsNotNullOrEmptyRule<string> { ValidationMessage = "Username should not be empty" }); _userName.Validations.Add(new IsNotNullOrEmptyRule<string> { ValidationMessage = "A username is required." });
_password.Validations.Add(new IsNotNullOrEmptyRule<string> { ValidationMessage = "Password should not be empty" }); _password.Validations.Add(new IsNotNullOrEmptyRule<string> { ValidationMessage = "A password is required." });
} }
public void InvalidateMock() public void InvalidateMock()

View File

@ -1,8 +1,7 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using eShopOnContainers.ViewModels.Base; using eShopOnContainers.Core.ViewModels.Base;
using eShopOnContainers.Core.Models.Navigation; using eShopOnContainers.Core.Models.Navigation;
using Xamarin.Forms; using Xamarin.Forms;
using eShopOnContainers.Core.ViewModels.Base;
using System.Windows.Input; using System.Windows.Input;
namespace eShopOnContainers.Core.ViewModels namespace eShopOnContainers.Core.ViewModels
@ -19,7 +18,7 @@ namespace eShopOnContainers.Core.ViewModels
{ {
// Change selected application tab // Change selected application tab
var tabIndex = ((TabParameter)navigationData).TabIndex; var tabIndex = ((TabParameter)navigationData).TabIndex;
MessagingCenter.Send(this, MessengerKeys.ChangeTab, tabIndex); MessagingCenter.Send(this, MessageKeys.ChangeTab, tabIndex);
} }
return base.InitializeAsync(navigationData); return base.InitializeAsync(navigationData);

View File

@ -1,6 +1,6 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using eShopOnContainers.Core.Models.Orders; using eShopOnContainers.Core.Models.Orders;
using eShopOnContainers.ViewModels.Base; using eShopOnContainers.Core.ViewModels.Base;
using eShopOnContainers.Core.Services.Catalog; using eShopOnContainers.Core.Services.Catalog;
using eShopOnContainers.Core.Services.Basket; using eShopOnContainers.Core.Services.Basket;
using eShopOnContainers.Core.Services.Order; using eShopOnContainers.Core.Services.Order;
@ -13,17 +13,10 @@ namespace eShopOnContainers.Core.ViewModels
{ {
private Order _order; private Order _order;
private IBasketService _orderService;
private ICatalogService _catalogService;
private IOrderService _ordersService; private IOrderService _ordersService;
public OrderDetailViewModel( public OrderDetailViewModel(IOrderService ordersService)
IBasketService orderService,
ICatalogService catalogService,
IOrderService ordersService)
{ {
_orderService = orderService;
_catalogService = catalogService;
_ordersService = ordersService; _ordersService = ordersService;
} }

View File

@ -3,7 +3,7 @@ using eShopOnContainers.Core.Helpers;
using eShopOnContainers.Core.Models.Orders; using eShopOnContainers.Core.Models.Orders;
using eShopOnContainers.Core.Models.User; using eShopOnContainers.Core.Models.User;
using eShopOnContainers.Core.Services.Order; using eShopOnContainers.Core.Services.Order;
using eShopOnContainers.ViewModels.Base; using eShopOnContainers.Core.ViewModels.Base;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Input; using System.Windows.Input;

View File

@ -1,4 +1,4 @@
using eShopOnContainers.ViewModels.Base; using eShopOnContainers.Core.ViewModels.Base;
using System.Windows.Input; using System.Windows.Input;
using Xamarin.Forms; using Xamarin.Forms;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -71,7 +71,7 @@ namespace eShopOnContainers.Core.ViewModels
private void MockServices() private void MockServices()
{ {
ViewModelLocator.Instance.UpdateDependencies(!UseAzureServices); ViewModelLocator.UpdateDependencies(!UseAzureServices);
UpdateInfo(); UpdateInfo();
} }

View File

@ -1,10 +1,12 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="eShopOnContainers.Core.Views.BasketView" x:Class="eShopOnContainers.Core.Views.BasketView"
xmlns:viewModelBase="clr-namespace:eShopOnContainers.Core.ViewModels.Base;assembly=eShopOnContainers.Core"
xmlns:behaviors="clr-namespace:eShopOnContainers.Core.Behaviors;assembly=eShopOnContainers.Core" xmlns:behaviors="clr-namespace:eShopOnContainers.Core.Behaviors;assembly=eShopOnContainers.Core"
xmlns:templates="clr-namespace:eShopOnContainers.Core.Views.Templates;assembly=eShopOnContainers.Core" xmlns:templates="clr-namespace:eShopOnContainers.Core.Views.Templates;assembly=eShopOnContainers.Core"
Title="Cart"> viewModelBase:ViewModelLocator.AutoWireViewModel="true"
Title="Cart">
<ContentPage.Resources> <ContentPage.Resources>
<ResourceDictionary> <ResourceDictionary>

View File

@ -1,12 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="eShopOnContainers.Core.Views.CatalogView" x:Class="eShopOnContainers.Core.Views.CatalogView"
xmlns:templates="clr-namespace:eShopOnContainers.Core.Views.Templates;assembly=eShopOnContainers.Core" xmlns:templates="clr-namespace:eShopOnContainers.Core.Views.Templates;assembly=eShopOnContainers.Core"
xmlns:views="clr-namespace:eShopOnContainers.Core.Views;assembly=eShopOnContainers.Core" xmlns:views="clr-namespace:eShopOnContainers.Core.Views;assembly=eShopOnContainers.Core"
xmlns:viewModelBase="clr-namespace:eShopOnContainers.Core.ViewModels.Base;assembly=eShopOnContainers.Core"
xmlns:animations="clr-namespace:eShopOnContainers.Core.Animations;assembly=eShopOnContainers.Core" xmlns:animations="clr-namespace:eShopOnContainers.Core.Animations;assembly=eShopOnContainers.Core"
xmlns:triggers="clr-namespace:eShopOnContainers.Core.Triggers;assembly=eShopOnContainers.Core" xmlns:triggers="clr-namespace:eShopOnContainers.Core.Triggers;assembly=eShopOnContainers.Core"
xmlns:behaviors="clr-namespace:eShopOnContainers.Core.Behaviors;assembly=eShopOnContainers.Core" xmlns:behaviors="clr-namespace:eShopOnContainers.Core.Behaviors;assembly=eShopOnContainers.Core"
viewModelBase:ViewModelLocator.AutoWireViewModel="true"
Title="Catalog"> Title="Catalog">
<ContentPage.Resources> <ContentPage.Resources>
<ResourceDictionary> <ResourceDictionary>

View File

@ -8,17 +8,15 @@ namespace eShopOnContainers.Core.Views
{ {
public partial class CatalogView : ContentPage, IMenuContainerPage public partial class CatalogView : ContentPage, IMenuContainerPage
{ {
private FiltersView _filterView; private FiltersView _filterView = new FiltersView();
public CatalogView() public CatalogView()
{ {
InitializeComponent(); InitializeComponent();
_filterView = new FiltersView();
SlideMenu = _filterView; SlideMenu = _filterView;
MessagingCenter.Subscribe<CatalogViewModel>(this, MessengerKeys.Filter, (sender) => MessagingCenter.Subscribe<CatalogViewModel>(this, MessageKeys.Filter, (sender) =>
{ {
Filter(); Filter();
}); });
@ -42,7 +40,6 @@ namespace eShopOnContainers.Core.Views
set; set;
} }
protected override void OnBindingContextChanged() protected override void OnBindingContextChanged()
{ {
base.OnBindingContextChanged(); base.OnBindingContextChanged();

View File

@ -1,8 +1,10 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="eShopOnContainers.Core.Views.CheckoutView" x:Class="eShopOnContainers.Core.Views.CheckoutView"
xmlns:templates="clr-namespace:eShopOnContainers.Core.Views.Templates;assembly=eShopOnContainers.Core" xmlns:viewModelBase="clr-namespace:eShopOnContainers.Core.ViewModels.Base;assembly=eShopOnContainers.Core"
xmlns:templates="clr-namespace:eShopOnContainers.Core.Views.Templates;assembly=eShopOnContainers.Core"
viewModelBase:ViewModelLocator.AutoWireViewModel="true"
Title="Checkout"> Title="Checkout">
<ContentPage.Resources> <ContentPage.Resources>
<ResourceDictionary> <ResourceDictionary>
@ -82,8 +84,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<!-- ORDER INFO --> <!-- ORDER INFO -->
<Grid <Grid>
x:Name="OrderInfo">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition /> <ColumnDefinition />
<ColumnDefinition /> <ColumnDefinition />
@ -139,8 +140,7 @@
</Grid> </Grid>
<!-- SHIPPING ADDRESS --> <!-- SHIPPING ADDRESS -->
<Grid <Grid
x:Name="ShippingAddress" Grid.Row="1"
Grid.Row="1"
Margin="12"> Margin="12">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
@ -167,9 +167,7 @@
</StackLayout> </StackLayout>
</Grid> </Grid>
<!-- ORDER ITEMS --> <!-- ORDER ITEMS -->
<Grid <Grid Grid.Row="2">
x:Name="OrderItems"
Grid.Row="2">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="*" /> <RowDefinition Height="*" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />

View File

@ -2,9 +2,11 @@
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="eShopOnContainers.Core.Views.LoginView" x:Class="eShopOnContainers.Core.Views.LoginView"
xmlns:viewModelBase="clr-namespace:eShopOnContainers.Core.ViewModels.Base;assembly=eShopOnContainers.Core"
xmlns:animations="clr-namespace:eShopOnContainers.Core.Animations;assembly=eShopOnContainers.Core" xmlns:animations="clr-namespace:eShopOnContainers.Core.Animations;assembly=eShopOnContainers.Core"
xmlns:triggers="clr-namespace:eShopOnContainers.Core.Triggers;assembly=eShopOnContainers.Core" xmlns:triggers="clr-namespace:eShopOnContainers.Core.Triggers;assembly=eShopOnContainers.Core"
xmlns:behaviors="clr-namespace:eShopOnContainers.Core.Behaviors;assembly=eShopOnContainers.Core"> xmlns:behaviors="clr-namespace:eShopOnContainers.Core.Behaviors;assembly=eShopOnContainers.Core"
viewModelBase:ViewModelLocator.AutoWireViewModel="true">
<ContentPage.Title> <ContentPage.Title>
<OnPlatform <OnPlatform
x:TypeArguments="x:String" x:TypeArguments="x:String"
@ -175,30 +177,60 @@
Margin="24"> Margin="24">
<Label <Label
Text="User name or email" Text="User name or email"
Style="{StaticResource HeaderLabelStyle}"/> Style="{StaticResource HeaderLabelStyle}" />
<Entry <Entry Text="{Binding UserName.Value, Mode=TwoWay}">
Text="{Binding UserName.Value, Mode=TwoWay}"> <Entry.Style>
<Entry.Style>
<OnPlatform x:TypeArguments="Style" <OnPlatform x:TypeArguments="Style"
iOS="{StaticResource EntryStyle}" iOS="{StaticResource EntryStyle}"
Android="{StaticResource EntryStyle}" Android="{StaticResource EntryStyle}"
WinPhone="{StaticResource UwpEntryStyle}"/> WinPhone="{StaticResource UwpEntryStyle}"/>
</Entry.Style> </Entry.Style>
<Entry.Behaviors>
<behaviors:EventToCommandBehavior
EventName="TextChanged"
Command="{Binding ValidateUserNameCommand}" />
</Entry.Behaviors>
<Entry.Triggers>
<DataTrigger
TargetType="Entry"
Binding="{Binding UserName.IsValid}"
Value="False">
<Setter Property="behaviors:LineColorBehavior.LineColor" Value="{StaticResource ErrorColor}" />
</DataTrigger>
</Entry.Triggers>
</Entry> </Entry>
<Label
Text="{Binding UserName.Errors, Converter={StaticResource FirstValidationErrorConverter}"
Style="{StaticResource ValidationErrorLabelStyle}" />
<Label <Label
Text="Password" Text="Password"
Style="{StaticResource HeaderLabelStyle}"/> Style="{StaticResource HeaderLabelStyle}"/>
<Entry <Entry
IsPassword="True" IsPassword="True"
Text="{Binding Password.Value, Mode=TwoWay}" Text="{Binding Password.Value, Mode=TwoWay}">
Style="{StaticResource EntryStyle}">
<Entry.Style> <Entry.Style>
<OnPlatform x:TypeArguments="Style" <OnPlatform x:TypeArguments="Style"
iOS="{StaticResource EntryStyle}" iOS="{StaticResource EntryStyle}"
Android="{StaticResource EntryStyle}" Android="{StaticResource EntryStyle}"
WinPhone="{StaticResource UwpEntryStyle}"/> WinPhone="{StaticResource UwpEntryStyle}"/>
</Entry.Style> </Entry.Style>
<Entry.Behaviors>
<behaviors:EventToCommandBehavior
EventName="TextChanged"
Command="{Binding ValidatePasswordCommand}" />
</Entry.Behaviors>
<Entry.Triggers>
<DataTrigger
TargetType="Entry"
Binding="{Binding Password.IsValid}"
Value="False">
<Setter Property="behaviors:LineColorBehavior.LineColor" Value="{StaticResource ErrorColor}" />
</DataTrigger>
</Entry.Triggers>
</Entry> </Entry>
<Label
Text="{Binding Password.Errors, Converter={StaticResource FirstValidationErrorConverter}"
Style="{StaticResource ValidationErrorLabelStyle}" />
</StackLayout> </StackLayout>
<!-- LOGIN BUTTON --> <!-- LOGIN BUTTON -->
<Grid <Grid

View File

@ -1,5 +1,4 @@
using eShopOnContainers.Core.Helpers; using eShopOnContainers.Core.ViewModels;
using eShopOnContainers.Core.ViewModels;
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -22,14 +21,16 @@ namespace eShopOnContainers.Core.Views
this.Content = null; this.Content = null;
this.Content = content; this.Content = content;
_animate = true; var vm = BindingContext as LoginViewModel;
await AnimateIn(); if (vm != null)
var vm = BindingContext as LoginViewModel;
if(vm != null)
{ {
vm.InvalidateMock(); vm.InvalidateMock();
if (!vm.IsMock)
{
_animate = true;
await AnimateIn();
}
} }
} }
@ -54,14 +55,13 @@ namespace eShopOnContainers.Core.Views
{ {
while (_animate) while (_animate)
{ {
await uiElement.ScaleTo(1.05, duration, Easing.SinInOut); await uiElement.ScaleTo(1.05, duration, Easing.SinInOut);
await Task.WhenAll(
await Task.WhenAll( uiElement.FadeTo(1, duration, Easing.SinInOut),
uiElement.FadeTo(1, duration, Easing.SinInOut), uiElement.LayoutTo(new Rectangle(new Point(0, 0), new Size(uiElement.Width, uiElement.Height))),
uiElement.LayoutTo(new Rectangle(new Point(0, 0), new Size(uiElement.Width, uiElement.Height))), uiElement.FadeTo(.9, duration, Easing.SinInOut),
uiElement.FadeTo(.9, duration, Easing.SinInOut), uiElement.ScaleTo(1.15, duration, Easing.SinInOut)
uiElement.ScaleTo(1.15, duration, Easing.SinInOut) );
);
} }
} }
catch (Exception ex) catch (Exception ex)

View File

@ -1,12 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms" <TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="eShopOnContainers.Core.Views.MainView" x:Class="eShopOnContainers.Core.Views.MainView"
xmlns:views="clr-namespace:eShopOnContainers.Core.Views;assembly=eShopOnContainers.Core" xmlns:views="clr-namespace:eShopOnContainers.Core.Views;assembly=eShopOnContainers.Core"
xmlns:viewModelBase="clr-namespace:eShopOnContainers.Core.ViewModels.Base;assembly=eShopOnContainers.Core"
xmlns:controls="clr-namespace:eShopOnContainers.Core.Controls;assembly=eShopOnContainers.Core" xmlns:controls="clr-namespace:eShopOnContainers.Core.Controls;assembly=eShopOnContainers.Core"
BarBackgroundColor="{StaticResource DarkGreenColor}" BarBackgroundColor="{StaticResource DarkGreenColor}"
BackgroundColor="{StaticResource BackgroundColor}" BackgroundColor="{StaticResource BackgroundColor}"
BarTextColor="{StaticResource WhiteColor}"> BarTextColor="{StaticResource WhiteColor}"
viewModelBase:ViewModelLocator.AutoWireViewModel="true">
<TabbedPage.Title> <TabbedPage.Title>
<OnPlatform <OnPlatform
x:TypeArguments="x:String" x:TypeArguments="x:String"

View File

@ -1,6 +1,5 @@
using eShopOnContainers.Core.ViewModels; using eShopOnContainers.Core.ViewModels;
using eShopOnContainers.Core.ViewModels.Base; using eShopOnContainers.Core.ViewModels.Base;
using eShopOnContainers.ViewModels.Base;
using Xamarin.Forms; using Xamarin.Forms;
namespace eShopOnContainers.Core.Views namespace eShopOnContainers.Core.Views
@ -16,7 +15,7 @@ namespace eShopOnContainers.Core.Views
{ {
base.OnAppearing(); base.OnAppearing();
MessagingCenter.Subscribe<MainViewModel, int>(this, MessengerKeys.ChangeTab, (sender, arg) => MessagingCenter.Subscribe<MainViewModel, int>(this, MessageKeys.ChangeTab, (sender, arg) =>
{ {
switch(arg) switch(arg)
{ {
@ -32,17 +31,9 @@ namespace eShopOnContainers.Core.Views
} }
}); });
var homeViewModel = ViewModelLocator.Instance.Resolve<CatalogViewModel>(); await ((CatalogViewModel)HomeView.BindingContext).InitializeAsync(null);
await homeViewModel.InitializeAsync(null); await ((BasketViewModel)BasketView.BindingContext).InitializeAsync(null);
HomeView.BindingContext = homeViewModel; await ((ProfileViewModel)ProfileView.BindingContext).InitializeAsync(null);
var basketViewModel = ViewModelLocator.Instance.Resolve<BasketViewModel>();
await basketViewModel.InitializeAsync(null);
BasketView.BindingContext = basketViewModel;
var profileViewModel = ViewModelLocator.Instance.Resolve<ProfileViewModel>();
await profileViewModel.InitializeAsync(null);
ProfileView.BindingContext = profileViewModel;
} }
} }
} }

View File

@ -1,10 +1,12 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="eShopOnContainers.Core.Views.OrderDetailView" x:Class="eShopOnContainers.Core.Views.OrderDetailView"
xmlns:viewModelBase="clr-namespace:eShopOnContainers.Core.ViewModels.Base;assembly=eShopOnContainers.Core"
xmlns:templates="clr-namespace:eShopOnContainers.Core.Views.Templates;assembly=eShopOnContainers.Core" xmlns:templates="clr-namespace:eShopOnContainers.Core.Views.Templates;assembly=eShopOnContainers.Core"
xmlns:animations="clr-namespace:eShopOnContainers.Core.Animations;assembly=eShopOnContainers.Core" xmlns:animations="clr-namespace:eShopOnContainers.Core.Animations;assembly=eShopOnContainers.Core"
xmlns:triggers="clr-namespace:eShopOnContainers.Core.Triggers;assembly=eShopOnContainers.Core" xmlns:triggers="clr-namespace:eShopOnContainers.Core.Triggers;assembly=eShopOnContainers.Core"
viewModelBase:ViewModelLocator.AutoWireViewModel="true"
Title="{Binding Order.OrderNumber}"> Title="{Binding Order.OrderNumber}">
<ContentPage.Resources> <ContentPage.Resources>
<ResourceDictionary> <ResourceDictionary>

View File

@ -1,10 +1,12 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="eShopOnContainers.Core.Views.ProfileView" x:Class="eShopOnContainers.Core.Views.ProfileView"
xmlns:views="clr-namespace:eShopOnContainers.Core.Views;assembly=eShopOnContainers.Core" xmlns:views="clr-namespace:eShopOnContainers.Core.Views;assembly=eShopOnContainers.Core"
xmlns:viewModelBase="clr-namespace:eShopOnContainers.Core.ViewModels.Base;assembly=eShopOnContainers.Core"
xmlns:templates="clr-namespace:eShopOnContainers.Core.Views.Templates;assembly=eShopOnContainers.Core" xmlns:templates="clr-namespace:eShopOnContainers.Core.Views.Templates;assembly=eShopOnContainers.Core"
xmlns:behaviors="clr-namespace:eShopOnContainers.Core.Behaviors;assembly=eShopOnContainers.Core" xmlns:behaviors="clr-namespace:eShopOnContainers.Core.Behaviors;assembly=eShopOnContainers.Core"
viewModelBase:ViewModelLocator.AutoWireViewModel="true"
Title="My profile"> Title="My profile">
<ContentPage.Resources> <ContentPage.Resources>
<ResourceDictionary> <ResourceDictionary>

View File

@ -1,11 +1,13 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="eShopOnContainers.Core.Views.SettingsView" x:Class="eShopOnContainers.Core.Views.SettingsView"
xmlns:viewModelBase="clr-namespace:eShopOnContainers.Core.ViewModels.Base;assembly=eShopOnContainers.Core"
xmlns:controls="clr-namespace:eShopOnContainers.Core.Controls;assembly=eShopOnContainers.Core" xmlns:controls="clr-namespace:eShopOnContainers.Core.Controls;assembly=eShopOnContainers.Core"
xmlns:animations="clr-namespace:eShopOnContainers.Core.Animations;assembly=eShopOnContainers.Core" xmlns:animations="clr-namespace:eShopOnContainers.Core.Animations;assembly=eShopOnContainers.Core"
xmlns:triggers="clr-namespace:eShopOnContainers.Core.Triggers;assembly=eShopOnContainers.Core" xmlns:triggers="clr-namespace:eShopOnContainers.Core.Triggers;assembly=eShopOnContainers.Core"
xmlns:behaviors="clr-namespace:eShopOnContainers.Core.Behaviors;assembly=eShopOnContainers.Core" xmlns:behaviors="clr-namespace:eShopOnContainers.Core.Behaviors;assembly=eShopOnContainers.Core"
viewModelBase:ViewModelLocator.AutoWireViewModel="true"
Title="Settings"> Title="Settings">
<ContentPage.Resources> <ContentPage.Resources>
<ResourceDictionary> <ResourceDictionary>

View File

@ -58,9 +58,7 @@
<Compile Include="Converters\ItemsToHeightConverter.cs" /> <Compile Include="Converters\ItemsToHeightConverter.cs" />
<Compile Include="Converters\ItemTappedEventArgsConverter.cs" /> <Compile Include="Converters\ItemTappedEventArgsConverter.cs" />
<Compile Include="Converters\ToUpperConverter.cs" /> <Compile Include="Converters\ToUpperConverter.cs" />
<Compile Include="Effects\LineColorEffect.cs" />
<Compile Include="Exceptions\ServiceAuthenticationException.cs" /> <Compile Include="Exceptions\ServiceAuthenticationException.cs" />
<Compile Include="Extensions\AnimationExtension.cs" />
<Compile Include="Extensions\ObservableExtension.cs" /> <Compile Include="Extensions\ObservableExtension.cs" />
<Compile Include="GlobalSettings.cs" /> <Compile Include="GlobalSettings.cs" />
<Compile Include="Helpers\EasingHelper.cs" /> <Compile Include="Helpers\EasingHelper.cs" />
@ -111,7 +109,7 @@
<Compile Include="Validations\IValidity.cs" /> <Compile Include="Validations\IValidity.cs" />
<Compile Include="Validations\ValidatableObject.cs" /> <Compile Include="Validations\ValidatableObject.cs" />
<Compile Include="ViewModels\Base\ExtendedBindableObject.cs" /> <Compile Include="ViewModels\Base\ExtendedBindableObject.cs" />
<Compile Include="ViewModels\Base\MessengerKeys.cs" /> <Compile Include="ViewModels\Base\MessageKeys.cs" />
<Compile Include="ViewModels\Base\ViewModelBase.cs" /> <Compile Include="ViewModels\Base\ViewModelBase.cs" />
<Compile Include="ViewModels\Base\ViewModelLocator.cs" /> <Compile Include="ViewModels\Base\ViewModelLocator.cs" />
<Compile Include="ViewModels\BasketViewModel.cs" /> <Compile Include="ViewModels\BasketViewModel.cs" />
@ -165,6 +163,9 @@
<DependentUpon>ProductTemplate.xaml</DependentUpon> <DependentUpon>ProductTemplate.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Converters\WebNavigatingEventArgsConverter.cs" /> <Compile Include="Converters\WebNavigatingEventArgsConverter.cs" />
<Compile Include="Converters\FirstValidationErrorConverter.cs" />
<Compile Include="Effects\EntryLineColorEffect.cs" />
<Compile Include="Behaviors\LineColorBehavior.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="app.config" /> <None Include="app.config" />

View File

@ -3,7 +3,7 @@ using eShopOnContainers.Droid.Effects;
using Xamarin.Forms.Platform.Android; using Xamarin.Forms.Platform.Android;
using System; using System;
using Android.Widget; using Android.Widget;
using eShopOnContainers.Core.Effects; using eShopOnContainers.Core.Behaviors;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
@ -34,7 +34,7 @@ namespace eShopOnContainers.Droid.Effects
protected override void OnElementPropertyChanged(PropertyChangedEventArgs args) protected override void OnElementPropertyChanged(PropertyChangedEventArgs args)
{ {
if (args.PropertyName == LineColorEffect.LineColorProperty.PropertyName) if (args.PropertyName == LineColorBehavior.LineColorProperty.PropertyName)
{ {
UpdateLineColor(); UpdateLineColor();
} }
@ -46,7 +46,7 @@ namespace eShopOnContainers.Droid.Effects
{ {
if (control != null) if (control != null)
{ {
control.Background.SetColorFilter(LineColorEffect.GetLineColor(Element).ToAndroid(), Android.Graphics.PorterDuff.Mode.SrcAtop); control.Background.SetColorFilter(LineColorBehavior.GetLineColor(Element).ToAndroid(), Android.Graphics.PorterDuff.Mode.SrcAtop);
} }
} }
catch (Exception ex) catch (Exception ex)

View File

@ -8,7 +8,7 @@ using Xamarin.Forms;
using Xamarin.Forms.Platform.UWP; using Xamarin.Forms.Platform.UWP;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using eShopOnContainers.Windows.Effects; using eShopOnContainers.Windows.Effects;
using eShopOnContainers.Core.Effects; using eShopOnContainers.Core.Behaviors;
[assembly: ResolutionGroupName("eShopOnContainers")] [assembly: ResolutionGroupName("eShopOnContainers")]
[assembly: ExportEffect(typeof(EntryLineColorEffect), "EntryLineColorEffect")] [assembly: ExportEffect(typeof(EntryLineColorEffect), "EntryLineColorEffect")]
@ -38,7 +38,7 @@ namespace eShopOnContainers.Windows.Effects
protected override void OnElementPropertyChanged(PropertyChangedEventArgs args) protected override void OnElementPropertyChanged(PropertyChangedEventArgs args)
{ {
if (args.PropertyName == LineColorEffect.LineColorProperty.PropertyName) if (args.PropertyName == LineColorBehavior.LineColorProperty.PropertyName)
{ {
UpdateLineColor(); UpdateLineColor();
} }
@ -49,7 +49,7 @@ namespace eShopOnContainers.Windows.Effects
if (control != null) if (control != null)
{ {
control.BorderThickness = new Xaml.Thickness(0, 0, 0, 1); control.BorderThickness = new Xaml.Thickness(0, 0, 0, 1);
var lineColor = XamarinFormColorToWindowsColor(LineColorEffect.GetLineColor(Element)); var lineColor = XamarinFormColorToWindowsColor(LineColorBehavior.GetLineColor(Element));
control.BorderBrush = new Media.SolidColorBrush(lineColor); control.BorderBrush = new Media.SolidColorBrush(lineColor);
var style = Xaml.Application.Current.Resources["FormTextBoxStyle"] as Xaml.Style; var style = Xaml.Application.Current.Resources["FormTextBoxStyle"] as Xaml.Style;

View File

@ -1,6 +1,6 @@
using CoreAnimation; using CoreAnimation;
using CoreGraphics; using CoreGraphics;
using eShopOnContainers.Core.Effects; using eShopOnContainers.Core.Behaviors;
using eShopOnContainers.iOS.Effects; using eShopOnContainers.iOS.Effects;
using System; using System;
using System.ComponentModel; using System.ComponentModel;
@ -39,7 +39,7 @@ namespace eShopOnContainers.iOS.Effects
{ {
base.OnElementPropertyChanged(args); base.OnElementPropertyChanged(args);
if (args.PropertyName == LineColorEffect.LineColorProperty.PropertyName || if (args.PropertyName == LineColorBehavior.LineColorProperty.PropertyName ||
args.PropertyName == "Height") args.PropertyName == "Height")
{ {
Initialize(); Initialize();
@ -71,7 +71,7 @@ namespace eShopOnContainers.iOS.Effects
} }
lineLayer.Frame = new CGRect(0f, Control.Frame.Height - 1f, Control.Bounds.Width, 1f); lineLayer.Frame = new CGRect(0f, Control.Frame.Height - 1f, Control.Bounds.Width, 1f);
lineLayer.BorderColor = LineColorEffect.GetLineColor(Element).ToCGColor(); lineLayer.BorderColor = LineColorBehavior.GetLineColor(Element).ToCGColor();
control.TintColor = control.TextColor; control.TintColor = control.TextColor;
} }

View File

@ -20,6 +20,7 @@
using System.IO; using System.IO;
using System.Data.Common; using System.Data.Common;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks;
public class Startup public class Startup
{ {
@ -48,7 +49,7 @@
services.AddHealthChecks(checks => services.AddHealthChecks(checks =>
{ {
checks.AddUrlCheck(Configuration["ExternalCatalogBaseUrl"]); checks.AddSqlCheck("Catalog_Db", Configuration["ConnectionString"]);
}); });
services.AddMvc(options => services.AddMvc(options =>

View File

@ -0,0 +1,42 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
using System.IO;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
namespace Identity.API.Certificate
{
static class Certificate
{
public static X509Certificate2 Get()
{
var assembly = typeof(Certificate).GetTypeInfo().Assembly;
var names = assembly.GetManifestResourceNames();
/***********************************************************************************************
* Please note that here we are using a local certificate only for testing purposes. In a
* real environment the certificate should be created and stored in a secure way, which is out
* of the scope of this project.
**********************************************************************************************/
using (var stream = assembly.GetManifestResourceStream("Identity.API.Certificate.idsrv3test.pfx"))
{
return new X509Certificate2(ReadStream(stream), "idsrv3test");
}
}
private static byte[] ReadStream(Stream input)
{
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
}
}

View File

@ -12,7 +12,7 @@
<PackageTargetFallback>$(PackageTargetFallback);dotnet5.6;portable-net45+win8</PackageTargetFallback> <PackageTargetFallback>$(PackageTargetFallback);dotnet5.6;portable-net45+win8</PackageTargetFallback>
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath> <DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="1.1.0" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="1.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="1.1.0" /> <PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="1.1.0" />
@ -57,6 +57,10 @@
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="1.0.0-msbuild3-final" /> <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="1.0.0-msbuild3-final" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Certificate\idsrv3test.pfx" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" /> <ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.Data\Microsoft.Extensions.HealthChecks.Data.csproj" /> <ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.Data\Microsoft.Extensions.HealthChecks.Data.csproj" />

View File

@ -18,6 +18,7 @@ using System.Threading;
using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure; using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.HealthChecks; using Microsoft.Extensions.HealthChecks;
using Identity.API.Certificate;
namespace eShopOnContainers.Identity namespace eShopOnContainers.Identity
{ {
@ -75,7 +76,7 @@ namespace eShopOnContainers.Identity
// Adds IdentityServer // Adds IdentityServer
services.AddIdentityServer(x => x.IssuerUri = "null") services.AddIdentityServer(x => x.IssuerUri = "null")
.AddTemporarySigningCredential() .AddSigningCredential(Certificate.Get())
.AddInMemoryScopes(Config.GetScopes()) .AddInMemoryScopes(Config.GetScopes())
.AddInMemoryClients(Config.GetClients(clientUrls)) .AddInMemoryClients(Config.GetClients(clientUrls))
.AddAspNetIdentity<ApplicationUser>() .AddAspNetIdentity<ApplicationUser>()

View File

@ -13,6 +13,7 @@ namespace WebMVC.Services.Utilities
/// <summary> /// <summary>
/// HttpClient wrapper that integrates Retry and Circuit /// HttpClient wrapper that integrates Retry and Circuit
/// breaker policies when invoking HTTP services. /// breaker policies when invoking HTTP services.
/// Based on Polly library: https://github.com/App-vNext/Polly
/// </summary> /// </summary>
public class ResilientHttpClient : IHttpClient public class ResilientHttpClient : IHttpClient
{ {

View File

@ -48,7 +48,10 @@ namespace Microsoft.eShopOnContainers.WebMVC
services.AddHealthChecks(checks => services.AddHealthChecks(checks =>
{ {
checks.AddUrlCheck(Configuration["CallBackUrl"]); checks.AddUrlCheck(Configuration["CatalogUrl"]);
checks.AddUrlCheck(Configuration["OrderingUrl"]);
checks.AddUrlCheck(Configuration["BasketUrl"]);
checks.AddUrlCheck(Configuration["IdentityUrl"]);
}); });
// Add application services. // Add application services.