Compare commits

...

119 Commits

Author SHA1 Message Date
Brandon Watson
b7578de226 Migrating cradle server 2021-03-05 23:13:57 -05:00
Brandon Watson
8d3efc00fa Merge remote-tracking branch 'aurora-cradle-sharp/develop' 2021-03-05 23:12:18 -05:00
Brandon Watson
a351fb0b67 mv . files 2021-03-05 23:12:07 -05:00
Brandon Watson
b8c0dadf91 Migrate aurora-sharp-desktop 2021-03-05 23:10:12 -05:00
Brandon Watson
d6496355a9 Merge remote-tracking branch 'aurora-sharp-desktop/master'
# Conflicts:
#	README.md
2021-03-05 23:09:55 -05:00
Brandon Watson
dc6776f70c Adding .vscode 2021-03-05 20:49:49 -05:00
Brandon Watson
0945ccfd12 Wip 2021-03-05 20:45:26 -05:00
Brandon Watson
e9065db23c First pass at party service 2021-03-05 19:09:42 -05:00
Brandon Watson
6f73df0fb7 Updated folder paths 2021-03-05 16:50:54 -05:00
Brandon Watson
4a4cef8dd7 Adding pagination tests 2021-03-05 16:13:25 -05:00
Brandon Watson
24fd683cb7 Adding cursor size tests 2021-03-05 14:30:25 -05:00
Brandon Watson
b61ffde4c9 WIP 2021-03-05 11:56:51 -05:00
Brandon Watson
91d0a55d5e Re-arranging files to add test project. Adding WIP cursor list 2021-03-04 12:08:53 -05:00
Brandon Watson
00ab0323c7 Initial Commit 2021-03-04 01:57:21 -05:00
Brandon Watson
e97698eddb Initial commit 2021-03-04 00:49:26 -05:00
watsonb8
5da500f380 Adding readme 2020-12-20 11:35:16 -05:00
watsonb8
aa876e8494 Removing test scripts 2020-12-20 10:39:04 -05:00
watsonb8
a8d4e6ff1d Updating readme 2020-12-19 17:10:40 -05:00
watsonb8
89b928bd00 Stability fixes with streaming 2020-02-05 18:44:48 -05:00
watsonb8
aae221801a Merge branch 'feature/proto.v2' 2020-02-02 17:28:56 -05:00
watsonb8
be5c9a8de0 using new api 2020-02-02 17:28:34 -05:00
watsonb8
51ab2d9c42 Removed old proto definitions (not tested) 2020-02-02 16:49:01 -05:00
watsonb8
2a7e10364e Added basic unit tests for all controllers 2020-02-02 13:05:14 -05:00
watsonb8
8231a18c3e More progress on IoC. Controllers are implemented 2020-02-02 10:26:47 -05:00
watsonb8
48d0ffa77d Adding dependency injection 2020-01-31 20:41:45 -05:00
watsonb8
f8ad2f459e Added more unit tests for members resource 2020-01-20 23:22:58 -05:00
watsonb8
df2a6b4bfc Successful unit test setup and tear down 2020-01-20 22:53:33 -05:00
watsonb8
28afcf12e4 Added unit test project 2020-01-20 18:38:05 -05:00
watsonb8
320967be89 First pass at members resource controller 2020-01-20 16:55:12 -05:00
watsonb8
4ec9db4a45 Proto builds 2020-01-19 17:30:09 -05:00
watsonb8
4f67ad908a First pass at v2 proto definitions 2020-01-19 16:11:13 -05:00
watsonb8
0967be50ea potential proto stubs 2020-01-18 18:08:03 -05:00
watsonb8
dc7879c23d Cosmetic refactoring 2020-01-18 18:07:31 -05:00
watsonb8
e796bf2f35 Event manager improvements. Changed to console.writeline instead of diagnostics 2020-01-13 19:57:02 -05:00
watsonb8
43c6a5a2c6 More styling 2019-12-23 20:07:07 -05:00
watsonb8
109457d6fa Fixed issue navigating away and back to tab view 2019-12-23 19:06:03 -05:00
watsonb8
f691deab6a Fixed members list 2019-12-23 13:29:06 -05:00
watsonb8
5f241615ad More tab view styling 2019-12-23 12:23:51 -05:00
watsonb8
fa82c4fa30 Merge branch 'feature/party_list' 2019-12-22 23:58:49 -05:00
watsonb8
1a55ce0be1 Progress on party page styling 2019-12-22 23:58:29 -05:00
watsonb8
cc0d113204 Working tab view 2019-12-22 19:30:58 -05:00
watsonb8
945b7e8e11 First pass at tab view 2019-12-22 17:10:06 -05:00
watsonb8
7560e122f8 Added tab view (not working) 2019-12-21 22:21:07 -05:00
watsonb8
881d339ffd Formatting party dialog 2019-12-21 20:12:53 -05:00
watsonb8
7f2080119f Merge branch 'feature/data_grid_enhancements' 2019-12-18 23:04:17 -05:00
watsonb8
7d2f3f9553 Styling changes 2019-12-18 23:04:00 -05:00
watsonb8
1e7e71f29d Second pass at modal 2019-12-18 22:32:08 -05:00
watsonb8
8affc8d2af Progress 2019-12-18 21:55:01 -05:00
watsonb8
9e75dd66c0 Revert "Possible problem detected"
This reverts commit 3b8fe7fb97.
2019-12-18 21:04:23 -05:00
watsonb8
3b8fe7fb97 Possible problem detected 2019-12-18 20:54:47 -05:00
watsonb8
93dc9ae8c9 Work in progress 2019-12-18 20:23:59 -05:00
watsonb8
555eb07ec1 Readability changes to datagrid. Functional changes to come 2019-12-10 21:40:17 -05:00
watsonb8
cf05045448 Progress 2019-12-10 15:10:27 -05:00
watsonb8
01736333e9 First pass at modal dialog 2019-12-07 13:47:45 -05:00
watsonb8
3576a906e2 Moved music playing controls from individual viewmodels to main view 2019-12-04 20:42:23 -08:00
watsonb8
187de97503 Using System.Diagnostics.Debug. First pass at player controls styling 2019-12-04 14:53:49 -08:00
watsonb8
22a524cfd1 Icons finally working with pngs (SVGs later maybe) 2019-12-03 15:51:16 -08:00
watsonb8
c24ff95bfc Progress with icons (not working) 2019-12-03 11:31:02 -08:00
watsonb8
6bb4b5fdd5 More styling 2019-12-01 20:20:55 -08:00
watsonb8
89d7d65d8d Styling improvements 2019-12-01 16:14:36 -08:00
watsonb8
b60f2a4f47 Serious styling. Added data grid src for future modifications in performance 2019-12-01 15:26:13 -08:00
watsonb8
061adabff8 First pass at some styling 2019-12-01 06:53:30 -05:00
watsonb8
ee0f8afd86 Updated grpc version on both projects 2019-11-30 19:30:39 -05:00
watsonb8
82b8705a0c Using css after update (Fix your ish Microsoft) 2019-11-30 15:46:09 -05:00
watsonb8
042a0d466a Updated Xamarin forms and replaced main page with grid instead of master 2019-11-30 14:41:36 -05:00
watsonb8
41e853b1c6 Pretty good audio sync if I do say so myself :) 2019-11-29 22:04:55 -05:00
watsonb8
8bea1d03da Refactored error handler for events 2019-11-29 20:54:49 -05:00
watsonb8
e822829cc0 Now able to switch screens away from party without crashing 2019-11-29 20:51:48 -05:00
watsonb8
ad1fca2009 Added a little more stability (not really) 2019-11-29 19:27:31 -05:00
watsonb8
85ab39defd Code refactoring for cleaner view model design 2019-11-29 12:37:57 -05:00
watsonb8
3398d145ac First pass at syncing worked with some bug fixes 2019-11-12 20:09:45 -05:00
watsonb8
1acc383e90 First pass at sync working. Need to ignore for special cases 2019-11-11 15:10:08 -05:00
watsonb8
5f035e9bcb Both clients playing music 2019-11-10 15:33:06 -05:00
watsonb8
bbf8f3ae57 I think i've got simultaneous playback working but it is hard to test 2019-11-09 14:55:09 -05:00
watsonb8
426a368385 Player working for party view 2019-11-08 20:25:36 -05:00
watsonb8
63efcdad69 Working player contained within main page and control delegated to viewmodels 2019-11-08 19:54:51 -05:00
watsonb8
794b4739b1 Player controls now get dynamically assigned to view model base classes.
This gives view models more freedom in how play events from the player are handled
2019-11-06 22:32:43 -05:00
watsonb8
759c05e53b Successfully playing a song in a party with one member 2019-11-04 01:43:26 -05:00
watsonb8
ac17d9a432 Updated debug scripts 2019-11-04 01:27:55 -05:00
watsonb8
f8ad0399b8 Merge branch 'master' of ssh://watsonb8.ddns.net:2122/aurora/aurora-sharp-desktop 2019-11-03 23:17:46 -05:00
watsonb8
a537edd657 Remote playback almost working 2019-11-03 23:17:34 -05:00
Brandon Watson
12cacc8001 Add README.md 2019-11-03 20:06:01 -05:00
watsonb8
a13e491a7e Added GetQueue method that returns the hosts library 2019-11-03 16:04:05 -05:00
watsonb8
9a34e31f9c Code runs 2019-11-02 15:47:41 -04:00
watsonb8
a3937e78da Viewmodels are now maintained throughout the app lifecycle 2019-07-15 15:03:59 -04:00
watsonb8
00b39b1d84 EventManager rewritten to support a push arch instead of an internal poll. Crash finally fixed!!! The dangers of threading. 2019-07-15 12:14:38 -04:00
watsonb8
d78dce44f0 Fixed issue with Horizontal list not refreshing. Added clientId to joinPartyResponse. Crashing on multiple user joins. 2019-07-12 11:34:06 -04:00
watsonb8
11a585ecc0 Merge branch 'feature/single_executor' 2019-07-10 18:23:40 -04:00
watsonb8
6a70b3d90f Removed executors. All traffic goes through RPC 2019-07-10 18:23:19 -04:00
watsonb8
e0d5a66cac Left off last commit 2019-07-10 17:17:31 -04:00
watsonb8
c99f752174 Attempts to get horizontal list to work 2019-07-10 17:17:10 -04:00
watsonb8
823e1341ca First pass at events almost buttoned up.
The goal is to get the members list to update when new users enter and leave the party.
2019-07-07 17:12:13 -04:00
Brandon Watson
74f5d3e9c6 Merge branch 'feature/party_playback_proto' into 'master'
Feature/party playback proto

See merge request aurora/aurora-sharp-desktop!1
2019-07-06 15:53:46 -04:00
watsonb8
2a3290defc Can now somewhat reliably join a party 2019-07-06 15:52:28 -04:00
watsonb8
0d64c0732e Members now appearing on host 2019-07-05 17:37:10 -04:00
watsonb8
b18abf0400 Added script for starting a second instance 2019-07-05 14:17:31 -04:00
watsonb8
ec6a7586c7 Reorganization 2019-07-05 14:17:09 -04:00
watsonb8
a01d399a1f Refactored to only having one executor per platform 2019-07-05 11:37:44 -04:00
watsonb8
0cb0546741 Progress 2019-06-25 21:17:52 -04:00
watsonb8
613365f7ad Merge branch 'master' into feature/party_playback_proto
# Conflicts:
#	Aurora/Aurora.csproj
2019-06-03 11:00:51 -04:00
watsonb8
3d92926922 Merge branch 'feature/party_view' 2019-06-03 10:57:36 -04:00
watsonb8
b0307cf7b3 Beginning stages for party executors 2019-06-03 10:57:05 -04:00
watsonb8
6503d2c410 Protobufs compile 2019-05-31 10:17:14 -04:00
watsonb8
7d94c75f27 Added components to support the party view 2019-05-31 10:12:03 -04:00
watsonb8
d3f51371dd Initial commit for a party view which displays members and the shared queue 2019-05-27 11:23:14 -05:00
watsonb8
9354c0b27b Double click to play a song in the library 2019-05-26 11:33:07 -05:00
watsonb8
64c2285817 MediaChangedEvent now hooked up to player component. 2019-05-24 17:17:14 -04:00
watsonb8
80e9a4543d Added base classes to encapsulate metadata in media 2019-05-24 15:59:26 -04:00
watsonb8
93be6dc100 See commit description for changes
Added PageContainer to dynamically load pages within the main content. Added player component to control music playback(Half functional). Added playback changed event not the player service.
2019-05-24 10:27:19 -04:00
watsonb8
2dbe9cead9 vscode and mono now the supported dev environment 2019-05-22 19:47:27 -04:00
watsonb8
5427d08dd7 Playing works when ran with mono debug 2019-05-22 18:59:15 -04:00
watsonb8
a4276a0d5d Hooked up view with play button
Set up data structures for holding and playing music
2019-05-22 10:30:41 -04:00
watsonb8
65d56a838c And now it builds and runs 2019-05-19 20:25:31 -04:00
watsonb8
4b7c146041 Restructuring. Added services. 2019-05-19 20:21:54 -04:00
watsonb8
1fcaffb9b1 First pass at songs view
Using data grid for songs view. Added FileSystemUtil for async folder traversal
2019-05-19 17:25:42 -04:00
watsonb8
ae6bd68707 Group headings working for navigation menu 2019-05-18 18:18:28 -04:00
watsonb8
9dcd411090 Navigation menu is now a reusable component 2019-05-18 17:25:36 -04:00
watsonb8
62579677cf First pass at navigation with MasterDetail 2019-05-17 18:21:02 -04:00
watsonb8
4f8b6f49fa Initial commit 2019-05-16 18:07:36 -04:00
210 changed files with 11268 additions and 2 deletions

View File

@ -1,2 +0,0 @@
# aurora

36
aurora-cradle-sharp/.gitignore vendored Normal file
View File

@ -0,0 +1,36 @@
*.swp
*.*~
project.lock.json
.DS_Store
*.pyc
nupkg/
# Visual Studio Code
# Rider
.idea
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
build/
bld/
[Bb]in/
[Oo]bj/
[Oo]ut/
msbuild.log
msbuild.err
msbuild.wrn
# Visual Studio 2015
.vs/

27
aurora-cradle-sharp/.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,27 @@
{
"version": "0.2.0",
"configurations": [
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
"name": ".NET Core Launch (console)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/AuroraCradle/bin/Debug/netcoreapp3.1/aurora-cradle-sharp.dll",
"args": [],
"cwd": "${workspaceFolder}",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "internalConsole",
"stopAtEntry": false
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach",
"processId": "${command:pickProcess}"
}
]
}

42
aurora-cradle-sharp/.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,42 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/AuroraCradle/aurora-cradle-sharp.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/aurora-cradle-sharp.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"${workspaceFolder}/aurora-cradle-sharp.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
}
]
}

View File

@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Faker.Net" Version="1.4.108" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="1.3.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AuroraCradle\aurora-cradle-sharp.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,163 @@
using Xunit;
using Aurora.Services.Signal;
using Aurora.Cursor;
using System.Collections.Generic;
using System.Linq;
namespace AuroraCradle.test
{
public class CursorListTest
{
[Theory()]
[InlineData(Aurora.Cursor.SortDirection.Asc)]
[InlineData(Aurora.Cursor.SortDirection.Desc)]
public void CursorListSortOnStringValue(Aurora.Cursor.SortDirection direction)
{
CursorList<Party> list = new CursorList<Party>();
list.Add(new Party() { Name = "asdf", Id = Faker.RandomNumber.Next().ToString() });
list.Add(new Party() { Name = "bsdf", Id = Faker.RandomNumber.Next().ToString() });
list.Add(new Party() { Name = "csdf", Id = Faker.RandomNumber.Next().ToString() });
CursorResult<Party> result = new Cursor<Party>(ref list)
.WithSort(item => item.Value.Name, direction)
.GetNextPage();
if (direction == Aurora.Cursor.SortDirection.Desc)
{
Assert.Collection<Party>(result.Result,
item => item.Name.Equals("asdf"),
item => item.Name.Equals("bsdf"),
item => item.Name.Equals("csdf"));
}
else
{
Assert.Collection<Party>(result.Result,
item => item.Name.Equals("csdf"),
item => item.Name.Equals("bsdf"),
item => item.Name.Equals("asdf"));
}
}
[Theory()]
[InlineData(2)]
[InlineData(10)]
[InlineData(49)]
[InlineData(51)]
[InlineData(-1)]
public void CursorListSizeTest(int size)
{
int numOfItems = 50;
CursorList<Party> list = new CursorList<Party>();
// Add items to cursor list
for (int i = 0; i < numOfItems; i++)
{
list.Add(new Party()
{
Name = string.Join(" ",
Faker.Lorem.Words(2)),
Id = Faker.RandomNumber.Next().ToString()
});
}
Cursor<Party> cursor = new Cursor<Party>(ref list);
if (size < 0)
{
Assert.Throws<System.InvalidOperationException>(() =>
{
cursor.WithSize(size).GetNextPage();
});
}
else if (size > numOfItems)
{
CursorResult<Party> res = cursor.WithSize(size).GetNextPage();
Assert.Equal(res.Result.Count, numOfItems);
}
else if (size < numOfItems && size > 0)
{
CursorResult<Party> res = cursor.WithSize(size).GetNextPage();
Assert.Equal(res.Result.Count, size);
}
}
[Theory()]
[InlineData(2)]
[InlineData(10)]
[InlineData(3)]
public void CursorPaginationTest(int pageSize)
{
int numOfItems = 50;
CursorList<Party> list = new CursorList<Party>();
// Add items to cursor list
for (int i = 0; i < numOfItems; i++)
{
list.Add(new Party()
{
Name = string.Join(" ",
Faker.Lorem.Words(2)),
Id = Faker.RandomNumber.Next().ToString()
});
}
string pageToken = null;
Cursor<Party> cursor = new Cursor<Party>(ref list);
List<Party> pagedResults = new List<Party>();
while (pageToken != string.Empty)
{
CursorResult<Party> res = cursor
.WithSize(pageSize)
.WithNextPageToken(pageToken)
.GetNextPage();
pagedResults.AddRange(res.Result);
pageToken = res.NextPageToken;
}
Assert.Equal(pagedResults.Count, numOfItems);
}
[Fact()]
public void CursorPaginationWithSortTest()
{
int numOfItems = 50;
CursorList<Party> cursorList = new CursorList<Party>();
// Add items to cursor list
for (int i = 0; i < numOfItems; i++)
{
cursorList.Add(new Party()
{
Name = string.Join(" ",
Faker.Lorem.Words(2)),
Id = Faker.RandomNumber.Next().ToString()
});
}
var orderedList = cursorList.ToList().OrderBy(item => item.Value.Name).ToList().ConvertAll(item => item.Value);
string pageToken = null;
Cursor<Party> cursor = new Cursor<Party>(ref cursorList);
List<Party> pagedResults = new List<Party>();
while (pageToken != string.Empty)
{
CursorResult<Party> res = cursor
.WithSize(10)
.WithSort(item => item.Value.Name, Aurora.Cursor.SortDirection.Asc)
.WithNextPageToken(pageToken)
.GetNextPage();
pagedResults.AddRange(res.Result);
pageToken = res.NextPageToken;
}
var list = cursorList.ToList();
for (int i = 0; i < orderedList.Count; i++)
{
Assert.Equal(orderedList[i], pagedResults[i]);
}
}
}
}

View File

@ -0,0 +1,9 @@
using Aurora.Cursor;
namespace Aurora.Services.Signal
{
public partial class Party : ICursorObject
{
}
}

View File

@ -0,0 +1,126 @@
using System;
using System.Collections.Generic;
using System.Linq;
#nullable enable
namespace Aurora.Cursor
{
public enum SortDirection
{
Asc,
Desc,
}
public class Cursor<T> where T : ICursorObject
{
private CursorList<T> _list;
private string? _previousPageToken;
private string? _nextPageToken;
private int _pageSize;
private Func<KeyValuePair<string, T>, string> _sortDelgate;
private SortDirection _direction;
public Cursor(ref CursorList<T> list)
{
this._list = list;
this._previousPageToken = string.Empty;
this._nextPageToken = string.Empty;
this._pageSize = 10;
this._sortDelgate = delegate (KeyValuePair<string, T> item)
{
return item.Key;
};
}
public CursorResult<T> GetNextPage()
{
if (this._pageSize < 0)
{
throw new InvalidOperationException("Page Size must be greater than zero");
}
List<KeyValuePair<string, T>> tmpList;
// Sort reference list
if (this._direction == SortDirection.Desc)
{
tmpList = this._list.OrderByDescending(this._sortDelgate).ToList();
}
else
{
tmpList = this._list.OrderBy(this._sortDelgate).ToList();
}
if (tmpList == null)
{
throw new System.NullReferenceException();
}
int startIdx = 0;
if (!string.IsNullOrEmpty(this._nextPageToken))
{
// TODO find another way to index into the list that's not a regular array search
startIdx = tmpList.FindIndex(item => item.Key == this._nextPageToken) + 1;
}
int adjustedSize = this._pageSize;
if (startIdx + this._pageSize > tmpList.Count)
{
adjustedSize = this._pageSize - ((startIdx + _pageSize) - tmpList.Count);
}
List<KeyValuePair<string, T>> selection = new List<KeyValuePair<string, T>>();
if (adjustedSize != 0)
{
selection = tmpList.GetRange(startIdx, adjustedSize);
}
return new CursorResult<T>
{
NextPageToken = this._pageSize == selection.Count ? selection[selection.Count - 1].Key : string.Empty,
PrevPageToken = string.Empty,
Count = this._list.Count,
Result = selection.ConvertAll(item => item.Value)
};
}
public CursorResult<T> GetPreviousPage()
{
throw new NotImplementedException();
}
public Cursor<T> WithNextPageToken(string nextPageToken)
{
this._nextPageToken = nextPageToken;
return this;
}
public Cursor<T> WithPreviousPageToken(string prevPageToken)
{
this._previousPageToken = prevPageToken;
return this;
}
public Cursor<T> WithSort(Func<KeyValuePair<string, T>, string> sortDelegate, SortDirection direction)
{
this._sortDelgate = sortDelegate;
this._direction = direction;
return this;
}
public Cursor<T> WithSort(string key, SortDirection direction)
{
this._sortDelgate = (item) => key;
this._direction = direction;
return this;
}
public Cursor<T> WithSize(int size)
{
this._pageSize = size;
return this;
}
}
}

View File

@ -0,0 +1,37 @@
using System.Collections.Generic;
using System.Collections;
using System;
using System.Linq;
using Aurora.Utils;
#nullable enable
namespace Aurora.Cursor
{
public class CursorList<T> : SortedList<string, T> where T : ICursorObject
{
public CursorList()
{
}
public CursorList<T> Add(T item)
{
string id = item.Id;
if (item.Id == null)
{
id = HashUtil.GetHash(new string[] { item.GetHashCode().ToString() }).ToString();
item.Id = id;
}
bool res = this.TryAdd(id, item);
if (res == false)
{
throw new System.Exception("Failed to add item to cursor list");
}
return this;
}
}
}

View File

@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Aurora.Cursor
{
public interface ICursorObject
{
string Id { get; set; }
}
}

View File

@ -0,0 +1,25 @@
using System.Collections.Generic;
namespace Aurora.Cursor
{
public class CursorResult<T>
{
public CursorResult()
{
Result = new List<T>();
}
public CursorResult(CursorResult<T> cpy)
{
NextPageToken = cpy.NextPageToken;
PrevPageToken = cpy.PrevPageToken;
Result = cpy.Result;
Count = cpy.Count;
}
public string NextPageToken { get; set; }
public string PrevPageToken { get; set; }
public List<T> Result { get; set; }
public int Count { get; set; }
}
}

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
namespace Aurora
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
// Additional configuration is required to successfully run gRPC on macOS.
// For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}

View File

@ -0,0 +1,167 @@
syntax = "proto3";
option csharp_namespace = "Aurora.Services.Signal";
package signal;
import "google/protobuf/timestamp.proto";
import "google/protobuf/field_mask.proto";
import "google/protobuf/empty.proto";
service Signal {
//**************
//Party Resource
//**************
//Get Party
rpc ListParties(ListPartiesRequest) returns (ListPartiesResponse);
rpc GetParty(GetPartyRequest) returns (Party);
rpc UpdateParty(UpdatePartyRequest) returns (Party);
rpc CreateParty(CreatePartyRequest) returns (Party);
rpc DeleteParty(DeletePartyRequest) returns (google.protobuf.Empty);
//***************************
//EventSubscriptions Resource
//***************************
//List
rpc ListEventSubscriptions(ListEventSubscriptionsRequest) returns (ListEventSubscriptionsResponse);
//Create
rpc SubscribeToEvent(EventSubscriptionRequest) returns (EventSubscription);
//Delete
rpc DeleteEventSubscription(DeleteEventSubscriptionRequest) returns (google.protobuf.Empty);
//CUSTOM: Create EventSubscription List
rpc SubscribeToEvents(EventSubscriptionListRequest) returns (EventSubscriptionListResponse);
//CUSTOM: Delete all
rpc DeleteAllEventSubscriptions(DeleteAllEventSubscriptionsRequest) returns (google.protobuf.Empty);
//*****
//Event
//*****
//Get
rpc GetEventStream(GetEventsRequest) returns (stream BaseEvent) {};
}
message Party {
//The resource name of the party
string name = 1;
string id = 2;
string display_name = 3;
string description = 4;
string host_ip = 5;
google.protobuf.Timestamp created_on = 6;
}
message PartyListItem {
string name = 1;
string id = 2;
}
message ListPartiesRequest {
int32 page_size = 1;
string page_token = 2;
string order_by = 3;
SortDirection order_direction = 4;
}
enum SortDirection {
Asc = 0;
Desc = 1;
}
message ListPartiesResponse {
repeated PartyListItem parties = 1;
string next_page_token = 2;
}
message GetPartyRequest {
string party_id = 1;
}
message CreatePartyRequest {
string party_id = 1;
Party party = 2;
}
message DeletePartyRequest {
string party_id = 1;
}
message UpdatePartyRequest {
Party party = 1;
google.protobuf.FieldMask update_mask = 2;
}
/* Event Types */
enum EventType {
NewPartiesAvailable = 0;
}
message NewPartiesAvailableEvent {
}
message BaseEvent {
//Resource name of the event ?
string name = 1;
EventType event_type = 2;
oneof derivedEvent {
NewPartiesAvailableEvent new_parties_available_event = 3;
}
}
message EventSubscription {
EventType type = 2;
}
message ListEventSubscriptionsRequest {
//Resource name of parent to the subscription list (The member)
string parent = 1;
int32 page_size = 2;
string page_token = 3;
}
message ListEventSubscriptionsResponse {
repeated EventSubscription subscriptions = 1;
string next_page_token = 2;
}
message EventSubscriptionRequest {
//Resource name of the parent to the subscription list (The member)
string parent = 1;
EventSubscription event_subscription = 2;
}
message DeleteEventSubscriptionRequest {
//Resource name of the subscription to delete
string parent = 1;
EventType type = 2;
}
message EventSubscriptionListRequest {
//Resource name of the parent to the subscription list (The member)
string parent = 1;
repeated EventSubscription event_subscriptions = 2;
}
message EventSubscriptionListResponse {
repeated EventSubscription event_subscriptions = 1;
}
message DeleteAllEventSubscriptionsRequest {
//Resource name of the parent to the subscription list (the member)
string parent = 1;
}
message GetEventsRequest {
//Resource name of the parent to the event stream (the member)
string parent = 1;
}

View File

@ -0,0 +1,7 @@
namespace Aurora.Services.Signal
{
public partial class SignalService : Signal.SignalBase
{
}
}

View File

@ -0,0 +1,79 @@
using System.Threading.Tasks;
using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
using Aurora.Cursor;
using Microsoft.Extensions.Logging;
namespace Aurora.Services.Signal
{
public partial class SignalService : Signal.SignalBase
{
private CursorList<Party> _partyList;
public override Task<Party> CreateParty(CreatePartyRequest request, ServerCallContext context)
{
Party party = new Party(request.Party);
_partyList.Add(party);
this._logger.LogInformation(string.Format("Added party with name: ${0} to parties", party.Name));
return Task.FromResult(party);
}
public override Task<Empty> DeleteParty(DeletePartyRequest request, ServerCallContext context)
{
if (this._partyList.ContainsKey(request.PartyId))
{
this._partyList.Remove(request.PartyId);
}
this._logger.LogInformation(string.Format("Deleted party with id: ${0} to parties", request.PartyId));
return Task.FromResult(new Empty());
}
public override Task<ListPartiesResponse> ListParties(ListPartiesRequest request, ServerCallContext context)
{
Cursor<Party> cursor = new Cursor<Party>(ref this._partyList);
Aurora.Cursor.SortDirection direction = Aurora.Cursor.SortDirection.Asc;
if (request.OrderDirection == SortDirection.Desc)
{
direction = Aurora.Cursor.SortDirection.Desc;
}
CursorResult<Party> res = cursor
.WithSort(request.OrderBy, direction)
.WithNextPageToken(request.PageToken)
.WithSize(request.PageSize)
.GetNextPage();
ListPartiesResponse response = new ListPartiesResponse()
{
NextPageToken = res.NextPageToken
};
response.Parties.AddRange(res.Result.ConvertAll(party => new PartyListItem()
{
Name = party.Name,
Id = party.Id
}));
return Task.FromResult(response);
}
public override Task<Party> GetParty(GetPartyRequest request, ServerCallContext context)
{
Party party = new Party();
if (this._partyList.ContainsKey(request.PartyId))
{
this._partyList.TryGetValue(request.PartyId, out party);
}
return Task.FromResult(party);
}
public override Task<Party> UpdateParty(UpdatePartyRequest request, ServerCallContext context)
{
throw new System.NotImplementedException();
}
}
}

View File

@ -0,0 +1,17 @@
using Microsoft.Extensions.Logging;
using Aurora.Cursor;
namespace Aurora.Services.Signal
{
public partial class SignalService : Signal.SignalBase
{
private readonly ILogger<SignalService> _logger;
public SignalService(ILogger<SignalService> logger)
{
_logger = logger;
this._partyList = new CursorList<Party>();
}
}
}

View File

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Aurora.Services.Signal;
namespace Aurora
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddGrpc();
services.AddGrpcReflection();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<SignalService>();
if (env.IsDevelopment())
{
endpoints.MapGrpcReflectionService();
}
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
});
});
}
}
}

View File

@ -0,0 +1,25 @@
using System.Security.Cryptography;
using System.Text;
using System;
namespace Aurora.Utils
{
public class HashUtil
{
public static Guid GetHash(string[] inputs)
{
string input = "";
foreach (string str in inputs)
{
input += str;
}
byte[] stringbytes = Encoding.UTF8.GetBytes(input);
byte[] hashedBytes = new System.Security.Cryptography
.SHA1CryptoServiceProvider()
.ComputeHash(stringbytes);
Array.Resize(ref hashedBytes, 16);
return new Guid(hashedBytes);
}
}
}

View File

@ -0,0 +1,10 @@
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Grpc": "Information",
"Microsoft": "Information"
}
}
}

View File

@ -0,0 +1,15 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"Kestrel": {
"EndpointDefaults": {
"Protocols": "Http1"
}
}
}

View File

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Protobuf Include="Src\Protos\signal.proto" GrpcServices="Server" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Grpc.AspNetCore" Version="2.27.0" />
<PackageReference Include="Grpc.AspNetCore.Server.Reflection" Version="2.35.0" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,2 @@
# aurora-cradle-sharp

View File

@ -0,0 +1,15 @@
{
"folders": [
{
"path": "."
}
],
"settings": {
"files.exclude": {
"**/obj": true
},
"dotnet-test-explorer.testProjectPath": "./AuroraCradle.test",
"editor.formatOnSave": true,
"editor.defaultFormatter": "ms-dotnettools.csharp"
}
}

351
aurora-sharp-desktop/.gitignore vendored Normal file
View File

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

View File

@ -0,0 +1,36 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"preLaunchTask": "build-and-start-debug-server",
"name": "Start and Attach",
"type": "mono",
"request": "attach",
"address": "localhost",
"port": 55555,
},
{
"preLaunchTask": "Attach",
"name": "Attach",
"type": "mono",
"request": "attach",
"address": "localhost",
"port": 55555,
},
{
"preLaunchTask": "build",
"name": "Launch",
"type": "mono",
"request": "launch",
"console": "internalConsole",
"program": "${workspaceFolder}/Aurora.gtk/bin/Debug/Aurora.gtk.exe",
"args": [
"--debug",
"--debuggre-agent=transport=dt_socket,server=y,address=127.0.0.1:5555"
]
}
]
}

45
aurora-sharp-desktop/.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,45 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "build",
"type": "shell",
"command": "msbuild",
"args": [
// Ask msbuild to generate full paths for file names.
"/property:GenerateFullPaths=true",
"/t:build"
],
"group": "build",
"problemMatcher": "$msCompile"
},
{
"label": "build-and-start-debug-server",
"type": "shell",
"isBackground": true,
"command": "./start.sh",
// This task is run before some debug tasks.
// Problem is, it's a watch script, and since it never exits, VSCode
// complains. All this is needed so VSCode just lets it run.
"problemMatcher": [
{
"pattern": [
{
"regexp": ".",
"file": 1,
"location": 2,
"message": 3
}
],
"background": {
"activeOnStart": true,
"beginsPattern": ".",
"endsPattern": ".",
}
}
]
}
]
}

View File

@ -0,0 +1,549 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\Xamarin.Forms.4.3.0.991211\build\Xamarin.Forms.props" Condition="Exists('..\packages\Xamarin.Forms.4.3.0.991211\build\Xamarin.Forms.props')" />
<Import Project="..\packages\Grpc.Tools.2.25.0\build\Grpc.Tools.props" Condition="Exists('..\packages\Grpc.Tools.2.25.0\build\Grpc.Tools.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">iPhoneSimulator</Platform>
<ProjectGuid>{E8C8C24A-5C51-47CB-B241-F5A9F0E808B1}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>Aurora.gtk</RootNamespace>
<AssemblyName>Aurora.gtk</AssemblyName>
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhoneSimulator' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhoneSimulator' ">
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="gtk-sharp, Version=2.4.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="gdk-sharp, Version=2.4.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="glib-sharp, Version=2.4.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="glade-sharp, Version=2.4.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="pango-sharp, Version=2.4.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="atk-sharp, Version=2.4.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="Mono.Posix" />
<Reference Include="Xamarin.Forms.Core">
<HintPath>..\packages\Xamarin.Forms.4.3.0.991211\lib\netstandard2.0\Xamarin.Forms.Core.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Platform">
<HintPath>..\packages\Xamarin.Forms.4.3.0.991211\lib\netstandard2.0\Xamarin.Forms.Platform.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Xaml">
<HintPath>..\packages\Xamarin.Forms.4.3.0.991211\lib\netstandard2.0\Xamarin.Forms.Xaml.dll</HintPath>
</Reference>
<Reference Include="OpenTK">
<HintPath>..\packages\OpenTK.3.1.0\lib\net20\OpenTK.dll</HintPath>
</Reference>
<Reference Include="webkit-sharp">
<HintPath>..\packages\Xamarin.Forms.Platform.GTK.4.3.0.991211\lib\net45\webkit-sharp.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Platform.GTK">
<HintPath>..\packages\Xamarin.Forms.Platform.GTK.4.3.0.991211\lib\net45\Xamarin.Forms.Platform.GTK.dll</HintPath>
</Reference>
<Reference Include="System.Reflection">
<HintPath>..\packages\System.Reflection.4.3.0\lib\net462\System.Reflection.dll</HintPath>
</Reference>
<Reference Include="mscorlib" />
<Reference Include="System.Reflection.TypeExtensions">
<HintPath>..\packages\System.Reflection.TypeExtensions.4.6.0\lib\net461\System.Reflection.TypeExtensions.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.Serialization.Primitives">
<HintPath>..\packages\System.Runtime.Serialization.Primitives.4.3.0\lib\net46\System.Runtime.Serialization.Primitives.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.Serialization" />
<Reference Include="taglib-sharp">
<HintPath>..\packages\taglib-sharp-netstandard2.0.2.1.0\lib\netstandard2.0\taglib-sharp.dll</HintPath>
</Reference>
<Reference Include="System.Windows.Forms" />
<Reference Include="Microsoft.Threading.Tasks">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.Net" />
<Reference Include="System.ValueTuple">
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="LibVLCSharp">
<HintPath>..\packages\LibVLCSharp.3.3.1\lib\net40\LibVLCSharp.dll</HintPath>
</Reference>
<Reference Include="LibVLCSharp.Forms">
<HintPath>..\packages\LibVLCSharp.Forms.3.3.1\lib\netstandard2.0\LibVLCSharp.Forms.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.InteropServices.RuntimeInformation">
<HintPath>..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
</Reference>
<Reference Include="LibVLCSharp.GTK">
<HintPath>..\packages\LibVLCSharp.GTK.3.3.1\lib\net47\LibVLCSharp.GTK.dll</HintPath>
</Reference>
<Reference Include="LibVLCSharp.Forms.Platforms.GTK">
<HintPath>..\packages\LibVLCSharp.Forms.GTK.3.3.1\lib\net47\LibVLCSharp.Forms.Platforms.GTK.dll</HintPath>
</Reference>
<Reference Include="Google.Protobuf">
<HintPath>..\packages\Google.Protobuf.3.10.1\lib\net45\Google.Protobuf.dll</HintPath>
</Reference>
<Reference Include="System.Interactive.Async">
<HintPath>..\packages\System.Interactive.Async.4.0.0\lib\net461\System.Interactive.Async.dll</HintPath>
</Reference>
<Reference Include="Grpc.Core.Api">
<HintPath>..\packages\Grpc.Core.Api.2.25.0\lib\net45\Grpc.Core.Api.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Grpc.Core">
<HintPath>..\packages\Grpc.Core.2.25.0\lib\net45\Grpc.Core.dll</HintPath>
</Reference>
<Reference Include="Plugin.Settings.Abstractions">
<HintPath>..\packages\Xam.Plugins.Settings.3.1.1\lib\net45\Plugin.Settings.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Plugin.Settings">
<HintPath>..\packages\Xam.Plugins.Settings.3.1.1\lib\net45\Plugin.Settings.dll</HintPath>
</Reference>
<Reference Include="Sharpnado.Infrastructure">
<HintPath>..\packages\Sharpnado.Forms.HorizontalListView.1.3.0\lib\netstandard2.0\Sharpnado.Infrastructure.dll</HintPath>
</Reference>
<Reference Include="Sharpnado.Presentation.Forms">
<HintPath>..\packages\Sharpnado.Forms.HorizontalListView.1.3.0\lib\netstandard2.0\Sharpnado.Presentation.Forms.dll</HintPath>
</Reference>
<Reference Include="System.Buffers">
<HintPath>..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll</HintPath>
</Reference>
<Reference Include="System.Numerics.Vectors">
<HintPath>..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Runtime.CompilerServices.Unsafe">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Memory">
<HintPath>..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks.Extensions">
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.2\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Bcl.AsyncInterfaces">
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
</Reference>
<Reference Include="System.Linq.Async">
<HintPath>..\packages\System.Linq.Async.4.0.0\lib\net461\System.Linq.Async.dll</HintPath>
</Reference>
<Reference Include="OpenTK.GLControl">
<HintPath>..\packages\OpenTK.GLControl.3.0.1\lib\net20\OpenTK.GLControl.dll</HintPath>
</Reference>
<Reference Include="DLToolkit.Forms.Controls.FlowListView">
<HintPath>..\packages\DLToolkit.Forms.Controls.FlowListView.2.0.11\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10+netstandard1.0\DLToolkit.Forms.Controls.FlowListView.dll</HintPath>
</Reference>
<Reference Include="CarouselView.FormsPlugin.Abstractions">
<HintPath>..\packages\CarouselView.FormsPlugin.5.2.0\lib\netstandard2.0\CarouselView.FormsPlugin.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Autofac">
<HintPath>..\packages\Autofac.5.0.0\lib\net461\Autofac.dll</HintPath>
</Reference>
<Reference Include="System.ComponentModel.Composition" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="gtk-gui\gui.stetic">
<LogicalName>gui.stetic</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="LibVLCSharp.GTK.dll.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
<EmbeddedResource Include="LibVLCSharp.dll.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Compile Include="gtk-gui\generated.cs" />
<Compile Include="MainWindow.cs" />
<Compile Include="gtk-gui\MainWindow.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Helpers\Settings.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="Themes\apps.rc" />
<None Include="Themes\assets-dark.svg" />
<None Include="Themes\assets.svg" />
<None Include="Themes\assets.txt" />
<None Include="Themes\gtkrc" />
<None Include="Themes\gtkrc-dark" />
<None Include="Themes\gtkrc-light" />
<None Include="Themes\hacks.rc" />
<None Include="Themes\main.rc" />
<None Include="Themes\render-assets-dark.sh" />
<None Include="Themes\render-assets.sh" />
<None Include="Themes\assets\border.png" />
<None Include="Themes\assets\button-active.png" />
<None Include="Themes\assets\button-hover.png" />
<None Include="Themes\assets\button-insensitive.png" />
<None Include="Themes\assets\button.png" />
<None Include="Themes\assets\checkbox-checked-active.png" />
<None Include="Themes\assets\checkbox-checked-hover.png" />
<None Include="Themes\assets\checkbox-checked-insensitive.png" />
<None Include="Themes\assets\checkbox-checked.png" />
<None Include="Themes\assets\checkbox-mixed-active.png" />
<None Include="Themes\assets\checkbox-mixed-hover.png" />
<None Include="Themes\assets\checkbox-mixed-insensitive.png" />
<None Include="Themes\assets\checkbox-mixed.png" />
<None Include="Themes\assets\checkbox-unchecked-active.png" />
<None Include="Themes\assets\checkbox-unchecked-hover.png" />
<None Include="Themes\assets\checkbox-unchecked-insensitive.png" />
<None Include="Themes\assets\checkbox-unchecked.png" />
<None Include="Themes\assets\combo-ltr-button-active.png" />
<None Include="Themes\assets\combo-ltr-button-hover.png" />
<None Include="Themes\assets\combo-ltr-button-insensitive.png" />
<None Include="Themes\assets\combo-ltr-button.png" />
<None Include="Themes\assets\combo-ltr-entry-active.png" />
<None Include="Themes\assets\combo-ltr-entry-insensitive.png" />
<None Include="Themes\assets\combo-ltr-entry.png" />
<None Include="Themes\assets\combo-rtl-button-active.png" />
<None Include="Themes\assets\combo-rtl-button-hover.png" />
<None Include="Themes\assets\combo-rtl-button-insensitive.png" />
<None Include="Themes\assets\combo-rtl-button.png" />
<None Include="Themes\assets\combo-rtl-entry-active.png" />
<None Include="Themes\assets\combo-rtl-entry-insensitive.png" />
<None Include="Themes\assets\combo-rtl-entry.png" />
<None Include="Themes\assets\entry-active.png" />
<None Include="Themes\assets\entry-background-insensitive.png" />
<None Include="Themes\assets\entry-background.png" />
<None Include="Themes\assets\entry-insensitive.png" />
<None Include="Themes\assets\entry.png" />
<None Include="Themes\assets\flat-button-active.png" />
<None Include="Themes\assets\flat-button-hover.png" />
<None Include="Themes\assets\flat-button-insensitive.png" />
<None Include="Themes\assets\flat-button.png" />
<None Include="Themes\assets\focus.png" />
<None Include="Themes\assets\frame-inline.png" />
<None Include="Themes\assets\frame-notebook.png" />
<None Include="Themes\assets\frame.png" />
<None Include="Themes\assets\handle-horz-active.png" />
<None Include="Themes\assets\handle-horz-hover.png" />
<None Include="Themes\assets\handle-horz.png" />
<None Include="Themes\assets\handle-vert-active.png" />
<None Include="Themes\assets\handle-vert-hover.png" />
<None Include="Themes\assets\handle-vert.png" />
<None Include="Themes\assets\menu-checkbox-checked-insensitive.png" />
<None Include="Themes\assets\menu-checkbox-checked.png" />
<None Include="Themes\assets\menu-checkbox-mixed-insensitive.png" />
<None Include="Themes\assets\menu-checkbox-mixed.png" />
<None Include="Themes\assets\menu-checkbox-unchecked-insensitive.png" />
<None Include="Themes\assets\menu-checkbox-unchecked.png" />
<None Include="Themes\assets\menu-radio-checked-insensitive.png" />
<None Include="Themes\assets\menu-radio-checked.png" />
<None Include="Themes\assets\menu-radio-mixed-insensitive.png" />
<None Include="Themes\assets\menu-radio-mixed.png" />
<None Include="Themes\assets\menu-radio-unchecked-insensitive.png" />
<None Include="Themes\assets\menu-radio-unchecked.png" />
<None Include="Themes\assets\notebook-combo-ltr-entry-active.png" />
<None Include="Themes\assets\notebook-combo-ltr-entry-insensitive.png" />
<None Include="Themes\assets\notebook-combo-ltr-entry.png" />
<None Include="Themes\assets\notebook-combo-rtl-entry-active.png" />
<None Include="Themes\assets\notebook-combo-rtl-entry-insensitive.png" />
<None Include="Themes\assets\notebook-combo-rtl-entry.png" />
<None Include="Themes\assets\notebook-entry-active.png" />
<None Include="Themes\assets\notebook-entry-insensitive.png" />
<None Include="Themes\assets\notebook-entry.png" />
<None Include="Themes\assets\pan-down-alt-insensitive.png" />
<None Include="Themes\assets\pan-down-alt.png" />
<None Include="Themes\assets\pan-down-insensitive.png" />
<None Include="Themes\assets\pan-down.png" />
<None Include="Themes\assets\pan-left-alt-insensitive.png" />
<None Include="Themes\assets\pan-left-alt.png" />
<None Include="Themes\assets\pan-left-insensitive.png" />
<None Include="Themes\assets\pan-left-semi.png" />
<None Include="Themes\assets\pan-left.png" />
<None Include="Themes\assets\pan-right-alt-insensitive.png" />
<None Include="Themes\assets\pan-right-alt.png" />
<None Include="Themes\assets\pan-right-insensitive.png" />
<None Include="Themes\assets\pan-right-semi.png" />
<None Include="Themes\assets\pan-right.png" />
<None Include="Themes\assets\pan-up-alt-insensitive.png" />
<None Include="Themes\assets\pan-up-alt.png" />
<None Include="Themes\assets\pan-up-insensitive.png" />
<None Include="Themes\assets\pan-up.png" />
<None Include="Themes\assets\progressbar-progress.png" />
<None Include="Themes\assets\progressbar-trough.png" />
<None Include="Themes\assets\radio-checked-active.png" />
<None Include="Themes\assets\radio-checked-hover.png" />
<None Include="Themes\assets\radio-checked-insensitive.png" />
<None Include="Themes\assets\radio-checked.png" />
<None Include="Themes\assets\radio-mixed-active.png" />
<None Include="Themes\assets\radio-mixed-hover.png" />
<None Include="Themes\assets\radio-mixed-insensitive.png" />
<None Include="Themes\assets\radio-mixed.png" />
<None Include="Themes\assets\radio-unchecked-active.png" />
<None Include="Themes\assets\radio-unchecked-hover.png" />
<None Include="Themes\assets\radio-unchecked-insensitive.png" />
<None Include="Themes\assets\radio-unchecked.png" />
<None Include="Themes\assets\scale-horz-trough-active.png" />
<None Include="Themes\assets\scale-horz-trough-insensitive.png" />
<None Include="Themes\assets\scale-horz-trough.png" />
<None Include="Themes\assets\scale-slider-active.png" />
<None Include="Themes\assets\scale-slider-hover.png" />
<None Include="Themes\assets\scale-slider-insensitive.png" />
<None Include="Themes\assets\scale-slider.png" />
<None Include="Themes\assets\scale-vert-trough-active.png" />
<None Include="Themes\assets\scale-vert-trough-insensitive.png" />
<None Include="Themes\assets\scale-vert-trough.png" />
<None Include="Themes\assets\scrollbar-horz-slider-active.png" />
<None Include="Themes\assets\scrollbar-horz-slider-hover.png" />
<None Include="Themes\assets\scrollbar-horz-slider-insensitive.png" />
<None Include="Themes\assets\scrollbar-horz-slider.png" />
<None Include="Themes\assets\scrollbar-horz-trough.png" />
<None Include="Themes\assets\scrollbar-vert-ltr-slider-active.png" />
<None Include="Themes\assets\scrollbar-vert-ltr-slider-hover.png" />
<None Include="Themes\assets\scrollbar-vert-ltr-slider-insensitive.png" />
<None Include="Themes\assets\scrollbar-vert-ltr-slider.png" />
<None Include="Themes\assets\scrollbar-vert-ltr-trough.png" />
<None Include="Themes\assets\scrollbar-vert-rtl-slider-active.png" />
<None Include="Themes\assets\scrollbar-vert-rtl-slider-hover.png" />
<None Include="Themes\assets\scrollbar-vert-rtl-slider-insensitive.png" />
<None Include="Themes\assets\scrollbar-vert-rtl-slider.png" />
<None Include="Themes\assets\scrollbar-vert-rtl-trough.png" />
<None Include="Themes\assets\spin-ltr-down-active.png" />
<None Include="Themes\assets\spin-ltr-down-hover.png" />
<None Include="Themes\assets\spin-ltr-down-insensitive.png" />
<None Include="Themes\assets\spin-ltr-down.png" />
<None Include="Themes\assets\spin-ltr-up-active.png" />
<None Include="Themes\assets\spin-ltr-up-hover.png" />
<None Include="Themes\assets\spin-ltr-up-insensitive.png" />
<None Include="Themes\assets\spin-ltr-up.png" />
<None Include="Themes\assets\spin-rtl-down-active.png" />
<None Include="Themes\assets\spin-rtl-down-hover.png" />
<None Include="Themes\assets\spin-rtl-down-insensitive.png" />
<None Include="Themes\assets\spin-rtl-down.png" />
<None Include="Themes\assets\spin-rtl-up-active.png" />
<None Include="Themes\assets\spin-rtl-up-hover.png" />
<None Include="Themes\assets\spin-rtl-up-insensitive.png" />
<None Include="Themes\assets\spin-rtl-up.png" />
<None Include="Themes\assets\tab.png" />
<None Include="Themes\assets\treeview-ltr-button-active.png" />
<None Include="Themes\assets\treeview-ltr-button-hover.png" />
<None Include="Themes\assets\treeview-ltr-button.png" />
<None Include="Themes\assets\treeview-rtl-button-active.png" />
<None Include="Themes\assets\treeview-rtl-button-hover.png" />
<None Include="Themes\assets\treeview-rtl-button.png" />
<None Include="Themes\assets-dark\border.png" />
<None Include="Themes\assets-dark\button-active.png" />
<None Include="Themes\assets-dark\button-hover.png" />
<None Include="Themes\assets-dark\button-insensitive.png" />
<None Include="Themes\assets-dark\button.png" />
<None Include="Themes\assets-dark\checkbox-checked-active.png" />
<None Include="Themes\assets-dark\checkbox-checked-hover.png" />
<None Include="Themes\assets-dark\checkbox-checked-insensitive.png" />
<None Include="Themes\assets-dark\checkbox-checked.png" />
<None Include="Themes\assets-dark\checkbox-mixed-active.png" />
<None Include="Themes\assets-dark\checkbox-mixed-hover.png" />
<None Include="Themes\assets-dark\checkbox-mixed-insensitive.png" />
<None Include="Themes\assets-dark\checkbox-mixed.png" />
<None Include="Themes\assets-dark\checkbox-unchecked-active.png" />
<None Include="Themes\assets-dark\checkbox-unchecked-hover.png" />
<None Include="Themes\assets-dark\checkbox-unchecked-insensitive.png" />
<None Include="Themes\assets-dark\checkbox-unchecked.png" />
<None Include="Themes\assets-dark\combo-ltr-button-active.png" />
<None Include="Themes\assets-dark\combo-ltr-button-hover.png" />
<None Include="Themes\assets-dark\combo-ltr-button-insensitive.png" />
<None Include="Themes\assets-dark\combo-ltr-button.png" />
<None Include="Themes\assets-dark\combo-ltr-entry-active.png" />
<None Include="Themes\assets-dark\combo-ltr-entry-insensitive.png" />
<None Include="Themes\assets-dark\combo-ltr-entry.png" />
<None Include="Themes\assets-dark\combo-rtl-button-active.png" />
<None Include="Themes\assets-dark\combo-rtl-button-hover.png" />
<None Include="Themes\assets-dark\combo-rtl-button-insensitive.png" />
<None Include="Themes\assets-dark\combo-rtl-button.png" />
<None Include="Themes\assets-dark\combo-rtl-entry-active.png" />
<None Include="Themes\assets-dark\combo-rtl-entry-insensitive.png" />
<None Include="Themes\assets-dark\combo-rtl-entry.png" />
<None Include="Themes\assets-dark\entry-active.png" />
<None Include="Themes\assets-dark\entry-background-insensitive.png" />
<None Include="Themes\assets-dark\entry-background.png" />
<None Include="Themes\assets-dark\entry-insensitive.png" />
<None Include="Themes\assets-dark\entry.png" />
<None Include="Themes\assets-dark\flat-button-active.png" />
<None Include="Themes\assets-dark\flat-button-hover.png" />
<None Include="Themes\assets-dark\flat-button-insensitive.png" />
<None Include="Themes\assets-dark\flat-button.png" />
<None Include="Themes\assets-dark\focus.png" />
<None Include="Themes\assets-dark\frame-inline.png" />
<None Include="Themes\assets-dark\frame-notebook.png" />
<None Include="Themes\assets-dark\frame.png" />
<None Include="Themes\assets-dark\handle-horz-active.png" />
<None Include="Themes\assets-dark\handle-horz-hover.png" />
<None Include="Themes\assets-dark\handle-horz.png" />
<None Include="Themes\assets-dark\handle-vert-active.png" />
<None Include="Themes\assets-dark\handle-vert-hover.png" />
<None Include="Themes\assets-dark\handle-vert.png" />
<None Include="Themes\assets-dark\menu-checkbox-checked-insensitive.png" />
<None Include="Themes\assets-dark\menu-checkbox-checked.png" />
<None Include="Themes\assets-dark\menu-checkbox-mixed-insensitive.png" />
<None Include="Themes\assets-dark\menu-checkbox-mixed.png" />
<None Include="Themes\assets-dark\menu-checkbox-unchecked-insensitive.png" />
<None Include="Themes\assets-dark\menu-checkbox-unchecked.png" />
<None Include="Themes\assets-dark\menu-radio-checked-insensitive.png" />
<None Include="Themes\assets-dark\menu-radio-checked.png" />
<None Include="Themes\assets-dark\menu-radio-mixed-insensitive.png" />
<None Include="Themes\assets-dark\menu-radio-mixed.png" />
<None Include="Themes\assets-dark\menu-radio-unchecked-insensitive.png" />
<None Include="Themes\assets-dark\menu-radio-unchecked.png" />
<None Include="Themes\assets-dark\notebook-combo-ltr-entry-active.png" />
<None Include="Themes\assets-dark\notebook-combo-ltr-entry-insensitive.png" />
<None Include="Themes\assets-dark\notebook-combo-ltr-entry.png" />
<None Include="Themes\assets-dark\notebook-combo-rtl-entry-active.png" />
<None Include="Themes\assets-dark\notebook-combo-rtl-entry-insensitive.png" />
<None Include="Themes\assets-dark\notebook-combo-rtl-entry.png" />
<None Include="Themes\assets-dark\notebook-entry-active.png" />
<None Include="Themes\assets-dark\notebook-entry-insensitive.png" />
<None Include="Themes\assets-dark\notebook-entry.png" />
<None Include="Themes\assets-dark\pan-down-alt-insensitive.png" />
<None Include="Themes\assets-dark\pan-down-alt.png" />
<None Include="Themes\assets-dark\pan-down-insensitive.png" />
<None Include="Themes\assets-dark\pan-down.png" />
<None Include="Themes\assets-dark\pan-left-alt-insensitive.png" />
<None Include="Themes\assets-dark\pan-left-alt.png" />
<None Include="Themes\assets-dark\pan-left-insensitive.png" />
<None Include="Themes\assets-dark\pan-left-semi.png" />
<None Include="Themes\assets-dark\pan-left.png" />
<None Include="Themes\assets-dark\pan-right-alt-insensitive.png" />
<None Include="Themes\assets-dark\pan-right-alt.png" />
<None Include="Themes\assets-dark\pan-right-insensitive.png" />
<None Include="Themes\assets-dark\pan-right-semi.png" />
<None Include="Themes\assets-dark\pan-right.png" />
<None Include="Themes\assets-dark\pan-up-alt-insensitive.png" />
<None Include="Themes\assets-dark\pan-up-alt.png" />
<None Include="Themes\assets-dark\pan-up-insensitive.png" />
<None Include="Themes\assets-dark\pan-up.png" />
<None Include="Themes\assets-dark\progressbar-progress.png" />
<None Include="Themes\assets-dark\progressbar-trough.png" />
<None Include="Themes\assets-dark\radio-checked-active.png" />
<None Include="Themes\assets-dark\radio-checked-hover.png" />
<None Include="Themes\assets-dark\radio-checked-insensitive.png" />
<None Include="Themes\assets-dark\radio-checked.png" />
<None Include="Themes\assets-dark\radio-mixed-active.png" />
<None Include="Themes\assets-dark\radio-mixed-hover.png" />
<None Include="Themes\assets-dark\radio-mixed-insensitive.png" />
<None Include="Themes\assets-dark\radio-mixed.png" />
<None Include="Themes\assets-dark\radio-unchecked-active.png" />
<None Include="Themes\assets-dark\radio-unchecked-hover.png" />
<None Include="Themes\assets-dark\radio-unchecked-insensitive.png" />
<None Include="Themes\assets-dark\radio-unchecked.png" />
<None Include="Themes\assets-dark\scale-horz-trough-active.png" />
<None Include="Themes\assets-dark\scale-horz-trough-insensitive.png" />
<None Include="Themes\assets-dark\scale-horz-trough.png" />
<None Include="Themes\assets-dark\scale-slider-active.png" />
<None Include="Themes\assets-dark\scale-slider-hover.png" />
<None Include="Themes\assets-dark\scale-slider-insensitive.png" />
<None Include="Themes\assets-dark\scale-slider.png" />
<None Include="Themes\assets-dark\scale-vert-trough-active.png" />
<None Include="Themes\assets-dark\scale-vert-trough-insensitive.png" />
<None Include="Themes\assets-dark\scale-vert-trough.png" />
<None Include="Themes\assets-dark\scrollbar-horz-slider-active.png" />
<None Include="Themes\assets-dark\scrollbar-horz-slider-hover.png" />
<None Include="Themes\assets-dark\scrollbar-horz-slider-insensitive.png" />
<None Include="Themes\assets-dark\scrollbar-horz-slider.png" />
<None Include="Themes\assets-dark\scrollbar-horz-trough.png" />
<None Include="Themes\assets-dark\scrollbar-vert-ltr-slider-active.png" />
<None Include="Themes\assets-dark\scrollbar-vert-ltr-slider-hover.png" />
<None Include="Themes\assets-dark\scrollbar-vert-ltr-slider-insensitive.png" />
<None Include="Themes\assets-dark\scrollbar-vert-ltr-slider.png" />
<None Include="Themes\assets-dark\scrollbar-vert-ltr-trough.png" />
<None Include="Themes\assets-dark\scrollbar-vert-rtl-slider-active.png" />
<None Include="Themes\assets-dark\scrollbar-vert-rtl-slider-hover.png" />
<None Include="Themes\assets-dark\scrollbar-vert-rtl-slider-insensitive.png" />
<None Include="Themes\assets-dark\scrollbar-vert-rtl-slider.png" />
<None Include="Themes\assets-dark\scrollbar-vert-rtl-trough.png" />
<None Include="Themes\assets-dark\spin-ltr-down-active.png" />
<None Include="Themes\assets-dark\spin-ltr-down-hover.png" />
<None Include="Themes\assets-dark\spin-ltr-down-insensitive.png" />
<None Include="Themes\assets-dark\spin-ltr-down.png" />
<None Include="Themes\assets-dark\spin-ltr-up-active.png" />
<None Include="Themes\assets-dark\spin-ltr-up-hover.png" />
<None Include="Themes\assets-dark\spin-ltr-up-insensitive.png" />
<None Include="Themes\assets-dark\spin-ltr-up.png" />
<None Include="Themes\assets-dark\spin-rtl-down-active.png" />
<None Include="Themes\assets-dark\spin-rtl-down-hover.png" />
<None Include="Themes\assets-dark\spin-rtl-down-insensitive.png" />
<None Include="Themes\assets-dark\spin-rtl-down.png" />
<None Include="Themes\assets-dark\spin-rtl-up-active.png" />
<None Include="Themes\assets-dark\spin-rtl-up-hover.png" />
<None Include="Themes\assets-dark\spin-rtl-up-insensitive.png" />
<None Include="Themes\assets-dark\spin-rtl-up.png" />
<None Include="Themes\assets-dark\tab.png" />
<None Include="Themes\assets-dark\treeview-ltr-button-active.png" />
<None Include="Themes\assets-dark\treeview-ltr-button-hover.png" />
<None Include="Themes\assets-dark\treeview-ltr-button.png" />
<None Include="Themes\assets-dark\treeview-rtl-button-active.png" />
<None Include="Themes\assets-dark\treeview-rtl-button-hover.png" />
<None Include="Themes\assets-dark\treeview-rtl-button.png" />
<None Include="libvlc.dylib">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="OpenTK.dll.config" />
<None Include="webkit-sharp.dll.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Aurora\Aurora.csproj">
<Project>{17F51282-39BE-4FE3-8EC7-6D108F5DD0FD}</Project>
<Name>Aurora</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="Resources\play.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Resources\like.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Resources\forwards.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Resources\backward.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Resources\pause.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Resources\menu.png">
</Content>
<Content Include="Resources\shuffle.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Resources\loop.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\Grpc.Tools.2.25.0\build\Grpc.Tools.targets" Condition="Exists('..\packages\Grpc.Tools.2.25.0\build\Grpc.Tools.targets')" />
<Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
<Import Project="..\packages\Grpc.Core.2.25.0\build\net45\Grpc.Core.targets" Condition="Exists('..\packages\Grpc.Core.2.25.0\build\net45\Grpc.Core.targets')" />
<Import Project="..\packages\VideoLAN.LibVLC.Mac.3.1.3.1\build\VideoLAN.LibVLC.Mac.targets" Condition="Exists('..\packages\VideoLAN.LibVLC.Mac.3.1.3.1\build\VideoLAN.LibVLC.Mac.targets')" />
<Import Project="..\packages\Xamarin.Forms.4.3.0.991211\build\Xamarin.Forms.targets" Condition="Exists('..\packages\Xamarin.Forms.4.3.0.991211\build\Xamarin.Forms.targets')" />
</Project>

View File

@ -0,0 +1,44 @@
/*
// Helpers/Settings.cs This file was automatically added when you installed the Settings Plugin. If you are not using a PCL then comment this file back in to use it.
using Plugin.Settings;
using Plugin.Settings.Abstractions;
namespace Aurora.gtk.Helpers
{
/// <summary>
/// This is the Settings static class that can be used in your Core solution or in any
/// of your client applications. All settings are laid out the same exact way with getters
/// and setters.
/// </summary>
public static class Settings
{
private static ISettings AppSettings
{
get
{
return CrossSettings.Current;
}
}
#region Setting Constants
private const string SettingsKey = "settings_key";
private static readonly string SettingsDefault = string.Empty;
#endregion
public static string GeneralSettings
{
get
{
return AppSettings.GetValueOrDefault(SettingsKey, SettingsDefault);
}
set
{
AppSettings.AddOrUpdateValue(SettingsKey, value);
}
}
}
}*/

View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<dllmap
os="linux"
dll="opengl32.dll"
target="libGL.so.1"/>
<dllmap
os="linux"
dll="glu32.dll"
target="libGLU.so.1"/>
<dllmap
os="linux"
dll="openal32.dll"
target="libopenal.so.1"/>
<dllmap
os="linux"
dll="alut.dll"
target="libalut.so.0"/>
<dllmap
os="linux"
dll="opencl.dll"
target="libOpenCL.so"/>
<dllmap
os="linux"
dll="libX11"
target="libX11.so.6"/>
<dllmap
os="linux"
dll="libXi"
target="libXi.so.6"/>
<dllmap
os="linux"
dll="SDL2.dll"
target="libSDL2-2.0.so.0"/>
<dllmap
os="osx"
dll="opengl32.dll"
target="/System/Library/Frameworks/OpenGL.framework/OpenGL"/>
<dllmap
os="osx"
dll="openal32.dll"
target="/System/Library/Frameworks/OpenAL.framework/OpenAL"/>
<dllmap
os="osx"
dll="alut.dll"
target="/System/Library/Frameworks/OpenAL.framework/OpenAL"/>
<dllmap
os="osx"
dll="libGLES.dll"
target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES"/>
<dllmap
os="osx"
dll="libGLESv1_CM.dll"
target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES"/>
<dllmap
os="osx"
dll="libGLESv2.dll"
target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES"/>
<dllmap
os="osx"
dll="opencl.dll"
target="/System/Library/Frameworks/OpenCL.framework/OpenCL"/>
<dllmap
os="osx"
dll="SDL2.dll"
target="libSDL2.dylib"/><!-- XQuartz compatibility (X11 on Mac) -->
<dllmap
os="osx"
dll="libGL.so.1"
target="/usr/X11/lib/libGL.dylib"/>
<dllmap
os="osx"
dll="libX11"
target="/usr/X11R6/lib/libX11.dylib"/>
<dllmap
os="osx"
dll="libXcursor.so.1"
target="/usr/X11/lib/libXcursor.dylib"/>
<dllmap
os="osx"
dll="libXi"
target="/usr/X11/lib/libXi.dylib"/>
<dllmap
os="osx"
dll="libXinerama"
target="/usr/X11/lib/libXinerama.dylib"/>
<dllmap
os="osx"
dll="libXrandr.so.2"
target="/usr/X11/lib/libXrandr.dylib"/>
</configuration>

View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<dllmap
os="linux"
dll="opengl32.dll"
target="libGL.so.1"/>
<dllmap
os="linux"
dll="glu32.dll"
target="libGLU.so.1"/>
<dllmap
os="linux"
dll="openal32.dll"
target="libopenal.so.1"/>
<dllmap
os="linux"
dll="alut.dll"
target="libalut.so.0"/>
<dllmap
os="linux"
dll="opencl.dll"
target="libOpenCL.so"/>
<dllmap
os="linux"
dll="libX11"
target="libX11.so.6"/>
<dllmap
os="linux"
dll="libXi"
target="libXi.so.6"/>
<dllmap
os="linux"
dll="SDL2.dll"
target="libSDL2-2.0.so.0"/>
<dllmap
os="osx"
dll="opengl32.dll"
target="/System/Library/Frameworks/OpenGL.framework/OpenGL"/>
<dllmap
os="osx"
dll="openal32.dll"
target="/System/Library/Frameworks/OpenAL.framework/OpenAL"/>
<dllmap
os="osx"
dll="alut.dll"
target="/System/Library/Frameworks/OpenAL.framework/OpenAL"/>
<dllmap
os="osx"
dll="libGLES.dll"
target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES"/>
<dllmap
os="osx"
dll="libGLESv1_CM.dll"
target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES"/>
<dllmap
os="osx"
dll="libGLESv2.dll"
target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES"/>
<dllmap
os="osx"
dll="opencl.dll"
target="/System/Library/Frameworks/OpenCL.framework/OpenCL"/>
<dllmap
os="osx"
dll="SDL2.dll"
target="libSDL2.dylib"/><!-- XQuartz compatibility (X11 on Mac) -->
<dllmap
os="osx"
dll="libGL.so.1"
target="/usr/X11/lib/libGL.dylib"/>
<dllmap
os="osx"
dll="libX11"
target="/usr/X11R6/lib/libX11.dylib"/>
<dllmap
os="osx"
dll="libXcursor.so.1"
target="/usr/X11/lib/libXcursor.dylib"/>
<dllmap
os="osx"
dll="libXi"
target="/usr/X11/lib/libXi.dylib"/>
<dllmap
os="osx"
dll="libXinerama"
target="/usr/X11/lib/libXinerama.dylib"/>
<dllmap
os="osx"
dll="libXrandr.so.2"
target="/usr/X11/lib/libXrandr.dylib"/>
</configuration>

View File

@ -0,0 +1,16 @@
using System;
using Gtk;
public partial class MainWindow : Gtk.Window
{
public MainWindow() : base(Gtk.WindowType.Toplevel)
{
Build();
}
protected void OnDeleteEvent(object sender, DeleteEventArgs a)
{
Application.Quit();
a.RetVal = true;
}
}

View File

@ -0,0 +1,25 @@
<configuration>
<dllmap os="linux" dll="opengl32.dll" target="libGL.so.1"/>
<dllmap os="linux" dll="glu32.dll" target="libGLU.so.1"/>
<dllmap os="linux" dll="openal32.dll" target="libopenal.so.1"/>
<dllmap os="linux" dll="alut.dll" target="libalut.so.0"/>
<dllmap os="linux" dll="opencl.dll" target="libOpenCL.so"/>
<dllmap os="linux" dll="libX11" target="libX11.so.6"/>
<dllmap os="linux" dll="libXi" target="libXi.so.6"/>
<dllmap os="linux" dll="SDL2.dll" target="libSDL2-2.0.so.0"/>
<dllmap os="osx" dll="opengl32.dll" target="/System/Library/Frameworks/OpenGL.framework/OpenGL"/>
<dllmap os="osx" dll="openal32.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
<dllmap os="osx" dll="alut.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
<dllmap os="osx" dll="libGLES.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
<dllmap os="osx" dll="libGLESv1_CM.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
<dllmap os="osx" dll="libGLESv2.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
<dllmap os="osx" dll="opencl.dll" target="/System/Library/Frameworks/OpenCL.framework/OpenCL"/>
<dllmap os="osx" dll="SDL2.dll" target="libSDL2.dylib"/>
<!-- XQuartz compatibility (X11 on Mac) -->
<dllmap os="osx" dll="libGL.so.1" target="/usr/X11/lib/libGL.dylib"/>
<dllmap os="osx" dll="libX11" target="/usr/X11/lib/libX11.dylib"/>
<dllmap os="osx" dll="libXcursor.so.1" target="/usr/X11/lib/libXcursor.dylib"/>
<dllmap os="osx" dll="libXi" target="/usr/X11/lib/libXi.dylib"/>
<dllmap os="osx" dll="libXinerama" target="/usr/X11/lib/libXinerama.dylib"/>
<dllmap os="osx" dll="libXrandr.so.2" target="/usr/X11/lib/libXrandr.dylib"/>
</configuration>

View File

@ -0,0 +1,31 @@
using System;
using LibVLCSharp.Forms.Shared;
using Xamarin.Forms.Platform.GTK;
namespace Aurora.gtk
{
class MainClass
{
[STAThread]
public static void Main(string[] args)
{
Gtk.Application.Init();
LibVLCSharpFormsRenderer.Init();
DLToolkit.Forms.Controls.FlowListView.Init();
// For some reason, Xamarin does not pick the LibVLCSharp.Form.Platforms.Gtk assembly as a renderer assembly.
// Add it manually.
//Also css doesn't work without adding the Xaml assembly
global::Xamarin.Forms.Forms.Init(new[] { typeof(LibVLCSharp.Forms.Platforms.GTK.VideoViewRenderer).Assembly, typeof(Xamarin.Forms.Xaml.ArrayExtension).Assembly });
var app = new App();
var window = new FormsWindow();
window.LoadApplication(app);
window.SetApplicationTitle("Aurora");
window.Show();
Gtk.Application.Run();
}
}
}

View File

@ -0,0 +1,26 @@
using System.Reflection;
using System.Runtime.CompilerServices;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
[assembly: AssemblyTitle("Aurora.gtk")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("1.0.*")]
// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.
//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")]

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1,22 @@
// This file has been generated by the GUI designer. Do not modify.
public partial class MainWindow
{
protected virtual void Build()
{
global::Stetic.Gui.Initialize(this);
// Widget MainWindow
this.Name = "MainWindow";
this.Title = global::Mono.Unix.Catalog.GetString("MainWindow");
this.WindowPosition = ((global::Gtk.WindowPosition)(4));
if ((this.Child != null))
{
this.Child.ShowAll();
}
this.DefaultWidth = 400;
this.DefaultHeight = 300;
this.Show();
this.DeleteEvent += new global::Gtk.DeleteEventHandler(this.OnDeleteEvent);
}
}

View File

@ -0,0 +1,30 @@
// This file has been generated by the GUI designer. Do not modify.
namespace Stetic
{
internal class Gui
{
private static bool initialized;
internal static void Initialize(Gtk.Widget iconRenderer)
{
if ((Stetic.Gui.initialized == false))
{
Stetic.Gui.initialized = true;
}
}
}
internal class ActionGroups
{
public static Gtk.ActionGroup GetActionGroup(System.Type type)
{
return Stetic.ActionGroups.GetActionGroup(type.FullName);
}
public static Gtk.ActionGroup GetActionGroup(string name)
{
return null;
}
}
}

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<stetic-interface>
<configuration>
<images-root-path>..</images-root-path>
</configuration>
<import>
<widget-library name="glade-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
<widget-library name="../../packages/Xamarin.Forms.Platform.GTK.4.3.0.991211/lib/net45/webkit-sharp.dll" />
<widget-library name="../../packages/LibVLCSharp.GTK.3.3.1/lib/net47/LibVLCSharp.GTK.dll" />
<widget-library name="../bin/Debug/Aurora.gtk.exe" internal="true" />
</import>
<widget class="Gtk.Window" id="MainWindow" design-size="400 300">
<property name="MemberName" />
<property name="Title" translatable="yes">MainWindow</property>
<property name="WindowPosition">CenterOnParent</property>
<signal name="DeleteEvent" handler="OnDeleteEvent" />
<child>
<placeholder />
</child>
</widget>
</stetic-interface>

Binary file not shown.

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Autofac" version="5.0.0" targetFramework="net47" />
<package id="CarouselView.FormsPlugin" version="5.2.0" targetFramework="net47" />
<package id="DLToolkit.Forms.Controls.FlowListView" version="2.0.11" targetFramework="net47" />
<package id="Google.Protobuf" version="3.10.1" targetFramework="net47" />
<package id="Grpc" version="2.25.0" targetFramework="net47" />
<package id="Grpc.Core" version="2.25.0" targetFramework="net47" />
<package id="Grpc.Core.Api" version="2.25.0" targetFramework="net47" />
<package id="Grpc.Tools" version="2.25.0" targetFramework="net47" developmentDependency="true" />
<package id="LibVLCSharp" version="3.3.1" targetFramework="net47" />
<package id="LibVLCSharp.Forms" version="3.3.1" targetFramework="net47" />
<package id="LibVLCSharp.Forms.GTK" version="3.3.1" targetFramework="net47" />
<package id="LibVLCSharp.GTK" version="3.3.1" targetFramework="net47" />
<package id="Microsoft.Bcl" version="1.1.10" targetFramework="net47" />
<package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net47" />
<package id="Microsoft.Bcl.AsyncInterfaces" version="1.1.0" targetFramework="net47" />
<package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net47" />
<package id="OpenTK" version="3.1.0" targetFramework="net47" />
<package id="OpenTK.GLControl" version="3.0.1" targetFramework="net47" />
<package id="Sharpnado.Forms.HorizontalListView" version="1.3.0" targetFramework="net47" />
<package id="System.Buffers" version="4.4.0" targetFramework="net47" />
<package id="System.Interactive.Async" version="4.0.0" targetFramework="net47" />
<package id="System.Linq.Async" version="4.0.0" targetFramework="net47" />
<package id="System.Memory" version="4.5.3" targetFramework="net47" />
<package id="System.Numerics.Vectors" version="4.4.0" targetFramework="net47" />
<package id="System.Reflection" version="4.3.0" targetFramework="net47" />
<package id="System.Reflection.TypeExtensions" version="4.6.0" targetFramework="net47" />
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net47" />
<package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net47" />
<package id="System.Runtime.Serialization.Primitives" version="4.3.0" targetFramework="net47" />
<package id="System.Threading.Tasks.Extensions" version="4.5.2" targetFramework="net47" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net47" />
<package id="taglib-sharp-netstandard2.0" version="2.1.0" targetFramework="net47" />
<package id="VideoLAN.LibVLC.Mac" version="3.1.3.1" targetFramework="net47" />
<package id="Xam.Plugins.Settings" version="3.1.1" targetFramework="net47" />
<package id="Xamarin.Forms" version="4.3.0.991211" targetFramework="net47" />
<package id="Xamarin.Forms.Platform.GTK" version="4.3.0.991211" targetFramework="net47" />
</packages>

View File

@ -0,0 +1,5 @@
<configuration>
<dllmap dll="webkit-1.0" target="libwebkitgtk-1.0.0.dylib"/>
<dllmap dll="webkit-1.0" os="linux" target="libwebkitgtk-1.0.so.0"/>
<dllmap dll="webkit-1.0" os="windows" target="libwebkitgtk-1.0-0.dll"/>
</configuration>

View File

@ -0,0 +1,57 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aurora", "Aurora\Aurora.csproj", "{17F51282-39BE-4FE3-8EC7-6D108F5DD0FD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aurora.gtk", "Aurora.gtk\Aurora.gtk.csproj", "{E8C8C24A-5C51-47CB-B241-F5A9F0E808B1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aurora.test", "Aurora.test\Aurora.test.csproj", "{45680D8A-1AF1-4D93-AAC0-59CDB01CED5D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|iPhoneSimulator = Debug|iPhoneSimulator
Release|iPhoneSimulator = Release|iPhoneSimulator
Debug|iPhone = Debug|iPhone
Release|iPhone = Release|iPhone
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{17F51282-39BE-4FE3-8EC7-6D108F5DD0FD}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{17F51282-39BE-4FE3-8EC7-6D108F5DD0FD}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{17F51282-39BE-4FE3-8EC7-6D108F5DD0FD}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{17F51282-39BE-4FE3-8EC7-6D108F5DD0FD}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{17F51282-39BE-4FE3-8EC7-6D108F5DD0FD}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{17F51282-39BE-4FE3-8EC7-6D108F5DD0FD}.Debug|iPhone.Build.0 = Debug|Any CPU
{17F51282-39BE-4FE3-8EC7-6D108F5DD0FD}.Release|iPhone.ActiveCfg = Release|Any CPU
{17F51282-39BE-4FE3-8EC7-6D108F5DD0FD}.Release|iPhone.Build.0 = Release|Any CPU
{17F51282-39BE-4FE3-8EC7-6D108F5DD0FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{17F51282-39BE-4FE3-8EC7-6D108F5DD0FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{17F51282-39BE-4FE3-8EC7-6D108F5DD0FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{17F51282-39BE-4FE3-8EC7-6D108F5DD0FD}.Release|Any CPU.Build.0 = Release|Any CPU
{E8C8C24A-5C51-47CB-B241-F5A9F0E808B1}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{E8C8C24A-5C51-47CB-B241-F5A9F0E808B1}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{E8C8C24A-5C51-47CB-B241-F5A9F0E808B1}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
{E8C8C24A-5C51-47CB-B241-F5A9F0E808B1}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
{E8C8C24A-5C51-47CB-B241-F5A9F0E808B1}.Debug|iPhone.ActiveCfg = Debug|iPhoneSimulator
{E8C8C24A-5C51-47CB-B241-F5A9F0E808B1}.Debug|iPhone.Build.0 = Debug|iPhoneSimulator
{E8C8C24A-5C51-47CB-B241-F5A9F0E808B1}.Release|iPhone.ActiveCfg = Release|iPhoneSimulator
{E8C8C24A-5C51-47CB-B241-F5A9F0E808B1}.Release|iPhone.Build.0 = Release|iPhoneSimulator
{E8C8C24A-5C51-47CB-B241-F5A9F0E808B1}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator
{E8C8C24A-5C51-47CB-B241-F5A9F0E808B1}.Debug|Any CPU.Build.0 = Debug|iPhoneSimulator
{E8C8C24A-5C51-47CB-B241-F5A9F0E808B1}.Release|Any CPU.ActiveCfg = Release|iPhoneSimulator
{E8C8C24A-5C51-47CB-B241-F5A9F0E808B1}.Release|Any CPU.Build.0 = Release|iPhoneSimulator
{45680D8A-1AF1-4D93-AAC0-59CDB01CED5D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{45680D8A-1AF1-4D93-AAC0-59CDB01CED5D}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{45680D8A-1AF1-4D93-AAC0-59CDB01CED5D}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{45680D8A-1AF1-4D93-AAC0-59CDB01CED5D}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{45680D8A-1AF1-4D93-AAC0-59CDB01CED5D}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{45680D8A-1AF1-4D93-AAC0-59CDB01CED5D}.Debug|iPhone.Build.0 = Debug|Any CPU
{45680D8A-1AF1-4D93-AAC0-59CDB01CED5D}.Release|iPhone.ActiveCfg = Release|Any CPU
{45680D8A-1AF1-4D93-AAC0-59CDB01CED5D}.Release|iPhone.Build.0 = Release|Any CPU
{45680D8A-1AF1-4D93-AAC0-59CDB01CED5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{45680D8A-1AF1-4D93-AAC0-59CDB01CED5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{45680D8A-1AF1-4D93-AAC0-59CDB01CED5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{45680D8A-1AF1-4D93-AAC0-59CDB01CED5D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,117 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="nunit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="Grpc.Core" Version="2.26.0" />
<PackageReference Include="Grpc.Tools" Version="2.26.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Grpc" Version="2.26.0" />
<PackageReference Include="Autofac" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
<Protobuf Remove="..\Aurora\Proto\general.proto" />
<Protobuf Remove="..\Aurora\Proto\party.v2.proto" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Aurora\Aurora.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="Resources\Jidenna\The Chief\01 A Bull%27s Tale.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Jidenna\The Chief\04 Bambi.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Jidenna\The Chief\14 Bully Of The Earth.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Jidenna\The Chief\12 Some Kind Of Way.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Jidenna\The Chief\03 Trampoline.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Jidenna\The Chief\09 Safari.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Jidenna\The Chief\05 Helicopters _ Beware.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Jidenna\The Chief\08 The Let Out.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Jidenna\The Chief\10 Adaora.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Jidenna\The Chief\07 2 Points.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Jidenna\The Chief\06 Long Live The Chief.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Jidenna\The Chief\02 Chief Don%27t Run.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Jidenna\The Chief\11 Little Bit More.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Jidenna\The Chief\13 White Niggas.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\16 BDE Bonus %28Prod. By_ ID Labs%29.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\11 Play Ya Cards %28Prod By_ Chuck Inglish%29.m4a">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\08 All Around The World %28Prod. By_ Just Blaze%29.m4a">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\10 In The Air %28Prod By_ Ritz Reynolds%29.m4a">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\05 I%27ll Be There %28feat. Phonte%29 %28Prod. By_ Beanz %27n%27 Kornbread%29.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\03 Donald Trump %28Prod. By_ Sap%29.m4a">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\13 Life Ain%27t Easy %28Prod. By_ ID Labs%29.m4a">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\09 Down The Rabbit Hole %28Prod. By_ Blue of The Sore Losers%29.m4a">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\07 Wake Up %28Prod By_ Sap &amp; ID Labs%29.m4a">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\04 Oy Vey %28Prod By_ ID Labs%29.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\01 Best Day Ever %28Prod. By_ ID Labs%29.m4a">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\02 Get Up %28Prod. By_ Teddy Roxpin%29.m4a">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\14 Snooze %28Prod By_ ID Labs%29.m4a">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\12 She Said %28Prod By_ Khrysis%29.m4a">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\15 Keep Floatin%27 %28feat. Wiz Khalifa%29 %28Prod. By_ ID Labs%29.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\06 Wear My Hat %28Prod. By_ Chuck Inglish%29.m4a">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@ -0,0 +1,100 @@
using NUnit.Framework;
using Aurora.Proto.Party;
using Aurora.Services.Server;
using Aurora.Services.EventManager;
using Grpc.Core;
using System.Threading.Tasks;
using System.Threading;
using Autofac;
namespace Aurora.test.ControllerTests
{
public class EventTest
{
private RemotePartyService.RemotePartyServiceClient _remotePartyService;
private Channel _channel;
private IContainer _container;
private IServerService _serverService;
#region Setup
[SetUp]
public void Setup()
{
_container = SetupUtil.SetupOneTime();
_remotePartyService = SetupUtil.Setup(ref _container, ref _serverService, ref _channel);
}
[TearDown]
public async Task TearDown()
{
await _serverService.Stop();
await _channel.ShutdownAsync();
_container.Dispose();
}
#endregion Setup
[Test]
[TestCase(EventType.MediaPlaying)]
public void Asdf(EventType value)
{
Assert.AreEqual(1, 1);
}
[Test]
[TestCase(EventType.MediaPlaying)]
[TestCase(EventType.MediaStopped)]
[TestCase(EventType.MemberCreated)]
[TestCase(EventType.MemberDeleted)]
public async Task TestEventSubscriptions(EventType value)
{
using (var scope = _container.BeginLifetimeScope())
{
IEventManager eventManager = scope.Resolve<IEventManager>();
//Create new party member
Member member = _remotePartyService.CreateMember(new CreateMemberRequest()
{
Parent = "party1",
Member = new Member()
{
UserName = "newMember1",
IpAddress = ServerService.GetLocalIPAddress(),
}
});
//Subscribe to event type
_remotePartyService.CreateEventSubscription(new CreateEventSubscriptionRequest()
{
Parent = member.Name,
EventSubscription = new EventSubscription()
{
Type = value
}
});
BaseEvent @event = new BaseEvent
{
EventType = value,
};
//Fire event
CancellationTokenSource eventCancellationTokenSource = new CancellationTokenSource();
BaseEvent newEvent = null;
Task.Run(async () => { await Task.Delay(1000); eventManager.FireEvent(@event); });
using (AsyncServerStreamingCall<BaseEvent> eventStream = _remotePartyService
.GetEvents(new GetEventsRequest() { Parent = member.Name }))
{
while ((!eventCancellationTokenSource.Token.IsCancellationRequested &&
await eventStream.ResponseStream.MoveNext(eventCancellationTokenSource.Token)))
{
newEvent = new BaseEvent(eventStream.ResponseStream.Current);
break;
}
};
Assert.AreEqual(newEvent.EventType, value);
}
}
}
}

View File

@ -0,0 +1,78 @@
using NUnit.Framework;
using Aurora.Proto.Party;
using Aurora.Services.Server;
using Grpc.Core;
using System.Threading.Tasks;
using System.Linq;
using System.IO;
using Autofac;
namespace Aurora.test.ControllerTests
{
public class MediaControllerTests
{
private RemotePartyService.RemotePartyServiceClient _remotePartyService;
private Channel _channel;
private IContainer _container;
private IServerService _serverService;
#region Setup
[OneTimeSetUp]
public void SetupOneTime()
{
_container = SetupUtil.SetupOneTime();
}
[OneTimeTearDown]
public void TearDownOneTime()
{
_container.Dispose();
}
[SetUp]
public void Setup()
{
_remotePartyService = SetupUtil.Setup(ref _container, ref _serverService, ref _channel);
}
[TearDown]
public async Task TearDown()
{
await _serverService.Stop();
await _channel.ShutdownAsync();
}
#endregion Setup
[Test]
public void TestNotEmpty()
{
ListMediaResponse resp = _remotePartyService.ListMedia(new ListMediaRequest()
{
Parent = "testParty",
PageSize = 5
});
Assert.NotNull(resp.Media);
Assert.NotZero(resp.Media.Count);
Assert.AreEqual(resp.Media.Count, 5);
}
[Test]
public void GetMediaTest()
{
ListMediaResponse resp = _remotePartyService.ListMedia(new ListMediaRequest()
{
Parent = "testParty",
PageSize = 5
});
Media media = _remotePartyService.GetMedia(new GetMediaRequest()
{
Name = resp.Media[0].Name
});
Assert.NotNull(media);
Assert.AreEqual(media.Name, resp.Media[0].Name);
}
}
}

View File

@ -0,0 +1,206 @@
using NUnit.Framework;
using Aurora.Proto.Party;
using Aurora.Services.Server;
using Grpc.Core;
using System.Threading.Tasks;
using System.Linq;
using Autofac;
namespace Aurora.test.ControllerTests
{
public class MemberControllerTests
{
private RemotePartyService.RemotePartyServiceClient _remotePartyService;
private Channel _channel;
private IContainer _container;
private IServerService _serverService;
#region Setup
[OneTimeSetUp]
public void SetupOneTime()
{
_container = SetupUtil.SetupOneTime();
}
[OneTimeTearDown]
public void TearDownOneTime()
{
_container.Dispose();
}
[SetUp]
public void Setup()
{
_remotePartyService = SetupUtil.Setup(ref _container, ref _serverService, ref _channel);
}
[TearDown]
public async Task TearDown()
{
await _serverService.Stop();
await _channel.ShutdownAsync();
}
#endregion Setup
[Test]
public void DefaultTest()
{
ListMembersResponse resp = _remotePartyService.ListMembers(new ListMembersRequest()
{
Parent = "party1",
PageSize = 10,
});
Assert.NotNull(resp);
Assert.GreaterOrEqual(resp.Members.Count, 1);
}
[Test]
[TestCase("Alex")]
[TestCase("Alex Goldberg")]
[TestCase("Alex/goldberg")]
[TestCase("alex@welcome.com")]
public void CreateMemberTest(string value)
{
Member member = _remotePartyService.CreateMember(new CreateMemberRequest()
{
Parent = "party1",
Member = new Member()
{
UserName = value,
IpAddress = ServerService.GetLocalIPAddress(),
}
});
Assert.NotNull(member);
}
static object[] MultipleMembersCases =
{
new object[] {"Tupac", "Aubrey Grahm", "Beyonce Knowls", "Ke$ha", "A$ap Ferg"},
};
[Test]
[TestCaseSource("MultipleMembersCases")]
public void CreateMultiplMembersTest(object[] memberNames)
{
//Add members
foreach (string name in memberNames)
{
Member member = _remotePartyService.CreateMember(new CreateMemberRequest()
{
Parent = "party1",
Member = new Member()
{
UserName = name
}
});
Assert.NotNull(member);
}
//List members
ListMembersResponse resp = _remotePartyService.ListMembers(new ListMembersRequest()
{
Parent = "party1",
PageSize = 10,
});
Assert.NotNull(resp);
Assert.AreEqual(resp.Members.Count, 6);
}
[Test]
[TestCaseSource("MultipleMembersCases")]
public void DeleteMemberTest(object[] memberNames)
{
//Add members
foreach (string name in memberNames)
{
Member member = _remotePartyService.CreateMember(new CreateMemberRequest()
{
Parent = "party1",
Member = new Member()
{
UserName = name
}
});
Assert.NotNull(member);
}
//List members
ListMembersResponse resp = _remotePartyService.ListMembers(new ListMembersRequest()
{
Parent = "party1",
PageSize = 10,
});
Assert.NotNull(resp);
Assert.AreEqual(resp.Members.Count, 6);
string keshaResourceName = resp.Members.First(member => member.UserName == "Ke$ha").Name;
//Delete member
_remotePartyService.DeleteMember(new DeleteMemberRequest()
{
Name = keshaResourceName
});
//List members
resp = _remotePartyService.ListMembers(new ListMembersRequest()
{
Parent = "party1",
PageSize = 10,
});
Assert.NotNull(resp);
Assert.AreEqual(resp.Members.Count, 5);
Assert.False(resp.Members.Any(member => member.UserName == "Ke$sha"));
}
static object[] PagingCases =
{
new object[] {"Tupac", "Aubrey Grahm", "Beyonce Knowls", "Ke$ha", "A$ap Ferg", "asdf", "sdfa", "dfas", "fasd"},
};
[Test]
[TestCaseSource("PagingCases")]
public void MemberPagingTest(object[] members)
{
foreach (string name in members)
{
Member member = _remotePartyService.CreateMember(new CreateMemberRequest()
{
Parent = "party1",
Member = new Member()
{
UserName = name
}
});
Assert.NotNull(member);
}
//List members
ListMembersResponse resp = _remotePartyService.ListMembers(new ListMembersRequest()
{
Parent = "party1",
PageSize = 2,
});
string nextPageToken = resp.NextPageToken;
Assert.AreEqual(resp.Members.Count, 2);
//List members
resp = _remotePartyService.ListMembers(new ListMembersRequest()
{
Parent = "party1",
PageSize = 2,
PageToken = nextPageToken,
});
Assert.AreEqual(resp.Members.Count, 2);
}
}
}

View File

@ -0,0 +1,53 @@
using System.Threading.Tasks;
using NUnit.Framework;
using Aurora.Proto.Party;
using Aurora.Services.Server;
using Grpc.Core;
using Autofac;
namespace Aurora.test.ControllerTests
{
public class PartyControllerTests
{
private RemotePartyService.RemotePartyServiceClient _remotePartyService;
private Channel _channel;
private IContainer _container;
private IServerService _serverService;
#region Setup
[OneTimeSetUp]
public void SetupOneTime()
{
_container = SetupUtil.SetupOneTime();
}
[OneTimeTearDown]
public void TearDownOneTime()
{
_container.Dispose();
}
[SetUp]
public void Setup()
{
_remotePartyService = SetupUtil.Setup(ref _container, ref _serverService, ref _channel);
}
[TearDown]
public async Task TearDown()
{
await _serverService.Stop();
await _channel.ShutdownAsync();
}
#endregion Setup
[Test]
public void DefaultTest()
{
Party party = _remotePartyService.GetParty(new Proto.General.Empty());
Assert.NotNull(party);
Assert.AreEqual(party.Name, "party/party1");
}
}
}

View File

@ -0,0 +1,39 @@
using Autofac;
using Aurora.Proto.Party;
using Aurora.Services.Server;
using Aurora.Services.Library;
using Aurora.Services.Settings;
using Aurora.Services.EventManager;
using Aurora.test.Models.Mock;
using System.IO;
using Grpc.Core;
namespace Aurora.test.ControllerTests
{
public class SetupUtil
{
public static IContainer SetupOneTime()
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<ServerService>().As<IServerService>().SingleInstance();
builder.RegisterInstance<ISettingsService>(new SettingsServiceMock()
{
Username = "Test User 1",
DefaultPort = 4005,
LibraryLocation = string.Format("{0}/Resources", Directory.GetCurrentDirectory())
}).SingleInstance();
builder.RegisterType<LibraryService>().As<ILibraryService>().SingleInstance();
builder.RegisterType<EventManager>().As<IEventManager>().SingleInstance();
return builder.Build();
}
public static RemotePartyService.RemotePartyServiceClient Setup(ref IContainer container, ref IServerService serverService, ref Channel channel)
{
serverService = container.Resolve<IServerService>();
serverService.Start("testParty", "asdf");
channel = new Channel(string.Format("{0}:{1}", ServerService.GetLocalIPAddress(), 8080), ChannelCredentials.Insecure);
return new RemotePartyService.RemotePartyServiceClient(channel);
}
}
}

View File

@ -0,0 +1,39 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core;
namespace Aurora.test.Models
{
public class CallContext : ServerCallContext
{
protected override string MethodCore => throw new NotImplementedException();
protected override string HostCore => throw new NotImplementedException();
protected override string PeerCore => throw new NotImplementedException();
protected override DateTime DeadlineCore => throw new NotImplementedException();
protected override Metadata RequestHeadersCore => throw new NotImplementedException();
protected override CancellationToken CancellationTokenCore => throw new NotImplementedException();
protected override Metadata ResponseTrailersCore => throw new NotImplementedException();
protected override Status StatusCore { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
protected override WriteOptions WriteOptionsCore { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
protected override AuthContext AuthContextCore => throw new NotImplementedException();
protected override ContextPropagationToken CreatePropagationTokenCore(ContextPropagationOptions options)
{
throw new NotImplementedException();
}
protected override Task WriteResponseHeadersAsyncCore(Metadata responseHeaders)
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,35 @@
using Aurora.Services.Settings;
using Plugin.Settings.Abstractions;
namespace Aurora.test.Models.Mock
{
public class SettingsServiceMock : ISettingsService
{
public SettingsServiceMock()
{
}
public ISettings AppSettings { get; set; }
/// <summary>
/// The user's username. This is persisted.
/// </summary>
/// <value></value>
public string Username { get; set; }
/// <summary>
/// The default port to use. This is persisted.
/// </summary>
/// <value></value>
public int DefaultPort { get; set; }
/// <summary>
/// The current sessions clientId. This is assigned by the server. This is not persisted.
/// </summary>
/// <value></value>
public string ClientName { get; set; }
public string LibraryLocation { get; set; }
}
}

View File

@ -0,0 +1,11 @@
.primaryColor {
background-color: #000000;
}
.accentColor {
background-color: #181818;
}
.secondAccentColor {
background-color: #303030
}

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<Application
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:converters="clr-namespace:Aurora.Design.Converters"
x:Class="Aurora.App">
<Application.Resources>
<ResourceDictionary><!-- GENERAL COLORS -->
<Color
x:Key="WhiteColor">#FFFFFF</Color>
<Color
x:Key="BlackColor">#000000</Color><!-- THEME COLORS -->
<Color
x:Key="AccentColor">#F5C210</Color>
<Color
x:Key="ToolbarColor">#151C25</Color>
<Color
x:Key="BackgroundColor">#1E2634</Color>
<Color
x:Key="DarkBackgroundColor">#151C25</Color>
<Color
x:Key="MenuBackgroundColor">#44545C</Color><!-- CONVERTERS -->
<converters:InverseBoolConverter
x:Key="InverseBoolConverter"/>
<converters:ToUpperConverter
x:Key="ToUpperConverter"/>
<StyleSheet
Source="App.css"/>
</ResourceDictionary>
</Application.Resources>
</Application>

View File

@ -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<IPlayer>(new PlayerService()).SingleInstance();
_builder.RegisterType<PlayerService>().As<IPlayer>().SingleInstance();
_builder.RegisterType<SettingsService>().As<ISettingsService>().SingleInstance();
_builder.RegisterType<LibraryService>().As<ILibraryService>().SingleInstance();
_builder.RegisterType<EventManager>().As<IEventManager>().SingleInstance();
_builder.RegisterType<ServerService>().As<IServerService>().SingleInstance();
_builder.RegisterType<ClientService>().As<IClientService>().SingleInstance();
_builder.RegisterType<MainView>().SingleInstance();
_builder.RegisterType<AlbumsViewModel>();
_builder.RegisterType<ArtistsViewModel>();
_builder.RegisterType<PartyViewModel>();
_builder.RegisterType<ProfileViewModel>();
_builder.RegisterType<SongsViewModel>();
_builder.RegisterType<StationsViewModel>();
// _builder.RegisterInstance<ISettingsService>(new SettingsService()).SingleInstance();
_container = _builder.Build();
MainPage = _container.Resolve<MainView>();
}
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
}
}
}

View File

@ -0,0 +1,3 @@
using Xamarin.Forms.Xaml;
[assembly: XamlCompilation(XamlCompilationOptions.Compile)]

View File

@ -0,0 +1,85 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<ProduceAssemblyReference>true</ProduceAssemblyReference>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>pdbonly</DebugType>
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Xamarin.Forms" Version="4.3.0.991211" />
<PackageReference Include="Xamarin.Essentials" Version="1.3.1" />
<PackageReference Include="taglib-sharp-netstandard2.0" Version="2.1.0" />
<PackageReference Include="LibVLCSharp.Forms" Version="3.3.1" />
<PackageReference Include="VideoLAN.LibVLC.Mac" Version="3.1.3.1" />
<PackageReference Include="Grpc" Version="2.25.0" />
<PackageReference Include="Grpc.Tools" Version="2.25.0" PrivateAssests="All">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Google.Protobuf" Version="3.10.1" />
<PackageReference Include="Xam.Plugins.Settings" Version="3.1.1" />
<PackageReference Include="Sharpnado.Forms.HorizontalListView" Version="1.3.0" />
<PackageReference Include="DLToolkit.Forms.Controls.FlowListView" Version="2.0.11" />
<PackageReference Include="CarouselView.FormsPlugin" Version="5.2.0" />
<PackageReference Include="Autofac" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="Design\" />
<Folder Include="Design\Components\" />
<Folder Include="Design\Views\" />
<Folder Include="Design\Views\Songs\" />
<Folder Include="Design\Views\MainView\" />
<Folder Include="Design\Behaviors\" />
<Folder Include="Design\Components\NavigationMenu\" />
<Folder Include="Design\Views\Albums\" />
<Folder Include="Design\Views\Artists\" />
<Folder Include="Design\Views\Stations\" />
<Folder Include="Utils\" />
<Folder Include="Models\" />
<Folder Include="Services\" />
<Folder Include="Design\Views\Party\" />
<Folder Include="Design\Components\MemberList\" />
<Folder Include="Design\Components\Library\" />
<Folder Include="Design\Views\Profile\" />
<Folder Include="Design\Components\DataGrid\" />
<Folder Include="Resources\" />
<Folder Include="Design\Extensions\" />
<Folder Include="Design\Components\ImageButton\" />
<Folder Include="Design\Components\Dialogs\" />
<Folder Include="Design\Views\Party\NewPartyDialog\" />
<Folder Include="Design\Components\TabView\" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Design\Behaviors\DeselectItemBehaviorBase.cs" />
</ItemGroup>
<ItemGroup>
<Compile Update="Design\Components\MusicPlayer\Player.xaml.cs">
<DependentUpon>Player.xaml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<Protobuf Include="Proto\general.proto" />
<Protobuf Include="Proto\party.proto" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\backward.png" />
<EmbeddedResource Include="Resources\forwards.png" />
<EmbeddedResource Include="Resources\like.png" />
<EmbeddedResource Include="Resources\play.png" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Design\Components\NavigationMenu\NavigationMenu.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Remove="Design\Resources\unselected.png" />
<None Remove="Design\Components\MediaPlayer\play.png" />
<None Remove="Resources\backward.png" />
<None Remove="Resources\forwards.png" />
<None Remove="Resources\like.png" />
<None Remove="Resources\play.png" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,42 @@
using System;
using Xamarin.Forms;
namespace Aurora.Design.Behaviors
{
public class BehaviorBase<T> : Behavior<T> 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;
}
}
}

View File

@ -0,0 +1,132 @@
using System;
using System.Reflection;
using System.Windows.Input;
using Xamarin.Forms;
namespace Aurora.Design.Behaviors
{
public class EventToCommandBehavior : BehaviorBase<View>
{
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);
}
}
}

View File

@ -0,0 +1,8 @@
using System.Collections.Generic;
namespace Aurora.Design.Components.DataGrid
{
public sealed class ColumnCollection : List<DataGridColumn>
{
}
}

View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<Grid
x:Name="self"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Aurora.Design.Components.DataGrid.DataGrid"
Padding="0"
RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition
Height="Auto"/>
<RowDefinition
Height="*"/>
</Grid.RowDefinitions>
<Grid
x:Name="_headerView"
RowSpacing="0">
<Grid.Resources>
<ResourceDictionary>
<!--Default Header Style-->
<Style
x:Key="HeaderDefaultStyle"
TargetType="Label">
<Setter
Property="FontSize"
Value="{Binding HeaderFontSize, Source={x:Reference self}}"/>
<Setter
Property="FontAttributes"
Value="Bold"/>
<Setter
Property="HorizontalOptions"
Value="Center"/>
<Setter
Property="VerticalOptions"
Value="Center"/>
<Setter
Property="TextColor"
Value="{Binding HeaderTextColor,Source={x:Reference self}}"/>
<Setter
Property="LineBreakMode"
Value="WordWrap"/>
</Style>
<Style
TargetType="Grid">
<Setter
Property="BackgroundColor"
Value="{Binding HeaderBackground,Source={x:Reference self}}"/>
</Style>
<Style
x:Key="ImageStyleBase"
TargetType="Image">
<Setter
Property="Aspect"
Value="AspectFill"/>
<Setter
Property="VerticalOptions"
Value="Center"/>
<Setter
Property="HorizontalOptions"
Value="Center"/>
<Setter
Property="HeightRequest"
Value="5"/>
<Setter
Property="WidthRequest"
Value="9"/>
<Setter
Property="Margin"
Value="0,0,4,0"/>
</Style>
<Style
x:Key="AscendingIconStyle"
TargetType="Image"
BasedOn="{StaticResource ImageStyleBase}">
<Setter
Property="Source"
Value="{Binding AscendingIcon, Source={x:Reference self}}"/>
</Style>
<Style
x:Key="DescendingIconStyle"
TargetType="Image"
BasedOn="{StaticResource ImageStyleBase}">
<Setter
Property="Source"
Value="{Binding DescendingIcon, Source={x:Reference self}}"/>
</Style>
</ResourceDictionary>
</Grid.Resources>
</Grid>
<ListView x:Name="DataList" Grid.Row="1" BackgroundColor="#222222" />
<ContentView
x:Name="_noDataView"
Grid.RowSpan="2"
IsVisible="False"/>
</Grid>

View File

@ -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<object> _internalItems;
private Dictionary<int, SortingOrder> _sortingOrders;
#endregion Fields
#region Constructor
public DataGrid() : this(ListViewCachingStrategy.RetainElement)
{
}
public DataGrid(ListViewCachingStrategy cachingStrategy)
{
InitializeComponent();
BackgroundColor = Color.Transparent;
_sortingOrders = new Dictionary<int, SortingOrder>();
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<SelectedItemChangedEventArgs> 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<object>(((IEnumerable<object>)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<object> 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<object>(_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
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}
}

View File

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

Some files were not shown because too many files have changed in this diff Show More