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)
}
protected Page CreateAndBindPage(Type viewModelType, object parameter)
{ {
Type pageType = GetPageTypeForViewModel(viewModelType); Type pageType = GetPageTypeForViewModel(viewModelType);
if (pageType == null) if (pageType == null)
{ {
throw new Exception($"Mapping type for {viewModelType} is not a page"); throw new Exception($"Cannot locate page type for {viewModelType}");
} }
Page page = Activator.CreateInstance(pageType) as Page; Page page = Activator.CreateInstance(pageType) as Page;
ViewModelBase viewModel = ViewModelLocator.Instance.Resolve(viewModelType) as ViewModelBase;
page.BindingContext = viewModel;
return page; 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,38 +10,37 @@ 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();
public static void Initialize()
{
// Services // Services
_unityContainer.RegisterType<IDialogService, DialogService>(); _unityContainer.RegisterType<IDialogService, DialogService>();
RegisterSingleton<INavigationService, NavigationService>(); _unityContainer.RegisterType<INavigationService, NavigationService>(new ContainerControlledLifetimeManager());
_unityContainer.RegisterType<IOpenUrlService, OpenUrlService>(); _unityContainer.RegisterType<IOpenUrlService, OpenUrlService>();
_unityContainer.RegisterType<IRequestProvider, RequestProvider>(); _unityContainer.RegisterType<IRequestProvider, RequestProvider>();
_unityContainer.RegisterType<IIdentityService, IdentityService>(); _unityContainer.RegisterType<IIdentityService, IdentityService>();
_unityContainer.RegisterType<ICatalogService, CatalogMockService>(); _unityContainer.RegisterType<ICatalogService, CatalogMockService>();
_unityContainer.RegisterType<IBasketService, BasketMockService>(); _unityContainer.RegisterType<IBasketService, BasketMockService>();
_unityContainer.RegisterType<IUserService, UserMockService>(); _unityContainer.RegisterType<IUserService, UserMockService>();
@ -56,7 +56,7 @@ namespace eShopOnContainers.ViewModels.Base
_unityContainer.RegisterType<SettingsViewModel>(); _unityContainer.RegisterType<SettingsViewModel>();
} }
public void UpdateDependencies(bool useMockServices) public static void UpdateDependencies(bool useMockServices)
{ {
// Change injected dependencies // Change injected dependencies
if (useMockServices) if (useMockServices)
@ -80,29 +80,31 @@ namespace eShopOnContainers.ViewModels.Base
} }
} }
public T Resolve<T>() public static T Resolve<T>()
{ {
return _unityContainer.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;
} }
var viewModel = _unityContainer.Resolve(viewModelType);
public void RegisterSingleton<TInterface, T>() where T : TInterface 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

@ -2,8 +2,10 @@
<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"
viewModelBase:ViewModelLocator.AutoWireViewModel="true"
Title="Cart"> 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: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"
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,7 +140,6 @@
</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>
@ -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;
await AnimateIn();
var vm = BindingContext as LoginViewModel; var vm = BindingContext as LoginViewModel;
if (vm != null)
if(vm != null)
{ {
vm.InvalidateMock(); vm.InvalidateMock();
if (!vm.IsMock)
{
_animate = true;
await AnimateIn();
}
} }
} }
@ -55,7 +56,6 @@ 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))),

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

@ -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.