diff --git a/aurora-sharp-desktop/.gitignore b/aurora-sharp-desktop/.gitignore new file mode 100644 index 0000000..23e17b6 --- /dev/null +++ b/aurora-sharp-desktop/.gitignore @@ -0,0 +1,351 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.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 + +# Visual Studio Trace Files +*.e2e + +# 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 + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# 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 +# Note: 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 +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable 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 +*.appx +*.appxbundle +*.appxupload + +# 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 +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# 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 +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# 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/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +start*.sh diff --git a/Aurora.gtk/Aurora.gtk.csproj b/aurora-sharp-desktop/Aurora.gtk/Aurora.gtk.csproj similarity index 100% rename from Aurora.gtk/Aurora.gtk.csproj rename to aurora-sharp-desktop/Aurora.gtk/Aurora.gtk.csproj diff --git a/Aurora.gtk/Helpers/Settings.cs b/aurora-sharp-desktop/Aurora.gtk/Helpers/Settings.cs similarity index 100% rename from Aurora.gtk/Helpers/Settings.cs rename to aurora-sharp-desktop/Aurora.gtk/Helpers/Settings.cs diff --git a/Aurora.gtk/LibVLCSharp.GTK.dll.config b/aurora-sharp-desktop/Aurora.gtk/LibVLCSharp.GTK.dll.config similarity index 100% rename from Aurora.gtk/LibVLCSharp.GTK.dll.config rename to aurora-sharp-desktop/Aurora.gtk/LibVLCSharp.GTK.dll.config diff --git a/Aurora.gtk/LibVLCSharp.dll.config b/aurora-sharp-desktop/Aurora.gtk/LibVLCSharp.dll.config similarity index 100% rename from Aurora.gtk/LibVLCSharp.dll.config rename to aurora-sharp-desktop/Aurora.gtk/LibVLCSharp.dll.config diff --git a/Aurora.gtk/MainWindow.cs b/aurora-sharp-desktop/Aurora.gtk/MainWindow.cs similarity index 100% rename from Aurora.gtk/MainWindow.cs rename to aurora-sharp-desktop/Aurora.gtk/MainWindow.cs diff --git a/Aurora.gtk/OpenTK.dll.config b/aurora-sharp-desktop/Aurora.gtk/OpenTK.dll.config similarity index 100% rename from Aurora.gtk/OpenTK.dll.config rename to aurora-sharp-desktop/Aurora.gtk/OpenTK.dll.config diff --git a/Aurora.gtk/Program.cs b/aurora-sharp-desktop/Aurora.gtk/Program.cs similarity index 100% rename from Aurora.gtk/Program.cs rename to aurora-sharp-desktop/Aurora.gtk/Program.cs diff --git a/Aurora.gtk/Properties/AssemblyInfo.cs b/aurora-sharp-desktop/Aurora.gtk/Properties/AssemblyInfo.cs similarity index 100% rename from Aurora.gtk/Properties/AssemblyInfo.cs rename to aurora-sharp-desktop/Aurora.gtk/Properties/AssemblyInfo.cs diff --git a/Aurora.gtk/Resources/backward.png b/aurora-sharp-desktop/Aurora.gtk/Resources/backward.png similarity index 100% rename from Aurora.gtk/Resources/backward.png rename to aurora-sharp-desktop/Aurora.gtk/Resources/backward.png diff --git a/Aurora.gtk/Resources/forwards.png b/aurora-sharp-desktop/Aurora.gtk/Resources/forwards.png similarity index 100% rename from Aurora.gtk/Resources/forwards.png rename to aurora-sharp-desktop/Aurora.gtk/Resources/forwards.png diff --git a/Aurora.gtk/Resources/like.png b/aurora-sharp-desktop/Aurora.gtk/Resources/like.png similarity index 100% rename from Aurora.gtk/Resources/like.png rename to aurora-sharp-desktop/Aurora.gtk/Resources/like.png diff --git a/Aurora.gtk/Resources/loop.png b/aurora-sharp-desktop/Aurora.gtk/Resources/loop.png similarity index 100% rename from Aurora.gtk/Resources/loop.png rename to aurora-sharp-desktop/Aurora.gtk/Resources/loop.png diff --git a/Aurora.gtk/Resources/menu.png b/aurora-sharp-desktop/Aurora.gtk/Resources/menu.png similarity index 100% rename from Aurora.gtk/Resources/menu.png rename to aurora-sharp-desktop/Aurora.gtk/Resources/menu.png diff --git a/Aurora.gtk/Resources/pause.png b/aurora-sharp-desktop/Aurora.gtk/Resources/pause.png similarity index 100% rename from Aurora.gtk/Resources/pause.png rename to aurora-sharp-desktop/Aurora.gtk/Resources/pause.png diff --git a/Aurora.gtk/Resources/play.png b/aurora-sharp-desktop/Aurora.gtk/Resources/play.png similarity index 100% rename from Aurora.gtk/Resources/play.png rename to aurora-sharp-desktop/Aurora.gtk/Resources/play.png diff --git a/Aurora.gtk/Resources/shuffle.png b/aurora-sharp-desktop/Aurora.gtk/Resources/shuffle.png similarity index 100% rename from Aurora.gtk/Resources/shuffle.png rename to aurora-sharp-desktop/Aurora.gtk/Resources/shuffle.png diff --git a/Aurora.gtk/gtk-gui/MainWindow.cs b/aurora-sharp-desktop/Aurora.gtk/gtk-gui/MainWindow.cs similarity index 100% rename from Aurora.gtk/gtk-gui/MainWindow.cs rename to aurora-sharp-desktop/Aurora.gtk/gtk-gui/MainWindow.cs diff --git a/Aurora.gtk/gtk-gui/generated.cs b/aurora-sharp-desktop/Aurora.gtk/gtk-gui/generated.cs similarity index 100% rename from Aurora.gtk/gtk-gui/generated.cs rename to aurora-sharp-desktop/Aurora.gtk/gtk-gui/generated.cs diff --git a/Aurora.gtk/gtk-gui/gui.stetic b/aurora-sharp-desktop/Aurora.gtk/gtk-gui/gui.stetic similarity index 100% rename from Aurora.gtk/gtk-gui/gui.stetic rename to aurora-sharp-desktop/Aurora.gtk/gtk-gui/gui.stetic diff --git a/Aurora.gtk/libvlc.dylib b/aurora-sharp-desktop/Aurora.gtk/libvlc.dylib similarity index 100% rename from Aurora.gtk/libvlc.dylib rename to aurora-sharp-desktop/Aurora.gtk/libvlc.dylib diff --git a/Aurora.gtk/packages.config b/aurora-sharp-desktop/Aurora.gtk/packages.config similarity index 100% rename from Aurora.gtk/packages.config rename to aurora-sharp-desktop/Aurora.gtk/packages.config diff --git a/Aurora.gtk/webkit-sharp.dll.config b/aurora-sharp-desktop/Aurora.gtk/webkit-sharp.dll.config similarity index 100% rename from Aurora.gtk/webkit-sharp.dll.config rename to aurora-sharp-desktop/Aurora.gtk/webkit-sharp.dll.config diff --git a/Aurora.sln b/aurora-sharp-desktop/Aurora.sln similarity index 100% rename from Aurora.sln rename to aurora-sharp-desktop/Aurora.sln diff --git a/Aurora.test/Aurora.test.csproj b/aurora-sharp-desktop/Aurora.test/Aurora.test.csproj similarity index 100% rename from Aurora.test/Aurora.test.csproj rename to aurora-sharp-desktop/Aurora.test/Aurora.test.csproj diff --git a/Aurora.test/ControllerTests/EventTests.cs b/aurora-sharp-desktop/Aurora.test/ControllerTests/EventTests.cs similarity index 100% rename from Aurora.test/ControllerTests/EventTests.cs rename to aurora-sharp-desktop/Aurora.test/ControllerTests/EventTests.cs diff --git a/Aurora.test/ControllerTests/MediaControllerTest.cs b/aurora-sharp-desktop/Aurora.test/ControllerTests/MediaControllerTest.cs similarity index 100% rename from Aurora.test/ControllerTests/MediaControllerTest.cs rename to aurora-sharp-desktop/Aurora.test/ControllerTests/MediaControllerTest.cs diff --git a/Aurora.test/ControllerTests/MembersControllerTest.cs b/aurora-sharp-desktop/Aurora.test/ControllerTests/MembersControllerTest.cs similarity index 100% rename from Aurora.test/ControllerTests/MembersControllerTest.cs rename to aurora-sharp-desktop/Aurora.test/ControllerTests/MembersControllerTest.cs diff --git a/Aurora.test/ControllerTests/PartyControllerTest.cs b/aurora-sharp-desktop/Aurora.test/ControllerTests/PartyControllerTest.cs similarity index 100% rename from Aurora.test/ControllerTests/PartyControllerTest.cs rename to aurora-sharp-desktop/Aurora.test/ControllerTests/PartyControllerTest.cs diff --git a/Aurora.test/ControllerTests/Setup.cs b/aurora-sharp-desktop/Aurora.test/ControllerTests/Setup.cs similarity index 100% rename from Aurora.test/ControllerTests/Setup.cs rename to aurora-sharp-desktop/Aurora.test/ControllerTests/Setup.cs diff --git a/Aurora.test/Models/CallContext.cs b/aurora-sharp-desktop/Aurora.test/Models/CallContext.cs similarity index 100% rename from Aurora.test/Models/CallContext.cs rename to aurora-sharp-desktop/Aurora.test/Models/CallContext.cs diff --git a/Aurora.test/Models/Mock/SettingsServiceMock.cs b/aurora-sharp-desktop/Aurora.test/Models/Mock/SettingsServiceMock.cs similarity index 100% rename from Aurora.test/Models/Mock/SettingsServiceMock.cs rename to aurora-sharp-desktop/Aurora.test/Models/Mock/SettingsServiceMock.cs diff --git a/Aurora.test/Resources/Jidenna/The Chief/01 A Bull's Tale.mp3 b/aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/01 A Bull's Tale.mp3 similarity index 100% rename from Aurora.test/Resources/Jidenna/The Chief/01 A Bull's Tale.mp3 rename to aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/01 A Bull's Tale.mp3 diff --git a/Aurora.test/Resources/Jidenna/The Chief/02 Chief Don't Run.mp3 b/aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/02 Chief Don't Run.mp3 similarity index 100% rename from Aurora.test/Resources/Jidenna/The Chief/02 Chief Don't Run.mp3 rename to aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/02 Chief Don't Run.mp3 diff --git a/Aurora.test/Resources/Jidenna/The Chief/03 Trampoline.mp3 b/aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/03 Trampoline.mp3 similarity index 100% rename from Aurora.test/Resources/Jidenna/The Chief/03 Trampoline.mp3 rename to aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/03 Trampoline.mp3 diff --git a/Aurora.test/Resources/Jidenna/The Chief/04 Bambi.mp3 b/aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/04 Bambi.mp3 similarity index 100% rename from Aurora.test/Resources/Jidenna/The Chief/04 Bambi.mp3 rename to aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/04 Bambi.mp3 diff --git a/Aurora.test/Resources/Jidenna/The Chief/05 Helicopters _ Beware.mp3 b/aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/05 Helicopters _ Beware.mp3 similarity index 100% rename from Aurora.test/Resources/Jidenna/The Chief/05 Helicopters _ Beware.mp3 rename to aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/05 Helicopters _ Beware.mp3 diff --git a/Aurora.test/Resources/Jidenna/The Chief/06 Long Live The Chief.mp3 b/aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/06 Long Live The Chief.mp3 similarity index 100% rename from Aurora.test/Resources/Jidenna/The Chief/06 Long Live The Chief.mp3 rename to aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/06 Long Live The Chief.mp3 diff --git a/Aurora.test/Resources/Jidenna/The Chief/07 2 Points.mp3 b/aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/07 2 Points.mp3 similarity index 100% rename from Aurora.test/Resources/Jidenna/The Chief/07 2 Points.mp3 rename to aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/07 2 Points.mp3 diff --git a/Aurora.test/Resources/Jidenna/The Chief/08 The Let Out.mp3 b/aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/08 The Let Out.mp3 similarity index 100% rename from Aurora.test/Resources/Jidenna/The Chief/08 The Let Out.mp3 rename to aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/08 The Let Out.mp3 diff --git a/Aurora.test/Resources/Jidenna/The Chief/09 Safari.mp3 b/aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/09 Safari.mp3 similarity index 100% rename from Aurora.test/Resources/Jidenna/The Chief/09 Safari.mp3 rename to aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/09 Safari.mp3 diff --git a/Aurora.test/Resources/Jidenna/The Chief/10 Adaora.mp3 b/aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/10 Adaora.mp3 similarity index 100% rename from Aurora.test/Resources/Jidenna/The Chief/10 Adaora.mp3 rename to aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/10 Adaora.mp3 diff --git a/Aurora.test/Resources/Jidenna/The Chief/11 Little Bit More.mp3 b/aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/11 Little Bit More.mp3 similarity index 100% rename from Aurora.test/Resources/Jidenna/The Chief/11 Little Bit More.mp3 rename to aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/11 Little Bit More.mp3 diff --git a/Aurora.test/Resources/Jidenna/The Chief/12 Some Kind Of Way.mp3 b/aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/12 Some Kind Of Way.mp3 similarity index 100% rename from Aurora.test/Resources/Jidenna/The Chief/12 Some Kind Of Way.mp3 rename to aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/12 Some Kind Of Way.mp3 diff --git a/Aurora.test/Resources/Jidenna/The Chief/13 White Niggas.mp3 b/aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/13 White Niggas.mp3 similarity index 100% rename from Aurora.test/Resources/Jidenna/The Chief/13 White Niggas.mp3 rename to aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/13 White Niggas.mp3 diff --git a/Aurora.test/Resources/Jidenna/The Chief/14 Bully Of The Earth.mp3 b/aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/14 Bully Of The Earth.mp3 similarity index 100% rename from Aurora.test/Resources/Jidenna/The Chief/14 Bully Of The Earth.mp3 rename to aurora-sharp-desktop/Aurora.test/Resources/Jidenna/The Chief/14 Bully Of The Earth.mp3 diff --git a/Aurora.test/Resources/Mac Miller/Best Day Ever/01 Best Day Ever (Prod. By_ ID Labs).m4a b/aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/01 Best Day Ever (Prod. By_ ID Labs).m4a similarity index 100% rename from Aurora.test/Resources/Mac Miller/Best Day Ever/01 Best Day Ever (Prod. By_ ID Labs).m4a rename to aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/01 Best Day Ever (Prod. By_ ID Labs).m4a diff --git a/Aurora.test/Resources/Mac Miller/Best Day Ever/02 Get Up (Prod. By_ Teddy Roxpin).m4a b/aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/02 Get Up (Prod. By_ Teddy Roxpin).m4a similarity index 100% rename from Aurora.test/Resources/Mac Miller/Best Day Ever/02 Get Up (Prod. By_ Teddy Roxpin).m4a rename to aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/02 Get Up (Prod. By_ Teddy Roxpin).m4a diff --git a/Aurora.test/Resources/Mac Miller/Best Day Ever/03 Donald Trump (Prod. By_ Sap).m4a b/aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/03 Donald Trump (Prod. By_ Sap).m4a similarity index 100% rename from Aurora.test/Resources/Mac Miller/Best Day Ever/03 Donald Trump (Prod. By_ Sap).m4a rename to aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/03 Donald Trump (Prod. By_ Sap).m4a diff --git a/Aurora.test/Resources/Mac Miller/Best Day Ever/04 Oy Vey (Prod By_ ID Labs).mp3 b/aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/04 Oy Vey (Prod By_ ID Labs).mp3 similarity index 100% rename from Aurora.test/Resources/Mac Miller/Best Day Ever/04 Oy Vey (Prod By_ ID Labs).mp3 rename to aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/04 Oy Vey (Prod By_ ID Labs).mp3 diff --git a/Aurora.test/Resources/Mac Miller/Best Day Ever/05 I'll Be There (feat. Phonte) (Prod. By_ Beanz 'n' Kornbread).mp3 b/aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/05 I'll Be There (feat. Phonte) (Prod. By_ Beanz 'n' Kornbread).mp3 similarity index 100% rename from Aurora.test/Resources/Mac Miller/Best Day Ever/05 I'll Be There (feat. Phonte) (Prod. By_ Beanz 'n' Kornbread).mp3 rename to aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/05 I'll Be There (feat. Phonte) (Prod. By_ Beanz 'n' Kornbread).mp3 diff --git a/Aurora.test/Resources/Mac Miller/Best Day Ever/06 Wear My Hat (Prod. By_ Chuck Inglish).m4a b/aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/06 Wear My Hat (Prod. By_ Chuck Inglish).m4a similarity index 100% rename from Aurora.test/Resources/Mac Miller/Best Day Ever/06 Wear My Hat (Prod. By_ Chuck Inglish).m4a rename to aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/06 Wear My Hat (Prod. By_ Chuck Inglish).m4a diff --git a/Aurora.test/Resources/Mac Miller/Best Day Ever/07 Wake Up (Prod By_ Sap & ID Labs).m4a b/aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/07 Wake Up (Prod By_ Sap & ID Labs).m4a similarity index 100% rename from Aurora.test/Resources/Mac Miller/Best Day Ever/07 Wake Up (Prod By_ Sap & ID Labs).m4a rename to aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/07 Wake Up (Prod By_ Sap & ID Labs).m4a diff --git a/Aurora.test/Resources/Mac Miller/Best Day Ever/08 All Around The World (Prod. By_ Just Blaze).m4a b/aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/08 All Around The World (Prod. By_ Just Blaze).m4a similarity index 100% rename from Aurora.test/Resources/Mac Miller/Best Day Ever/08 All Around The World (Prod. By_ Just Blaze).m4a rename to aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/08 All Around The World (Prod. By_ Just Blaze).m4a diff --git a/Aurora.test/Resources/Mac Miller/Best Day Ever/09 Down The Rabbit Hole (Prod. By_ Blue of The Sore Losers).m4a b/aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/09 Down The Rabbit Hole (Prod. By_ Blue of The Sore Losers).m4a similarity index 100% rename from Aurora.test/Resources/Mac Miller/Best Day Ever/09 Down The Rabbit Hole (Prod. By_ Blue of The Sore Losers).m4a rename to aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/09 Down The Rabbit Hole (Prod. By_ Blue of The Sore Losers).m4a diff --git a/Aurora.test/Resources/Mac Miller/Best Day Ever/10 In The Air (Prod By_ Ritz Reynolds).m4a b/aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/10 In The Air (Prod By_ Ritz Reynolds).m4a similarity index 100% rename from Aurora.test/Resources/Mac Miller/Best Day Ever/10 In The Air (Prod By_ Ritz Reynolds).m4a rename to aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/10 In The Air (Prod By_ Ritz Reynolds).m4a diff --git a/Aurora.test/Resources/Mac Miller/Best Day Ever/11 Play Ya Cards (Prod By_ Chuck Inglish).m4a b/aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/11 Play Ya Cards (Prod By_ Chuck Inglish).m4a similarity index 100% rename from Aurora.test/Resources/Mac Miller/Best Day Ever/11 Play Ya Cards (Prod By_ Chuck Inglish).m4a rename to aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/11 Play Ya Cards (Prod By_ Chuck Inglish).m4a diff --git a/Aurora.test/Resources/Mac Miller/Best Day Ever/12 She Said (Prod By_ Khrysis).m4a b/aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/12 She Said (Prod By_ Khrysis).m4a similarity index 100% rename from Aurora.test/Resources/Mac Miller/Best Day Ever/12 She Said (Prod By_ Khrysis).m4a rename to aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/12 She Said (Prod By_ Khrysis).m4a diff --git a/Aurora.test/Resources/Mac Miller/Best Day Ever/13 Life Ain't Easy (Prod. By_ ID Labs).m4a b/aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/13 Life Ain't Easy (Prod. By_ ID Labs).m4a similarity index 100% rename from Aurora.test/Resources/Mac Miller/Best Day Ever/13 Life Ain't Easy (Prod. By_ ID Labs).m4a rename to aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/13 Life Ain't Easy (Prod. By_ ID Labs).m4a diff --git a/Aurora.test/Resources/Mac Miller/Best Day Ever/14 Snooze (Prod By_ ID Labs).m4a b/aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/14 Snooze (Prod By_ ID Labs).m4a similarity index 100% rename from Aurora.test/Resources/Mac Miller/Best Day Ever/14 Snooze (Prod By_ ID Labs).m4a rename to aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/14 Snooze (Prod By_ ID Labs).m4a diff --git a/Aurora.test/Resources/Mac Miller/Best Day Ever/15 Keep Floatin' (feat. Wiz Khalifa) (Prod. By_ ID Labs).mp3 b/aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/15 Keep Floatin' (feat. Wiz Khalifa) (Prod. By_ ID Labs).mp3 similarity index 100% rename from Aurora.test/Resources/Mac Miller/Best Day Ever/15 Keep Floatin' (feat. Wiz Khalifa) (Prod. By_ ID Labs).mp3 rename to aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/15 Keep Floatin' (feat. Wiz Khalifa) (Prod. By_ ID Labs).mp3 diff --git a/Aurora.test/Resources/Mac Miller/Best Day Ever/16 BDE Bonus (Prod. By_ ID Labs).mp3 b/aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/16 BDE Bonus (Prod. By_ ID Labs).mp3 similarity index 100% rename from Aurora.test/Resources/Mac Miller/Best Day Ever/16 BDE Bonus (Prod. By_ ID Labs).mp3 rename to aurora-sharp-desktop/Aurora.test/Resources/Mac Miller/Best Day Ever/16 BDE Bonus (Prod. By_ ID Labs).mp3 diff --git a/aurora-sharp-desktop/Aurora/App.css b/aurora-sharp-desktop/Aurora/App.css new file mode 100644 index 0000000..2982121 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/App.css @@ -0,0 +1,11 @@ +.primaryColor { + background-color: #000000; +} + +.accentColor { + background-color: #181818; +} + +.secondAccentColor { + background-color: #303030 +} \ No newline at end of file diff --git a/aurora-sharp-desktop/Aurora/App.xaml b/aurora-sharp-desktop/Aurora/App.xaml new file mode 100644 index 0000000..ffbf554 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/App.xaml @@ -0,0 +1,31 @@ + + + + + #FFFFFF + #000000 + #F5C210 + #151C25 + #1E2634 + #151C25 + #44545C + + + + + + \ No newline at end of file diff --git a/aurora-sharp-desktop/Aurora/App.xaml.cs b/aurora-sharp-desktop/Aurora/App.xaml.cs new file mode 100644 index 0000000..487ba7d --- /dev/null +++ b/aurora-sharp-desktop/Aurora/App.xaml.cs @@ -0,0 +1,72 @@ +using System; +using Aurora.Design.Views.Main; +using Aurora.Design.Views.Albums; +using Aurora.Design.Views.Artists; +using Aurora.Design.Views.Party; +using Aurora.Design.Views.Profile; +using Aurora.Design.Views.Songs; +using Aurora.Design.Views.Stations; +using Aurora.Services.EventManager; +using Aurora.Services.Server; +using Aurora.Services.Client; +using Autofac; +using LibVLCSharp.Shared; +using Xamarin.Forms; +using Aurora.Services.Player; +using Aurora.Services.Settings; +using Aurora.Services.Library; + +namespace Aurora +{ + public partial class App : Application + { + private static IContainer _container; + public App() + { + InitializeComponent(); + Core.Initialize(); + + //Register DI + ContainerBuilder _builder = new ContainerBuilder(); + // _builder.RegisterInstance(new PlayerService()).SingleInstance(); + _builder.RegisterType().As().SingleInstance(); + _builder.RegisterType().As().SingleInstance(); + _builder.RegisterType().As().SingleInstance(); + _builder.RegisterType().As().SingleInstance(); + _builder.RegisterType().As().SingleInstance(); + _builder.RegisterType().As().SingleInstance(); + _builder.RegisterType().SingleInstance(); + _builder.RegisterType(); + _builder.RegisterType(); + _builder.RegisterType(); + _builder.RegisterType(); + _builder.RegisterType(); + _builder.RegisterType(); + + // _builder.RegisterInstance(new SettingsService()).SingleInstance(); + _container = _builder.Build(); + + MainPage = _container.Resolve(); + } + + public static IContainer Container + { + get { return _container; } + } + + protected override void OnStart() + { + // Handle when your app starts + } + + protected override void OnSleep() + { + // Handle when your app sleeps + } + + protected override void OnResume() + { + // Handle when your app resumes + } + } +} diff --git a/aurora-sharp-desktop/Aurora/AssemblyInfo.cs b/aurora-sharp-desktop/Aurora/AssemblyInfo.cs new file mode 100644 index 0000000..c859952 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using Xamarin.Forms.Xaml; + +[assembly: XamlCompilation(XamlCompilationOptions.Compile)] \ No newline at end of file diff --git a/aurora-sharp-desktop/Aurora/Aurora.csproj b/aurora-sharp-desktop/Aurora/Aurora.csproj new file mode 100644 index 0000000..06593eb --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Aurora.csproj @@ -0,0 +1,85 @@ + + + netstandard2.0 + true + + + pdbonly + true + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Player.xaml + + + + + + + + + + + + + + + PreserveNewest + + + + + + + + + + + \ No newline at end of file diff --git a/aurora-sharp-desktop/Aurora/Design/Behaviors/BehaviorBase.cs b/aurora-sharp-desktop/Aurora/Design/Behaviors/BehaviorBase.cs new file mode 100644 index 0000000..70993eb --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Behaviors/BehaviorBase.cs @@ -0,0 +1,42 @@ +using System; +using Xamarin.Forms; + +namespace Aurora.Design.Behaviors +{ + public class BehaviorBase : Behavior where T : BindableObject + { + public T AssociatedObject { get; private set; } + + protected override void OnAttachedTo(T bindable) + { + base.OnAttachedTo(bindable); + AssociatedObject = bindable; + + if (bindable.BindingContext != null) + { + BindingContext = bindable.BindingContext; + } + + bindable.BindingContextChanged += OnBindingContextChanged; + } + + protected override void OnDetachingFrom(T bindable) + { + base.OnDetachingFrom(bindable); + bindable.BindingContextChanged -= OnBindingContextChanged; + AssociatedObject = null; + } + + void OnBindingContextChanged(object sender, EventArgs e) + { + OnBindingContextChanged(); + } + + protected override void OnBindingContextChanged() + { + base.OnBindingContextChanged(); + BindingContext = AssociatedObject.BindingContext; + } + } +} + diff --git a/aurora-sharp-desktop/Aurora/Design/Behaviors/EventToCommandBehavior.cs b/aurora-sharp-desktop/Aurora/Design/Behaviors/EventToCommandBehavior.cs new file mode 100644 index 0000000..b8c111a --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Behaviors/EventToCommandBehavior.cs @@ -0,0 +1,132 @@ +using System; +using System.Reflection; +using System.Windows.Input; +using Xamarin.Forms; + +namespace Aurora.Design.Behaviors +{ + public class EventToCommandBehavior : BehaviorBase + { + Delegate eventHandler; + + public static readonly BindableProperty EventNameProperty = BindableProperty.Create("EventName", typeof(string), typeof(EventToCommandBehavior), null, propertyChanged: OnEventNameChanged); + public static readonly BindableProperty CommandProperty = BindableProperty.Create("Command", typeof(ICommand), typeof(EventToCommandBehavior), null); + public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create("CommandParameter", typeof(object), typeof(EventToCommandBehavior), null); + public static readonly BindableProperty InputConverterProperty = BindableProperty.Create("Converter", typeof(IValueConverter), typeof(EventToCommandBehavior), null); + + public string EventName + { + get { return (string)GetValue(EventNameProperty); } + set { SetValue(EventNameProperty, value); } + } + + public ICommand Command + { + get { return (ICommand)GetValue(CommandProperty); } + set { SetValue(CommandProperty, value); } + } + + public object CommandParameter + { + get { return GetValue(CommandParameterProperty); } + set { SetValue(CommandParameterProperty, value); } + } + + public IValueConverter Converter + { + get { return (IValueConverter)GetValue(InputConverterProperty); } + set { SetValue(InputConverterProperty, value); } + } + + protected override void OnAttachedTo(View bindable) + { + base.OnAttachedTo(bindable); + RegisterEvent(EventName); + } + + protected override void OnDetachingFrom(View bindable) + { + DeregisterEvent(EventName); + base.OnDetachingFrom(bindable); + } + + void RegisterEvent(string name) + { + if (string.IsNullOrWhiteSpace(name)) + { + return; + } + + EventInfo eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name); + if (eventInfo == null) + { + throw new ArgumentException(string.Format("EventToCommandBehavior: Can't register the '{0}' event.", EventName)); + } + MethodInfo methodInfo = typeof(EventToCommandBehavior).GetTypeInfo().GetDeclaredMethod("OnEvent"); + eventHandler = methodInfo.CreateDelegate(eventInfo.EventHandlerType, this); + eventInfo.AddEventHandler(AssociatedObject, eventHandler); + } + + void DeregisterEvent(string name) + { + if (string.IsNullOrWhiteSpace(name)) + { + return; + } + + if (eventHandler == null) + { + return; + } + EventInfo eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name); + if (eventInfo == null) + { + throw new ArgumentException(string.Format("EventToCommandBehavior: Can't de-register the '{0}' event.", EventName)); + } + eventInfo.RemoveEventHandler(AssociatedObject, eventHandler); + eventHandler = null; + } + + void OnEvent(object sender, object eventArgs) + { + if (Command == null) + { + return; + } + + object resolvedParameter; + if (CommandParameter != null) + { + resolvedParameter = CommandParameter; + } + else if (Converter != null) + { + resolvedParameter = Converter.Convert(eventArgs, typeof(object), null, null); + } + else + { + resolvedParameter = eventArgs; + } + + if (Command.CanExecute(resolvedParameter)) + { + Command.Execute(resolvedParameter); + } + } + + static void OnEventNameChanged(BindableObject bindable, object oldValue, object newValue) + { + var behavior = (EventToCommandBehavior)bindable; + if (behavior.AssociatedObject == null) + { + return; + } + + string oldEventName = (string)oldValue; + string newEventName = (string)newValue; + + behavior.DeregisterEvent(oldEventName); + behavior.RegisterEvent(newEventName); + } + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/ColumnCollection.cs b/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/ColumnCollection.cs new file mode 100644 index 0000000..1906bcb --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/ColumnCollection.cs @@ -0,0 +1,8 @@ +using System.Collections.Generic; + +namespace Aurora.Design.Components.DataGrid +{ + public sealed class ColumnCollection : List + { + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/DataGrid.xaml b/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/DataGrid.xaml new file mode 100644 index 0000000..d6ae78c --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/DataGrid.xaml @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/DataGrid.xaml.cs b/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/DataGrid.xaml.cs new file mode 100644 index 0000000..fe7e878 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/DataGrid.xaml.cs @@ -0,0 +1,756 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reflection; +using System.Windows.Input; +using Xamarin.Forms; +using Aurora.Utils; + +namespace Aurora.Design.Components.DataGrid +{ + public partial class DataGrid : Grid + { + #region Private Fields + private ObservableCollection _internalItems; + + private Dictionary _sortingOrders; + + #endregion Fields + + #region Constructor + + public DataGrid() : this(ListViewCachingStrategy.RetainElement) + { + } + + public DataGrid(ListViewCachingStrategy cachingStrategy) + { + InitializeComponent(); + BackgroundColor = Color.Transparent; + + _sortingOrders = new Dictionary(); + + DataList.ItemTemplate = new DataGridRowTemplateSelector(); + + DataList.ItemSelected += (s, e) => + { + if (SelectionEnabled) + { + SelectedItem = DataList.SelectedItem; + } + else + { + DataList.SelectedItem = null; + } + + ItemSelected?.Invoke(this, e); + }; + + DataList.Refreshing += (s, e) => + { + Refreshing?.Invoke(this, e); + }; + + DataList.SetBinding(ListView.RowHeightProperty, new Binding("RowHeight", source: this)); + } + #endregion Constructor + + #region Public Fields + public event EventHandler Refreshing; + public event EventHandler ItemSelected; + + #endregion Public Fields + + #region Bindable properties + public static readonly BindableProperty ActiveRowColorProperty = + BindableProperty.Create( + nameof(ActiveRowColor), + typeof(Color), + typeof(DataGrid), + Color.FromRgb(128, 144, 160), + coerceValue: (bindable, value) => + { + if (!(bindable as DataGrid).SelectionEnabled) + throw new InvalidOperationException("Datagrid must be SelectionEnabled=true to set ActiveRowColor"); + return value; + }); + + public static readonly BindableProperty HeaderBackgroundProperty = + BindableProperty.Create( + nameof(HeaderBackground), + typeof(Color), + typeof(DataGrid), + Color.White, + propertyChanged: (bindable, oldValue, newValue) => + { + var self = bindable as DataGrid; + if (self._headerView != null && !self.HeaderBordersVisible) + self._headerView.BackgroundColor = (Color)newValue; + }); + + public static readonly BindableProperty BorderColorProperty = + BindableProperty.Create( + nameof(BorderColor), + typeof(Color), + typeof(DataGrid), + Color.Black, + propertyChanged: (bindable, oldValue, newValue) => + { + var self = bindable as DataGrid; + if (self.HeaderBordersVisible) + self._headerView.BackgroundColor = (Color)newValue; + + if (self.Columns != null && self.ItemsSource != null) + self.Reload(); + }); + + public static readonly BindableProperty RowsBackgroundColorPaletteProperty = + BindableProperty.Create(nameof(RowsBackgroundColorPalette), + typeof(IColorProvider), + typeof(DataGrid), + new PaletteCollection { default(Color) }, + propertyChanged: (bindable, oldValue, newValue) => + { + var self = bindable as DataGrid; + if (self.Columns != null && self.ItemsSource != null) + self.Reload(); + }); + + public static readonly BindableProperty RowsTextColorPaletteProperty = + BindableProperty.Create( + nameof(RowsTextColorPalette), + typeof(IColorProvider), + typeof(DataGrid), + new PaletteCollection { Color.Black }, + propertyChanged: (bindable, oldValue, newValue) => + { + var self = bindable as DataGrid; + if (self.Columns != null && self.ItemsSource != null) + self.Reload(); + }); + + public static readonly BindableProperty ColumnsProperty = + BindableProperty.Create( + nameof(Columns), + typeof(ColumnCollection), + typeof(DataGrid), + propertyChanged: (bindable, oldValue, newValue) => + { + (bindable as DataGrid).InitHeaderView(); + }, + defaultValueCreator: bindable => { return new ColumnCollection(); } + ); + + public static BindableProperty ItemsSourceProperty = + BindableProperty.Create( + propertyName: nameof(ItemsSource), + returnType: typeof(IEnumerable), + declaringType: typeof(DataGrid), + defaultBindingMode: BindingMode.TwoWay, + propertyChanged: (bindable, oldValue, newValue) => + { + DataGrid self = bindable as DataGrid; + //ObservableCollection Tracking + if (oldValue != null && oldValue is INotifyCollectionChanged) + { + (oldValue as INotifyCollectionChanged).CollectionChanged -= self.HandleItemsSourceCollectionChanged; + } + + if (newValue != null && newValue is INotifyCollectionChanged) + { + (newValue as INotifyCollectionChanged).CollectionChanged += self.HandleItemsSourceCollectionChanged; + + self.InternalItems = new ObservableCollection(((IEnumerable)newValue)); + //Assign listview item source + self.DataList.ItemsSource = self.InternalItems; + self.DataList.SetBinding(ListView.ItemsSourceProperty, new Binding("ItemsSource", source: self)); + } + + if (self.SelectedItem != null && !self.InternalItems.Contains(self.SelectedItem)) + { + self.SelectedItem = null; + } + + if (self.NoDataView != null) + { + if (self.ItemsSource == null || self.InternalItems.Count() == 0) + { + self._noDataView.IsVisible = true; + } + + else if (self._noDataView.IsVisible) + { + self._noDataView.IsVisible = false; + } + } + }); + private void HandleItemsSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + + if (e.NewItems != null) + { + foreach (object item in e.NewItems) + { + InternalItems.Add(item); + } + } + + if (e.OldItems != null) + { + foreach (object item in e.OldItems) + { + InternalItems.Remove(item); + } + } + if (SelectedItem != null && !InternalItems.Contains(SelectedItem)) + { + SelectedItem = null; + } + } + + public static readonly BindableProperty RowHeightProperty = + BindableProperty.Create(nameof(RowHeight), typeof(int), typeof(DataGrid), 40, + propertyChanged: (bindable, oldValue, newValue) => + { + var self = bindable as DataGrid; + self.DataList.RowHeight = (int)newValue; + }); + + + public static readonly BindableProperty HeaderHeightProperty = + BindableProperty.Create(nameof(HeaderHeight), typeof(int), typeof(DataGrid), 40, + propertyChanged: (bindable, oldValue, newValue) => + { + var self = bindable as DataGrid; + self._headerView.HeightRequest = (int)newValue; + }); + + public static readonly BindableProperty IsSortableProperty = + BindableProperty.Create(nameof(IsSortable), typeof(bool), typeof(DataGrid), true); + + public static readonly BindableProperty FontSizeProperty = + BindableProperty.Create(nameof(FontSize), typeof(double), typeof(DataGrid), 13.0); + + public static readonly BindableProperty FontFamilyProperty = + BindableProperty.Create( + nameof(FontFamily), + typeof(string), + typeof(DataGrid), + Font.Default.FontFamily); + + public static readonly BindableProperty SelectedItemProperty = + BindableProperty.Create( + nameof(SelectedItem), + typeof(object), + typeof(DataGrid), + null, + BindingMode.TwoWay, + coerceValue: (bindable, value) => + { + var self = bindable as DataGrid; + if (!self.SelectionEnabled && value != null) + { + throw new InvalidOperationException("Datagrid must be SelectionEnabled=true to set SelectedItem"); + } + if (self.InternalItems != null && self.InternalItems.Contains(value)) + { + return value; + } + else + { + return null; + } + }, + propertyChanged: (bindable, oldValue, newValue) => + { + var self = bindable as DataGrid; + if (self.DataList.SelectedItem != newValue) + { + self.DataList.SelectedItem = newValue; + } + } + ); + + public static readonly BindableProperty SelectionEnabledProperty = + BindableProperty.Create(nameof(SelectionEnabled), typeof(bool), typeof(DataGrid), true, + propertyChanged: (bindable, oldValue, newValue) => + { + var self = bindable as DataGrid; + if (!self.SelectionEnabled && self.SelectedItem != null) + { + self.SelectedItem = null; + } + }); + + public static readonly BindableProperty PullToRefreshCommandProperty = + BindableProperty.Create(nameof(PullToRefreshCommand), typeof(ICommand), typeof(DataGrid), null, + propertyChanged: (bindable, oldValue, newValue) => + { + var self = bindable as DataGrid; + if (newValue == null) + { + self.DataList.IsPullToRefreshEnabled = false; + self.DataList.RefreshCommand = null; + } + else + { + self.DataList.IsPullToRefreshEnabled = true; + self.DataList.RefreshCommand = newValue as ICommand; + } + }); + + public static readonly BindableProperty IsRefreshingProperty = + BindableProperty.Create( + nameof(IsRefreshing), + typeof(bool), + typeof(DataGrid), + false, + BindingMode.TwoWay, + propertyChanged: (bindable, oldValue, newValue) => + { + (bindable as DataGrid).DataList.IsRefreshing = (bool)newValue; + }); + + public static readonly BindableProperty BorderThicknessProperty = + BindableProperty.Create( + nameof(BorderThickness), + typeof(Thickness), + typeof(DataGrid), + new Thickness(1), + propertyChanged: (bindable, oldValue, newValue) => + { + (bindable as DataGrid)._headerView.ColumnSpacing = ((Thickness)newValue).HorizontalThickness / 2; + (bindable as DataGrid)._headerView.Padding = ((Thickness)newValue).HorizontalThickness / 2; + }); + + public static readonly BindableProperty HeaderBordersVisibleProperty = + BindableProperty.Create( + nameof(HeaderBordersVisible), + typeof(bool), + typeof(DataGrid), + true, + propertyChanged: (bindable, oldValue, newValue) => (bindable as DataGrid)._headerView.BackgroundColor = (bool)newValue ? (bindable as DataGrid).BorderColor : (bindable as DataGrid).HeaderBackground); + + public static readonly BindableProperty SortedColumnIndexProperty = + BindableProperty.Create( + nameof(SortedColumnIndex), + typeof(SortData), + typeof(DataGrid), + null, + BindingMode.TwoWay, + validateValue: (bindable, v) => + { + var self = bindable as DataGrid; + var sData = (SortData)v; + + return + sData == null || //setted to null + self.Columns == null || // Columns binded but not setted + self.Columns.Count == 0 || //columns not setted yet + (sData.Index < self.Columns.Count && self.Columns.ElementAt(sData.Index).SortingEnabled); + }, + propertyChanged: (bindable, oldValue, newValue) => + { + var self = bindable as DataGrid; + if (oldValue != newValue) + self.SortItems((SortData)newValue); + }); + + + public static readonly BindableProperty HeaderLabelStyleProperty = + BindableProperty.Create(nameof(HeaderLabelStyle), typeof(Style), typeof(DataGrid)); + + public static readonly BindableProperty AscendingIconProperty = + BindableProperty.Create( + nameof(AscendingIcon), + typeof(ImageSource), + typeof(DataGrid), + ImageSource.FromResource("Xamarin.Forms.DataGrid.up.png", + typeof(DataGrid).GetTypeInfo().Assembly)); + + public static readonly BindableProperty DescendingIconProperty = + BindableProperty.Create( + nameof(DescendingIcon), + typeof(ImageSource), + typeof(DataGrid), + ImageSource.FromResource("Xamarin.Forms.DataGrid.down.png", + typeof(DataGrid).GetTypeInfo().Assembly)); + + public static readonly BindableProperty DescendingIconStyleProperty = + BindableProperty.Create(nameof(DescendingIconStyle), typeof(Style), typeof(DataGrid), null, + + propertyChanged: (bindable, oldValue, newValue) => + { + var self = bindable as DataGrid; + var style = (newValue as Style).Setters.FirstOrDefault(x => x.Property == Image.SourceProperty); + if (style != null) + { + if (style.Value is string vs) + self.DescendingIcon = ImageSource.FromFile(vs); + else + self.DescendingIcon = (ImageSource)style.Value; + } + }); + + public static readonly BindableProperty AscendingIconStyleProperty = + BindableProperty.Create(nameof(AscendingIconStyle), typeof(Style), typeof(DataGrid), null, + coerceValue: (bindable, v) => + { + var self = bindable as DataGrid; + + return v; + }, + + propertyChanged: (bindable, oldValue, newValue) => + { + var self = bindable as DataGrid; + if ((newValue as Style).Setters.Any(x => x.Property == Image.SourceProperty)) + { + var style = (newValue as Style).Setters.FirstOrDefault(x => x.Property == Image.SourceProperty); + if (style != null) + { + if (style.Value is string vs) + self.AscendingIcon = ImageSource.FromFile(vs); + else + self.AscendingIcon = (ImageSource)style.Value; + } + } + }); + + public static readonly BindableProperty NoDataViewProperty = + BindableProperty.Create(nameof(NoDataView), typeof(View), typeof(DataGrid), + propertyChanged: (bindable, oldValue, newValue) => + { + if (oldValue != newValue) + (bindable as DataGrid)._noDataView.Content = newValue as View; + }); + #endregion + + #region Properties + public Color ActiveRowColor + { + get { return (Color)GetValue(ActiveRowColorProperty); } + set { SetValue(ActiveRowColorProperty, value); } + } + + public Color HeaderBackground + { + get { return (Color)GetValue(HeaderBackgroundProperty); } + set { SetValue(HeaderBackgroundProperty, value); } + } + + [Obsolete("Please use HeaderLabelStyle", true)] + public Color HeaderTextColor + { + get; set; + } + + public Color BorderColor + { + get { return (Color)GetValue(BorderColorProperty); } + set { SetValue(BorderColorProperty, value); } + } + + public IColorProvider RowsBackgroundColorPalette + { + get { return (IColorProvider)GetValue(RowsBackgroundColorPaletteProperty); } + set { SetValue(RowsBackgroundColorPaletteProperty, value); } + } + + public IColorProvider RowsTextColorPalette + { + get { return (IColorProvider)GetValue(RowsTextColorPaletteProperty); } + set { SetValue(RowsTextColorPaletteProperty, value); } + } + + public IEnumerable ItemsSource + { + get { return (IEnumerable)GetValue(ItemsSourceProperty); } + set { SetValue(ItemsSourceProperty, value); } + } + + internal ObservableCollection InternalItems + { + get { return _internalItems; } + set + { + if (value != _internalItems) + { + _internalItems = value; + if (IsSortable && SortedColumnIndex != null) + { + SortItems(SortedColumnIndex); + } + } + DataList.ItemsSource = _internalItems; + } + } + + public ColumnCollection Columns + { + get { return (ColumnCollection)GetValue(ColumnsProperty); } + set { SetValue(ColumnsProperty, value); } + } + + public double FontSize + { + get { return (double)GetValue(FontSizeProperty); } + set { SetValue(FontSizeProperty, value); } + } + + [Obsolete("Please use HeaderLabelStyle", true)] + public double HeaderFontSize + { + get; set; + } + + public string FontFamily + { + get { return (string)GetValue(FontFamilyProperty); } + set { SetValue(FontFamilyProperty, value); } + } + + public int RowHeight + { + get { return (int)GetValue(RowHeightProperty); } + set { SetValue(RowHeightProperty, value); } + } + + public int HeaderHeight + { + get { return (int)GetValue(HeaderHeightProperty); } + set { SetValue(HeaderHeightProperty, value); } + } + + public bool IsSortable + { + get { return (bool)GetValue(IsSortableProperty); } + set { SetValue(IsSortableProperty, value); } + } + + public bool SelectionEnabled + { + get { return (bool)GetValue(SelectionEnabledProperty); } + set { SetValue(SelectionEnabledProperty, value); } + } + + public object SelectedItem + { + get { return GetValue(SelectedItemProperty); } + set { SetValue(SelectedItemProperty, value); } + } + + public ICommand PullToRefreshCommand + { + get { return (ICommand)GetValue(PullToRefreshCommandProperty); } + set { SetValue(PullToRefreshCommandProperty, value); } + } + + public bool IsRefreshing + { + get { return (bool)GetValue(IsRefreshingProperty); } + set { SetValue(IsRefreshingProperty, value); } + } + + public Thickness BorderThickness + { + get { return (Thickness)GetValue(BorderThicknessProperty); } + set { SetValue(BorderThicknessProperty, value); } + } + + public bool HeaderBordersVisible + { + get { return (bool)GetValue(HeaderBordersVisibleProperty); } + set { SetValue(HeaderBordersVisibleProperty, value); } + } + + public SortData SortedColumnIndex + { + get { return (SortData)GetValue(SortedColumnIndexProperty); } + set { SetValue(SortedColumnIndexProperty, value); } + } + + public Style HeaderLabelStyle + { + get { return (Style)GetValue(HeaderLabelStyleProperty); } + set { SetValue(HeaderLabelStyleProperty, value); } + } + + public ImageSource AscendingIcon + { + get { return (ImageSource)GetValue(AscendingIconProperty); } + set { SetValue(AscendingIconProperty, value); } + } + + public ImageSource DescendingIcon + { + get { return (ImageSource)GetValue(DescendingIconProperty); } + set { SetValue(DescendingIconProperty, value); } + } + + public Style AscendingIconStyle + { + get { return (Style)GetValue(AscendingIconStyleProperty); } + set { SetValue(AscendingIconStyleProperty, value); } + } + + public Style DescendingIconStyle + { + get { return (Style)GetValue(DescendingIconStyleProperty); } + set { SetValue(DescendingIconStyleProperty, value); } + } + + public View NoDataView + { + get { return (View)GetValue(NoDataViewProperty); } + set { SetValue(NoDataViewProperty, value); } + } + #endregion + + #region UI Methods + protected override void OnParentSet() + { + base.OnParentSet(); + InitHeaderView(); + } + + protected override void OnBindingContextChanged() + { + base.OnBindingContextChanged(); + SetColumnsBindingContext(); + } + + #endregion + + #region Private Methods + + private void Reload() + { + InternalItems = new ObservableCollection(_internalItems); + } + private void SortItems(SortData sData) + { + if (InternalItems == null || sData.Index >= Columns.Count || !Columns[sData.Index].SortingEnabled) + return; + + var items = InternalItems; + var column = Columns[sData.Index]; + SortingOrder order = sData.Order; + + if (!IsSortable) + throw new InvalidOperationException("This DataGrid is not sortable"); + else if (column.PropertyName == null) + throw new InvalidOperationException("Please set the PropertyName property of Column"); + + //Sort + // if (order == SortingOrder.Descendant) + // items = items.OrderByDescending(x => ReflectionUtils.GetValueByPath(x, column.PropertyName)).ToList(); + // else + // items = items.OrderBy(x => ReflectionUtils.GetValueByPath(x, column.PropertyName)).ToList(); + + column.SortingIcon.Style = (order == SortingOrder.Descendant) ? + AscendingIconStyle ?? (Style)_headerView.Resources["DescendingIconStyle"] : + DescendingIconStyle ?? (Style)_headerView.Resources["AscendingIconStyle"]; + + //Support DescendingIcon property (if setted) + if (!column.SortingIcon.Style.Setters.Any(x => x.Property == Image.SourceProperty)) + { + if (order == SortingOrder.Descendant && DescendingIconProperty.DefaultValue != DescendingIcon) + column.SortingIcon.Source = DescendingIcon; + if (order == SortingOrder.Ascendant && AscendingIconProperty.DefaultValue != AscendingIcon) + column.SortingIcon.Source = AscendingIcon; + } + + for (int i = 0; i < Columns.Count; i++) + { + if (i != sData.Index) + { + if (Columns[i].SortingIcon.Style != null) + Columns[i].SortingIcon.Style = null; + if (Columns[i].SortingIcon.Source != null) + Columns[i].SortingIcon.Source = null; + _sortingOrders[i] = SortingOrder.None; + } + } + + _internalItems = items; + + _sortingOrders[sData.Index] = order; + SortedColumnIndex = sData; + } + + private View GetHeaderViewForColumn(DataGridColumn column) + { + column.HeaderLabel.Style = column.HeaderLabelStyle ?? this.HeaderLabelStyle ?? (Style)_headerView.Resources["HeaderDefaultStyle"]; + + Grid grid = new Grid + { + ColumnSpacing = 0, + }; + + grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }); + grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) }); + + if (IsSortable) + { + column.SortingIcon.Style = (Style)_headerView.Resources["ImageStyleBase"]; + + grid.Children.Add(column.SortingIcon); + Grid.SetColumn(column.SortingIcon, 1); + + TapGestureRecognizer tgr = new TapGestureRecognizer(); + tgr.Tapped += (s, e) => + { + int index = Columns.IndexOf(column); + SortingOrder order = _sortingOrders[index] == SortingOrder.Ascendant ? SortingOrder.Descendant : SortingOrder.Ascendant; + + if (Columns.ElementAt(index).SortingEnabled) + SortedColumnIndex = new SortData(index, order); + }; + grid.GestureRecognizers.Add(tgr); + } + + grid.Children.Add(column.HeaderLabel); + + return grid; + } + + private void InitHeaderView() + { + SetColumnsBindingContext(); + _headerView.Children.Clear(); + _headerView.ColumnDefinitions.Clear(); + _sortingOrders.Clear(); + + _headerView.Padding = new Thickness(BorderThickness.Left, BorderThickness.Top, BorderThickness.Right, 0); + _headerView.ColumnSpacing = BorderThickness.HorizontalThickness / 2; + + if (Columns != null) + { + foreach (var col in Columns) + { + _headerView.ColumnDefinitions.Add(new ColumnDefinition { Width = col.Width }); + + var cell = GetHeaderViewForColumn(col); + + _headerView.Children.Add(cell); + Grid.SetColumn(cell, Columns.IndexOf(col)); + + _sortingOrders.Add(Columns.IndexOf(col), SortingOrder.None); + } + } + } + + private void SetColumnsBindingContext() + { + if (Columns != null) + foreach (var c in Columns) + c.BindingContext = BindingContext; + } + + #endregion Private Methods + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/DataGridColumn.cs b/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/DataGridColumn.cs new file mode 100644 index 0000000..59d2ab5 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/DataGridColumn.cs @@ -0,0 +1,135 @@ +using System; +using Xamarin.Forms; + +namespace Aurora.Design.Components.DataGrid +{ + public class DataGridColumn : BindableObject, IDefinition + { + #region bindable properties + public static readonly BindableProperty WidthProperty = + BindableProperty.Create(nameof(Width), typeof(GridLength), typeof(DataGridColumn), new GridLength(1, GridUnitType.Star), + propertyChanged: (bindable, oldValue, newValue) => + { + if (oldValue != newValue) + { + (bindable as DataGridColumn).OnSizeChanged(); + }; + }); + + public static readonly BindableProperty TitleProperty = + BindableProperty.Create(nameof(Title), typeof(string), typeof(DataGridColumn), string.Empty, + propertyChanged: (b, o, n) => (b as DataGridColumn).HeaderLabel.Text = (string)n); + + public static readonly BindableProperty FormattedTitleProperty = + BindableProperty.Create(nameof(FormattedTitle), typeof(FormattedString), typeof(DataGridColumn), + propertyChanged: (b, o, n) => (b as DataGridColumn).HeaderLabel.FormattedText = (FormattedString)n); + + public static readonly BindableProperty PropertyNameProperty = + BindableProperty.Create(nameof(PropertyName), typeof(string), typeof(DataGridColumn), null); + + public static readonly BindableProperty StringFormatProperty = + BindableProperty.Create(nameof(StringFormat), typeof(string), typeof(DataGridColumn), null); + + public static readonly BindableProperty CellTemplateProperty = + BindableProperty.Create(nameof(CellTemplate), typeof(DataTemplate), typeof(DataGridColumn), null); + + public static readonly BindableProperty HorizontalContentAlignmentProperty = + BindableProperty.Create(nameof(HorizontalContentAlignment), typeof(LayoutOptions), typeof(DataGridColumn), LayoutOptions.Center); + + public static readonly BindableProperty VerticalContentAlignmentProperty = + BindableProperty.Create(nameof(VerticalContentAlignment), typeof(LayoutOptions), typeof(DataGridColumn), LayoutOptions.Center); + + public static readonly BindableProperty SortingEnabledProperty = + BindableProperty.Create(nameof(SortingEnabled), typeof(bool), typeof(DataGridColumn), true); + + public static readonly BindableProperty HeaderLabelStyleProperty = + BindableProperty.Create(nameof(HeaderLabelStyle), typeof(Style), typeof(DataGridColumn), + propertyChanged: (b, o, n) => + { + if ((b as DataGridColumn).HeaderLabel != null && (o != n)) + (b as DataGridColumn).HeaderLabel.Style = n as Style; + }); + + #endregion + + #region properties + + public GridLength Width + { + get { return (GridLength)GetValue(WidthProperty); } + set { SetValue(WidthProperty, value); } + } + + public string Title + { + get { return (string)GetValue(TitleProperty); } + set { SetValue(TitleProperty, value); } + } + + public FormattedString FormattedTitle + { + get { return (string)GetValue(FormattedTitleProperty); } + set { SetValue(FormattedTitleProperty, value); } + } + public string PropertyName + { + get { return (string)GetValue(PropertyNameProperty); } + set { SetValue(PropertyNameProperty, value); } + } + + public string StringFormat + { + get { return (string)GetValue(StringFormatProperty); } + set { SetValue(StringFormatProperty, value); } + } + + public DataTemplate CellTemplate + { + get { return (DataTemplate)GetValue(CellTemplateProperty); } + set { SetValue(CellTemplateProperty, value); } + } + + internal Image SortingIcon { get; set; } + internal Label HeaderLabel { get; set; } + + public LayoutOptions HorizontalContentAlignment + { + get { return (LayoutOptions)GetValue(HorizontalContentAlignmentProperty); } + set { SetValue(HorizontalContentAlignmentProperty, value); } + } + + public LayoutOptions VerticalContentAlignment + { + get { return (LayoutOptions)GetValue(VerticalContentAlignmentProperty); } + set { SetValue(VerticalContentAlignmentProperty, value); } + } + + public bool SortingEnabled + { + get { return (bool)GetValue(SortingEnabledProperty); } + set { SetValue(SortingEnabledProperty, value); } + } + + public Style HeaderLabelStyle + { + get { return (Style)GetValue(HeaderLabelStyleProperty); } + set { SetValue(HeaderLabelStyleProperty, value); } + } + + #endregion + + public event EventHandler SizeChanged; + + public DataGridColumn() + { + HeaderLabel = new Label(); + SortingIcon = new Image(); + } + + void OnSizeChanged() + { + SizeChanged?.Invoke(this, EventArgs.Empty); + } + } + +} diff --git a/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/DataGridRowTemplateSelector.cs b/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/DataGridRowTemplateSelector.cs new file mode 100644 index 0000000..b27648b --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/DataGridRowTemplateSelector.cs @@ -0,0 +1,30 @@ +using Xamarin.Forms; +namespace Aurora.Design.Components.DataGrid +{ + internal class DataGridRowTemplateSelector : DataTemplateSelector + { + private static DataTemplate _dataGridRowTemplate; + + public DataGridRowTemplateSelector() + { + _dataGridRowTemplate = new DataTemplate(typeof(DataGridViewCell)); + } + + protected override DataTemplate OnSelectTemplate(object item, BindableObject container) + { + ListView listView = container as ListView; + DataGrid dataGrid = listView.Parent as DataGrid; + var items = dataGrid.InternalItems; + + _dataGridRowTemplate.SetValue(DataGridViewCell.DataGridProperty, dataGrid); + _dataGridRowTemplate.SetValue(DataGridViewCell.RowContextProperty, item); + + if (items != null) + { + _dataGridRowTemplate.SetValue(DataGridViewCell.IndexProperty, items.IndexOf(item)); + } + + return _dataGridRowTemplate; + } + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/DataGridViewCell.cs b/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/DataGridViewCell.cs new file mode 100644 index 0000000..7ba1c1f --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/DataGridViewCell.cs @@ -0,0 +1,163 @@ +using Xamarin.Forms; +namespace Aurora.Design.Components.DataGrid +{ + internal sealed class DataGridViewCell : ViewCell + { + #region Fields + Grid _mainLayout; + Color _bgColor; + Color _textColor; + bool _hasSelected; + #endregion + + #region properties + public DataGrid DataGrid + { + get { return (DataGrid)GetValue(DataGridProperty); } + set { SetValue(DataGridProperty, value); } + } + + public int Index + { + get { return (int)GetValue(IndexProperty); } + set { SetValue(IndexProperty, value); } + } + + public object RowContext + { + get { return GetValue(RowContextProperty); } + set { SetValue(RowContextProperty, value); } + } + #endregion + + #region Bindable Properties + public static readonly BindableProperty DataGridProperty = + BindableProperty.Create( + nameof(DataGrid), + typeof(DataGrid), + typeof(DataGridViewCell), + null, + propertyChanged: (b, o, n) => (b as DataGridViewCell).CreateView()); + + public static readonly BindableProperty IndexProperty = + BindableProperty.Create( + nameof(Index), + typeof(int), + typeof(DataGridViewCell), + 0, + propertyChanged: (b, o, n) => (b as DataGridViewCell).UpdateBackgroundColor()); + + public static readonly BindableProperty RowContextProperty = + BindableProperty.Create( + nameof(RowContext), + typeof(object), + typeof(DataGridViewCell), + propertyChanged: (b, o, n) => (b as DataGridViewCell).UpdateBackgroundColor()); + #endregion + + #region Methods + private void CreateView() + { + UpdateBackgroundColor(); + + _mainLayout = new Grid() + { + BackgroundColor = DataGrid.BorderColor, + RowSpacing = 0, + ColumnSpacing = DataGrid.BorderThickness.HorizontalThickness / 2, + Padding = new Thickness(DataGrid.BorderThickness.HorizontalThickness / 2, + DataGrid.BorderThickness.VerticalThickness / 2), + }; + + foreach (var col in DataGrid.Columns) + { + _mainLayout.ColumnDefinitions.Add(new ColumnDefinition() { Width = col.Width }); + View cell; + + if (col.CellTemplate != null) + { + cell = new ContentView() { Content = col.CellTemplate.CreateContent() as View }; + if (col.PropertyName != null) + { + cell.SetBinding(BindingContextProperty, + new Binding(col.PropertyName, source: RowContext)); + } + } + else + { + var text = new Label + { + TextColor = _textColor, + HorizontalOptions = col.HorizontalContentAlignment, + VerticalOptions = col.VerticalContentAlignment, + LineBreakMode = LineBreakMode.WordWrap, + }; + text.SetBinding(Label.TextProperty, new Binding(col.PropertyName, BindingMode.Default, stringFormat: col.StringFormat)); + text.SetBinding(Label.FontSizeProperty, new Binding(DataGrid.FontSizeProperty.PropertyName, BindingMode.Default, source: DataGrid)); + text.SetBinding(Label.FontFamilyProperty, new Binding(DataGrid.FontFamilyProperty.PropertyName, BindingMode.Default, source: DataGrid)); + + cell = new ContentView + { + Padding = 0, + BackgroundColor = _bgColor, + Content = text, + }; + } + + _mainLayout.Children.Add(cell); + Grid.SetColumn(cell, DataGrid.Columns.IndexOf(col)); + } + + View = _mainLayout; + } + + private void UpdateBackgroundColor() + { + _hasSelected = DataGrid.SelectedItem == RowContext; + int actualIndex = DataGrid?.InternalItems?.IndexOf(BindingContext) ?? -1; + if (actualIndex > -1) + { + _bgColor = (DataGrid.SelectionEnabled && DataGrid.SelectedItem != null && DataGrid.SelectedItem == RowContext) ? + DataGrid.ActiveRowColor : DataGrid.RowsBackgroundColorPalette.GetColor(Index, BindingContext); + _textColor = DataGrid.RowsTextColorPalette.GetColor(actualIndex, BindingContext); + + ChangeColor(_bgColor); + } + } + + private void ChangeColor(Color color) + { + foreach (var v in _mainLayout.Children) + { + v.BackgroundColor = color; + var contentView = v as ContentView; + if (contentView?.Content is Label) + ((Label)contentView.Content).TextColor = _textColor; + } + } + + protected override void OnBindingContextChanged() + { + base.OnBindingContextChanged(); + UpdateBackgroundColor(); + } + + protected override void OnParentSet() + { + base.OnParentSet(); + if (Parent != null) + DataGrid.ItemSelected += DataGrid_ItemSelected; + else + DataGrid.ItemSelected -= DataGrid_ItemSelected; + } + + private void DataGrid_ItemSelected(object sender, SelectedItemChangedEventArgs e) + { + if (DataGrid.SelectionEnabled && (e.SelectedItem == RowContext || _hasSelected)) + { + UpdateBackgroundColor(); + } + } + #endregion + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/IColorProvider.cs b/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/IColorProvider.cs new file mode 100644 index 0000000..3cc9825 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/IColorProvider.cs @@ -0,0 +1,8 @@ +using Xamarin.Forms; +namespace Aurora.Design.Components.DataGrid +{ + public interface IColorProvider + { + Color GetColor(int rowIndex, object item); + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/PaletteCollection.cs b/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/PaletteCollection.cs new file mode 100644 index 0000000..770c8d9 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/PaletteCollection.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using System.Linq; +using Xamarin.Forms; + +namespace Aurora.Design.Components.DataGrid +{ + public sealed class PaletteCollection : List, IColorProvider + { + public Color GetColor(int rowIndex, object item) + { + if (Count > 0) + return this.ElementAt(rowIndex % Count); + else + return default(Color); + } + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/SortData.cs b/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/SortData.cs new file mode 100644 index 0000000..1552d09 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/SortData.cs @@ -0,0 +1,51 @@ +using System; +using Xamarin.Forms; + +namespace Aurora.Design.Components.DataGrid +{ + + [TypeConverter(typeof(SortDataTypeConverter))] + public class SortData + { + + #region ctor + public SortData() + { + } + + public SortData(int index, SortingOrder order) + { + Index = index; + Order = order; + } + + #endregion + + #region Properties + public SortingOrder Order { get; set; } + + public int Index { get; set; } + #endregion + + public static implicit operator SortData(int index) + { + return new SortData + { + Index = Math.Abs(index), + Order = index < 0 ? SortingOrder.Descendant : SortingOrder.Ascendant + }; + } + + public override bool Equals(object obj) + { + if (obj is SortData) + { + SortData other = obj as SortData; + return other.Index == Index && other.Order == Order; + } + else + return false; + } + + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/SortDataTypeConverter.cs b/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/SortDataTypeConverter.cs new file mode 100644 index 0000000..baf0d0d --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/SortDataTypeConverter.cs @@ -0,0 +1,24 @@ +using System; +using Xamarin.Forms; + +namespace Aurora.Design.Components.DataGrid +{ + public class SortDataTypeConverter : TypeConverter + { + + public override bool CanConvertFrom(Type sourceType) + { + return base.CanConvertFrom(sourceType); + } + + public override object ConvertFromInvariantString(string value) + { + int index = 0; + + if (int.TryParse(value, out index)) + return (SortData)index; + else + return null; + } + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/SortingOrder.cs b/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/SortingOrder.cs new file mode 100644 index 0000000..78c9520 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/SortingOrder.cs @@ -0,0 +1,9 @@ +namespace Aurora.Design.Components.DataGrid +{ + public enum SortingOrder + { + None = 0, + Ascendant = 1, + Descendant = 2, + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/down.png b/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/down.png new file mode 100644 index 0000000..3a359e8 Binary files /dev/null and b/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/down.png differ diff --git a/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/up.png b/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/up.png new file mode 100644 index 0000000..bd675ae Binary files /dev/null and b/aurora-sharp-desktop/Aurora/Design/Components/DataGrid/up.png differ diff --git a/aurora-sharp-desktop/Aurora/Design/Components/Dialogs/Modal.xaml b/aurora-sharp-desktop/Aurora/Design/Components/Dialogs/Modal.xaml new file mode 100644 index 0000000..0d275d3 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/Dialogs/Modal.xaml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/aurora-sharp-desktop/Aurora/Design/Components/Dialogs/Modal.xaml.cs b/aurora-sharp-desktop/Aurora/Design/Components/Dialogs/Modal.xaml.cs new file mode 100644 index 0000000..d356dca --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/Dialogs/Modal.xaml.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using Xamarin.Forms; + +namespace Aurora.Design.Components.Dialogs +{ + public partial class Modal : ContentView + { + public Modal() + { + InitializeComponent(); + } + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Components/HorizontalList/HorizontalList.cs b/aurora-sharp-desktop/Aurora/Design/Components/HorizontalList/HorizontalList.cs new file mode 100755 index 0000000..c5b95ee --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/HorizontalList/HorizontalList.cs @@ -0,0 +1,208 @@ +using System; +using System.Linq; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Windows.Input; +using Xamarin.Forms; + +namespace Aurora.Design.Components.HorizontalList +{ + public class HorizontalList : Grid + { + private ICommand _innerSelectedCommand; + private readonly ScrollView _scrollView; + private readonly StackLayout _itemsStackLayout; + + public event EventHandler SelectedItemChanged; + private NotifyCollectionChangedEventHandler _itemsChangedHandler; + + public StackOrientation ListOrientation { get; set; } + + public double Spacing { get; set; } + + public static readonly BindableProperty SelectedCommandProperty = + BindableProperty.Create("SelectedCommand", typeof(ICommand), typeof(HorizontalList), null); + + public static readonly BindableProperty ItemsSourceProperty = + BindableProperty.Create("ItemsSource", + returnType: typeof(ObservableCollection), + declaringType: typeof(HorizontalList), + defaultValue: default(ObservableCollection), + defaultBindingMode: BindingMode.TwoWay, + propertyChanged: ItemsSourceChanged); + + public static readonly BindableProperty SelectedItemProperty = + BindableProperty.Create("SelectedItem", typeof(object), typeof(HorizontalList), null, BindingMode.TwoWay, propertyChanged: OnSelectedItemChanged); + + public static readonly BindableProperty ItemTemplateProperty = + BindableProperty.Create("ItemTemplate", typeof(DataTemplate), typeof(HorizontalList), default(DataTemplate)); + + public ICommand SelectedCommand + { + get { return (ICommand)GetValue(SelectedCommandProperty); } + set { SetValue(SelectedCommandProperty, value); } + } + + public ObservableCollection ItemsSource + { + get { return (ObservableCollection)GetValue(ItemsSourceProperty); } + set { SetValue(ItemsSourceProperty, value); } + } + + public object SelectedItem + { + get { return (object)GetValue(SelectedItemProperty); } + set { SetValue(SelectedItemProperty, value); } + } + + public DataTemplate ItemTemplate + { + get { return (DataTemplate)GetValue(ItemTemplateProperty); } + set { SetValue(ItemTemplateProperty, value); } + } + + private static void ItemsSourceChanged(BindableObject bindable, object oldValue, object newValue) + { + HorizontalList itemsLayout = bindable as HorizontalList; + itemsLayout.SetItems(); + } + + public HorizontalList() + { + _itemsChangedHandler = OnItemsChanged; + // BackgroundColor = Color.FromHex("#1E2634"); + Spacing = 6; + _scrollView = new ScrollView(); + _itemsStackLayout = new StackLayout + { + Padding = Padding, + Spacing = Spacing, + HorizontalOptions = LayoutOptions.FillAndExpand + }; + + _scrollView.Content = _itemsStackLayout; + Children.Add(_scrollView); + } + + ~HorizontalList() + { + ItemsSource.CollectionChanged -= _itemsChangedHandler; + } + + protected virtual void SetItems() + { + _itemsStackLayout.Children.Clear(); + _itemsStackLayout.Spacing = Spacing; + + _innerSelectedCommand = new Command(view => + { + SelectedItem = view.BindingContext; + SelectedItem = null; // Allowing item second time selection + }); + + _itemsStackLayout.Orientation = ListOrientation; + _scrollView.Orientation = ListOrientation == StackOrientation.Horizontal + ? ScrollOrientation.Horizontal + : ScrollOrientation.Vertical; + + if (ItemsSource == null) + { + return; + } + + //Setup collection events + ItemsSource.CollectionChanged += _itemsChangedHandler; + + foreach (var item in ItemsSource) + { + _itemsStackLayout.Children.Add(GetItemView(item)); + } + + SelectedItem = null; + } + + protected virtual View GetItemView(object item) + { + var content = ItemTemplate.CreateContent(); + var view = content as View; + + if (view == null) + { + return null; + } + + view.BindingContext = item; + + var gesture = new TapGestureRecognizer + { + Command = _innerSelectedCommand, + CommandParameter = view + }; + + AddGesture(view, gesture); + return view; + } + + private void AddGesture(View view, TapGestureRecognizer gesture) + { + view.GestureRecognizers.Add(gesture); + + var layout = view as Layout; + + if (layout == null) + { + return; + } + + foreach (var child in layout.Children) + { + AddGesture(child, gesture); + } + } + + private static void OnSelectedItemChanged(BindableObject bindable, object oldValue, object newValue) + { + var itemsView = (HorizontalList)bindable; + + if (newValue == oldValue && newValue != null) + { + return; + } + + itemsView.SelectedItemChanged?.Invoke(itemsView, EventArgs.Empty); + + if (itemsView.SelectedCommand?.CanExecute(newValue) ?? false) + { + itemsView.SelectedCommand?.Execute(newValue); + } + } + + private void OnItemsChanged(object sender, NotifyCollectionChangedEventArgs e) + { + switch (e.Action) + { + case System.Collections.Specialized.NotifyCollectionChangedAction.Add: + { + foreach (object item in e.NewItems) + { + _itemsStackLayout.Children.Add(GetItemView(item)); + } + break; + } + case System.Collections.Specialized.NotifyCollectionChangedAction.Remove: + { + foreach (object item in e.OldItems) + { + //Clear layout and rebuild + _itemsStackLayout.Children.Clear(); + foreach (var source in ItemsSource) + { + _itemsStackLayout.Children.Add(GetItemView(item)); + } + } + break; + } + } + } + } +} \ No newline at end of file diff --git a/aurora-sharp-desktop/Aurora/Design/Components/ImageButton/ImageButton.xaml b/aurora-sharp-desktop/Aurora/Design/Components/ImageButton/ImageButton.xaml new file mode 100644 index 0000000..0ad022c --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/ImageButton/ImageButton.xaml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/aurora-sharp-desktop/Aurora/Design/Components/ImageButton/ImageButton.xaml.cs b/aurora-sharp-desktop/Aurora/Design/Components/ImageButton/ImageButton.xaml.cs new file mode 100644 index 0000000..cf5d90a --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/ImageButton/ImageButton.xaml.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using Xamarin.Forms; + +namespace Aurora.Design.Components.ImageButton +{ + public partial class ImageButton : ContentView + { + public ImageButton() + { + InitializeComponent(); + } + + public static readonly BindableProperty SourceProperty = + BindableProperty.Create( + "Source", + typeof(ImageSource), + typeof(ImageButton), + null, + BindingMode.TwoWay, + propertyChanged: (bindable, oldValue, newValue) => + { + ImageButton control = (ImageButton)bindable; + + control.imgButton.Source = (ImageSource)newValue; + }); + + public static readonly BindableProperty CommandProperty = BindableProperty.Create( + "Command", + typeof(Command), + typeof(ImageButton), + null, + propertyChanged: (bindable, oldValue, newValue) => + { + ImageButton control = (ImageButton)bindable; + var command = (Command)newValue; + + CanExecute(command, control); + + command.CanExecuteChanged += (sender, e) => + { + CanExecute(sender, control); + }; + }); + + public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create( + "CommandParameter", + typeof(object), + typeof(ImageButton), + null); + + private static void CanExecute(object sender, ImageButton control) + { + var cmd = (Command)sender; + control.imgButton.IsEnabled = cmd.CanExecute(null); + } + + public ImageSource Source + { + get { return (ImageSource)GetValue(SourceProperty); } + set { SetValue(SourceProperty, value); } + } + + + public event EventHandler Tapped; + + public Command Command + { + get { return (Command)GetValue(CommandProperty); } + set { SetValue(CommandProperty, value); } + } + + public object CommandParameter + { + get { return GetValue(CommandParameterProperty); } + set { SetValue(CommandParameterProperty, value); } + } + + protected void OnButtonTapped(object sender, EventArgs args) + { + object resolvedParameter; + + if (CommandParameter != null) + { + resolvedParameter = CommandParameter; + } + else + { + resolvedParameter = args; + } + + if (Command?.CanExecute(resolvedParameter) ?? true) + { + this.AbortAnimation("imgButtonAnim"); + new Animation(v => imgButton.Scale = v, 1, 0.5).Commit(imgButton, "imgButtonAnim", 16, 150, Easing.SinOut, + (v, c) => + { + imgButton.Scale = 1; + Tapped?.Invoke(this, args); + Command?.Execute(resolvedParameter); + }); + } + } + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Components/Library/Library.css b/aurora-sharp-desktop/Aurora/Design/Components/Library/Library.css new file mode 100644 index 0000000..14ba302 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/Library/Library.css @@ -0,0 +1,7 @@ +Label { + margin-left: 25; + text-align: left; + vertical-align: middle; + word-wrap: break-word; + font-size: 14; +} diff --git a/aurora-sharp-desktop/Aurora/Design/Components/Library/Library.xaml b/aurora-sharp-desktop/Aurora/Design/Components/Library/Library.xaml new file mode 100644 index 0000000..8c06a8c --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/Library/Library.xaml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + White + + + + + Transparent + + + + + \ No newline at end of file diff --git a/aurora-sharp-desktop/Aurora/Design/Components/Library/Library.xaml.cs b/aurora-sharp-desktop/Aurora/Design/Components/Library/Library.xaml.cs new file mode 100644 index 0000000..698dd90 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/Library/Library.xaml.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Xamarin.Forms; + +namespace Aurora.Design.Components.Library +{ + public partial class Library : ContentView + { + public Library() + { + InitializeComponent(); + this.LibraryDataGrid.ItemSelected += (sender, e) => + { + this.SelectedItem = e.SelectedItem; + }; + } + + #region ItemsSource Property + /// + /// Bindable Property for the ItemsSource of the datagrid. + /// + /// + /// + /// + public static readonly BindableProperty ItemsSourceProperty = + BindableProperty.Create(propertyName: "ItemsSource", + returnType: typeof(IEnumerable), + declaringType: typeof(Library), + defaultBindingMode: BindingMode.Default, + propertyChanged: (BindableObject bindable, object oldValue, object newValue) => + { + Library control = bindable as Library; + control.LibraryDataGrid.ItemsSource = (IEnumerable)newValue; + }); + + + /// + /// Backing property for the ItemsSource property. + /// + /// + public IEnumerable ItemsSource + { + get + { + return (IEnumerable)GetValue(ItemsSourceProperty); + } + set + { + SetValue(ItemsSourceProperty, value); + } + } + + + #endregion ItemsSource Property + + /// + /// Bindable property for the selected item field on the datagrid. + /// + /// + /// + /// + public static readonly BindableProperty SelectedItemProperty = + BindableProperty.Create(propertyName: "SelectedItem", + returnType: typeof(object), + declaringType: typeof(Library), + defaultBindingMode: BindingMode.TwoWay); + + /// + /// Backing property for the SelectedItem property. + /// + /// + public object SelectedItem + { + get + { + return ((object)GetValue(SelectedItemProperty)); + } + set + { + SetValue(SelectedItemProperty, value); + } + } + + + /// + /// Bindable property for the item double clicked command + /// + /// + /// + /// + public static readonly BindableProperty ItemDoubleClickedProperty = + BindableProperty.Create(propertyName: "ItemDoubleClicked", + returnType: typeof(Command), + declaringType: typeof(Library), + propertyChanged: OnDoubleClickPropertyChanged); + + /// + /// Public backing property + /// + /// + public Command ItemDoubleClicked + { + get + { + return (Command)GetValue(ItemDoubleClickedProperty); + } + set + { + SetValue(ItemDoubleClickedProperty, value); + } + } + + /// + /// Event handler for double click property. Adds command execute handler. + /// + /// + /// + /// + private static void OnDoubleClickPropertyChanged(BindableObject bindable, object newValue, object oldValue) + { + Library control = bindable as Library; + var dataGrid = control.LibraryDataGrid; + if (dataGrid.GestureRecognizers.Count > 0) + { + var gestureRecognizer = dataGrid.GestureRecognizers.First(); + + if (gestureRecognizer is TapGestureRecognizer) + { + TapGestureRecognizer tap = gestureRecognizer as TapGestureRecognizer; + tap.Tapped += (sender, e) => + { + control.ItemDoubleClicked.Execute(null); + }; + } + } + } + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Components/MediaPlayer/Player.css b/aurora-sharp-desktop/Aurora/Design/Components/MediaPlayer/Player.css new file mode 100644 index 0000000..4cd53b3 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/MediaPlayer/Player.css @@ -0,0 +1,44 @@ +#PlayerControlContainer { + background-color: #303030; +} + +Label { + color: white; + text-align: left; + vertical-align: middle; + word-wrap: break-word; +} + +#MediaInfoContainer { + width: 150; + margin-top: 10; + margin-bottom: 10; +} + + #MediaInfoContainer label { + margin-left: 20; + } + +#AlbumArtBoxView { + background-color: black; + width: 80; +} + +.PlayButton { + width: 40; +} + +.DirectionButton { + width: 30; +} + +.LibraryButton { + width: 25; +} + +ImageButton { + margin-top: 10; + margin-left: 15; + margin-right: 15; + margin-bottom: 10; +} diff --git a/aurora-sharp-desktop/Aurora/Design/Components/MediaPlayer/Player.xaml b/aurora-sharp-desktop/Aurora/Design/Components/MediaPlayer/Player.xaml new file mode 100644 index 0000000..6966c06 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/MediaPlayer/Player.xaml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/aurora-sharp-desktop/Aurora/Design/Components/MediaPlayer/Player.xaml.cs b/aurora-sharp-desktop/Aurora/Design/Components/MediaPlayer/Player.xaml.cs new file mode 100644 index 0000000..8f3802b --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/MediaPlayer/Player.xaml.cs @@ -0,0 +1,303 @@ +using System; +using Xamarin.Forms; + +namespace Aurora.Design.Components.MediaPlayer +{ + public partial class Player : ContentView + { + public Player() + { + + InitializeComponent(); + PlayButton.Source = ImageSource.FromFile("Resources/play.png"); + } + + #region SongTitle Bindable + public static readonly BindableProperty SongTitleProperty = + BindableProperty.Create(propertyName: "SongTitle", + returnType: typeof(string), + declaringType: typeof(Player), + propertyChanged: (BindableObject bindable, object oldValue, object newValue) => + { + Player component = bindable as Player; + component.SongTitleLabel.Text = (string)newValue; + }); + + public string SongTitle + { + get + { + return (string)GetValue(SongTitleProperty); + } + set + { + SetValue(SongTitleProperty, value); + } + } + + #endregion SongTitle Bindable + + #region ArtistName Bindable + public static readonly BindableProperty ArtistNameProperty = + BindableProperty.Create(propertyName: "ArtistName", + returnType: typeof(string), + declaringType: typeof(Player), + propertyChanged: (BindableObject bindable, object oldValue, object newValue) => + { + Player component = bindable as Player; + component.ArtistNameLabel.Text = (string)newValue; + }); + + public string ArtistName + { + get + { + return (string)GetValue(ArtistNameProperty); + } + set + { + SetValue(ArtistNameProperty, value); + } + } + + #endregion ArtistName Bindable + + #region PreviousButton + public static readonly BindableProperty PreviousButtonCommandProperty = + BindableProperty.Create(propertyName: "PreviousButtonCommand", + returnType: typeof(Command), + propertyChanged: OnPreviousButtonPropertyChanged, + declaringType: typeof(Player)); + + public Command PreviousButtonCommand + { + get + { + return (Command)GetValue(PreviousButtonCommandProperty); + } + set + { + SetValue(PreviousButtonCommandProperty, value); + } + } + + private void OnPreviousButtonClicked(object sender, EventArgs args) + { + if (PreviousButtonCommand.CanExecute(null)) + { + PreviousButtonCommand.Execute(null); + PreviousButtonCommand.ChangeCanExecute(); + PlayButtonCommand.ChangeCanExecute(); + NextButtonCommand.ChangeCanExecute(); + } + } + + /// + /// Event handler to hook up can execute events on property changed + /// + /// + /// + /// + private static void OnPreviousButtonPropertyChanged(BindableObject bindable, object oldValue, object newValue) + { + Player component = bindable as Player; + if (newValue is Command) + { + Command cmd = newValue as Command; + component.PreviousButton.Tapped += component.OnPreviousButtonClicked; + cmd.CanExecuteChanged += (sender, e) => OnPreviousButtonCanExecuteChanged(sender, e, component, cmd); + } + + if (oldValue is Command && oldValue != null) + { + Command cmd = newValue as Command; + component.PreviousButton.Tapped -= component.OnPreviousButtonClicked; + cmd.CanExecuteChanged -= (sender, e) => OnPreviousButtonCanExecuteChanged(sender, e, component, cmd); + } + } + + /// + /// Can execute changed event handler + /// + /// + /// + /// + /// + private static void OnPreviousButtonCanExecuteChanged(object sender, + EventArgs eventArgs, + Player component, + Command cmd) + { + component.NextButton.IsEnabled = cmd.CanExecute(null); + } + #endregion PreviousButton + + #region PlayButton + public static readonly BindableProperty PlayButtonCommandProperty = + BindableProperty.Create(propertyName: "PlayButtonCommand", + returnType: typeof(Command), + propertyChanged: OnPlayButtonPropertyChanged, + declaringType: typeof(Player)); + + public Command PlayButtonCommand + { + get + { + return (Command)GetValue(PlayButtonCommandProperty); + } + set + { + SetValue(PlayButtonCommandProperty, value); + } + } + + private void OnPlayButtonClicked(object sender, EventArgs args) + { + if (PlayButtonCommand.CanExecute(null)) + { + PlayButtonCommand.Execute(null); + PreviousButtonCommand.ChangeCanExecute(); + PlayButtonCommand.ChangeCanExecute(); + NextButtonCommand.ChangeCanExecute(); + } + } + + /// + /// Event handler to hook up can execute events on property changed + /// + /// + /// + /// + private static void OnPlayButtonPropertyChanged(BindableObject bindable, object oldValue, object newValue) + { + Player component = bindable as Player; + if (newValue is Command) + { + Command cmd = newValue as Command; + component.PlayButton.Tapped += component.OnPlayButtonClicked; + cmd.CanExecuteChanged += (sender, e) => OnPlayButtonCanExecuteChanged(sender, e, component, cmd); + } + + if (oldValue is Command && oldValue != null) + { + Command cmd = newValue as Command; + component.PlayButton.Tapped -= component.OnPlayButtonClicked; + cmd.CanExecuteChanged -= (sender, e) => OnPlayButtonCanExecuteChanged(sender, e, component, cmd); + } + } + + /// + /// Can execute changed event handler + /// + /// + /// + /// + /// + private static void OnPlayButtonCanExecuteChanged(object sender, + EventArgs eventArgs, + Player component, + Command cmd) + { + component.NextButton.IsEnabled = cmd.CanExecute(null); + } + #endregion PlayButton + + #region NextButton + public static readonly BindableProperty NextButtonCommandProperty = + BindableProperty.Create(propertyName: "NextButtonCommand", + returnType: typeof(Command), + declaringType: typeof(Player), + propertyChanged: OnNextButtonPropertyChanged); + + public Command NextButtonCommand + { + get + { + return (Command)GetValue(NextButtonCommandProperty); + } + set + { + SetValue(NextButtonCommandProperty, value); + } + } + + private void OnNextButtonClicked(object sender, EventArgs args) + { + if (NextButtonCommand.CanExecute(null)) + { + NextButtonCommand.Execute(null); + PreviousButtonCommand.ChangeCanExecute(); + PlayButtonCommand.ChangeCanExecute(); + NextButtonCommand.ChangeCanExecute(); + } + } + + /// + /// Event handler to hook up can execute events on property changed + /// + /// + /// + /// + private static void OnNextButtonPropertyChanged(BindableObject bindable, object oldValue, object newValue) + { + Player component = bindable as Player; + if (newValue is Command) + { + Command cmd = newValue as Command; + component.NextButton.Tapped += component.OnNextButtonClicked; + cmd.CanExecuteChanged += (sender, e) => OnNextButtonCanExecuteChanged(sender, e, component, cmd); + } + + if (oldValue is Command && oldValue != null) + { + Command cmd = oldValue as Command; + component.NextButton.Tapped -= component.OnNextButtonClicked; + cmd.CanExecuteChanged -= (sender, e) => OnNextButtonCanExecuteChanged(sender, e, component, cmd); + } + } + + /// + /// Can execute changed event handler + /// + /// + /// + /// + /// + private static void OnNextButtonCanExecuteChanged(object sender, + EventArgs eventArgs, + Player component, + Command cmd) + { + + component.NextButton.IsEnabled = cmd.CanExecute(null); + } + #endregion PlayButton + + #region Playing Bindable + public static readonly BindableProperty IsPlayingProperty = + BindableProperty.Create( + propertyName: "IsPlaying", + returnType: typeof(bool), + declaringType: typeof(Player), + propertyChanged: (BindableObject bindable, object oldValue, object newValue) => + { + Player control = (Player)bindable; + if ((bool)newValue == true) + { + control.PlayButton.Source = ImageSource.FromFile("Resources/pause.png"); + } + else + { + control.PlayButton.Source = ImageSource.FromFile("Resources/play.png"); + } + }); + + public bool IsPlaying + { + get { return (bool)GetValue(IsPlayingProperty); } + set { SetValue(IsPlayingProperty, value); } + } + + #endregion Playing Binadable + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Components/MemberList/MemberList.css b/aurora-sharp-desktop/Aurora/Design/Components/MemberList/MemberList.css new file mode 100644 index 0000000..ae63d98 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/MemberList/MemberList.css @@ -0,0 +1,20 @@ +#MembersList { + background-color: #1e1e1e; +} + +Grid { + margin-left: 20; + margin-right: 20; + margin-top: 20; + margin-bottom: 20; + width: 150; + border-radius: 25; + background-color: #626363; +} + +Grid Label { + text-align: center; + vertical-align: middle; + color: white; + font-size: 20; +} \ No newline at end of file diff --git a/aurora-sharp-desktop/Aurora/Design/Components/MemberList/MemberList.xaml b/aurora-sharp-desktop/Aurora/Design/Components/MemberList/MemberList.xaml new file mode 100644 index 0000000..1be0462 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/MemberList/MemberList.xaml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/aurora-sharp-desktop/Aurora/Design/Components/MemberList/MemberList.xaml.cs b/aurora-sharp-desktop/Aurora/Design/Components/MemberList/MemberList.xaml.cs new file mode 100644 index 0000000..0d09652 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/MemberList/MemberList.xaml.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Collections; +using System.Linq; +using Xamarin.Forms; +using Aurora.Proto.Party; +using DLToolkit.Forms.Controls; + +namespace Aurora.Design.Components.MemberList +{ + public partial class MemberList : ContentView + { + public MemberList() + { + InitializeComponent(); + } + + /// + /// Bindable property for members list. + /// + /// + /// + /// + public static readonly BindableProperty MembersProperty = + BindableProperty.Create(propertyName: "Members", + returnType: typeof(ObservableCollection), + declaringType: typeof(MemberList), + defaultBindingMode: BindingMode.Default, + propertyChanged: OnMembersChanged); + + /// + /// Backing property for MembersProperty + /// + /// + public ObservableCollection Members + { + get + { + return (ObservableCollection)GetValue(MembersProperty); + } + set + { + SetValue(MembersProperty, value); + } + } + + + /// + /// Memberes changed event handler. Assign member list source. + /// + /// + /// + /// + private static void OnMembersChanged(BindableObject bindable, object oldValue, object newValue) + { + var control = (MemberList)bindable; + var membersList = control.FindByName("MembersList") as FlowListView; + + if (newValue is ICollection source) + { + membersList.FlowItemsSource = source; + } + } + } +} + diff --git a/aurora-sharp-desktop/Aurora/Design/Components/NavigationMenu/NavigationGroupItem.cs b/aurora-sharp-desktop/Aurora/Design/Components/NavigationMenu/NavigationGroupItem.cs new file mode 100644 index 0000000..3876274 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/NavigationMenu/NavigationGroupItem.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace Aurora.Design.Components.NavigationMenu +{ + public class NavigationGroupItem : List + { + public NavigationGroupItem() + { + } + + public NavigationGroupItem(string heading) + { + GroupHeading = heading; + } + + public List Items => this; + public string GroupHeading { get; set; } + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Components/NavigationMenu/NavigationItem.cs b/aurora-sharp-desktop/Aurora/Design/Components/NavigationMenu/NavigationItem.cs new file mode 100644 index 0000000..4571caa --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/NavigationMenu/NavigationItem.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Aurora.Design.Views.Main; + +namespace Aurora.Design.Components.NavigationMenu +{ + public class NavigationItem + { + public NavigationItem() + { + } + public int Id { get; set; } + public string Title { get; set; } + public string Group { get; set; } + public Type TargetType { get; set; } + public Type TargetViewModelType { get; set; } + + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Components/NavigationMenu/NavigationMenu.css b/aurora-sharp-desktop/Aurora/Design/Components/NavigationMenu/NavigationMenu.css new file mode 100644 index 0000000..b4c88d1 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/NavigationMenu/NavigationMenu.css @@ -0,0 +1,25 @@ +ListView { + margin-left: 15; + margin-top: 40; +} + +#GroupTemplate { + align-items: end; +} + +#GroupCell Label { + color: lightgray; + font-size: 12; + font-family: Courier New, Courier, monospace; + font-style: italic; + padding-top: 20; +} + +#ItemCell Label { + color: white; + font-size: 15; + font-family: Courier New, Courier, monospace; + font-style: normal; + text-align: left; + padding-top: 12; +} diff --git a/aurora-sharp-desktop/Aurora/Design/Components/NavigationMenu/NavigationMenu.xaml b/aurora-sharp-desktop/Aurora/Design/Components/NavigationMenu/NavigationMenu.xaml new file mode 100644 index 0000000..f8b6dc0 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/NavigationMenu/NavigationMenu.xaml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/aurora-sharp-desktop/Aurora/Design/Components/NavigationMenu/NavigationMenu.xaml.cs b/aurora-sharp-desktop/Aurora/Design/Components/NavigationMenu/NavigationMenu.xaml.cs new file mode 100644 index 0000000..6bbc0a6 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/NavigationMenu/NavigationMenu.xaml.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using Xamarin.Forms; + +namespace Aurora.Design.Components.NavigationMenu +{ + public partial class NavigationMenu : ContentView + { + public NavigationMenu() + { + InitializeComponent(); + ListView = MenuItemsListView; + ListView.ItemSelected += ListView_ItemSelected; + } + + private void ListView_ItemSelected(object sender, SelectedItemChangedEventArgs e) + { + this.SelectedItem = e.SelectedItem as NavigationItem; + } + + public ListView ListView; + + public static readonly BindableProperty SelectedItemProperty = + BindableProperty.Create(propertyName: nameof(SelectedItem), + returnType: typeof(NavigationItem), + declaringType: typeof(NavigationMenu), + defaultBindingMode: BindingMode.OneWayToSource); + + public NavigationItem SelectedItem + { + get + { + return (NavigationItem)GetValue(SelectedItemProperty); + } + set + { + SetValue(SelectedItemProperty, value); + } + } + + + public static readonly BindableProperty ItemsProperty = + BindableProperty.Create(propertyName: nameof(Items), + returnType: typeof(ObservableCollection), + declaringType: typeof(NavigationMenu), + defaultBindingMode: BindingMode.TwoWay, + propertyChanged: OnItemsChanged); + + public ObservableCollection Items + { + get + { + return (ObservableCollection)GetValue(ItemsProperty); + } + set + { + SetValue(ItemsProperty, value); + } + } + + /// + /// Items changed event handler. Organizes items in groups for display. + /// + /// The changed Item. + /// The previous value. + /// The new value. + private static void OnItemsChanged(BindableObject bindable, object oldValue, object newValue) + { + var control = (NavigationMenu)bindable; + ObservableCollection items = (ObservableCollection)newValue; + Dictionary groupDictioanry = new Dictionary(); + + //Populate dictionary where group heading is the key + foreach (NavigationItem item in items) + { + if (groupDictioanry.ContainsKey(item.Group)) + { + groupDictioanry.TryGetValue(item.Group, out var groupItem); + groupItem.Items.Add(item); + } + else + { + NavigationGroupItem groupItem = new NavigationGroupItem(item.Group); + groupItem.Add(item); + + groupDictioanry.Add(item.Group, groupItem); + } + } + + ObservableCollection groups = new ObservableCollection(); + foreach (string groupHeading in groupDictioanry.Keys) + { + groupDictioanry.TryGetValue(groupHeading, out var groupItem); + groups.Add(groupItem); + } + + control.MenuItemsListView.ItemsSource = groups; + } + + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Components/TabView/TabItem.cs b/aurora-sharp-desktop/Aurora/Design/Components/TabView/TabItem.cs new file mode 100644 index 0000000..9e1ff02 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/TabView/TabItem.cs @@ -0,0 +1,111 @@ +using Xamarin.Forms; + +namespace Aurora.Design.Components.TabView +{ + [ContentProperty(nameof(Content))] + public class TabItem : BindableObject + { + public TabItem() + { + //Parameterless constructor required for xaml instantiation. + } + + public void TriggerPropertyChange(string propertyName = null) + { + base.OnPropertyChanged(propertyName); + } + + public TabItem(string headerText, View content, ImageSource headerIcon = null) + { + HeaderText = headerText; + Content = content; + if (headerIcon != null) + HeaderIcon = headerIcon; + } + + public static readonly BindableProperty HeaderIconProperty = BindableProperty.Create(nameof(HeaderIcon), typeof(ImageSource), typeof(TabItem)); + public ImageSource HeaderIcon + { + get => (ImageSource)GetValue(HeaderIconProperty); + set { SetValue(HeaderIconProperty, value); } + } + + public readonly BindableProperty HeaderIconSizeProperty = BindableProperty.Create(nameof(HeaderIconSize), typeof(double), typeof(TabItem), 32.0); + public double HeaderIconSize + { + get => (double)GetValue(HeaderIconSizeProperty); + set { SetValue(HeaderIconSizeProperty, value); } + } + + public static readonly BindableProperty HeaderTextProperty = BindableProperty.Create(nameof(HeaderText), typeof(string), typeof(TabItem), string.Empty); + public string HeaderText + { + get => (string)GetValue(HeaderTextProperty); + set { SetValue(HeaderTextProperty, value); } + } + + public static readonly BindableProperty ContentProperty = BindableProperty.Create(nameof(Content), typeof(View), typeof(TabItem)); + public View Content + { + get => (View)GetValue(ContentProperty); + set { SetValue(ContentProperty, value); } + } + + public static readonly BindableProperty IsCurrentProperty = BindableProperty.Create(nameof(IsCurrent), typeof(bool), typeof(TabItem), false); + public bool IsCurrent + { + get => (bool)GetValue(IsCurrentProperty); + set { SetValue(IsCurrentProperty, value); } + } + + public static readonly BindableProperty HeaderTextColorProperty = BindableProperty.Create(nameof(HeaderTextColor), typeof(Color), typeof(TabItem), Color.White); + public Color HeaderTextColor + { + get => (Color)GetValue(HeaderTextColorProperty); + set { SetValue(HeaderTextColorProperty, value); } + } + + public static readonly BindableProperty HeaderSelectionUnderlineColorProperty = BindableProperty.Create(nameof(HeaderSelectionUnderlineColor), typeof(Color), typeof(TabItem), Color.Transparent); + public Color HeaderSelectionUnderlineColor + { + get => (Color)GetValue(HeaderSelectionUnderlineColorProperty); + set { SetValue(HeaderSelectionUnderlineColorProperty, value); } + } + + public static readonly BindableProperty HeaderSelectionUnderlineThicknessProperty = BindableProperty.Create(nameof(HeaderSelectionUnderlineThickness), typeof(double), typeof(TabItem), (double)5); + public double HeaderSelectionUnderlineThickness + { + get => (double)GetValue(HeaderSelectionUnderlineThicknessProperty); + set { SetValue(HeaderSelectionUnderlineThicknessProperty, value); } + } + + public static readonly BindableProperty HeaderSelectionUnderlineWidthProperty = BindableProperty.Create(nameof(HeaderSelectionUnderlineWidth), typeof(double), typeof(TabItem), (double)40); + public double HeaderSelectionUnderlineWidth + { + get => (double)GetValue(HeaderSelectionUnderlineWidthProperty); + set { SetValue(HeaderSelectionUnderlineWidthProperty, value); } + } + + public static readonly BindableProperty HeaderTabTextFontSizeProperty = BindableProperty.Create(nameof(HeaderTabTextFontSize), typeof(double), typeof(TabItem), TabDefaults.DefaultTextSize); + [TypeConverter(typeof(FontSizeConverter))] + public double HeaderTabTextFontSize + { + get => (double)GetValue(HeaderTabTextFontSizeProperty); + set { SetValue(HeaderTabTextFontSizeProperty, value); } + } + + public static readonly BindableProperty HeaderTabTextFontFamilyProperty = BindableProperty.Create(nameof(HeaderTabTextFontFamily), typeof(string), typeof(TabItem)); + public string HeaderTabTextFontFamily + { + get => (string)GetValue(HeaderTabTextFontFamilyProperty); + set { SetValue(HeaderTabTextFontFamilyProperty, value); } + } + + public static readonly BindableProperty HeaderTabTextFontAttributesProperty = BindableProperty.Create(nameof(HeaderTabTextFontAttributes), typeof(FontAttributes), typeof(TabItem), FontAttributes.None); + public FontAttributes HeaderTabTextFontAttributes + { + get => (FontAttributes)GetValue(HeaderTabTextFontAttributesProperty); + set { SetValue(HeaderTabTextFontAttributesProperty, value); } + } + } +} \ No newline at end of file diff --git a/aurora-sharp-desktop/Aurora/Design/Components/TabView/TabView.cs b/aurora-sharp-desktop/Aurora/Design/Components/TabView/TabView.cs new file mode 100644 index 0000000..81cbbb2 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Components/TabView/TabView.cs @@ -0,0 +1,571 @@ +// using CarouselView.FormsPlugin.Abstractions; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Linq; +using Xamarin.Forms; +using Aurora.Design.Converters; + +namespace Aurora.Design.Components.TabView +{ + public delegate void PositionChangingEventHandler(object sender, TabChangingEventArgs e); + public delegate void PositionChangedEventHandler(object sender, TabChangedEventArgs e); + + public class TabChangingEventArgs : EventArgs + { + public bool Canceled { get; set; } + public int NewPosition { get; set; } + public int OldPosition { get; set; } + } + + public class TabChangedEventArgs : EventArgs + { + public int NewPosition { get; set; } + public int OldPosition { get; set; } + } + + static class TabDefaults + { + public static readonly Color DefaultColor = Color.White; + public const double DefaultThickness = 5; + public const double DefaultTextSize = 14; + } + + public class TabViewControl : ContentView + { + private StackLayout _mainContainerSL; + private Grid _headerContainerGrid; + private ScrollView _tabHeadersContainerSv; + + public event PositionChangingEventHandler PositionChanging; + public event PositionChangedEventHandler PositionChanged; + + protected virtual void OnTabChanging(ref TabChangingEventArgs e) + { + PositionChangingEventHandler handler = PositionChanging; + handler?.Invoke(this, e); + } + + protected virtual void OnTabChanged(TabChangedEventArgs e) + { + PositionChangedEventHandler handler = PositionChanged; + handler?.Invoke(this, e); + } + + public TabViewControl() + { + //Parameterless constructor required for xaml instantiation. + Init(); + } + + public TabViewControl(IList tabItems, int selectedTabIndex = 0) + { + Init(); + foreach (var tab in tabItems) + { + ItemSource.Add(tab); + } + if (selectedTabIndex > 0) + { + SelectedTabIndex = selectedTabIndex; + } + } + + void ItemSource_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + if (e.NewItems != null) + { + foreach (var tab in e.NewItems) + { + if (tab is TabItem newTab) + { + SetTabProps(newTab); + AddTabToView(newTab); + } + } + } + } + + private void SetTabProps(TabItem tab) + { + //Set the tab properties from the main control only if not set in xaml at the individual tab level. + if (tab.HeaderTextColor == TabDefaults.DefaultColor && HeaderTabTextColor != TabDefaults.DefaultColor) + tab.HeaderTextColor = HeaderTabTextColor; + if (tab.HeaderSelectionUnderlineColor == TabDefaults.DefaultColor && HeaderSelectionUnderlineColor != TabDefaults.DefaultColor) + tab.HeaderSelectionUnderlineColor = HeaderSelectionUnderlineColor; + if (tab.HeaderSelectionUnderlineThickness.Equals(TabDefaults.DefaultThickness) && !HeaderSelectionUnderlineThickness.Equals(TabDefaults.DefaultThickness)) + tab.HeaderSelectionUnderlineThickness = HeaderSelectionUnderlineThickness; + if (tab.HeaderSelectionUnderlineWidth > 0) + tab.HeaderSelectionUnderlineWidth = HeaderSelectionUnderlineWidth; + if (tab.HeaderTabTextFontSize.Equals(TabDefaults.DefaultTextSize) && !HeaderTabTextFontSize.Equals(TabDefaults.DefaultTextSize)) + tab.HeaderTabTextFontSize = HeaderTabTextFontSize; + if (tab.HeaderTabTextFontFamily is null && !string.IsNullOrWhiteSpace(HeaderTabTextFontFamily)) + tab.HeaderTabTextFontFamily = HeaderTabTextFontFamily; + if (tab.HeaderTabTextFontAttributes == FontAttributes.None && HeaderTabTextFontAttributes != FontAttributes.None) + tab.HeaderTabTextFontAttributes = HeaderTabTextFontAttributes; + } + + private void Init() + { + ItemSource = new ObservableCollection(); + + _headerContainerGrid = new Grid + { + HorizontalOptions = LayoutOptions.FillAndExpand, + VerticalOptions = LayoutOptions.Start, + // BackgroundColor = Color.White, // tab sepeartor color + MinimumHeightRequest = 50, + ColumnSpacing = 0, // seperator thickness + }; + + _tabHeadersContainerSv = new ScrollView() + { + HorizontalScrollBarVisibility = ScrollBarVisibility.Never, + Orientation = ScrollOrientation.Horizontal, + Content = _headerContainerGrid, + BackgroundColor = HeaderBackgroundColor, + HorizontalOptions = LayoutOptions.FillAndExpand + }; + + _mainContainerSL = new StackLayout + { + HorizontalOptions = LayoutOptions.FillAndExpand, + VerticalOptions = LayoutOptions.FillAndExpand, + Children = { _tabHeadersContainerSv }, + Spacing = 0 + }; + + Content = _mainContainerSL; + ItemSource.CollectionChanged += ItemSource_CollectionChanged; + } + + protected override void OnBindingContextChanged() + { + base.OnBindingContextChanged(); + if (BindingContext != null) + { + foreach (var tab in ItemSource) + { + if (tab is TabItem view) + { + view.Content.BindingContext = BindingContext; + } + } + + SetCurrentTab(SelectedTabIndex, true); + } + } + + private void AddTabToView(TabItem tab) + { + var tabSize = (TabSizeOption.IsAbsolute && TabSizeOption.Value.Equals(0)) ? new GridLength(1, GridUnitType.Star) : TabSizeOption; + + _headerContainerGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = tabSize }); + + tab.IsCurrent = _headerContainerGrid.ColumnDefinitions.Count - 1 == SelectedTabIndex; + + var headerIcon = new Image + { + Margin = new Thickness(0, 8, 0, 0), + BindingContext = tab, + HorizontalOptions = LayoutOptions.CenterAndExpand, + VerticalOptions = LayoutOptions.Center, + WidthRequest = tab.HeaderIconSize, + HeightRequest = tab.HeaderIconSize + }; + headerIcon.SetBinding(Image.SourceProperty, nameof(TabItem.HeaderIcon)); + headerIcon.SetBinding(IsVisibleProperty, nameof(TabItem.HeaderIcon), converter: new NullToBoolConverter()); + + var headerLabel = new Label + { + BindingContext = tab, + VerticalTextAlignment = TextAlignment.Center, + HorizontalTextAlignment = TextAlignment.Center, + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.CenterAndExpand, + Margin = new Thickness(5, 8, 5, 5) + }; + + headerLabel.SetBinding(Label.TextProperty, nameof(TabItem.HeaderText)); + headerLabel.SetBinding(Label.TextColorProperty, nameof(TabItem.HeaderTextColor)); + headerLabel.SetBinding(Label.FontSizeProperty, nameof(TabItem.HeaderTabTextFontSize)); + headerLabel.SetBinding(Label.FontFamilyProperty, nameof(TabItem.HeaderTabTextFontFamily)); + headerLabel.SetBinding(Label.FontAttributesProperty, nameof(TabItem.HeaderTabTextFontAttributes)); + headerLabel.SetBinding(IsVisibleProperty, nameof(TabItem.HeaderText), converter: new NullToBoolConverter()); + + var selectionBarBoxView = new BoxView + { + VerticalOptions = LayoutOptions.End, + BindingContext = tab, + HeightRequest = HeaderSelectionUnderlineThickness, + WidthRequest = HeaderSelectionUnderlineWidth + }; + var underlineColorBinding = new Binding(nameof(TabItem.IsCurrent), BindingMode.OneWay, new SelectedTabHeaderToTabBackgroundColorConverter(), this); + selectionBarBoxView.SetBinding(BoxView.BackgroundColorProperty, underlineColorBinding); + + selectionBarBoxView.SetBinding(WidthRequestProperty, nameof(TabItem.HeaderSelectionUnderlineWidth)); + selectionBarBoxView.SetBinding(HeightRequestProperty, nameof(TabItem.HeaderSelectionUnderlineThickness)); + selectionBarBoxView.SetBinding(HorizontalOptionsProperty, + nameof(TabItem.HeaderSelectionUnderlineWidthProperty), + converter: new DoubleToLayoutOptionsConverter()); + + selectionBarBoxView.PropertyChanged += (object sender, PropertyChangedEventArgs e) => + { + if (e.PropertyName == nameof(TabItem.IsCurrent)) + { + SetCurrentTab(ItemSource.IndexOf((TabItem)((BoxView)sender).BindingContext)); + } + if (e.PropertyName == nameof(WidthRequest)) + { + selectionBarBoxView.HorizontalOptions = tab.HeaderSelectionUnderlineWidth > 0 ? LayoutOptions.CenterAndExpand : LayoutOptions.FillAndExpand; + } + }; + + var headerItemSL = new StackLayout + { + VerticalOptions = LayoutOptions.FillAndExpand, + Children = { headerIcon, headerLabel, selectionBarBoxView }, + BackgroundColor = HeaderBackgroundColor, + Spacing = 0 + }; + var tapRecognizer = new TapGestureRecognizer(); + + tapRecognizer.Tapped += (object s, EventArgs e) => + { + var capturedIndex = _headerContainerGrid.Children.IndexOf((View)s); + SetCurrentTab(capturedIndex); + }; + + headerItemSL.GestureRecognizers.Add(tapRecognizer); + _headerContainerGrid.Children.Add(headerItemSL, _headerContainerGrid.ColumnDefinitions.Count - 1, 0); + } + + #region HeaderBackgroundColor + public Color HeaderBackgroundColor + { + get { return (Color)GetValue(HeaderBackgroundColorProperty); } + set { SetValue(HeaderBackgroundColorProperty, value); } + } + private static void HeaderBackgroundColorChanged(BindableObject bindable, object oldValue, object newValue) + { + if (bindable is TabViewControl tabViewControl) + { + tabViewControl._tabHeadersContainerSv.BackgroundColor = (Color)newValue; + } + } + public static readonly BindableProperty HeaderBackgroundColorProperty = BindableProperty.Create(nameof(HeaderBackgroundColor), typeof(Color), typeof(TabViewControl), Color.SkyBlue, BindingMode.Default, null, HeaderBackgroundColorChanged); + #endregion + + #region HeaderTabTextColor + public Color HeaderTabTextColor + { + get { return (Color)GetValue(HeaderTabTextColorProperty); } + set { SetValue(HeaderTabTextColorProperty, value); } + } + private static void HeaderTabTextColorChanged(BindableObject bindable, object oldValue, object newValue) + { + if (bindable is TabViewControl tabViewControl && tabViewControl.ItemSource != null) + { + foreach (var tab in tabViewControl.ItemSource) + { + tab.HeaderTextColor = (Color)newValue; + } + } + } + public static readonly BindableProperty HeaderTabTextColorProperty = + BindableProperty.Create(nameof(HeaderTabTextColor), typeof(Color), typeof(TabViewControl), TabDefaults.DefaultColor, BindingMode.OneWay, null, HeaderTabTextColorChanged); + #endregion + + #region ContentHeight + public double ContentHeight + { + get { return (double)GetValue(ContentHeightProperty); } + set { SetValue(ContentHeightProperty, value); } + } + private static void ContentHeightChanged(BindableObject bindable, object oldValue, object newValue) + { + throw new NotImplementedException(); + // if (bindable is TabViewControl tabViewControl && tabViewControl._carouselView != null) + // { + // tabViewControl._carouselView.HeightRequest = (double)newValue; + // } + } + public static readonly BindableProperty ContentHeightProperty = BindableProperty.Create(nameof(ContentHeight), typeof(double), typeof(TabViewControl), (double)200, BindingMode.Default, null, ContentHeightChanged); + #endregion + + #region HeaderSelectionUnderlineColor + public Color HeaderSelectionUnderlineColor + { + get { return (Color)GetValue(HeaderSelectionUnderlineColorProperty); } + set { SetValue(HeaderSelectionUnderlineColorProperty, value); } + } + private static void HeaderSelectionUnderlineColorChanged(BindableObject bindable, object oldValue, object newValue) + { + if (bindable is TabViewControl tabViewControl && tabViewControl.ItemSource != null) + { + foreach (var tab in tabViewControl.ItemSource) + { + tab.HeaderSelectionUnderlineColor = (Color)newValue; + tab.TriggerPropertyChange(nameof(tab.IsCurrent)); + } + } + } + public static readonly BindableProperty HeaderSelectionUnderlineColorProperty = BindableProperty.Create(nameof(HeaderSelectionUnderlineColor), typeof(Color), typeof(TabViewControl), Color.White, BindingMode.Default, null, HeaderSelectionUnderlineColorChanged); + #endregion + + #region HeaderSelectionUnderlineThickness + public double HeaderSelectionUnderlineThickness + { + get { return (double)GetValue(HeaderSelectionUnderlineThicknessProperty); } + set { SetValue(HeaderSelectionUnderlineThicknessProperty, value); } + } + private static void HeaderSelectionUnderlineThicknessChanged(BindableObject bindable, object oldValue, object newValue) + { + if (bindable is TabViewControl tabViewControl && tabViewControl.ItemSource != null) + { + foreach (var tab in tabViewControl.ItemSource) + { + tab.HeaderSelectionUnderlineThickness = (double)newValue; + } + } + } + public static readonly BindableProperty HeaderSelectionUnderlineThicknessProperty = BindableProperty.Create(nameof(HeaderSelectionUnderlineThickness), typeof(double), typeof(TabViewControl), TabDefaults.DefaultThickness, BindingMode.Default, null, HeaderSelectionUnderlineThicknessChanged); + #endregion + + #region HeaderSelectionUnderlineWidth + public double HeaderSelectionUnderlineWidth + { + get { return (double)GetValue(HeaderSelectionUnderlineWidthProperty); } + set { SetValue(HeaderSelectionUnderlineWidthProperty, value); } + } + private static void HeaderSelectionUnderlineWidthChanged(BindableObject bindable, object oldValue, object newValue) + { + if (bindable is TabViewControl tabViewControl && tabViewControl.ItemSource != null) + { + foreach (var tab in tabViewControl.ItemSource) + { + tab.HeaderSelectionUnderlineWidth = (double)newValue; + } + } + } + public static readonly BindableProperty HeaderSelectionUnderlineWidthProperty = BindableProperty.Create(nameof(HeaderSelectionUnderlineWidth), typeof(double), typeof(TabViewControl), (double)0, BindingMode.Default, null, HeaderSelectionUnderlineWidthChanged); + #endregion + + #region HeaderTabTextFontSize + [Xamarin.Forms.TypeConverter(typeof(FontSizeConverter))] + public double HeaderTabTextFontSize + { + get { return (double)GetValue(HeaderTabTextFontSizeProperty); } + set { SetValue(HeaderTabTextFontSizeProperty, value); } + } + private static void HeaderTabTextFontSizeChanged(BindableObject bindable, object oldValue, object newValue) + { + if (bindable is TabViewControl tabViewControl && tabViewControl.ItemSource != null) + { + foreach (var tab in tabViewControl.ItemSource) + { + tab.HeaderTabTextFontSize = (double)newValue; + } + } + } + public static readonly BindableProperty HeaderTabTextFontSizeProperty = BindableProperty.Create(nameof(HeaderTabTextFontSize), typeof(double), typeof(TabViewControl), (double)14, BindingMode.Default, null, HeaderTabTextFontSizeChanged); + #endregion + + #region HeaderTabTextFontFamily + public string HeaderTabTextFontFamily + { + get { return (string)GetValue(HeaderTabTextFontFamilyProperty); } + set { SetValue(HeaderTabTextFontFamilyProperty, value); } + } + private static void HeaderTabTextFontFamilyChanged(BindableObject bindable, object oldValue, object newValue) + { + if (bindable is TabViewControl tabViewControl && tabViewControl.ItemSource != null) + { + foreach (var tab in tabViewControl.ItemSource) + { + tab.HeaderTabTextFontFamily = (string)newValue; + } + } + } + public static readonly BindableProperty HeaderTabTextFontFamilyProperty = BindableProperty.Create(nameof(HeaderTabTextFontFamily), typeof(string), typeof(TabViewControl), null, BindingMode.Default, null, HeaderTabTextFontFamilyChanged); + #endregion + + #region HeaderTabTextFontAttributes + public FontAttributes HeaderTabTextFontAttributes + { + get { return (FontAttributes)GetValue(HeaderTabTextFontAttributesProperty); } + set { SetValue(HeaderTabTextFontAttributesProperty, value); } + } + private static void HeaderTabTextFontAttributesChanged(BindableObject bindable, object oldValue, object newValue) + { + if (bindable is TabViewControl tabViewControl && tabViewControl.ItemSource != null) + { + foreach (var tab in tabViewControl.ItemSource) + { + tab.HeaderTabTextFontAttributes = (FontAttributes)newValue; + } + } + } + public static readonly BindableProperty HeaderTabTextFontAttributesProperty = BindableProperty.Create(nameof(HeaderTabTextFontAttributes), typeof(FontAttributes), typeof(TabViewControl), FontAttributes.None, BindingMode.Default, null, HeaderTabTextFontAttributesChanged); + #endregion + + #region ItemSource + public static readonly BindableProperty ItemSourceProperty = BindableProperty.Create(nameof(ItemSource), typeof(ObservableCollection), typeof(TabViewControl)); + public ObservableCollection ItemSource + { + get => (ObservableCollection)GetValue(ItemSourceProperty); + set { SetValue(ItemSourceProperty, value); } + } + #endregion + + #region TabSizeOption + public static readonly BindableProperty TabSizeOptionProperty = BindableProperty.Create(nameof(TabSizeOption), typeof(GridLength), typeof(TabViewControl), default(GridLength), propertyChanged: OnTabSizeOptionChanged); + private static void OnTabSizeOptionChanged(BindableObject bindable, object oldValue, object newValue) + { + if (bindable is TabViewControl tabViewControl && tabViewControl._headerContainerGrid != null && tabViewControl.ItemSource != null) + { + foreach (var tabContainer in tabViewControl._headerContainerGrid.ColumnDefinitions) + { + tabContainer.Width = (GridLength)newValue; + } + } + } + public GridLength TabSizeOption + { + get => (GridLength)GetValue(TabSizeOptionProperty); + set { SetValue(TabSizeOptionProperty, value); } + } + #endregion + + #region SelectedTabIndex + public static readonly BindableProperty SelectedTabIndexProperty = BindableProperty.Create( + nameof(SelectedTabIndex), + typeof(int), + typeof(TabViewControl), + defaultValue: 0, + defaultBindingMode: BindingMode.TwoWay, + propertyChanged: OnSelectedTabIndexChanged); + private static void OnSelectedTabIndexChanged(BindableObject bindable, object oldValue, object newValue) + { + if (bindable is TabViewControl tabViewControl && tabViewControl.ItemSource != null) + { + tabViewControl.SetCurrentTab((int)newValue); + } + } + public int SelectedTabIndex + { + get => (int)GetValue(SelectedTabIndexProperty); + set { SetValue(SelectedTabIndexProperty, value); } + } + #endregion + + public void SetCurrentTab(int position, bool initialRun = false) + { + if (SelectedTabIndex == position && !initialRun) + { + return; + } + int oldPosition = SelectedTabIndex; + + var tabChangingArgs = new TabChangingEventArgs() + { + Canceled = false, + NewPosition = position, + OldPosition = oldPosition + }; + OnTabChanging(ref tabChangingArgs); + + if (tabChangingArgs != null && tabChangingArgs.Canceled) + { + return; + } + + if (((position >= 0 && position < ItemSource.Count) || initialRun)) + { + if (oldPosition < ItemSource.Count) + { + List tabActiveList = ItemSource.Select((TabItem tab, int index) => + { + return index == position; + }) + .ToList(); + + for (int i = 0; i < tabActiveList.Count(); i++) + { + ItemSource[i].IsCurrent = tabActiveList[i]; + } + // Remove second child + if (_mainContainerSL.Children.Count == 2) + { + _mainContainerSL.Children.RemoveAt(1); + } + } + _mainContainerSL.Children.Add(ItemSource[position].Content); + SelectedTabIndex = position; + Device.BeginInvokeOnMainThread(async () => await _tabHeadersContainerSv.ScrollToAsync(_headerContainerGrid.Children[position], ScrollToPosition.MakeVisible, false)); + + } + + var tabChangedArgs = new TabChangedEventArgs() + { + NewPosition = SelectedTabIndex, + OldPosition = oldPosition + }; + OnTabChanged(tabChangedArgs); + } + + public void SelectNext() + { + SetCurrentTab(SelectedTabIndex + 1); + } + + public void SelectPrevious() + { + SetCurrentTab(SelectedTabIndex - 1); + } + + public void SelectFirst() + { + SetCurrentTab(0); + } + + public void SelectLast() + { + SetCurrentTab(ItemSource.Count - 1); + } + + public void AddTab(TabItem tab, int position = -1, bool selectNewPosition = false) + { + if (position > -1) + { + ItemSource.Insert(position, tab); + } + else + { + ItemSource.Add(tab); + } + if (selectNewPosition) + { + SelectedTabIndex = position; + } + } + + public void RemoveTab(int position = -1) + { + if (position > -1) + { + ItemSource.RemoveAt(position); + _headerContainerGrid.Children.RemoveAt(position); + _headerContainerGrid.ColumnDefinitions.RemoveAt(position); + } + else + { + ItemSource.Remove(ItemSource.Last()); + _headerContainerGrid.Children.RemoveAt(_headerContainerGrid.Children.Count - 1); + _headerContainerGrid.ColumnDefinitions.Remove(_headerContainerGrid.ColumnDefinitions.Last()); + } + SelectedTabIndex = position >= 0 && position < ItemSource.Count ? position : ItemSource.Count - 1; + } + } +} \ No newline at end of file diff --git a/aurora-sharp-desktop/Aurora/Design/Converters/DoubleToLayoutOptions.cs b/aurora-sharp-desktop/Aurora/Design/Converters/DoubleToLayoutOptions.cs new file mode 100644 index 0000000..eb690cb --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Converters/DoubleToLayoutOptions.cs @@ -0,0 +1,24 @@ +using System; +using System.Globalization; +using Xamarin.Forms; + +namespace Aurora.Design.Converters +{ + public class DoubleToLayoutOptionsConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + var result = double.TryParse(value.ToString(), out double val); + if (result && val > 0) + { + return LayoutOptions.CenterAndExpand; + } + return LayoutOptions.FillAndExpand; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return null; + } + } +} \ No newline at end of file diff --git a/aurora-sharp-desktop/Aurora/Design/Converters/InverseBoolConverter.cs b/aurora-sharp-desktop/Aurora/Design/Converters/InverseBoolConverter.cs new file mode 100644 index 0000000..cc50c59 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Converters/InverseBoolConverter.cs @@ -0,0 +1,24 @@ +using System; +using System.Globalization; +using Xamarin.Forms; + +namespace Aurora.Design.Converters +{ + public class InverseBoolConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (!(value is bool)) + { + throw new InvalidOperationException("The target must be a boolean"); + } + + return !(bool)value; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return null; + } + } +} \ No newline at end of file diff --git a/aurora-sharp-desktop/Aurora/Design/Converters/NullToBullConverter.cs b/aurora-sharp-desktop/Aurora/Design/Converters/NullToBullConverter.cs new file mode 100644 index 0000000..45a2b4a --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Converters/NullToBullConverter.cs @@ -0,0 +1,19 @@ +using System; +using System.Globalization; +using Xamarin.Forms; + +namespace Aurora.Design.Converters +{ + public class NullToBoolConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return value != null; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return null; + } + } +} \ No newline at end of file diff --git a/aurora-sharp-desktop/Aurora/Design/Converters/PlayIconConverter.cs b/aurora-sharp-desktop/Aurora/Design/Converters/PlayIconConverter.cs new file mode 100644 index 0000000..f1da0c6 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Converters/PlayIconConverter.cs @@ -0,0 +1,10 @@ +using System; +namespace Aurora.Design.Converters +{ + public class PlayIconConverter + { + public PlayIconConverter() + { + } + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Converters/SelectedTabHeaderToTabBackgroundColorConverter.cs b/aurora-sharp-desktop/Aurora/Design/Converters/SelectedTabHeaderToTabBackgroundColorConverter.cs new file mode 100644 index 0000000..246360a --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Converters/SelectedTabHeaderToTabBackgroundColorConverter.cs @@ -0,0 +1,31 @@ +using System; +using System.Globalization; +using Aurora.Design.Components.TabView; +using Xamarin.Forms; + +namespace Aurora.Design.Converters +{ + class SelectedTabHeaderToTabBackgroundColorConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + bool isCurrentTabSelected = false; + if (!string.IsNullOrWhiteSpace(value?.ToString())) + bool.TryParse(value.ToString(), out isCurrentTabSelected); + + if (parameter is TabViewControl tvc && isCurrentTabSelected) + { + return tvc.HeaderSelectionUnderlineColor; + } + else + { + return Color.Transparent; + } + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Converters/ToUpperConverter.cs b/aurora-sharp-desktop/Aurora/Design/Converters/ToUpperConverter.cs new file mode 100644 index 0000000..b1c6c59 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Converters/ToUpperConverter.cs @@ -0,0 +1,19 @@ +using System; +using System.Globalization; +using Xamarin.Forms; + +namespace Aurora.Design.Converters +{ + public class ToUpperConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return value.ToString().ToUpper(); + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return null; + } + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Extensions/ImageResourceExtension.cs b/aurora-sharp-desktop/Aurora/Design/Extensions/ImageResourceExtension.cs new file mode 100644 index 0000000..22a0421 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Extensions/ImageResourceExtension.cs @@ -0,0 +1,42 @@ +using System; +using System.Linq; +using System.Reflection; +using Xamarin.Forms; +using Xamarin.Forms.Xaml; + +namespace Aurora.Design.Extensions +{ + [ContentProperty(nameof(Source))] + public class ImageResourceExtension : IMarkupExtension + { + public string Source { get; set; } + + public object ProvideValue(IServiceProvider serviceProvider) + { + if (Source == null) + { + return null; + } + Assembly[] referencedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); + var gtkAsm = referencedAssemblies.FirstOrDefault((e) => + { + return e.FullName.Contains("Aurora.gtk"); + }); + + foreach (var res in gtkAsm.GetManifestResourceNames()) + { + Console.WriteLine("found resource: " + res); + } + + if (gtkAsm == null && gtkAsm is Assembly) + { + return null; + } + + // Do your translation lookup here, using whatever method you require + var imageSource = ImageSource.FromResource(Source, gtkAsm); + + return imageSource; + } + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Views/Albums/AlbumsView.xaml b/aurora-sharp-desktop/Aurora/Design/Views/Albums/AlbumsView.xaml new file mode 100644 index 0000000..0ecaa0e --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Views/Albums/AlbumsView.xaml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/aurora-sharp-desktop/Aurora/Design/Views/Albums/AlbumsView.xaml.cs b/aurora-sharp-desktop/Aurora/Design/Views/Albums/AlbumsView.xaml.cs new file mode 100644 index 0000000..5463a48 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Views/Albums/AlbumsView.xaml.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; + +using Xamarin.Forms; + +namespace Aurora.Design.Views.Albums +{ + public partial class AlbumsView : ContentView + { + public AlbumsView() + { + InitializeComponent(); + } + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Views/Albums/AlbumsViewModel.cs b/aurora-sharp-desktop/Aurora/Design/Views/Albums/AlbumsViewModel.cs new file mode 100644 index 0000000..56dda23 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Views/Albums/AlbumsViewModel.cs @@ -0,0 +1,10 @@ +using System; +namespace Aurora.Design.Views.Albums +{ + public class AlbumsViewModel : BaseViewModel + { + public AlbumsViewModel() + { + } + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Views/Artists/ArtistsView.xaml b/aurora-sharp-desktop/Aurora/Design/Views/Artists/ArtistsView.xaml new file mode 100644 index 0000000..b56d9a0 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Views/Artists/ArtistsView.xaml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/aurora-sharp-desktop/Aurora/Design/Views/Artists/ArtistsView.xaml.cs b/aurora-sharp-desktop/Aurora/Design/Views/Artists/ArtistsView.xaml.cs new file mode 100644 index 0000000..d6ee899 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Views/Artists/ArtistsView.xaml.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; + +using Xamarin.Forms; + +namespace Aurora.Design.Views.Artists +{ + public partial class ArtistsView : ContentView + { + public ArtistsView() + { + InitializeComponent(); + } + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Views/Artists/ArtistsViewModel.cs b/aurora-sharp-desktop/Aurora/Design/Views/Artists/ArtistsViewModel.cs new file mode 100644 index 0000000..aa9cb03 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Views/Artists/ArtistsViewModel.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Threading.Tasks; +namespace Aurora.Design.Views.Artists +{ + public class TestObj + { + public string Test1 { get; set; } + public string Test2 { get; set; } + } + public class ArtistsViewModel : BaseViewModel + { + public ArtistsViewModel() + { + } + + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Views/BaseDialogViewModel.cs b/aurora-sharp-desktop/Aurora/Design/Views/BaseDialogViewModel.cs new file mode 100644 index 0000000..279c0f7 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Views/BaseDialogViewModel.cs @@ -0,0 +1,15 @@ +using System; +using Aurora.Design.Views.Main; +namespace Aurora.Design.Views +{ + public class BaseDialogViewModel : BaseViewModel + { + public BaseDialogViewModel() + { + } + + public FinishDialogDelegate Finish { get; set; } + + public object ReturnObject { get; protected set; } + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Views/BaseViewModel.cs b/aurora-sharp-desktop/Aurora/Design/Views/BaseViewModel.cs new file mode 100644 index 0000000..d9aefeb --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Views/BaseViewModel.cs @@ -0,0 +1,104 @@ +using System; +using System.ComponentModel; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Aurora.Models.Media; +using Xamarin.Forms; +using Aurora.Design.Views.Main; + +namespace Aurora.Design.Views +{ + + public class BaseViewModel : INotifyPropertyChanged + { + public BaseViewModel() + { + } + + #region Player + + /// + /// Command event handler for player play button + /// + public virtual void OnPlayButtonCommandExecute() { } + public virtual bool CanPlayButtonCommandExecute() + { + return true; + } + + /// + /// Command event handler for player next button + /// + public virtual void OnNextButtonExecute() { } + public virtual bool CanNextButtonCommandExecute() + { + return true; + } + + /// + /// Command event handler for player previous button + /// + public virtual void OnPreviousButtonExecute() { } + public virtual bool CanPreviousButtonCommandExecute() + { + return true; + } + + /// + /// Delegate for interacting with main screen player control + /// + /// + public SetPlayerDelegate ChangePlayerState { get; set; } + + /// + /// Delegate for checking if main screen player control is currently playing + /// + /// + public GetIsPlayingDelegate IsPlaying { get; set; } + + public ShowModalDelegate ShowModal { get; set; } + + public HideModalDelegate HideModal { get; set; } + + + #endregion Player + + #region Lifecycle + /// + /// Called by main screen on view appearing + /// + /// + /// + public virtual Task OnActive() { return Task.FromResult(null); } + + /// + /// Called by main screen on view disappearing + /// + /// + /// + public virtual Task OnInactive() { return Task.FromResult(null); } + + #endregion + + #region INotifyPropertyChanged Implementation + public bool SetProperty(ref T storage, T value, [CallerMemberName] string propertyName = null) + { + if (Object.Equals(storage, value)) + return false; + + storage = value; + OnPropertyChanged(propertyName); + return true; + } + + public event PropertyChangedEventHandler PropertyChanged; + public void OnPropertyChanged([CallerMemberName] string propertyName = "") + { + if (PropertyChanged == null) + return; + + PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + #endregion + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Views/MainView/MainView.css b/aurora-sharp-desktop/Aurora/Design/Views/MainView/MainView.css new file mode 100644 index 0000000..c033d59 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Views/MainView/MainView.css @@ -0,0 +1,41 @@ +#Header { + background-color: transparent; + margin-top: 10; +} + + #Header > Entry { + margin-left: 155; + margin-top: 2; + margin-bottom: 2; + } + +#TitleContainer { + margin-top: 10; + margin-left: 10; + background-color: transparent; +} + + #TitleContainer Label { + color: white; + margin-left: 155; + font-size: 22; + vertical-align: bottom; + } + +#Player { + background-color: #303030; + height: 60; +} + +#Content { + margin-right: 10; +} + +#Modal { + height: 500; + width: 400; + margin-top: 20; + margin-bottom: 20; + border-radius: 15; + background-color: #626363; +} diff --git a/aurora-sharp-desktop/Aurora/Design/Views/MainView/MainView.xaml b/aurora-sharp-desktop/Aurora/Design/Views/MainView/MainView.xaml new file mode 100644 index 0000000..20caa21 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Views/MainView/MainView.xaml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/aurora-sharp-desktop/Aurora/Design/Views/MainView/MainView.xaml.cs b/aurora-sharp-desktop/Aurora/Design/Views/MainView/MainView.xaml.cs new file mode 100644 index 0000000..67d7f16 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Views/MainView/MainView.xaml.cs @@ -0,0 +1,263 @@ +using System; +using System.Collections.ObjectModel; +using System.Collections.Generic; +using System.Threading.Tasks; +using System.Linq; +using Aurora.Design.Components.NavigationMenu; +using Aurora.Design.Views.MainView; +using Xamarin.Forms; +using Xamarin.Forms.Xaml; +using Aurora.Models.Media; +using Aurora.Design.Components.MediaPlayer; +using Aurora.Services.Player; +using Autofac; + +namespace Aurora.Design.Views.Main +{ + public enum PlayAction + { + Play, + Pause, + Resume, + Stop + } + + /// + /// Delegate for updating player metadata + /// + /// + public delegate Task SetPlayerDelegate(BaseMedia media, PlayAction action); + public delegate bool GetIsPlayingDelegate(); + public delegate void ShowModalDelegate(Type view, BaseDialogViewModel viewModel); + public delegate void HideModalDelegate(); + public delegate void FinishDialogDelegate(); + + [XamlCompilation(XamlCompilationOptions.Compile)] + public partial class MainView : ContentPage//, IDisposable + { + private Dictionary _viewModels; + private BaseViewModel _lastViewModel; + private Player _playerComponent; + private IPlayer _playerService; + private ContentPresenter _viewContent; + + public MainView(IPlayer player) + { + InitializeComponent(); + BindingContext = new MainViewModel(); + _viewModels = new Dictionary(); + + _playerComponent = Player; + + _viewContent = (ContentPresenter)Content.FindByName("ViewContent"); + _playerService = player; + + MasterPage.ListView.ItemSelected += OnNavItemSelected; + + Appearing += OnAppearing; + } + + public void Dispose() + { + Appearing -= OnAppearing; + } + + /// + /// Event handler for side bar items being selected + /// + /// + /// + private void OnNavItemSelected(object sender, SelectedItemChangedEventArgs e) + { + var item = e.SelectedItem as NavigationItem; + if (item == null) + return; + + var view = (View)Activator.CreateInstance(item.TargetType); + + //Check if we have an instantiated viewModel + BaseViewModel vm = new BaseViewModel(); + if (_viewModels.ContainsKey(item.Id)) + { + _viewModels.TryGetValue(item.Id, out vm); + } + else + { + if (item.TargetViewModelType.BaseType != typeof(BaseViewModel)) + { + throw new InvalidOperationException("TargetViewModel field must be of type BaseViewModel"); + } + + //Instantiate new view model + vm = (BaseViewModel)App.Container.Resolve(item.TargetViewModelType); //Activator.CreateInstance(item.TargetViewModelType); + _viewModels.Add(item.Id, vm); + + } + + //Assign player controls to viewmodel + AssignPlayerControls(vm); + ChangeModalVisiblity(false); + + //Activate viewmodel + vm.OnActive(); + + //Deactivate last viewModel + _lastViewModel.OnInactive(); + //Unasign deactivating vm + UnassignPlayerControls(_lastViewModel); + + //Assign viewModel + _lastViewModel = vm; + view.BindingContext = vm; + + _viewContent.Content = view; + } + + /// + /// Event handler for page appearing. + /// + /// The object that fired the event. + /// The event arguments + private void OnAppearing(object sender, EventArgs args) + { + //Set initial view from first item in list + ObservableCollection screenList = (ObservableCollection)MasterPage.ListView.ItemsSource; + + //Assign viewModel + NavigationItem firstNavItem = screenList.FirstOrDefault().FirstOrDefault(); + var view = (View)Activator.CreateInstance(firstNavItem.TargetType); + + BaseViewModel vm = new BaseViewModel(); + if (_viewModels.ContainsKey(firstNavItem.Id)) + { + _viewModels.TryGetValue(firstNavItem.Id, out vm); + } + else + { + //Instantiate new view model + vm = (BaseViewModel)App.Container.Resolve(firstNavItem.TargetViewModelType); //(BaseViewModel)Activator.CreateInstance(firstNavItem.TargetViewModelType); + _viewModels.Add(firstNavItem.Id, vm); + } + + view.BindingContext = vm; + _lastViewModel = vm; + AssignPlayerControls(vm); + ChangeModalVisiblity(false); + vm.OnActive(); + + _viewContent.Content = view; + + } + + /// + /// Unassign setplayer delegate to prevent vms from changing player info when inactive + /// + /// + private void UnassignPlayerControls(BaseViewModel vm) + { + vm.ChangePlayerState = null; + vm.IsPlaying = null; + vm.ShowModal = null; + } + + /// + /// Assign main views music player controls to a view model + /// + /// BaseViewModel to assign controls to + private void AssignPlayerControls(BaseViewModel vm) + { + _playerComponent.PlayButtonCommand = new Command(vm.OnPlayButtonCommandExecute, vm.CanPlayButtonCommandExecute); + _playerComponent.NextButtonCommand = new Command(vm.OnNextButtonExecute, vm.CanNextButtonCommandExecute); + _playerComponent.PreviousButtonCommand = new Command(vm.OnPreviousButtonExecute, vm.CanPreviousButtonCommandExecute); + + vm.ChangePlayerState = ChangePlayerState; + vm.IsPlaying = () => + { + return _playerService.PlaybackState == PlaybackState.Playing; + }; + vm.ShowModal = this.ShowModal; + vm.HideModal = this.HideModal; + + } + + /// + /// Delegate handler for a view model controling music playback + /// + /// + /// + /// + private async Task ChangePlayerState(BaseMedia media, PlayAction action) + { + if (media != null && media.Metadata is AudioMetadata) + { + AudioMetadata meta = (AudioMetadata)media.Metadata; + _playerComponent.ArtistName = meta.Artist; + _playerComponent.SongTitle = meta.Title; + } + + switch (action) + { + case PlayAction.Pause: + { + _playerService.Pause(); + _playerComponent.IsPlaying = false; + break; + } + case PlayAction.Play: + { + if (media == null) + { + break; + } + + if (!_playerService.IsMediaLoaded(media)) + { + await _playerService.LoadMedia(media).ConfigureAwait(true); + } + + _playerService.Play(); + _playerComponent.IsPlaying = true; + break; + } + case PlayAction.Resume: + { + _playerService.Play(); + _playerComponent.IsPlaying = true; + break; + } + case PlayAction.Stop: + { + _playerService.Stop(); + _playerComponent.IsPlaying = false; + break; + } + } + + } + + private void ShowModal(Type view, BaseDialogViewModel viewModel) + { + ContentPresenter modalContainer = (ContentPresenter)Modal.FindByName("ViewContent"); + var vw = (View)Activator.CreateInstance(view); + + vw.BindingContext = viewModel; + + //Set modal container content + modalContainer.Content = vw; + + //Set visibility + ChangeModalVisiblity(true); + } + + private void HideModal() + { + ChangeModalVisiblity(false); + } + + private void ChangeModalVisiblity(bool isVisible) + { + Modal.IsVisible = isVisible; + Content.IsVisible = !isVisible; + } + } +} \ No newline at end of file diff --git a/aurora-sharp-desktop/Aurora/Design/Views/MainView/MainViewModel.cs b/aurora-sharp-desktop/Aurora/Design/Views/MainView/MainViewModel.cs new file mode 100644 index 0000000..c2771f1 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Views/MainView/MainViewModel.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Runtime.CompilerServices; +using Aurora.Design.Components.NavigationMenu; +using Aurora.Design.Views.Albums; +using Aurora.Design.Views.Artists; +using Aurora.Design.Views.Songs; +using Aurora.Design.Views.Stations; +using Aurora.Design.Views.Party; +using Aurora.Design.Views.Profile; + +namespace Aurora.Design.Views.MainView +{ + public class MainViewModel : BaseViewModel + { + private ObservableCollection _pages; + public ObservableCollection Pages + { + get { return _pages; } + set + { + if (value != _pages) + { + _pages = value; + OnPropertyChanged("Pages"); + } + + } + } + + private NavigationItem _selectedItem; + public NavigationItem SelectedItem + { + get + { + return _selectedItem; + } + set + { + SetProperty(ref _selectedItem, value); + OnPropertyChanged("Title"); + } + } + + public string Title + { + get + { + return (_selectedItem != null && !string.IsNullOrWhiteSpace(_selectedItem.Title)) ? + _selectedItem.Title : ""; + } + } + + public MainViewModel() + { + _pages = new ObservableCollection(new[] + { + new NavigationItem { Id = 0, Title = "Songs", Group="Your Music", TargetType = typeof(SongsView), TargetViewModelType = typeof(SongsViewModel) }, + new NavigationItem { Id = 1, Title = "Artists", Group="Your Music", TargetType = typeof(ArtistsView), TargetViewModelType = typeof(ArtistsViewModel)}, + new NavigationItem { Id = 2, Title = "Albums", Group="Your Music", TargetType = typeof(AlbumsView), TargetViewModelType = typeof(AlbumsViewModel)}, + new NavigationItem { Id = 3, Title = "Stations", Group="Your Music", TargetType = typeof(StationsView), TargetViewModelType = typeof(StationsViewModel)}, + new NavigationItem { Id = 4, Title = "Party", Group="Social", TargetType = typeof(PartyView), TargetViewModelType = typeof(PartyViewModel)}, + new NavigationItem { Id = 5, Title = "Profile", Group="Social", TargetType = typeof(ProfileView), TargetViewModelType = typeof(ProfileViewModel)}, + new NavigationItem { Id = 6, Title = "A + B", Group="Playlists", TargetType = typeof(StationsView), TargetViewModelType = typeof(StationsViewModel)} + }); + + } + + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Views/MainView/PageContainer.xaml b/aurora-sharp-desktop/Aurora/Design/Views/MainView/PageContainer.xaml new file mode 100644 index 0000000..4e50c92 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Views/MainView/PageContainer.xaml @@ -0,0 +1,14 @@ + + + + + + + + + \ No newline at end of file diff --git a/aurora-sharp-desktop/Aurora/Design/Views/MainView/PageContainer.xaml.cs b/aurora-sharp-desktop/Aurora/Design/Views/MainView/PageContainer.xaml.cs new file mode 100644 index 0000000..e0e9f81 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Views/MainView/PageContainer.xaml.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; + +using Xamarin.Forms; + +namespace Aurora.Design.Views.MainView +{ + public partial class PageContainer : ContentView + { + public PageContainer() + { + InitializeComponent(); + } + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Views/Party/NewPartyDialog/ConnectionDetails.cs b/aurora-sharp-desktop/Aurora/Design/Views/Party/NewPartyDialog/ConnectionDetails.cs new file mode 100644 index 0000000..ea51311 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Views/Party/NewPartyDialog/ConnectionDetails.cs @@ -0,0 +1,20 @@ +using System; +namespace Aurora.Design.Views.Party.NewPartyDialog +{ + public enum ConnectionType + { + Host, + Join + } + + public class ConnectionDetails + { + public ConnectionDetails() + { + } + + public string HostName { get; set; } + public ConnectionType ConnectionType { get; set; } + + } +} diff --git a/aurora-sharp-desktop/Aurora/Design/Views/Party/NewPartyDialog/NewPartyDialog.css b/aurora-sharp-desktop/Aurora/Design/Views/Party/NewPartyDialog/NewPartyDialog.css new file mode 100644 index 0000000..01e7912 --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Views/Party/NewPartyDialog/NewPartyDialog.css @@ -0,0 +1,25 @@ +#View { + width: 300; + height: 500; +} + +#DialogTitle { + text-align: center; + text-align-last: center; + margin-top: 20; + margin-bottom: 40; + margin-left: 20; + margin-right: 30; + color: white; + font-size: 50; + word-wrap: break-word; +} + +#Container { + background-color: transparent; +} + +Button { + background-color: transparent; +} + diff --git a/aurora-sharp-desktop/Aurora/Design/Views/Party/NewPartyDialog/NewPartyDialog.xaml b/aurora-sharp-desktop/Aurora/Design/Views/Party/NewPartyDialog/NewPartyDialog.xaml new file mode 100644 index 0000000..b58731a --- /dev/null +++ b/aurora-sharp-desktop/Aurora/Design/Views/Party/NewPartyDialog/NewPartyDialog.xaml @@ -0,0 +1,46 @@ + + + + + + + +