diff --git a/src/Mobile/.gitignore b/src/Mobile/.gitignore new file mode 100644 index 000000000..8cb6c2831 --- /dev/null +++ b/src/Mobile/.gitignore @@ -0,0 +1,256 @@ + +# Created by https://www.gitignore.io/api/visualstudio + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ + +# Uncomment if you have tasks that create the project's static files in wwwroot +wwwroot/ + + + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ diff --git a/src/Mobile/eShopOnContainers.Xamarin.sln b/src/Mobile/eShopOnContainers.Xamarin.sln new file mode 100644 index 000000000..95260a4d1 --- /dev/null +++ b/src/Mobile/eShopOnContainers.Xamarin.sln @@ -0,0 +1,261 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "eShopOnContainers.Droid", "eShopOnContainers\eShopOnContainers.Droid\eShopOnContainers.Droid.csproj", "{62DBB163-9CA9-4818-B48B-13233DF37C24}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "eShopOnContainers.iOS", "eShopOnContainers\eShopOnContainers.iOS\eShopOnContainers.iOS.csproj", "{6EEB23DC-7063-4444-9AF8-90DF24F549C0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "eShopOnContainers.Core", "eShopOnContainers\eShopOnContainers.Core\eShopOnContainers.Core.csproj", "{65116D1C-145B-4693-ABDA-F0FB6F425191}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "eShopOnContainers.Windows", "eShopOnContainers\eShopOnContainers.Windows\eShopOnContainers.Windows.csproj", "{C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Ad-Hoc|Any CPU = Ad-Hoc|Any CPU + Ad-Hoc|ARM = Ad-Hoc|ARM + Ad-Hoc|iPhone = Ad-Hoc|iPhone + Ad-Hoc|iPhoneSimulator = Ad-Hoc|iPhoneSimulator + Ad-Hoc|x64 = Ad-Hoc|x64 + Ad-Hoc|x86 = Ad-Hoc|x86 + AppStore|Any CPU = AppStore|Any CPU + AppStore|ARM = AppStore|ARM + AppStore|iPhone = AppStore|iPhone + AppStore|iPhoneSimulator = AppStore|iPhoneSimulator + AppStore|x64 = AppStore|x64 + AppStore|x86 = AppStore|x86 + Debug|Any CPU = Debug|Any CPU + Debug|ARM = Debug|ARM + Debug|iPhone = Debug|iPhone + Debug|iPhoneSimulator = Debug|iPhoneSimulator + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|ARM = Release|ARM + Release|iPhone = Release|iPhone + Release|iPhoneSimulator = Release|iPhoneSimulator + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Ad-Hoc|Any CPU.Deploy.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Ad-Hoc|ARM.Build.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Ad-Hoc|ARM.Deploy.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Ad-Hoc|iPhone.Deploy.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Ad-Hoc|iPhoneSimulator.Deploy.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Ad-Hoc|x64.Build.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Ad-Hoc|x64.Deploy.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Ad-Hoc|x86.Build.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Ad-Hoc|x86.Deploy.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.AppStore|Any CPU.Build.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.AppStore|Any CPU.Deploy.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.AppStore|ARM.ActiveCfg = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.AppStore|ARM.Build.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.AppStore|ARM.Deploy.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.AppStore|iPhone.Build.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.AppStore|iPhone.Deploy.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.AppStore|iPhoneSimulator.Deploy.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.AppStore|x64.ActiveCfg = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.AppStore|x64.Build.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.AppStore|x64.Deploy.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.AppStore|x86.ActiveCfg = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.AppStore|x86.Build.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.AppStore|x86.Deploy.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Debug|Any CPU.Build.0 = Debug|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Debug|ARM.ActiveCfg = Debug|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Debug|ARM.Build.0 = Debug|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Debug|ARM.Deploy.0 = Debug|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Debug|iPhone.Build.0 = Debug|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Debug|iPhone.Deploy.0 = Debug|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Debug|x64.ActiveCfg = Debug|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Debug|x64.Build.0 = Debug|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Debug|x64.Deploy.0 = Debug|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Debug|x86.ActiveCfg = Debug|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Debug|x86.Build.0 = Debug|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Debug|x86.Deploy.0 = Debug|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Release|Any CPU.ActiveCfg = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Release|Any CPU.Build.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Release|Any CPU.Deploy.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Release|ARM.ActiveCfg = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Release|ARM.Build.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Release|ARM.Deploy.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Release|iPhone.ActiveCfg = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Release|iPhone.Build.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Release|iPhone.Deploy.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Release|x64.ActiveCfg = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Release|x64.Build.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Release|x64.Deploy.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Release|x86.ActiveCfg = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Release|x86.Build.0 = Release|Any CPU + {62DBB163-9CA9-4818-B48B-13233DF37C24}.Release|x86.Deploy.0 = Release|Any CPU + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Ad-Hoc|ARM.ActiveCfg = Ad-Hoc|iPhone + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Ad-Hoc|x64.ActiveCfg = Ad-Hoc|iPhone + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Ad-Hoc|x86.ActiveCfg = Ad-Hoc|iPhone + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.AppStore|ARM.ActiveCfg = AppStore|iPhone + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.AppStore|iPhone.ActiveCfg = AppStore|iPhone + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.AppStore|iPhone.Build.0 = AppStore|iPhone + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.AppStore|x64.ActiveCfg = AppStore|iPhone + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.AppStore|x86.ActiveCfg = AppStore|iPhone + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Debug|Any CPU.ActiveCfg = Debug|iPhone + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Debug|Any CPU.Build.0 = Debug|iPhone + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Debug|ARM.ActiveCfg = Debug|iPhone + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Debug|iPhone.ActiveCfg = Debug|iPhone + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Debug|iPhone.Build.0 = Debug|iPhone + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Debug|x64.ActiveCfg = Debug|iPhone + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Debug|x86.ActiveCfg = Debug|iPhone + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Release|Any CPU.ActiveCfg = Release|iPhone + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Release|ARM.ActiveCfg = Release|iPhone + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Release|iPhone.ActiveCfg = Release|iPhone + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Release|iPhone.Build.0 = Release|iPhone + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Release|x64.ActiveCfg = Release|iPhone + {6EEB23DC-7063-4444-9AF8-90DF24F549C0}.Release|x86.ActiveCfg = Release|iPhone + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Ad-Hoc|ARM.Build.0 = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Ad-Hoc|x64.Build.0 = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Ad-Hoc|x86.Build.0 = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.AppStore|Any CPU.Build.0 = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.AppStore|ARM.ActiveCfg = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.AppStore|ARM.Build.0 = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.AppStore|iPhone.Build.0 = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.AppStore|x64.ActiveCfg = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.AppStore|x64.Build.0 = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.AppStore|x86.ActiveCfg = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.AppStore|x86.Build.0 = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Debug|Any CPU.Build.0 = Debug|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Debug|ARM.ActiveCfg = Debug|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Debug|ARM.Build.0 = Debug|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Debug|iPhone.Build.0 = Debug|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Debug|x64.ActiveCfg = Debug|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Debug|x64.Build.0 = Debug|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Debug|x86.ActiveCfg = Debug|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Debug|x86.Build.0 = Debug|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Release|Any CPU.ActiveCfg = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Release|Any CPU.Build.0 = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Release|ARM.ActiveCfg = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Release|ARM.Build.0 = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Release|iPhone.ActiveCfg = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Release|iPhone.Build.0 = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Release|x64.ActiveCfg = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Release|x64.Build.0 = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Release|x86.ActiveCfg = Release|Any CPU + {65116D1C-145B-4693-ABDA-F0FB6F425191}.Release|x86.Build.0 = Release|Any CPU + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Ad-Hoc|Any CPU.ActiveCfg = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Ad-Hoc|Any CPU.Build.0 = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Ad-Hoc|Any CPU.Deploy.0 = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Ad-Hoc|ARM.ActiveCfg = Release|ARM + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Ad-Hoc|ARM.Build.0 = Release|ARM + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Ad-Hoc|ARM.Deploy.0 = Release|ARM + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Ad-Hoc|iPhone.ActiveCfg = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Ad-Hoc|iPhone.Build.0 = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Ad-Hoc|iPhone.Deploy.0 = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Ad-Hoc|iPhoneSimulator.Deploy.0 = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Ad-Hoc|x64.ActiveCfg = Release|x64 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Ad-Hoc|x64.Build.0 = Release|x64 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Ad-Hoc|x64.Deploy.0 = Release|x64 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Ad-Hoc|x86.ActiveCfg = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Ad-Hoc|x86.Build.0 = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Ad-Hoc|x86.Deploy.0 = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.AppStore|Any CPU.ActiveCfg = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.AppStore|Any CPU.Build.0 = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.AppStore|Any CPU.Deploy.0 = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.AppStore|ARM.ActiveCfg = Release|ARM + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.AppStore|ARM.Build.0 = Release|ARM + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.AppStore|ARM.Deploy.0 = Release|ARM + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.AppStore|iPhone.ActiveCfg = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.AppStore|iPhone.Build.0 = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.AppStore|iPhone.Deploy.0 = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.AppStore|iPhoneSimulator.ActiveCfg = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.AppStore|iPhoneSimulator.Build.0 = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.AppStore|iPhoneSimulator.Deploy.0 = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.AppStore|x64.ActiveCfg = Release|x64 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.AppStore|x64.Build.0 = Release|x64 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.AppStore|x64.Deploy.0 = Release|x64 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.AppStore|x86.ActiveCfg = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.AppStore|x86.Build.0 = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.AppStore|x86.Deploy.0 = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Debug|Any CPU.ActiveCfg = Debug|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Debug|Any CPU.Build.0 = Debug|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Debug|Any CPU.Deploy.0 = Debug|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Debug|ARM.ActiveCfg = Debug|ARM + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Debug|ARM.Build.0 = Debug|ARM + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Debug|ARM.Deploy.0 = Debug|ARM + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Debug|iPhone.ActiveCfg = Debug|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Debug|iPhoneSimulator.ActiveCfg = Debug|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Debug|x64.ActiveCfg = Debug|x64 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Debug|x64.Build.0 = Debug|x64 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Debug|x64.Deploy.0 = Debug|x64 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Debug|x86.ActiveCfg = Debug|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Debug|x86.Build.0 = Debug|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Debug|x86.Deploy.0 = Debug|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Release|Any CPU.ActiveCfg = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Release|ARM.ActiveCfg = Release|ARM + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Release|ARM.Build.0 = Release|ARM + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Release|ARM.Deploy.0 = Release|ARM + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Release|iPhone.ActiveCfg = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Release|iPhoneSimulator.ActiveCfg = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Release|x64.ActiveCfg = Release|x64 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Release|x64.Build.0 = Release|x64 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Release|x64.Deploy.0 = Release|x64 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Release|x86.ActiveCfg = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Release|x86.Build.0 = Release|x86 + {C3C1E2CF-B1F7-4654-BBDC-50143DB22E0B}.Release|x86.Deploy.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/Mobile/eShopOnContainers/CommonResources/Fonts/Montserrat-Bold.ttf b/src/Mobile/eShopOnContainers/CommonResources/Fonts/Montserrat-Bold.ttf new file mode 100644 index 000000000..ae33a4538 Binary files /dev/null and b/src/Mobile/eShopOnContainers/CommonResources/Fonts/Montserrat-Bold.ttf differ diff --git a/src/Mobile/eShopOnContainers/CommonResources/Fonts/Montserrat-Regular.ttf b/src/Mobile/eShopOnContainers/CommonResources/Fonts/Montserrat-Regular.ttf new file mode 100644 index 000000000..5b4b5afe6 Binary files /dev/null and b/src/Mobile/eShopOnContainers/CommonResources/Fonts/Montserrat-Regular.ttf differ diff --git a/src/Mobile/eShopOnContainers/CommonResources/Fonts/SourceSansPro-Regular.ttf b/src/Mobile/eShopOnContainers/CommonResources/Fonts/SourceSansPro-Regular.ttf new file mode 100644 index 000000000..ffe27865a Binary files /dev/null and b/src/Mobile/eShopOnContainers/CommonResources/Fonts/SourceSansPro-Regular.ttf differ diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Animations/Base/AnimationBase.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Animations/Base/AnimationBase.cs new file mode 100644 index 000000000..08b978508 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Animations/Base/AnimationBase.cs @@ -0,0 +1,120 @@ +using System; +using System.Diagnostics; +using System.Threading.Tasks; +using Xamarin.Forms; + +namespace eShopOnContainers.Core.Animations.Base +{ + public abstract class AnimationBase : BindableObject + { + private bool _isRunning = false; + + public static readonly BindableProperty TargetProperty = + BindableProperty.Create("Target", typeof(VisualElement), typeof(AnimationBase), null, + propertyChanged: (bindable, oldValue, newValue) => + ((AnimationBase)bindable).Target = (VisualElement)newValue); + + public VisualElement Target + { + get { return (VisualElement)GetValue(TargetProperty); } + set { SetValue(TargetProperty, value); } + } + + public static readonly BindableProperty DurationProperty = + BindableProperty.Create("Duration", typeof(string), typeof(AnimationBase), "1000", + propertyChanged: (bindable, oldValue, newValue) => + ((AnimationBase)bindable).Duration = (string)newValue); + + public string Duration + { + get { return (string)GetValue(DurationProperty); } + set { SetValue(DurationProperty, value); } + } + + public static readonly BindableProperty EasingProperty = + BindableProperty.Create("Easing", typeof(EasingType), typeof(AnimationBase), EasingType.Linear, + propertyChanged: (bindable, oldValue, newValue) => + ((AnimationBase)bindable).Easing = (EasingType)newValue); + + public EasingType Easing + { + get { return (EasingType)GetValue(EasingProperty); } + set { SetValue(EasingProperty, value); } + } + + public static readonly BindableProperty RepeatForeverProperty = + BindableProperty.Create("RepeatForever", typeof(bool), typeof(AnimationBase), false, + propertyChanged: (bindable, oldValue, newValue) => + ((AnimationBase)bindable).RepeatForever = (bool)newValue); + + public bool RepeatForever + { + get { return (bool)GetValue(RepeatForeverProperty); } + set { SetValue(RepeatForeverProperty, value); } + } + + public static readonly BindableProperty DelayProperty = + BindableProperty.Create("Delay", typeof(int), typeof(AnimationBase), 0, + propertyChanged: (bindable, oldValue, newValue) => + ((AnimationBase)bindable).Delay = (int)newValue); + + public int Delay + { + get { return (int)GetValue(DelayProperty); } + set { SetValue(DelayProperty, value); } + } + + protected abstract Task BeginAnimation(); + + public async Task Begin() + { + try + { + + if (!_isRunning) + { + _isRunning = true; + + await InternalBegin() + .ContinueWith(t => t.Exception, TaskContinuationOptions.OnlyOnFaulted) + .ConfigureAwait(false); + } + } + catch (TaskCanceledException) + { + } + catch (Exception ex) + { + Debug.WriteLine($"Exception in animation {ex}"); + } + } + + protected abstract Task ResetAnimation(); + + public async Task Reset() + { + await ResetAnimation(); + } + + private async Task InternalBegin() + { + if (Delay > 0) + { + await Task.Delay(Delay); + } + + if (!RepeatForever) + { + await BeginAnimation(); + } + else + { + do + { + await BeginAnimation(); + await ResetAnimation(); + } while (RepeatForever); + } + } + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Animations/Base/EasingType.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Animations/Base/EasingType.cs new file mode 100644 index 000000000..3e678191b --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Animations/Base/EasingType.cs @@ -0,0 +1,17 @@ +namespace eShopOnContainers.Core.Animations.Base +{ + public enum EasingType + { + BounceIn, + BounceOut, + CubicIn, + CubicInOut, + CubicOut, + Linear, + SinIn, + SinInOut, + SinOut, + SpringIn, + SpringOut + } +} \ No newline at end of file diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Animations/FadeToAnimation.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Animations/FadeToAnimation.cs new file mode 100644 index 000000000..805d7813a --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Animations/FadeToAnimation.cs @@ -0,0 +1,163 @@ +using eShopOnContainers.Core.Animations.Base; +using eShopOnContainers.Core.Helpers; +using System; +using System.Threading.Tasks; +using Xamarin.Forms; + +namespace eShopOnContainers.Core.Animations +{ + public class FadeToAnimation : AnimationBase + { + public static readonly BindableProperty OpacityProperty = + BindableProperty.Create("Opacity", typeof(double), typeof(FadeToAnimation), 0.0d, + propertyChanged: (bindable, oldValue, newValue) => + ((FadeToAnimation)bindable).Opacity = (double)newValue); + + public double Opacity + { + get { return (double)GetValue(OpacityProperty); } + set { SetValue(OpacityProperty, value); } + } + + protected override Task BeginAnimation() + { + if (Target == null) + { + throw new NullReferenceException("Null Target property."); + } + + return Target.FadeTo(Opacity, Convert.ToUInt32(Duration), EasingHelper.GetEasing(Easing)); + } + + protected override Task ResetAnimation() + { + if (Target == null) + { + throw new NullReferenceException("Null Target property."); + } + + return Target.FadeTo(0, 0, null); + } + } + + public class FadeInAnimation : AnimationBase + { + public enum FadeDirection + { + Up, + Down + } + + public static readonly BindableProperty DirectionProperty = + BindableProperty.Create("Direction", typeof(FadeDirection), typeof(FadeInAnimation), FadeDirection.Up, + propertyChanged: (bindable, oldValue, newValue) => + ((FadeInAnimation)bindable).Direction = (FadeDirection)newValue); + + public FadeDirection Direction + { + get { return (FadeDirection)GetValue(DirectionProperty); } + set { SetValue(DirectionProperty, value); } + } + + protected override Task BeginAnimation() + { + if (Target == null) + { + throw new NullReferenceException("Null Target property."); + } + + return Task.Run(() => + { + Device.BeginInvokeOnMainThread(() => + { + Target.Animate("FadeIn", FadeIn(), 16, Convert.ToUInt32(Duration)); + }); + }); + } + + protected override Task ResetAnimation() + { + if (Target == null) + { + throw new NullReferenceException("Null Target property."); + } + + return Target.FadeTo(0, 0, null); + } + + internal Animation FadeIn() + { + var animation = new Animation(); + + animation.WithConcurrent((f) => Target.Opacity = f, 0, 1, Xamarin.Forms.Easing.CubicOut); + + animation.WithConcurrent( + (f) => Target.TranslationY = f, + Target.TranslationY + ((Direction == FadeDirection.Up) ? 50 : -50), Target.TranslationY, + Xamarin.Forms.Easing.CubicOut, 0, 1); + + return animation; + } + } + + public class FadeOutAnimation : AnimationBase + { + public enum FadeDirection + { + Up, + Down + } + + public static readonly BindableProperty DirectionProperty = + BindableProperty.Create("Direction", typeof(FadeDirection), typeof(FadeOutAnimation), FadeDirection.Up, + propertyChanged: (bindable, oldValue, newValue) => + ((FadeOutAnimation)bindable).Direction = (FadeDirection)newValue); + + public FadeDirection Direction + { + get { return (FadeDirection)GetValue(DirectionProperty); } + set { SetValue(DirectionProperty, value); } + } + + protected override Task BeginAnimation() + { + if (Target == null) + { + throw new NullReferenceException("Null Target property."); + } + + return Task.Run(() => + { + Device.BeginInvokeOnMainThread(() => + { + Target.Animate("FadeOut", FadeOut(), 16, Convert.ToUInt32(Duration)); + }); + }); + } + + protected override Task ResetAnimation() + { + if (Target == null) + { + throw new NullReferenceException("Null Target property."); + } + + return Target.FadeTo(0, 0, null); + } + + internal Animation FadeOut() + { + var animation = new Animation(); + + animation.WithConcurrent( + (f) => Target.Opacity = f, + 1, 0); + + animation.WithConcurrent( + (f) => Target.TranslationY = f, + Target.TranslationY, Target.TranslationY + ((Direction == FadeDirection.Up) ? 50 : -50)); + + return animation; + } + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Animations/StoryBoard.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Animations/StoryBoard.cs new file mode 100644 index 000000000..21b672f33 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Animations/StoryBoard.cs @@ -0,0 +1,48 @@ +using eShopOnContainers.Core.Animations.Base; +using System.Collections.Generic; +using System.Threading.Tasks; +using Xamarin.Forms; + +namespace eShopOnContainers.Core.Animations +{ + [ContentProperty("Animations")] + public class StoryBoard : AnimationBase + { + public StoryBoard() + { + Animations = new List(); + } + + public StoryBoard(List animations) + { + Animations = animations; + } + + public List Animations + { + get; + } + + protected override async Task BeginAnimation() + { + foreach (var animation in Animations) + { + if (animation.Target == null) + animation.Target = Target; + + await animation.Begin(); + } + } + + protected override async Task ResetAnimation() + { + foreach (var animation in Animations) + { + if (animation.Target == null) + animation.Target = Target; + + await animation.Reset(); + } + } + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/App.xaml b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/App.xaml new file mode 100644 index 000000000..7e645f4c0 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/App.xaml @@ -0,0 +1,140 @@ + + + + + + + #ffffff + #000000 + #F4F6FA + #00857D + #83D01B + #00A69C + #00857D + #e2e2e2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/App.xaml.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/App.xaml.cs new file mode 100644 index 000000000..d6523392d --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/App.xaml.cs @@ -0,0 +1,48 @@ +using eShopOnContainers.Services; +using eShopOnContainers.ViewModels.Base; +using System.Threading.Tasks; +using Xamarin.Forms; +using Xamarin.Forms.Xaml; + +[assembly: XamlCompilation(XamlCompilationOptions.Compile)] +namespace eShopOnContainers +{ + public partial class App : Application + { + public App() + { + InitializeComponent(); + + if (Device.OS == TargetPlatform.Windows) + { + InitNavigation(); + } + } + + private Task InitNavigation() + { + var navigationService = ViewModelLocator.Instance.Resolve(); + return navigationService.InitializeAsync(); + } + + protected override async void OnStart() + { + base.OnStart(); + + if (Device.OS != TargetPlatform.Windows) + { + await InitNavigation(); + } + } + + protected override void OnSleep() + { + // Handle when your app sleeps + } + + protected override void OnResume() + { + // Handle when your app resumes + } + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Controls/BindablePicker.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Controls/BindablePicker.cs new file mode 100644 index 000000000..78dce2ef5 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Controls/BindablePicker.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections; +using Xamarin.Forms; + +namespace eShopOnContainers.Core.Controls +{ + public class BindablePicker : Picker + { + public static readonly BindableProperty ItemsSourceProperty = BindableProperty.Create("ItemsSource", + typeof(IEnumerable), typeof(BindablePicker), null, propertyChanged: OnItemsSourceChanged); + + public static readonly BindableProperty SelectedItemProperty = BindableProperty.Create("SelectedItem", + typeof(object), typeof(BindablePicker), null, BindingMode.TwoWay, propertyChanged: OnSelectedItemChanged); + + public BindablePicker() + { + SelectedIndexChanged += (o, e) => + { + if (SelectedIndex < 0 || ItemsSource == null || !ItemsSource.GetEnumerator().MoveNext()) + { + SelectedItem = null; + return; + } + + var index = 0; + foreach (var item in ItemsSource) + { + if (index == SelectedIndex) + { + SelectedItem = item; + break; + } + index++; + } + }; + } + + public IEnumerable ItemsSource + { + get { return (IEnumerable)GetValue(ItemsSourceProperty); } + set { SetValue(ItemsSourceProperty, value); } + } + + public Object SelectedItem + { + get { return GetValue(SelectedItemProperty); } + set + { + if (SelectedItem != value) + { + SetValue(SelectedItemProperty, value); + InternalUpdateSelectedIndex(); + } + } + } + + public event EventHandler ItemSelected; + + private void InternalUpdateSelectedIndex() + { + var selectedIndex = -1; + if (ItemsSource != null) + { + var index = 0; + foreach (var item in ItemsSource) + { + string strItem = item?.ToString(); + + if (item != null && SelectedItem != null + && !string.IsNullOrEmpty(strItem) + && item.ToString().Equals(SelectedItem.ToString())) + { + selectedIndex = index; + break; + } + index++; + } + } + + SelectedIndex = selectedIndex; + } + + private static void OnItemsSourceChanged(BindableObject bindable, object oldValue, object newValue) + { + var boundPicker = (BindablePicker)bindable; + + if (Equals(newValue, null) && !Equals(oldValue, null)) + return; + + boundPicker.Items.Clear(); + + if (!Equals(newValue, null)) + { + foreach (var item in (IEnumerable)newValue) + boundPicker.Items.Add(item.ToString()); + } + + boundPicker.InternalUpdateSelectedIndex(); + } + + private static void OnSelectedItemChanged(BindableObject bindable, object oldValue, object newValue) + { + var boundPicker = (BindablePicker)bindable; + if (boundPicker.ItemSelected != null) + { + boundPicker.ItemSelected(boundPicker, new SelectedItemChangedEventArgs(newValue)); + } + boundPicker.InternalUpdateSelectedIndex(); + } + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Controls/CustomTabbedPage.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Controls/CustomTabbedPage.cs new file mode 100644 index 000000000..9fe24758d --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Controls/CustomTabbedPage.cs @@ -0,0 +1,35 @@ +using Xamarin.Forms; + +namespace eShopOnContainers.Core.Controls +{ + public class CustomTabbedPage : TabbedPage + { + public static BindableProperty BadgeTextProperty = + BindableProperty.CreateAttached("BadgeText", typeof(string), typeof(CustomTabbedPage), default(string), + BindingMode.OneWay); + + public static BindableProperty BadgeColorProperty = + BindableProperty.CreateAttached("BadgeColor", typeof(Color), typeof(CustomTabbedPage), Color.Default, + BindingMode.OneWay); + + public static string GetBadgeText(BindableObject view) + { + return (string)view.GetValue(BadgeTextProperty); + } + + public static void SetBadgeText(BindableObject view, string value) + { + view.SetValue(BadgeTextProperty, value); + } + + public static Color GetBadgeColor(BindableObject view) + { + return (Color)view.GetValue(BadgeColorProperty); + } + + public static void SetBadgeColor(BindableObject view, Color value) + { + view.SetValue(BadgeColorProperty, value); + } + } +} \ No newline at end of file diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Converters/DatetimeConverter.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Converters/DatetimeConverter.cs new file mode 100644 index 000000000..175ccd132 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Converters/DatetimeConverter.cs @@ -0,0 +1,26 @@ +using System; +using System.Globalization; +using Xamarin.Forms; + +namespace eShopOnContainers.Core.Converters +{ + public class DatetimeConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if(value is DateTime) + { + var date = (DateTime)value; + + return date.ToString("MMMM dd yyyy").ToUpper(); + } + + return value; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Converters/ToUpperConverter.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Converters/ToUpperConverter.cs new file mode 100644 index 000000000..2db9a6805 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Converters/ToUpperConverter.cs @@ -0,0 +1,19 @@ +using System; +using System.Globalization; +using Xamarin.Forms; + +namespace eShopOnContainers.Core.Converters +{ + public class ToUpperConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return value.ToString().ToUpperInvariant(); + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Effects/LineColorEffect.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Effects/LineColorEffect.cs new file mode 100644 index 000000000..3c1759c24 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Effects/LineColorEffect.cs @@ -0,0 +1,67 @@ +using System.Linq; +using Xamarin.Forms; + +namespace eShopOnContainers.Core.Effects +{ + public static class LineColorEffect + { + public static readonly BindableProperty ApplyLineColorProperty = + BindableProperty.CreateAttached("ApplyLineColor", typeof(bool), typeof(LineColorEffect), false, + propertyChanged: OnApplyLineColorChanged); + + public static bool GetApplyLineColor(BindableObject view) + { + return (bool)view.GetValue(ApplyLineColorProperty); + } + + public static void SetApplyLineColor(BindableObject view, bool value) + { + view.SetValue(ApplyLineColorProperty, value); + } + + private static void OnApplyLineColorChanged(BindableObject bindable, object oldValue, object newValue) + { + var view = bindable as View; + + if (view == null) + { + return; + } + + bool hasShadow = (bool)newValue; + + if (hasShadow) + { + view.Effects.Add(new EntryLineColorEffect()); + } + else + { + var entryLineColorEffectToRemove = view.Effects.FirstOrDefault(e => e is EntryLineColorEffect); + if (entryLineColorEffectToRemove != null) + { + view.Effects.Remove(entryLineColorEffectToRemove); + } + } + } + + 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("BikeSharing.EntryLineColorEffect") + { + } + } + } +} \ No newline at end of file diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Extensions/AnimationExtension.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Extensions/AnimationExtension.cs new file mode 100644 index 000000000..edc9b07ab --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Extensions/AnimationExtension.cs @@ -0,0 +1,18 @@ +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(); + } + } +} \ No newline at end of file diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Helpers/EasingHelper.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Helpers/EasingHelper.cs new file mode 100644 index 000000000..b2ba7c762 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Helpers/EasingHelper.cs @@ -0,0 +1,39 @@ +using eShopOnContainers.Core.Animations.Base; +using Xamarin.Forms; + +namespace eShopOnContainers.Core.Helpers +{ + public static class EasingHelper + { + public static Easing GetEasing(EasingType type) + { + switch (type) + { + case EasingType.BounceIn: + return Easing.BounceIn; + case EasingType.BounceOut: + return Easing.BounceOut; + case EasingType.CubicIn: + return Easing.CubicIn; + case EasingType.CubicInOut: + return Easing.CubicInOut; + case EasingType.CubicOut: + return Easing.CubicOut; + case EasingType.Linear: + return Easing.Linear; + case EasingType.SinIn: + return Easing.SinIn; + case EasingType.SinInOut: + return Easing.SinInOut; + case EasingType.SinOut: + return Easing.SinOut; + case EasingType.SpringIn: + return Easing.SpringIn; + case EasingType.SpringOut: + return Easing.SpringOut; + } + + return null; + } + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Models/Orders/Order.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Models/Orders/Order.cs new file mode 100644 index 000000000..34502451b --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Models/Orders/Order.cs @@ -0,0 +1,12 @@ +using System; + +namespace eShopOnContainers.Core.Models.Orders +{ + public class Order + { + public long OrderNumber { get; set; } + public double Total { get; set; } + public DateTime Date { get; set; } + public OrderStatus Status { get; set; } + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Models/Orders/OrderStatus.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Models/Orders/OrderStatus.cs new file mode 100644 index 000000000..80e5e1258 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Models/Orders/OrderStatus.cs @@ -0,0 +1,10 @@ +namespace eShopOnContainers.Core.Models.Orders +{ + public enum OrderStatus + { + Pending, + WareHouse, + Delivered, + Lost + } +} \ No newline at end of file diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Models/Products/Product.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Models/Products/Product.cs new file mode 100644 index 000000000..7367752ea --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Models/Products/Product.cs @@ -0,0 +1,9 @@ +namespace eShopOnContainers.Core.Models.Products +{ + public class Product + { + public string Name { get; set; } + public string Image { get; set; } + public double Price { get; set; } + } +} \ No newline at end of file diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Properties/AssemblyInfo.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..fb975f83c --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Properties/AssemblyInfo.cs @@ -0,0 +1,30 @@ +using System.Resources; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("eShopOnContainers")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("eShopOnContainers")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: NeutralResourcesLanguage("en")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Dialog/DialogService.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Dialog/DialogService.cs new file mode 100644 index 000000000..7c731c9c1 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Dialog/DialogService.cs @@ -0,0 +1,13 @@ +using Acr.UserDialogs; +using System.Threading.Tasks; + +namespace eShopOnContainers.Services +{ + public class DialogService : IDialogService + { + public Task ShowAlertAsync(string message, string title, string buttonLabel) + { + return UserDialogs.Instance.AlertAsync(message, title, buttonLabel); + } + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Dialog/IDialogService.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Dialog/IDialogService.cs new file mode 100644 index 000000000..aaf3785e1 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Dialog/IDialogService.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace eShopOnContainers.Services +{ + public interface IDialogService + { + Task ShowAlertAsync(string message, string title, string buttonLabel); + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Navigation/INavigationService.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Navigation/INavigationService.cs new file mode 100644 index 000000000..ce3c56964 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Navigation/INavigationService.cs @@ -0,0 +1,25 @@ +using eShopOnContainers.ViewModels.Base; +using System; +using System.Threading.Tasks; + +namespace eShopOnContainers.Services +{ + public interface INavigationService + { + Task InitializeAsync(); + + Task NavigateToAsync() where TViewModel : ViewModelBase; + + Task NavigateToAsync(object parameter) where TViewModel : ViewModelBase; + + Task NavigateToAsync(Type viewModelType); + + Task NavigateToAsync(Type viewModelType, object parameter); + + Task NavigateBackAsync(); + + Task RemoveLastFromBackStackAsync(); + + Task RemoveBackStackAsync(); + } +} \ No newline at end of file diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Navigation/NavigationService.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Navigation/NavigationService.cs new file mode 100644 index 000000000..e55e31739 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Navigation/NavigationService.cs @@ -0,0 +1,159 @@ +using eShopOnContainers.Core.ViewModels; +using eShopOnContainers.Core.Views; +using eShopOnContainers.ViewModels.Base; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Xamarin.Forms; + +namespace eShopOnContainers.Services +{ + public class NavigationService : INavigationService + { + protected readonly Dictionary _mappings; + + protected Application CurrentApplication + { + get + { + return Application.Current; + } + } + + public NavigationService() + { + _mappings = new Dictionary(); + + CreatePageViewModelMappings(); + } + + public Task InitializeAsync() + { + return NavigateToAsync(); + } + + public Task NavigateToAsync() where TViewModel : ViewModelBase + { + return InternalNavigateToAsync(typeof(TViewModel), null); + } + + public Task NavigateToAsync(object parameter) where TViewModel : ViewModelBase + { + return InternalNavigateToAsync(typeof(TViewModel), parameter); + } + + public Task NavigateToAsync(Type viewModelType) + { + return InternalNavigateToAsync(viewModelType, null); + } + + public Task NavigateToAsync(Type viewModelType, object parameter) + { + return InternalNavigateToAsync(viewModelType, parameter); + } + + public async Task NavigateBackAsync() + { + if (CurrentApplication.MainPage is HomeView) + { + var mainPage = CurrentApplication.MainPage as HomeView; + await mainPage.Navigation.PopAsync(); + } + else if (CurrentApplication.MainPage != null) + { + await CurrentApplication.MainPage.Navigation.PopAsync(); + } + } + + public virtual Task RemoveLastFromBackStackAsync() + { + var mainPage = CurrentApplication.MainPage as CustomNavigationPage; + + if (mainPage != null) + { + mainPage.Navigation.RemovePage( + mainPage.Navigation.NavigationStack[mainPage.Navigation.NavigationStack.Count - 2]); + } + + return Task.FromResult(true); + } + + public virtual Task RemoveBackStackAsync() + { + var mainPage = CurrentApplication.MainPage as CustomNavigationPage; + + if (mainPage != null) + { + for (int i = 0; i < mainPage.Navigation.NavigationStack.Count - 1; i++) + { + var page = mainPage.Navigation.NavigationStack[i]; + mainPage.Navigation.RemovePage(page); + } + } + + return Task.FromResult(true); + } + + protected virtual async Task InternalNavigateToAsync(Type viewModelType, object parameter) + { + Page page = CreateAndBindPage(viewModelType, parameter); + + if (page is LoginView) + { + CurrentApplication.MainPage = new CustomNavigationPage(page); + } + else + { + var navigationPage = CurrentApplication.MainPage as CustomNavigationPage; + + if (navigationPage != null) + { + await navigationPage.PushAsync(page); + } + else + { + CurrentApplication.MainPage = new CustomNavigationPage(page); + } + } + + await (page.BindingContext as ViewModelBase).InitializeAsync(parameter); + } + + protected Type GetPageTypeForViewModel(Type viewModelType) + { + if (!_mappings.ContainsKey(viewModelType)) + { + throw new KeyNotFoundException($"No map for ${viewModelType} was found on navigation mappings"); + } + + return _mappings[viewModelType]; + } + + protected Page CreateAndBindPage(Type viewModelType, object parameter) + { + 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(CartViewModel), typeof(CartView)); + _mappings.Add(typeof(ProductsViewModel), typeof(HomeView)); + _mappings.Add(typeof(LoginViewModel), typeof(LoginView)); + _mappings.Add(typeof(MainViewModel), typeof(MainView)); + _mappings.Add(typeof(OrderDetailViewModel), typeof(OrderDetailView)); + _mappings.Add(typeof(OrdersViewModel), typeof(OrdersView)); + _mappings.Add(typeof(ProfileViewModel), typeof(ProfileView)); + } + } +} \ No newline at end of file diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Orders/FakeOrdersService.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Orders/FakeOrdersService.cs new file mode 100644 index 000000000..b85f7b257 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Orders/FakeOrdersService.cs @@ -0,0 +1,29 @@ +using eShopOnContainers.Core.Models.Orders; +using System; +using System.Collections.ObjectModel; +using System.Threading.Tasks; + +namespace eShopOnContainers.Core.Services.Orders +{ + public class FakeOrdersService : IOrdersService + { + public async Task> GetOrdersAsync() + { + await Task.Delay(500); + + return new ObservableCollection + { + new Order { OrderNumber = 0123456789, Total = 45.30, Date = DateTime.Now, Status = OrderStatus.Delivered }, + new Order { OrderNumber = 9123456780, Total = 39.95, Date = DateTime.Now, Status = OrderStatus.Delivered }, + new Order { OrderNumber = 8765432190, Total = 15.00, Date = DateTime.Now, Status = OrderStatus.Delivered }, + }; + } + + public async Task GetCartAsync() + { + await Task.Delay(500); + + return new Order { OrderNumber = 0123456789, Total = 45.99, Date = DateTime.Now, Status = OrderStatus.Pending }; + } + } +} \ No newline at end of file diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Orders/IOrdersService.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Orders/IOrdersService.cs new file mode 100644 index 000000000..eaafe72dd --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Orders/IOrdersService.cs @@ -0,0 +1,13 @@ +using eShopOnContainers.Core.Models.Orders; +using System.Collections.ObjectModel; +using System.Threading.Tasks; + +namespace eShopOnContainers.Core.Services.Orders +{ + public interface IOrdersService + { + Task> GetOrdersAsync(); + + Task GetCartAsync(); + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Products/FakeProductsService.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Products/FakeProductsService.cs new file mode 100644 index 000000000..43099ede1 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Products/FakeProductsService.cs @@ -0,0 +1,22 @@ +using eShopOnContainers.Core.Models.Products; +using System.Collections.ObjectModel; +using System.Threading.Tasks; +using Xamarin.Forms; + +namespace eShopOnContainers.Core.Services.Products +{ + public class FakeProductsService : IProductsService + { + public async Task> GetProductsAsync() + { + await Task.Delay(500); + + return new ObservableCollection + { + new Product { Image = Device.OS != TargetPlatform.Windows ? "fake_product_01" : "Assets/fake_product_01.png", Name = ".NET Bot Blue Sweatshirt (M)", Price = 19.50 }, + new Product { Image = Device.OS != TargetPlatform.Windows ? "fake_product_02": "Assets/fake_product_02.png", Name = ".NET Bot Purple Sweatshirt (M)", Price = 19.50 }, + new Product { Image = Device.OS != TargetPlatform.Windows ? "fake_product_03": "Assets/fake_product_03.png", Name = ".NET Bot Black Sweatshirt (M)", Price = 19.95 } + }; + } + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Products/IProductsService.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Products/IProductsService.cs new file mode 100644 index 000000000..ccaba6cd5 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Services/Products/IProductsService.cs @@ -0,0 +1,11 @@ +using eShopOnContainers.Core.Models.Products; +using System.Collections.ObjectModel; +using System.Threading.Tasks; + +namespace eShopOnContainers.Core.Services.Products +{ + public interface IProductsService + { + Task> GetProductsAsync(); + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Triggers/BeginAnimation.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Triggers/BeginAnimation.cs new file mode 100644 index 000000000..d0d109168 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Triggers/BeginAnimation.cs @@ -0,0 +1,16 @@ +using eShopOnContainers.Core.Animations.Base; +using Xamarin.Forms; + +namespace eShopOnContainers.Core.Triggers +{ + public class BeginAnimation : TriggerAction + { + public AnimationBase Animation { get; set; } + + protected override async void Invoke(VisualElement sender) + { + if (Animation != null) + await Animation.Begin(); + } + } +} \ No newline at end of file diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Validations/IValidationRule.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Validations/IValidationRule.cs new file mode 100644 index 000000000..d049e3074 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Validations/IValidationRule.cs @@ -0,0 +1,9 @@ +namespace eShopOnContainers.Core.Validations +{ + public interface IValidationRule + { + string ValidationMessage { get; set; } + + bool Check(T value); + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Validations/IValidity.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Validations/IValidity.cs new file mode 100644 index 000000000..e468c1fc2 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Validations/IValidity.cs @@ -0,0 +1,7 @@ +namespace eShopOnContainers.Core.Validations +{ + public interface IValidity + { + bool IsValid { get; set; } + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Validations/IsNotNullOrEmptyRule.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Validations/IsNotNullOrEmptyRule.cs new file mode 100644 index 000000000..3ae1a4565 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Validations/IsNotNullOrEmptyRule.cs @@ -0,0 +1,19 @@ +namespace eShopOnContainers.Core.Validations +{ + public class IsNotNullOrEmptyRule : IValidationRule + { + public string ValidationMessage { get; set; } + + public bool Check(T value) + { + if (value == null) + { + return false; + } + + var str = value as string; + + return !string.IsNullOrWhiteSpace(str); + } + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Validations/ValidatableObject.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Validations/ValidatableObject.cs new file mode 100644 index 000000000..b7caa0d0d --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Validations/ValidatableObject.cs @@ -0,0 +1,72 @@ +using eShopOnContainers.ViewModels.Base; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; + +namespace eShopOnContainers.Core.Validations +{ + public class ValidatableObject : ExtendedBindableObject, IValidity + { + private readonly List> _validations; + private readonly ObservableCollection _errors; + private T _value; + private bool _isValid; + + public List> Validations => _validations; + + public ObservableCollection Errors => _errors; + + public T Value + { + get + { + return _value; + } + + set + { + _value = value; + RaisePropertyChanged(() => Value); + } + } + + public bool IsValid + { + get + { + return _isValid; + } + + set + { + _isValid = value; + _errors.Clear(); + RaisePropertyChanged(() => IsValid); + } + } + + public ValidatableObject() + { + _isValid = true; + _errors = new ObservableCollection(); + _validations = new List>(); + } + + public bool Validate() + { + Errors.Clear(); + + IEnumerable errors = _validations.Where(v => !v.Check(Value)) + .Select(v => v.ValidationMessage); + + foreach (var error in errors) + { + Errors.Add(error); + } + + IsValid = !Errors.Any(); + + return this.IsValid; + } + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/Base/ExtendedBindableObject.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/Base/ExtendedBindableObject.cs new file mode 100644 index 000000000..eab1380aa --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/Base/ExtendedBindableObject.cs @@ -0,0 +1,32 @@ +using System; +using System.Linq.Expressions; +using System.Reflection; +using Xamarin.Forms; + +namespace eShopOnContainers.ViewModels.Base +{ + public abstract class ExtendedBindableObject : BindableObject + { + public void RaisePropertyChanged(Expression> property) + { + var name = GetMemberInfo(property).Name; + OnPropertyChanged(name); + } + + private MemberInfo GetMemberInfo(Expression expression) + { + MemberExpression operand; + LambdaExpression lambdaExpression = (LambdaExpression)expression; + if (lambdaExpression.Body as UnaryExpression != null) + { + UnaryExpression body = (UnaryExpression)lambdaExpression.Body; + operand = (MemberExpression)body.Operand; + } + else + { + operand = (MemberExpression)lambdaExpression.Body; + } + return operand.Member; + } + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/Base/MessengerKeys.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/Base/MessengerKeys.cs new file mode 100644 index 000000000..b5e1bdb46 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/Base/MessengerKeys.cs @@ -0,0 +1,8 @@ +namespace eShopOnContainers.Core.ViewModels.Base +{ + public class MessengerKeys + { + // Add product to cart + public const string AddProduct = "AddProduct"; + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/Base/ViewModelBase.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/Base/ViewModelBase.cs new file mode 100644 index 000000000..8b7e981d6 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/Base/ViewModelBase.cs @@ -0,0 +1,38 @@ +using eShopOnContainers.Services; +using System.Threading.Tasks; + +namespace eShopOnContainers.ViewModels.Base +{ + public abstract class ViewModelBase : ExtendedBindableObject + { + protected readonly IDialogService DialogService; + protected readonly INavigationService NavigationService; + + private bool _isBusy; + + public bool IsBusy + { + get + { + return _isBusy; + } + + set + { + _isBusy = value; + RaisePropertyChanged(() => IsBusy); + } + } + + public ViewModelBase() + { + DialogService = ViewModelLocator.Instance.Resolve(); + NavigationService = ViewModelLocator.Instance.Resolve(); + } + + public virtual Task InitializeAsync(object navigationData) + { + return Task.FromResult(false); + } + } +} \ No newline at end of file diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/Base/ViewModelLocator.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/Base/ViewModelLocator.cs new file mode 100644 index 000000000..8e03b8d39 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/Base/ViewModelLocator.cs @@ -0,0 +1,69 @@ +using Microsoft.Practices.Unity; +using eShopOnContainers.Core.Services.Orders; +using eShopOnContainers.Core.Services.Products; +using eShopOnContainers.Core.ViewModels; +using eShopOnContainers.Services; +using System; + +namespace eShopOnContainers.ViewModels.Base +{ + public class ViewModelLocator + { + private readonly IUnityContainer _unityContainer; + + private static readonly ViewModelLocator _instance = new ViewModelLocator(); + + public static ViewModelLocator Instance + { + get + { + return _instance; + } + } + + protected ViewModelLocator() + { + _unityContainer = new UnityContainer(); + + // services + _unityContainer.RegisterType(); + RegisterSingleton(); + _unityContainer.RegisterType(); + _unityContainer.RegisterType(); + + // view models + _unityContainer.RegisterType(); + _unityContainer.RegisterType(); + _unityContainer.RegisterType(); + _unityContainer.RegisterType(); + _unityContainer.RegisterType(); + _unityContainer.RegisterType(); + _unityContainer.RegisterType(); + } + + public T Resolve() + { + return _unityContainer.Resolve(); + } + + public object Resolve(Type type) + { + return _unityContainer.Resolve(type); + } + + public void Register(T instance) + { + _unityContainer.RegisterInstance(instance); + } + + public void Register() where T : TInterface + { + _unityContainer.RegisterType(); + } + + public void RegisterSingleton() where T : TInterface + { + _unityContainer.RegisterType(new ContainerControlledLifetimeManager()); + } + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/CartViewModel.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/CartViewModel.cs new file mode 100644 index 000000000..caf192fb8 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/CartViewModel.cs @@ -0,0 +1,52 @@ +using eShopOnContainers.Core.Models.Orders; +using eShopOnContainers.Core.Services.Orders; +using eShopOnContainers.Core.ViewModels.Base; +using eShopOnContainers.ViewModels.Base; +using System.Threading.Tasks; +using Xamarin.Forms; + +namespace eShopOnContainers.Core.ViewModels +{ + public class CartViewModel : ViewModelBase + { + private int _badgeCount; + private Order _order; + + private IOrdersService _orderService; + + public CartViewModel(IOrdersService orderService) + { + _orderService = orderService; + } + + public int BadgeCount + { + get { return _badgeCount; } + set + { + _badgeCount = value; + RaisePropertyChanged(() => BadgeCount); + } + } + + public Order Order + { + get { return _order; } + set + { + _order = value; + RaisePropertyChanged(() => Order); + } + } + + public override async Task InitializeAsync(object navigationData) + { + MessagingCenter.Subscribe(this, MessengerKeys.AddProduct, (sender) => + { + BadgeCount++; + }); + + Order = await _orderService.GetCartAsync(); + } + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/LoginViewModel.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/LoginViewModel.cs new file mode 100644 index 000000000..244ac2b92 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/LoginViewModel.cs @@ -0,0 +1,111 @@ +using eShopOnContainers.Core.Validations; +using eShopOnContainers.ViewModels.Base; +using System; +using System.Diagnostics; +using System.Windows.Input; +using Xamarin.Forms; + +namespace eShopOnContainers.Core.ViewModels +{ + public class LoginViewModel : ViewModelBase + { + private ValidatableObject _userName; + private ValidatableObject _password; + private bool _isValid; + + public LoginViewModel() + { + _userName = new ValidatableObject(); + _password = new ValidatableObject(); + + AddValidations(); + } + + public ValidatableObject UserName + { + get + { + return _userName; + } + set + { + _userName = value; + RaisePropertyChanged(() => UserName); + } + } + + public ValidatableObject Password + { + get + { + return _password; + } + set + { + _password = value; + RaisePropertyChanged(() => Password); + } + } + + public bool IsValid + { + get + { + return _isValid; + } + set + { + _isValid = value; + RaisePropertyChanged(() => IsValid); + } + } + + public ICommand SignInCommand => new Command(SignInAsync); + + private async void SignInAsync() + { + IsBusy = true; + IsValid = true; + bool isValid = Validate(); + bool isAuthenticated = false; + + if (isValid) + { + try + { + isAuthenticated = true; + } + catch (Exception ex) + { + Debug.WriteLine($"[SignIn] Error signing in: {ex}"); + } + } + else + { + IsValid = false; + } + + if (isAuthenticated) + { + await NavigationService.NavigateToAsync(); + await NavigationService.RemoveLastFromBackStackAsync(); + } + + IsBusy = false; + } + + private bool Validate() + { + bool isValidUser = _userName.Validate(); + bool isValidPassword = _password.Validate(); + + return isValidUser && isValidPassword; + } + + private void AddValidations() + { + _userName.Validations.Add(new IsNotNullOrEmptyRule { ValidationMessage = "Username should not be empty" }); + _password.Validations.Add(new IsNotNullOrEmptyRule { ValidationMessage = "Password should not be empty" }); + } + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/MainViewModel.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/MainViewModel.cs new file mode 100644 index 000000000..097b92869 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/MainViewModel.cs @@ -0,0 +1,9 @@ +using eShopOnContainers.ViewModels.Base; + +namespace eShopOnContainers.Core.ViewModels +{ + public class MainViewModel : ViewModelBase + { + + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/OrderDetailViewModel.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/OrderDetailViewModel.cs new file mode 100644 index 000000000..3be7cc976 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/OrderDetailViewModel.cs @@ -0,0 +1,8 @@ +using eShopOnContainers.ViewModels.Base; + +namespace eShopOnContainers.Core.ViewModels +{ + public class OrderDetailViewModel : ViewModelBase + { + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/OrdersViewModel.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/OrdersViewModel.cs new file mode 100644 index 000000000..0ef29191c --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/OrdersViewModel.cs @@ -0,0 +1,8 @@ +using eShopOnContainers.ViewModels.Base; + +namespace eShopOnContainers.Core.ViewModels +{ + public class OrdersViewModel : ViewModelBase + { + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/ProfileViewModel.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/ProfileViewModel.cs new file mode 100644 index 000000000..9ffd880a3 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/ProfileViewModel.cs @@ -0,0 +1,45 @@ +using eShopOnContainers.Core.Models.Orders; +using eShopOnContainers.Core.Services.Orders; +using eShopOnContainers.ViewModels.Base; +using System.Collections.ObjectModel; +using System.Threading.Tasks; +using System.Windows.Input; +using Xamarin.Forms; + +namespace eShopOnContainers.Core.ViewModels +{ + public class ProfileViewModel : ViewModelBase + { + private ObservableCollection _orders; + + private IOrdersService _ordersService; + + public ProfileViewModel(IOrdersService ordersService) + { + _ordersService = ordersService; + } + + public ObservableCollection Orders + { + get { return _orders; } + set + { + _orders = value; + RaisePropertyChanged(() => Orders); + } + } + + public ICommand LogoutCommand => new Command(LogoutAsync); + + public override async Task InitializeAsync(object navigationData) + { + Orders = await _ordersService.GetOrdersAsync(); + } + + private async void LogoutAsync() + { + await NavigationService.NavigateToAsync(); + await NavigationService.RemoveBackStackAsync(); + } + } +} \ No newline at end of file diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/pRODUCTSViewModel.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/pRODUCTSViewModel.cs new file mode 100644 index 000000000..f628ac9a0 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/ViewModels/pRODUCTSViewModel.cs @@ -0,0 +1,57 @@ +using System.Threading.Tasks; +using eShopOnContainers.ViewModels.Base; +using eShopOnContainers.Core.Services.Products; +using System.Collections.ObjectModel; +using eShopOnContainers.Core.Models.Products; +using Xamarin.Forms; +using eShopOnContainers.Core.ViewModels.Base; + +namespace eShopOnContainers.Core.ViewModels +{ + public class ProductsViewModel : ViewModelBase + { + private ObservableCollection _products; + private Product _product; + + private IProductsService _productsService; + + public ProductsViewModel(IProductsService productsService) + { + _productsService = productsService; + } + + public ObservableCollection Products + { + get { return _products; } + set + { + _products = value; + RaisePropertyChanged(() => Products); + } + } + + public Product Product + { + get { return _product; } + set + { + _product = value; + + if (_product != null) + { + AddProduct(); + } + } + } + + public override async Task InitializeAsync(object navigationData) + { + Products = await _productsService.GetProductsAsync(); + } + + private void AddProduct() + { + MessagingCenter.Send(this, MessengerKeys.AddProduct); + } + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/CartView.xaml b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/CartView.xaml new file mode 100644 index 000000000..fe1f2ffe6 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/CartView.xaml @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/CartView.xaml.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/CartView.xaml.cs new file mode 100644 index 000000000..76bdd19b4 --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/CartView.xaml.cs @@ -0,0 +1,12 @@ +using Xamarin.Forms; + +namespace eShopOnContainers.Core.Views +{ + public partial class CartView : ContentPage + { + public CartView() + { + InitializeComponent(); + } + } +} diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/CustomNavigationPage.xaml b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/CustomNavigationPage.xaml new file mode 100644 index 000000000..477ac142f --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/CustomNavigationPage.xaml @@ -0,0 +1,6 @@ + + + \ No newline at end of file diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/CustomNavigationPage.xaml.cs b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/CustomNavigationPage.xaml.cs new file mode 100644 index 000000000..a93f579ea --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/CustomNavigationPage.xaml.cs @@ -0,0 +1,17 @@ +using Xamarin.Forms; + +namespace eShopOnContainers.Core.Views +{ + public partial class CustomNavigationPage : NavigationPage + { + public CustomNavigationPage() : base() + { + InitializeComponent(); + } + + public CustomNavigationPage(Page root) : base(root) + { + InitializeComponent(); + } + } +} \ No newline at end of file diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/FiltersView.xaml b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/FiltersView.xaml new file mode 100644 index 000000000..ba7cc5e3f --- /dev/null +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/FiltersView.xaml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + +