From b8c0dadf91b80ae2456feec9389e5ade35809fcc Mon Sep 17 00:00:00 2001 From: Brandon Watson Date: Fri, 5 Mar 2021 23:10:12 -0500 Subject: [PATCH] Migrate aurora-sharp-desktop --- aurora-sharp-desktop/.gitignore | 351 ++++++++ .../Aurora.gtk}/Aurora.gtk.csproj | 0 .../Aurora.gtk}/Helpers/Settings.cs | 0 .../Aurora.gtk}/LibVLCSharp.GTK.dll.config | 0 .../Aurora.gtk}/LibVLCSharp.dll.config | 0 .../Aurora.gtk}/MainWindow.cs | 0 .../Aurora.gtk}/OpenTK.dll.config | 0 .../Aurora.gtk}/Program.cs | 0 .../Aurora.gtk}/Properties/AssemblyInfo.cs | 0 .../Aurora.gtk}/Resources/backward.png | Bin .../Aurora.gtk}/Resources/forwards.png | Bin .../Aurora.gtk}/Resources/like.png | Bin .../Aurora.gtk}/Resources/loop.png | Bin .../Aurora.gtk}/Resources/menu.png | Bin .../Aurora.gtk}/Resources/pause.png | Bin .../Aurora.gtk}/Resources/play.png | Bin .../Aurora.gtk}/Resources/shuffle.png | Bin .../Aurora.gtk}/gtk-gui/MainWindow.cs | 0 .../Aurora.gtk}/gtk-gui/generated.cs | 0 .../Aurora.gtk}/gtk-gui/gui.stetic | 0 .../Aurora.gtk}/libvlc.dylib | Bin .../Aurora.gtk}/packages.config | 0 .../Aurora.gtk}/webkit-sharp.dll.config | 0 Aurora.sln => aurora-sharp-desktop/Aurora.sln | 0 .../Aurora.test}/Aurora.test.csproj | 0 .../ControllerTests/EventTests.cs | 0 .../ControllerTests/MediaControllerTest.cs | 0 .../ControllerTests/MembersControllerTest.cs | 0 .../ControllerTests/PartyControllerTest.cs | 0 .../Aurora.test}/ControllerTests/Setup.cs | 0 .../Aurora.test}/Models/CallContext.cs | 0 .../Models/Mock/SettingsServiceMock.cs | 0 .../Jidenna/The Chief/01 A Bull's Tale.mp3 | Bin .../Jidenna/The Chief/02 Chief Don't Run.mp3 | Bin .../Jidenna/The Chief/03 Trampoline.mp3 | Bin .../Resources/Jidenna/The Chief/04 Bambi.mp3 | Bin .../The Chief/05 Helicopters _ Beware.mp3 | Bin .../The Chief/06 Long Live The Chief.mp3 | Bin .../Jidenna/The Chief/07 2 Points.mp3 | Bin .../Jidenna/The Chief/08 The Let Out.mp3 | Bin .../Resources/Jidenna/The Chief/09 Safari.mp3 | Bin .../Resources/Jidenna/The Chief/10 Adaora.mp3 | Bin .../Jidenna/The Chief/11 Little Bit More.mp3 | Bin .../Jidenna/The Chief/12 Some Kind Of Way.mp3 | Bin .../Jidenna/The Chief/13 White Niggas.mp3 | Bin .../The Chief/14 Bully Of The Earth.mp3 | Bin .../01 Best Day Ever (Prod. By_ ID Labs).m4a | Bin .../02 Get Up (Prod. By_ Teddy Roxpin).m4a | Bin .../03 Donald Trump (Prod. By_ Sap).m4a | Bin .../04 Oy Vey (Prod By_ ID Labs).mp3 | Bin ...honte) (Prod. By_ Beanz 'n' Kornbread).mp3 | Bin ... Wear My Hat (Prod. By_ Chuck Inglish).m4a | Bin .../07 Wake Up (Prod By_ Sap & ID Labs).m4a | Bin ...round The World (Prod. By_ Just Blaze).m4a | Bin ...le (Prod. By_ Blue of The Sore Losers).m4a | Bin ...10 In The Air (Prod By_ Ritz Reynolds).m4a | Bin ...Play Ya Cards (Prod By_ Chuck Inglish).m4a | Bin .../12 She Said (Prod By_ Khrysis).m4a | Bin ...13 Life Ain't Easy (Prod. By_ ID Labs).m4a | Bin .../14 Snooze (Prod By_ ID Labs).m4a | Bin ...feat. Wiz Khalifa) (Prod. By_ ID Labs).mp3 | Bin .../16 BDE Bonus (Prod. By_ ID Labs).mp3 | Bin aurora-sharp-desktop/Aurora/App.css | 11 + aurora-sharp-desktop/Aurora/App.xaml | 31 + aurora-sharp-desktop/Aurora/App.xaml.cs | 72 ++ aurora-sharp-desktop/Aurora/AssemblyInfo.cs | 3 + aurora-sharp-desktop/Aurora/Aurora.csproj | 85 ++ .../Aurora/Design/Behaviors/BehaviorBase.cs | 42 + .../Behaviors/EventToCommandBehavior.cs | 132 +++ .../Components/DataGrid/ColumnCollection.cs | 8 + .../Design/Components/DataGrid/DataGrid.xaml | 95 +++ .../Components/DataGrid/DataGrid.xaml.cs | 756 ++++++++++++++++++ .../Components/DataGrid/DataGridColumn.cs | 135 ++++ .../DataGrid/DataGridRowTemplateSelector.cs | 30 + .../Components/DataGrid/DataGridViewCell.cs | 163 ++++ .../Components/DataGrid/IColorProvider.cs | 8 + .../Components/DataGrid/PaletteCollection.cs | 17 + .../Design/Components/DataGrid/SortData.cs | 51 ++ .../DataGrid/SortDataTypeConverter.cs | 24 + .../Components/DataGrid/SortingOrder.cs | 9 + .../Design/Components/DataGrid/down.png | Bin 0 -> 7104 bytes .../Aurora/Design/Components/DataGrid/up.png | Bin 0 -> 7104 bytes .../Design/Components/Dialogs/Modal.xaml | 10 + .../Design/Components/Dialogs/Modal.xaml.cs | 14 + .../HorizontalList/HorizontalList.cs | 208 +++++ .../Components/ImageButton/ImageButton.xaml | 11 + .../ImageButton/ImageButton.xaml.cs | 105 +++ .../Design/Components/Library/Library.css | 7 + .../Design/Components/Library/Library.xaml | 99 +++ .../Design/Components/Library/Library.xaml.cs | 139 ++++ .../Design/Components/MediaPlayer/Player.css | 44 + .../Design/Components/MediaPlayer/Player.xaml | 64 ++ .../Components/MediaPlayer/Player.xaml.cs | 303 +++++++ .../Components/MemberList/MemberList.css | 20 + .../Components/MemberList/MemberList.xaml | 31 + .../Components/MemberList/MemberList.xaml.cs | 67 ++ .../NavigationMenu/NavigationGroupItem.cs | 21 + .../NavigationMenu/NavigationItem.cs | 22 + .../NavigationMenu/NavigationMenu.css | 25 + .../NavigationMenu/NavigationMenu.xaml | 45 ++ .../NavigationMenu/NavigationMenu.xaml.cs | 102 +++ .../Design/Components/TabView/TabItem.cs | 111 +++ .../Design/Components/TabView/TabView.cs | 571 +++++++++++++ .../Converters/DoubleToLayoutOptions.cs | 24 + .../Design/Converters/InverseBoolConverter.cs | 24 + .../Design/Converters/NullToBullConverter.cs | 19 + .../Design/Converters/PlayIconConverter.cs | 10 + ...dTabHeaderToTabBackgroundColorConverter.cs | 31 + .../Design/Converters/ToUpperConverter.cs | 19 + .../Extensions/ImageResourceExtension.cs | 42 + .../Design/Views/Albums/AlbumsView.xaml | 9 + .../Design/Views/Albums/AlbumsView.xaml.cs | 15 + .../Design/Views/Albums/AlbumsViewModel.cs | 10 + .../Design/Views/Artists/ArtistsView.xaml | 9 + .../Design/Views/Artists/ArtistsView.xaml.cs | 15 + .../Design/Views/Artists/ArtistsViewModel.cs | 19 + .../Design/Views/BaseDialogViewModel.cs | 15 + .../Aurora/Design/Views/BaseViewModel.cs | 104 +++ .../Aurora/Design/Views/MainView/MainView.css | 41 + .../Design/Views/MainView/MainView.xaml | 74 ++ .../Design/Views/MainView/MainView.xaml.cs | 263 ++++++ .../Design/Views/MainView/MainViewModel.cs | 71 ++ .../Design/Views/MainView/PageContainer.xaml | 14 + .../Views/MainView/PageContainer.xaml.cs | 15 + .../Party/NewPartyDialog/ConnectionDetails.cs | 20 + .../Party/NewPartyDialog/NewPartyDialog.css | 25 + .../Party/NewPartyDialog/NewPartyDialog.xaml | 46 ++ .../NewPartyDialog/NewPartyDialog.xaml.cs | 14 + .../NewPartyDialog/NewPartyDialogViewModel.cs | 71 ++ .../Aurora/Design/Views/Party/PartyView.css | 37 + .../Aurora/Design/Views/Party/PartyView.xaml | 61 ++ .../Design/Views/Party/PartyView.xaml.cs | 13 + .../Design/Views/Party/PartyViewModel.cs | 577 +++++++++++++ .../Design/Views/Profile/ProfileView.xaml | 35 + .../Design/Views/Profile/ProfileView.xaml.cs | 14 + .../Design/Views/Profile/ProfileViewModel.cs | 46 ++ .../Aurora/Design/Views/Songs/SongsView.xaml | 13 + .../Design/Views/Songs/SongsView.xaml.cs | 15 + .../Design/Views/Songs/SongsViewModel.cs | 115 +++ .../Views/Stations/StationsViewModel.xaml | 7 + .../Views/Stations/StationsViewModel.xaml.cs | 15 + .../Views/Stations/StatiosnViewModel.cs | 10 + .../Aurora/Models/Media/AudioMetadata.cs | 35 + .../Aurora/Models/Media/BaseMedia.cs | 63 ++ .../Aurora/Models/Media/BaseMetadata.cs | 17 + .../Aurora/Models/Media/LocalAudio.cs | 73 ++ .../Aurora/Models/Media/MediaTypeEnum.cs | 9 + .../Aurora/Models/Media/RemoteAudio.cs | 94 +++ .../Aurora/Models/PartyMember.cs | 22 + .../Aurora/Proto/general.proto | 10 + aurora-sharp-desktop/Aurora/Proto/party.proto | 289 +++++++ .../Aurora/Resources/backward.png | Bin 0 -> 12942 bytes .../Aurora/Resources/forwards.png | Bin 0 -> 13207 bytes .../Aurora/Resources/like.png | Bin 0 -> 14959 bytes .../Aurora/Resources/play.png | Bin 0 -> 12606 bytes .../Aurora/Services/Client/ClientService.cs | 46 ++ .../Aurora/Services/Client/IClientService.cs | 15 + .../Services/EventManager/EventAction.cs | 19 + .../Services/EventManager/EventManager.cs | 216 +++++ .../Services/EventManager/IEventManager.cs | 60 ++ .../Services/Library/ILibraryService.cs | 12 + .../Aurora/Services/Library/LibraryService.cs | 65 ++ .../Aurora/Services/Player/IPlayer.cs | 62 ++ .../Services/Player/MediaChangedEvent.cs | 19 + .../Aurora/Services/Player/PlaybackState.cs | 12 + .../Player/PlaybackStateChangedEvent.cs | 19 + .../Aurora/Services/Player/PlayerService.cs | 263 ++++++ .../Server/Controllers/Constructor.cs | 88 ++ .../Server/Controllers/EventController.cs | 35 + .../EventSubscriptionController.cs | 66 ++ .../Server/Controllers/MediaController.cs | 142 ++++ .../Server/Controllers/MemberController.cs | 129 +++ .../Server/Controllers/PartyController.cs | 33 + .../Services/Server/Server/IServerService.cs | 27 + .../Services/Server/Server/ServerService.cs | 144 ++++ .../Services/Settings/ISettingsService.cs | 29 + .../Services/Settings/SettingsService.cs | 76 ++ aurora-sharp-desktop/Aurora/Utils/Combine.cs | 25 + .../Aurora/Utils/FileSystemUtils.cs | 82 ++ aurora-sharp-desktop/Aurora/Utils/HashUtil.cs | 25 + .../Aurora/Utils/ReflectionUtils.cs | 77 ++ .../Aurora/Utils/TimeUtils.cs | 85 ++ .../Docs}/Aurora.png | Bin README.md => aurora-sharp-desktop/README.md | 0 .../aurora.code-workspace | 0 aurora-sharp-desktop/mono.sh | 19 + 186 files changed, 8521 insertions(+) create mode 100644 aurora-sharp-desktop/.gitignore rename {Aurora.gtk => aurora-sharp-desktop/Aurora.gtk}/Aurora.gtk.csproj (100%) rename {Aurora.gtk => aurora-sharp-desktop/Aurora.gtk}/Helpers/Settings.cs (100%) rename {Aurora.gtk => aurora-sharp-desktop/Aurora.gtk}/LibVLCSharp.GTK.dll.config (100%) rename {Aurora.gtk => aurora-sharp-desktop/Aurora.gtk}/LibVLCSharp.dll.config (100%) rename {Aurora.gtk => aurora-sharp-desktop/Aurora.gtk}/MainWindow.cs (100%) rename {Aurora.gtk => aurora-sharp-desktop/Aurora.gtk}/OpenTK.dll.config (100%) rename {Aurora.gtk => aurora-sharp-desktop/Aurora.gtk}/Program.cs (100%) rename {Aurora.gtk => aurora-sharp-desktop/Aurora.gtk}/Properties/AssemblyInfo.cs (100%) rename {Aurora.gtk => aurora-sharp-desktop/Aurora.gtk}/Resources/backward.png (100%) rename {Aurora.gtk => aurora-sharp-desktop/Aurora.gtk}/Resources/forwards.png (100%) rename {Aurora.gtk => aurora-sharp-desktop/Aurora.gtk}/Resources/like.png (100%) rename {Aurora.gtk => aurora-sharp-desktop/Aurora.gtk}/Resources/loop.png (100%) rename {Aurora.gtk => aurora-sharp-desktop/Aurora.gtk}/Resources/menu.png (100%) rename {Aurora.gtk => aurora-sharp-desktop/Aurora.gtk}/Resources/pause.png (100%) rename {Aurora.gtk => aurora-sharp-desktop/Aurora.gtk}/Resources/play.png (100%) rename {Aurora.gtk => aurora-sharp-desktop/Aurora.gtk}/Resources/shuffle.png (100%) rename {Aurora.gtk => aurora-sharp-desktop/Aurora.gtk}/gtk-gui/MainWindow.cs (100%) rename {Aurora.gtk => aurora-sharp-desktop/Aurora.gtk}/gtk-gui/generated.cs (100%) rename {Aurora.gtk => aurora-sharp-desktop/Aurora.gtk}/gtk-gui/gui.stetic (100%) rename {Aurora.gtk => aurora-sharp-desktop/Aurora.gtk}/libvlc.dylib (100%) rename {Aurora.gtk => aurora-sharp-desktop/Aurora.gtk}/packages.config (100%) rename {Aurora.gtk => aurora-sharp-desktop/Aurora.gtk}/webkit-sharp.dll.config (100%) rename Aurora.sln => aurora-sharp-desktop/Aurora.sln (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Aurora.test.csproj (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/ControllerTests/EventTests.cs (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/ControllerTests/MediaControllerTest.cs (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/ControllerTests/MembersControllerTest.cs (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/ControllerTests/PartyControllerTest.cs (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/ControllerTests/Setup.cs (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Models/CallContext.cs (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Models/Mock/SettingsServiceMock.cs (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Jidenna/The Chief/01 A Bull's Tale.mp3 (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Jidenna/The Chief/02 Chief Don't Run.mp3 (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Jidenna/The Chief/03 Trampoline.mp3 (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Jidenna/The Chief/04 Bambi.mp3 (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Jidenna/The Chief/05 Helicopters _ Beware.mp3 (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Jidenna/The Chief/06 Long Live The Chief.mp3 (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Jidenna/The Chief/07 2 Points.mp3 (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Jidenna/The Chief/08 The Let Out.mp3 (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Jidenna/The Chief/09 Safari.mp3 (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Jidenna/The Chief/10 Adaora.mp3 (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Jidenna/The Chief/11 Little Bit More.mp3 (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Jidenna/The Chief/12 Some Kind Of Way.mp3 (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Jidenna/The Chief/13 White Niggas.mp3 (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Jidenna/The Chief/14 Bully Of The Earth.mp3 (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Mac Miller/Best Day Ever/01 Best Day Ever (Prod. By_ ID Labs).m4a (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Mac Miller/Best Day Ever/02 Get Up (Prod. By_ Teddy Roxpin).m4a (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Mac Miller/Best Day Ever/03 Donald Trump (Prod. By_ Sap).m4a (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Mac Miller/Best Day Ever/04 Oy Vey (Prod By_ ID Labs).mp3 (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Mac Miller/Best Day Ever/05 I'll Be There (feat. Phonte) (Prod. By_ Beanz 'n' Kornbread).mp3 (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Mac Miller/Best Day Ever/06 Wear My Hat (Prod. By_ Chuck Inglish).m4a (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Mac Miller/Best Day Ever/07 Wake Up (Prod By_ Sap & ID Labs).m4a (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Mac Miller/Best Day Ever/08 All Around The World (Prod. By_ Just Blaze).m4a (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Mac Miller/Best Day Ever/09 Down The Rabbit Hole (Prod. By_ Blue of The Sore Losers).m4a (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Mac Miller/Best Day Ever/10 In The Air (Prod By_ Ritz Reynolds).m4a (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Mac Miller/Best Day Ever/11 Play Ya Cards (Prod By_ Chuck Inglish).m4a (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Mac Miller/Best Day Ever/12 She Said (Prod By_ Khrysis).m4a (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Mac Miller/Best Day Ever/13 Life Ain't Easy (Prod. By_ ID Labs).m4a (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Mac Miller/Best Day Ever/14 Snooze (Prod By_ ID Labs).m4a (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Mac Miller/Best Day Ever/15 Keep Floatin' (feat. Wiz Khalifa) (Prod. By_ ID Labs).mp3 (100%) rename {Aurora.test => aurora-sharp-desktop/Aurora.test}/Resources/Mac Miller/Best Day Ever/16 BDE Bonus (Prod. By_ ID Labs).mp3 (100%) create mode 100644 aurora-sharp-desktop/Aurora/App.css create mode 100644 aurora-sharp-desktop/Aurora/App.xaml create mode 100644 aurora-sharp-desktop/Aurora/App.xaml.cs create mode 100644 aurora-sharp-desktop/Aurora/AssemblyInfo.cs create mode 100644 aurora-sharp-desktop/Aurora/Aurora.csproj create mode 100644 aurora-sharp-desktop/Aurora/Design/Behaviors/BehaviorBase.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Behaviors/EventToCommandBehavior.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/DataGrid/ColumnCollection.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/DataGrid/DataGrid.xaml create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/DataGrid/DataGrid.xaml.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/DataGrid/DataGridColumn.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/DataGrid/DataGridRowTemplateSelector.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/DataGrid/DataGridViewCell.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/DataGrid/IColorProvider.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/DataGrid/PaletteCollection.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/DataGrid/SortData.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/DataGrid/SortDataTypeConverter.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/DataGrid/SortingOrder.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/DataGrid/down.png create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/DataGrid/up.png create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/Dialogs/Modal.xaml create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/Dialogs/Modal.xaml.cs create mode 100755 aurora-sharp-desktop/Aurora/Design/Components/HorizontalList/HorizontalList.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/ImageButton/ImageButton.xaml create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/ImageButton/ImageButton.xaml.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/Library/Library.css create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/Library/Library.xaml create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/Library/Library.xaml.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/MediaPlayer/Player.css create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/MediaPlayer/Player.xaml create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/MediaPlayer/Player.xaml.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/MemberList/MemberList.css create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/MemberList/MemberList.xaml create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/MemberList/MemberList.xaml.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/NavigationMenu/NavigationGroupItem.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/NavigationMenu/NavigationItem.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/NavigationMenu/NavigationMenu.css create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/NavigationMenu/NavigationMenu.xaml create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/NavigationMenu/NavigationMenu.xaml.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/TabView/TabItem.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Components/TabView/TabView.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Converters/DoubleToLayoutOptions.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Converters/InverseBoolConverter.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Converters/NullToBullConverter.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Converters/PlayIconConverter.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Converters/SelectedTabHeaderToTabBackgroundColorConverter.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Converters/ToUpperConverter.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Extensions/ImageResourceExtension.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/Albums/AlbumsView.xaml create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/Albums/AlbumsView.xaml.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/Albums/AlbumsViewModel.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/Artists/ArtistsView.xaml create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/Artists/ArtistsView.xaml.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/Artists/ArtistsViewModel.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/BaseDialogViewModel.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/BaseViewModel.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/MainView/MainView.css create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/MainView/MainView.xaml create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/MainView/MainView.xaml.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/MainView/MainViewModel.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/MainView/PageContainer.xaml create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/MainView/PageContainer.xaml.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/Party/NewPartyDialog/ConnectionDetails.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/Party/NewPartyDialog/NewPartyDialog.css create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/Party/NewPartyDialog/NewPartyDialog.xaml create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/Party/NewPartyDialog/NewPartyDialog.xaml.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/Party/NewPartyDialog/NewPartyDialogViewModel.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/Party/PartyView.css create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/Party/PartyView.xaml create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/Party/PartyView.xaml.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/Party/PartyViewModel.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/Profile/ProfileView.xaml create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/Profile/ProfileView.xaml.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/Profile/ProfileViewModel.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/Songs/SongsView.xaml create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/Songs/SongsView.xaml.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/Songs/SongsViewModel.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/Stations/StationsViewModel.xaml create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/Stations/StationsViewModel.xaml.cs create mode 100644 aurora-sharp-desktop/Aurora/Design/Views/Stations/StatiosnViewModel.cs create mode 100644 aurora-sharp-desktop/Aurora/Models/Media/AudioMetadata.cs create mode 100644 aurora-sharp-desktop/Aurora/Models/Media/BaseMedia.cs create mode 100644 aurora-sharp-desktop/Aurora/Models/Media/BaseMetadata.cs create mode 100644 aurora-sharp-desktop/Aurora/Models/Media/LocalAudio.cs create mode 100644 aurora-sharp-desktop/Aurora/Models/Media/MediaTypeEnum.cs create mode 100644 aurora-sharp-desktop/Aurora/Models/Media/RemoteAudio.cs create mode 100644 aurora-sharp-desktop/Aurora/Models/PartyMember.cs create mode 100644 aurora-sharp-desktop/Aurora/Proto/general.proto create mode 100644 aurora-sharp-desktop/Aurora/Proto/party.proto create mode 100644 aurora-sharp-desktop/Aurora/Resources/backward.png create mode 100644 aurora-sharp-desktop/Aurora/Resources/forwards.png create mode 100644 aurora-sharp-desktop/Aurora/Resources/like.png create mode 100644 aurora-sharp-desktop/Aurora/Resources/play.png create mode 100644 aurora-sharp-desktop/Aurora/Services/Client/ClientService.cs create mode 100644 aurora-sharp-desktop/Aurora/Services/Client/IClientService.cs create mode 100644 aurora-sharp-desktop/Aurora/Services/EventManager/EventAction.cs create mode 100644 aurora-sharp-desktop/Aurora/Services/EventManager/EventManager.cs create mode 100644 aurora-sharp-desktop/Aurora/Services/EventManager/IEventManager.cs create mode 100644 aurora-sharp-desktop/Aurora/Services/Library/ILibraryService.cs create mode 100644 aurora-sharp-desktop/Aurora/Services/Library/LibraryService.cs create mode 100644 aurora-sharp-desktop/Aurora/Services/Player/IPlayer.cs create mode 100644 aurora-sharp-desktop/Aurora/Services/Player/MediaChangedEvent.cs create mode 100644 aurora-sharp-desktop/Aurora/Services/Player/PlaybackState.cs create mode 100644 aurora-sharp-desktop/Aurora/Services/Player/PlaybackStateChangedEvent.cs create mode 100644 aurora-sharp-desktop/Aurora/Services/Player/PlayerService.cs create mode 100644 aurora-sharp-desktop/Aurora/Services/Server/Controllers/Constructor.cs create mode 100644 aurora-sharp-desktop/Aurora/Services/Server/Controllers/EventController.cs create mode 100644 aurora-sharp-desktop/Aurora/Services/Server/Controllers/EventSubscriptionController.cs create mode 100644 aurora-sharp-desktop/Aurora/Services/Server/Controllers/MediaController.cs create mode 100644 aurora-sharp-desktop/Aurora/Services/Server/Controllers/MemberController.cs create mode 100644 aurora-sharp-desktop/Aurora/Services/Server/Controllers/PartyController.cs create mode 100644 aurora-sharp-desktop/Aurora/Services/Server/Server/IServerService.cs create mode 100644 aurora-sharp-desktop/Aurora/Services/Server/Server/ServerService.cs create mode 100644 aurora-sharp-desktop/Aurora/Services/Settings/ISettingsService.cs create mode 100644 aurora-sharp-desktop/Aurora/Services/Settings/SettingsService.cs create mode 100644 aurora-sharp-desktop/Aurora/Utils/Combine.cs create mode 100644 aurora-sharp-desktop/Aurora/Utils/FileSystemUtils.cs create mode 100644 aurora-sharp-desktop/Aurora/Utils/HashUtil.cs create mode 100644 aurora-sharp-desktop/Aurora/Utils/ReflectionUtils.cs create mode 100644 aurora-sharp-desktop/Aurora/Utils/TimeUtils.cs rename {Docs => aurora-sharp-desktop/Docs}/Aurora.png (100%) rename README.md => aurora-sharp-desktop/README.md (100%) rename aurora.code-workspace => aurora-sharp-desktop/aurora.code-workspace (100%) create mode 100755 aurora-sharp-desktop/mono.sh 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 0000000000000000000000000000000000000000..3a359e82cce9634fc8738fadbf6269fe780ba10b GIT binary patch literal 7104 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 + + + + + \ 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 @@ + + + + + + + +