First pass at songs view
Using data grid for songs view. Added FileSystemUtil for async folder traversal
This commit is contained in:
parent
ae6bd68707
commit
1fcaffb9b1
15
.vscode/launch.json
vendored
Normal file
15
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
// 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": [
|
||||||
|
{
|
||||||
|
"name": "Launch",
|
||||||
|
"type": "xamarin",
|
||||||
|
"request": "launch",
|
||||||
|
"package": "com.your.app.package",
|
||||||
|
"intent": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -64,6 +64,23 @@
|
|||||||
<Reference Include="Xamarin.Forms.Platform.GTK">
|
<Reference Include="Xamarin.Forms.Platform.GTK">
|
||||||
<HintPath>..\packages\Xamarin.Forms.Platform.GTK.3.6.0.344457\lib\net45\Xamarin.Forms.Platform.GTK.dll</HintPath>
|
<HintPath>..\packages\Xamarin.Forms.Platform.GTK.3.6.0.344457\lib\net45\Xamarin.Forms.Platform.GTK.dll</HintPath>
|
||||||
</Reference>
|
</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.4.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="Xamarin.Forms.DataGrid">
|
||||||
|
<HintPath>..\packages\Xamarin.Forms.DataGrid.3.1.0\lib\netstandard2.0\Xamarin.Forms.DataGrid.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="gtk-gui\gui.stetic">
|
<EmbeddedResource Include="gtk-gui\gui.stetic">
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
|
<package id="System.Reflection" version="4.3.0" targetFramework="net47" />
|
||||||
|
<package id="System.Reflection.TypeExtensions" version="4.4.0" targetFramework="net47" />
|
||||||
|
<package id="System.Runtime.Serialization.Primitives" version="4.3.0" targetFramework="net47" />
|
||||||
|
<package id="taglib-sharp-netstandard2.0" version="2.1.0" targetFramework="net47" />
|
||||||
<package id="Xamarin.Forms" version="3.6.0.344457" targetFramework="net47" />
|
<package id="Xamarin.Forms" version="3.6.0.344457" targetFramework="net47" />
|
||||||
|
<package id="Xamarin.Forms.DataGrid" version="3.1.0" targetFramework="net47" />
|
||||||
<package id="Xamarin.Forms.Platform.GTK" version="3.6.0.344457" targetFramework="net47" />
|
<package id="Xamarin.Forms.Platform.GTK" version="3.6.0.344457" targetFramework="net47" />
|
||||||
</packages>
|
</packages>
|
@ -13,6 +13,8 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Xamarin.Forms" Version="3.6.0.264807" />
|
<PackageReference Include="Xamarin.Forms" Version="3.6.0.264807" />
|
||||||
<PackageReference Include="Xamarin.Essentials" Version="1.0.1" />
|
<PackageReference Include="Xamarin.Essentials" Version="1.0.1" />
|
||||||
|
<PackageReference Include="Xamarin.Forms.DataGrid" Version="3.1.0" />
|
||||||
|
<PackageReference Include="taglib-sharp-netstandard2.0" Version="2.1.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Frontend\" />
|
<Folder Include="Frontend\" />
|
||||||
|
41
Aurora/Frontend/Models/Song.cs
Normal file
41
Aurora/Frontend/Models/Song.cs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Aurora.Frontend.Views.Songs
|
||||||
|
{
|
||||||
|
public class Song
|
||||||
|
{
|
||||||
|
public Song()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The title of the song.
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
public string Title { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The artist of the song.
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
public string Artist { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The album from which the song belongs.
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
public string Album { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The duration of the song.
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
public string Duration { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extra data associated with a song.
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
public object Metadata { get; set; }
|
||||||
|
}
|
||||||
|
}
|
82
Aurora/Frontend/Utils/FileSystemUtils.cs
Normal file
82
Aurora/Frontend/Utils/FileSystemUtils.cs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Aurora.Frontend.Utils
|
||||||
|
{
|
||||||
|
public class FileSystemUtils
|
||||||
|
{
|
||||||
|
|
||||||
|
public FileSystemUtils()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronousely recursively traverse a directory path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path to the directory to traverse</param>
|
||||||
|
/// <param name="extensions">Comma separated list of file extensions to accept</param>
|
||||||
|
public static List<FileInfo> TraverseFoldersAsync(string path, string extensions)
|
||||||
|
{
|
||||||
|
string[] extensionList = extensions.Split(',');
|
||||||
|
|
||||||
|
ConcurrentBag<Task> tasks = new ConcurrentBag<Task>();
|
||||||
|
List<FileInfo> outFiles = new List<FileInfo>();
|
||||||
|
DirectoryInfo directoryInfo = new DirectoryInfo(path);
|
||||||
|
|
||||||
|
tasks.Add(Task.Run(() => Traverse(directoryInfo, tasks, outFiles, extensionList)));
|
||||||
|
|
||||||
|
Task waitingTask;
|
||||||
|
while (tasks.TryTake(out waitingTask))
|
||||||
|
{
|
||||||
|
waitingTask.Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
return outFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Recursive method to capture children of a directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dir">The directory to traverse</param>
|
||||||
|
/// <param name="tasks">The list of currently running tasks</param>
|
||||||
|
private static void Traverse(DirectoryInfo dir, ConcurrentBag<Task> tasks, List<FileInfo> outFiles, string[] extensions)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DirectoryInfo[] directoryInfos = dir.GetDirectories();
|
||||||
|
//Enque children
|
||||||
|
foreach (DirectoryInfo childInfo in directoryInfos)
|
||||||
|
{
|
||||||
|
tasks.Add(Task.Run(() => Traverse(childInfo, tasks, outFiles, extensions)));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Collect files
|
||||||
|
foreach (FileInfo fileInfo in dir.GetFiles())
|
||||||
|
{
|
||||||
|
if (extensions.Any(e => e == fileInfo.Extension))
|
||||||
|
{
|
||||||
|
//Don't know if this lock is necessary
|
||||||
|
lock (outFiles)
|
||||||
|
{
|
||||||
|
outFiles.Add(fileInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{ex.GetType()} {ex.Message}\n{ex.StackTrace}");
|
||||||
|
ex = ex.InnerException;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,38 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Aurora.Frontend.Views.Songs.SongsView">
|
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||||
|
xmlns:dg="clr-namespace:Xamarin.Forms.DataGrid;assembly=Xamarin.Forms.DataGrid"
|
||||||
|
x:Class="Aurora.Frontend.Views.Songs.SongsView">
|
||||||
<ContentPage.Content>
|
<ContentPage.Content>
|
||||||
<Label Text="Songs" />
|
<dg:DataGrid ItemsSource="{Binding SongsList}" SelectionEnabled="True" SelectedItem="{Binding SelectedSong}"
|
||||||
|
RowHeight="30" HeaderHeight="50" BorderColor="#CCCCCC" HeaderBackground="#E0E6F8">
|
||||||
|
|
||||||
|
<!-- Header -->
|
||||||
|
<dg:DataGrid.HeaderFontSize>
|
||||||
|
<OnIdiom x:TypeArguments="x:Double">
|
||||||
|
<OnIdiom.Tablet>15</OnIdiom.Tablet>
|
||||||
|
<OnIdiom.Phone>13</OnIdiom.Phone>
|
||||||
|
<OnIdiom.Desktop>20</OnIdiom.Desktop>
|
||||||
|
</OnIdiom>
|
||||||
|
</dg:DataGrid.HeaderFontSize>
|
||||||
|
|
||||||
|
<!-- Columns -->
|
||||||
|
<dg:DataGrid.Columns>
|
||||||
|
<dg:DataGridColumn Title="Title" PropertyName="Title" Width="2*"/>
|
||||||
|
<dg:DataGridColumn Title="Album" PropertyName="Album" Width="0.95*"/>
|
||||||
|
<dg:DataGridColumn Title="Artist" PropertyName="Artist" Width="1*"/>
|
||||||
|
<dg:DataGridColumn Title="Duration" PropertyName="Duration"/>
|
||||||
|
</dg:DataGrid.Columns>
|
||||||
|
|
||||||
|
<!-- Row Colors -->
|
||||||
|
<dg:DataGrid.RowsBackgroundColorPalette>
|
||||||
|
<dg:PaletteCollection>
|
||||||
|
<Color>#F2F2F2</Color>
|
||||||
|
<Color>#FFFFFF</Color>
|
||||||
|
</dg:PaletteCollection>
|
||||||
|
</dg:DataGrid.RowsBackgroundColorPalette>
|
||||||
|
|
||||||
|
|
||||||
|
</dg:DataGrid>
|
||||||
</ContentPage.Content>
|
</ContentPage.Content>
|
||||||
</ContentPage>
|
</ContentPage>
|
||||||
|
@ -10,6 +10,7 @@ namespace Aurora.Frontend.Views.Songs
|
|||||||
public SongsView()
|
public SongsView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
BindingContext = new SongsViewModel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,77 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.IO;
|
||||||
|
using Aurora.Frontend.Utils;
|
||||||
|
|
||||||
namespace Aurora.Frontend.Views.Songs
|
namespace Aurora.Frontend.Views.Songs
|
||||||
{
|
{
|
||||||
public class SongsViewModel
|
public class SongsViewModel : BaseViewModel
|
||||||
{
|
{
|
||||||
|
#region Fields
|
||||||
|
private string _pathName = "/Users/brandonwatson/Music/iTunes/iTunes Media/Music";
|
||||||
|
private string _extensions = ".wav,.mp3,.aiff,.flac,.m4a,.m4b,.wma";
|
||||||
|
private ObservableCollection<Song> _songsList;
|
||||||
|
private Song _selectedSong;
|
||||||
|
|
||||||
|
#endregion Fields
|
||||||
|
|
||||||
|
#region Constructor
|
||||||
public SongsViewModel()
|
public SongsViewModel()
|
||||||
{
|
{
|
||||||
|
_songsList = new ObservableCollection<Song>();
|
||||||
|
Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion Constructor
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
public ObservableCollection<Song> SongsList
|
||||||
|
{
|
||||||
|
get { return _songsList; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value != _songsList)
|
||||||
|
{
|
||||||
|
_songsList = value;
|
||||||
|
OnPropertyChanged("SongList");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Song SelectedSong
|
||||||
|
{
|
||||||
|
get { return _selectedSong; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value != _selectedSong)
|
||||||
|
{
|
||||||
|
_selectedSong = value;
|
||||||
|
OnPropertyChanged("SelectedSong");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
List<FileInfo> musicFiles = FileSystemUtils.TraverseFoldersAsync(_pathName, _extensions);
|
||||||
|
|
||||||
|
foreach (FileInfo file in musicFiles)
|
||||||
|
{
|
||||||
|
TagLib.File tagFile = TagLib.File.Create(file.FullName);
|
||||||
|
_songsList.Add(new Song()
|
||||||
|
{
|
||||||
|
Title = tagFile.Tag.Title,
|
||||||
|
Album = tagFile.Tag.Album,
|
||||||
|
Artist = tagFile.Tag.FirstAlbumArtist
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
7
aurora.code-workspace
Normal file
7
aurora.code-workspace
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"path": "."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
Reference in New Issue
Block a user