diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..ced5401 --- /dev/null +++ b/.vscode/launch.json @@ -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": "" + } + ] +} \ No newline at end of file diff --git a/Aurora.gtk/Aurora.gtk.csproj b/Aurora.gtk/Aurora.gtk.csproj index ae9fc38..dfeca64 100644 --- a/Aurora.gtk/Aurora.gtk.csproj +++ b/Aurora.gtk/Aurora.gtk.csproj @@ -64,6 +64,23 @@ ..\packages\Xamarin.Forms.Platform.GTK.3.6.0.344457\lib\net45\Xamarin.Forms.Platform.GTK.dll + + ..\packages\System.Reflection.4.3.0\lib\net462\System.Reflection.dll + + + + ..\packages\System.Reflection.TypeExtensions.4.4.0\lib\net461\System.Reflection.TypeExtensions.dll + + + ..\packages\System.Runtime.Serialization.Primitives.4.3.0\lib\net46\System.Runtime.Serialization.Primitives.dll + + + + ..\packages\taglib-sharp-netstandard2.0.2.1.0\lib\netstandard2.0\taglib-sharp.dll + + + ..\packages\Xamarin.Forms.DataGrid.3.1.0\lib\netstandard2.0\Xamarin.Forms.DataGrid.dll + diff --git a/Aurora.gtk/packages.config b/Aurora.gtk/packages.config index 8a64bff..e160d7a 100644 --- a/Aurora.gtk/packages.config +++ b/Aurora.gtk/packages.config @@ -1,5 +1,10 @@  + + + + + \ No newline at end of file diff --git a/Aurora/Aurora.csproj b/Aurora/Aurora.csproj index 03abbe3..0825bec 100644 --- a/Aurora/Aurora.csproj +++ b/Aurora/Aurora.csproj @@ -13,6 +13,8 @@ + + diff --git a/Aurora/Frontend/Models/Song.cs b/Aurora/Frontend/Models/Song.cs new file mode 100644 index 0000000..bf17f18 --- /dev/null +++ b/Aurora/Frontend/Models/Song.cs @@ -0,0 +1,41 @@ +using System; + +namespace Aurora.Frontend.Views.Songs +{ + public class Song + { + public Song() + { + } + + /// + /// The title of the song. + /// + /// + public string Title { get; set; } + + /// + /// The artist of the song. + /// + /// + public string Artist { get; set; } + + /// + /// The album from which the song belongs. + /// + /// + public string Album { get; set; } + + /// + /// The duration of the song. + /// + /// + public string Duration { get; set; } + + /// + /// Extra data associated with a song. + /// + /// + public object Metadata { get; set; } + } +} \ No newline at end of file diff --git a/Aurora/Frontend/Utils/FileSystemUtils.cs b/Aurora/Frontend/Utils/FileSystemUtils.cs new file mode 100644 index 0000000..b951088 --- /dev/null +++ b/Aurora/Frontend/Utils/FileSystemUtils.cs @@ -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() + { + } + + + /// + /// Asynchronousely recursively traverse a directory path. + /// + /// The path to the directory to traverse + /// Comma separated list of file extensions to accept + public static List TraverseFoldersAsync(string path, string extensions) + { + string[] extensionList = extensions.Split(','); + + ConcurrentBag tasks = new ConcurrentBag(); + List outFiles = new List(); + 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; + } + + + + /// + /// Recursive method to capture children of a directory. + /// + /// The directory to traverse + /// The list of currently running tasks + private static void Traverse(DirectoryInfo dir, ConcurrentBag tasks, List 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; + } + } + + } +} \ No newline at end of file diff --git a/Aurora/Frontend/Views/Songs/SongsView.xaml b/Aurora/Frontend/Views/Songs/SongsView.xaml index f6276ef..5a48407 100644 --- a/Aurora/Frontend/Views/Songs/SongsView.xaml +++ b/Aurora/Frontend/Views/Songs/SongsView.xaml @@ -1,6 +1,38 @@ - + - diff --git a/Aurora/Frontend/Views/Songs/SongsView.xaml.cs b/Aurora/Frontend/Views/Songs/SongsView.xaml.cs index 24e46e8..859ee32 100644 --- a/Aurora/Frontend/Views/Songs/SongsView.xaml.cs +++ b/Aurora/Frontend/Views/Songs/SongsView.xaml.cs @@ -10,6 +10,7 @@ namespace Aurora.Frontend.Views.Songs public SongsView() { InitializeComponent(); + BindingContext = new SongsViewModel(); } } } diff --git a/Aurora/Frontend/Views/Songs/SongsViewModel.cs b/Aurora/Frontend/Views/Songs/SongsViewModel.cs index ac83454..532d241 100644 --- a/Aurora/Frontend/Views/Songs/SongsViewModel.cs +++ b/Aurora/Frontend/Views/Songs/SongsViewModel.cs @@ -1,10 +1,77 @@ using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using Aurora.Frontend.Utils; + 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 _songsList; + private Song _selectedSong; + + #endregion Fields + + #region Constructor public SongsViewModel() { + _songsList = new ObservableCollection(); + Initialize(); } + + #endregion Constructor + + #region Properties + public ObservableCollection 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 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 + } } diff --git a/aurora.code-workspace b/aurora.code-workspace new file mode 100644 index 0000000..362d7c2 --- /dev/null +++ b/aurora.code-workspace @@ -0,0 +1,7 @@ +{ + "folders": [ + { + "path": "." + } + ] +} \ No newline at end of file