From b0c3f5e6ffe1e23f7b1f34a34fa876fc85168a82 Mon Sep 17 00:00:00 2001 From: Markil3 <75867393+Markil3@users.noreply.github.com> Date: Fri, 9 Jul 2021 10:36:17 -0600 Subject: [PATCH] Adds a view for displaying songs, as well as a basic song database API. --- build.gradle | 2 +- .../edu/regis/universe_player/data/Album.java | 33 ++ .../data/CompiledSongProvider.java | 349 ++++++++++++++++++ .../data/SimpleSongProvider.java | 178 +++++++++ .../edu/regis/universe_player/data/Song.java | 46 +++ .../universe_player/data/SongProvider.java | 113 ++++++ .../universe_player/player/AlbumInfo.java | 126 +++++++ .../universe_player/player/Interface.java | 5 + .../universe_player/player/SongList.java | 116 ++++++ .../main/resources/gui/icons/defaultart.png | Bin 0 -> 4222 bytes 10 files changed, 967 insertions(+), 1 deletion(-) create mode 100644 interface/src/main/java/edu/regis/universe_player/data/Album.java create mode 100644 interface/src/main/java/edu/regis/universe_player/data/CompiledSongProvider.java create mode 100644 interface/src/main/java/edu/regis/universe_player/data/SimpleSongProvider.java create mode 100644 interface/src/main/java/edu/regis/universe_player/data/Song.java create mode 100644 interface/src/main/java/edu/regis/universe_player/data/SongProvider.java create mode 100644 interface/src/main/java/edu/regis/universe_player/player/AlbumInfo.java create mode 100644 interface/src/main/java/edu/regis/universe_player/player/SongList.java create mode 100755 interface/src/main/resources/gui/icons/defaultart.png diff --git a/build.gradle b/build.gradle index 4a3fb55..dcd7189 100644 --- a/build.gradle +++ b/build.gradle @@ -9,4 +9,4 @@ * For more details take a look at the Java Quickstart chapter in the Gradle * user guide available at https://docs.gradle.org/4.4.1/userguide/tutorial_java_projects.html */ -ext.defaultPackage = "edu.regis" +ext.defaultPackage = "edu.regis.universe_player" diff --git a/interface/src/main/java/edu/regis/universe_player/data/Album.java b/interface/src/main/java/edu/regis/universe_player/data/Album.java new file mode 100644 index 0000000..2cf0718 --- /dev/null +++ b/interface/src/main/java/edu/regis/universe_player/data/Album.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2021 William Hubbard. All Rights Reserved. + */ + +package edu.regis.universe_player.data; + +import java.awt.Image; + +import javax.swing.ImageIcon; + +public class Album implements Comparable +{ + public int id; + public String name; + public String[] artists; + public ImageIcon art; + public int year; + public String[] genres; + public int totalTracks; + + @Override + public int compareTo(Album o) + { + if (o != null) + { + return this.name.compareTo(o.name); + } + else + { + return -1; + } + } +} diff --git a/interface/src/main/java/edu/regis/universe_player/data/CompiledSongProvider.java b/interface/src/main/java/edu/regis/universe_player/data/CompiledSongProvider.java new file mode 100644 index 0000000..3315f49 --- /dev/null +++ b/interface/src/main/java/edu/regis/universe_player/data/CompiledSongProvider.java @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2021 William Hubbard. All Rights Reserved. + */ + +package edu.regis.universe_player.data; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +/** + * A song provider that serves as a central point for any and all song providers, caching the results in memory for quick and easy access. + * + * @author William Hubbard + * @version 0.1 + */ +public class CompiledSongProvider implements SongProvider +{ + /** + * A set of all providers we pull from + */ + private HashMap> providers = new HashMap<>(); + + /** + * A cache of all albums used. + */ + private HashMap> cachedAlbums = new HashMap<>(); + + /** + * A cache of all album names. + */ + private HashMap cachedAlbumNames = new HashMap<>(); + + /** + * A cache of all songs used. + */ + private HashSet cachedSongs = new HashSet<>(); + + /** + * A cache of all song artists used. + */ + private HashMap> cachedArtists = new HashMap<>(); + + /** + * A cache of all album artists used. + */ + private HashMap> cachedAlbumArtists = new HashMap<>(); + + /** + * A cache of all genres used. + */ + private HashMap> cachedGenres = new HashMap<>(); + + /** + * A cache of all years used. + */ + private HashMap> cachedYears = new HashMap<>(); + + /** + * Creates a new CompiledSongProvider containing a set of existing providers. + * + * @param providers - Providers to add. + */ + public CompiledSongProvider(SongProvider... providers) + { + for (SongProvider provider : providers) + { + this.addProvider(provider); + } + } + + /** + * Adds a provider to the list + * + * @param provider - The provider to add. + */ + public void addProvider(SongProvider provider) + { + if (!this.providers.containsKey(provider)) + { + this.providers.put(provider, new HashSet<>(provider.getSongs())); + this.addToCache(provider); + } + } + + /** + * Caches all the songs contained in a provider. + * + * @param provider - The provider to cache. + */ + private void addToCache(SongProvider provider) + { + for (Song song : provider.getSongs()) + { + if (this.cachedSongs.add(song)) + { + this.cachedAlbumNames.put(song.album.name, song.album); + if (!this.cachedAlbums.containsKey(song.album)) + { + this.cachedAlbums.put(song.album, new HashSet<>()); + } + this.cachedAlbums.get(song.album).add(song); + for (String artist : song.artists) + { + if (!this.cachedArtists.containsKey(artist)) + { + this.cachedArtists.put(artist, new HashSet<>()); + } + this.cachedArtists.get(artist).add(song); + } + for (String artist : song.album.artists) + { + if (!this.cachedAlbumArtists.containsKey(artist)) + { + this.cachedAlbumArtists.put(artist, new HashSet<>()); + } + this.cachedAlbumArtists.get(artist).add(song.album); + } + for (String genre : song.album.genres) + { + if (!this.cachedGenres.containsKey(genre)) + { + this.cachedGenres.put(genre, new HashSet<>()); + } + this.cachedGenres.get(genre).add(song.album); + } + if (!this.cachedYears.containsKey(song.album.year)) + { + this.cachedYears.put(song.album.year, new HashSet<>()); + } + this.cachedYears.get(song.album.year).add(song.album); + } + else + { + /* + * If we couldn't add it, then another provider has provided that song already. We + * should remove it from our collection just to ensure that there is no confusion. + */ + this.providers.get(provider).remove(song); + } + } + } + + /** + * Removes a provider from the compilation. + * + * @param provider - The provider to remove. + */ + public void removeProvider(SongProvider provider) + { + this.removeFromCache(provider); + } + + /** + * Removes all songs from a provider from a cache. + * + * @param provider - The provider to move out. + */ + private void removeFromCache(SongProvider provider) + { + Set songs = this.providers.remove(provider); + if (songs != null) + { + for (Song song : songs) + { + this.cachedSongs.remove(song); + this.cachedAlbums.get(song.album).remove(song); + /* + * Remove empty albums + */ + if (this.cachedAlbums.get(song.album).isEmpty()) + { + this.cachedAlbums.remove(song.album); + this.cachedAlbumNames.remove(song.album.name); + } + for (String artist : song.artists) + { + this.cachedArtists.get(artist).remove(song); + if (this.cachedArtists.get(artist).isEmpty()) + { + this.cachedArtists.remove(artist); + } + } + for (String artist : song.album.artists) + { + this.cachedAlbumArtists.get(artist).remove(song.album); + if (this.cachedAlbumArtists.get(artist).isEmpty()) + { + this.cachedAlbumArtists.remove(artist); + } + } + for (String genre : song.album.genres) + { + this.cachedGenres.get(genre).remove(song.album); + if (this.cachedGenres.get(genre).isEmpty()) + { + this.cachedGenres.remove(genre); + } + } + this.cachedYears.get(song.album.year).remove(song.album); + if (this.cachedYears.get(song.album.year).isEmpty()) + { + this.cachedYears.remove(song.album.year); + } + } + } + } + + /** + * Obtains all albums within the collection. + * + * @return A list of albums. + */ + @Override + public Collection getAlbums() + { + return this.cachedAlbums.keySet(); + } + + /** + * Obtains all songs within the collection. + * + * @return A list of songs. + */ + @Override + public Collection getSongs() + { + return this.cachedSongs; + } + + /** + * Obtains a list of all artists. + * + * @return All artists. + */ + @Override + public Collection getArtists() + { + return this.cachedArtists.keySet(); + } + + /** + * Obtains a list of all album artists. + * + * @return All album artists. + */ + @Override + public Collection getAlbumArtists() + { + return this.cachedAlbumArtists.keySet(); + } + + /** + * Obtains a list of all genres. + * + * @return All genres. + */ + @Override + public Collection getGenres() + { + return this.cachedGenres.keySet(); + } + + /** + * Obtains a list of all years that have albums. + * + * @return All years. + */ + @Override + public Collection getYears() + { + return this.cachedYears.keySet(); + } + + /** + * Obtains all songs from an album. + * + * @param album - The album to obtain + * @return All songs from the requested album, or null if that album is not in the database. + */ + @Override + public Collection getSongsFromAlbum(Album album) + { + return this.cachedAlbums.get(album); + } + + /** + * Obtains all songs written by a given artist. + * + * @param artist - The artist to search for + * @return A list of all songs from the specified artist, or null if that artist is not in the + * database. + */ + @Override + public Collection getSongsFromArtist(String artist) + { + return this.cachedArtists.get(artist); + } + + /** + * Obtains an album by a specific name. + * + * @param name - The name to search for. + * @return - The first album that matches the given name, or null if that album name is not in + * the database. + */ + @Override + public Album getAlbumByName(String name) + { + return this.cachedAlbumNames.get(name); + } + + /** + * Obtains all albums that were written by a certain artist. + * + * @param artist - The artist to search for. + * @return - The collection on matching albums. + */ + @Override + public Collection getAlbumsFromArtist(String artist) + { + return this.cachedAlbumArtists.get(artist); + } + + /** + * Obtains all albums that match a certain genre + * + * @param genre - The genre to search for. + * @return - The collection on matching albums. + */ + @Override + public Collection getAlbumsFromGenre(String genre) + { + return this.cachedGenres.get(genre); + } + + /** + * Obtains all albums that were released a certain year. + * + * @param year - The year to search for. + * @return - The collection on matching albums. + */ + @Override + public Collection getAlbumsFromYear(int year) + { + return this.cachedYears.get(year); + } +} diff --git a/interface/src/main/java/edu/regis/universe_player/data/SimpleSongProvider.java b/interface/src/main/java/edu/regis/universe_player/data/SimpleSongProvider.java new file mode 100644 index 0000000..7dfbe05 --- /dev/null +++ b/interface/src/main/java/edu/regis/universe_player/data/SimpleSongProvider.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2021 William Hubbard. All Rights Reserved. + */ + +package edu.regis.universe_player.data; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Random; +import java.util.stream.Collectors; + +/** + * A test song database that automatically generates a handful of songs. + * + * @author William Hubbard + * @version 0.1 + */ +public class SimpleSongProvider implements SongProvider +{ + private ArrayList albums; + private ArrayList songs; + + @Override + public Collection getAlbums() + { + if (albums == null) + { + albums = new ArrayList<>(); + Random random = new Random(); + StringBuilder builder; + String albumName, albumArtist; + Album album; + for (int albumNum = 0, numAlbums = random + .nextInt(5) + 5; albumNum < numAlbums; albumNum++) + { + builder = new StringBuilder(); + for (int i = 0, l = random.nextInt(10) + 10; i < l; i++) + { + builder.append((char) (random.nextInt(26) + 97)); + } + albumName = builder.toString(); + + builder = new StringBuilder(); + for (int i = 0, l = random.nextInt(10) + 10; i < l; i++) + { + builder.append((char) (random.nextInt(26) + 97)); + } + albumArtist = builder.toString(); + + album = new Album() + { + }; + + album.name = albumName; + album.artists = new String[]{albumArtist}; + album.genres = new String[]{"Soundtrack"}; + album.year = 2019; + album.totalTracks = random.nextInt(10) + 10; + album.id = albumNum; + + albums.add(album); + } + } + + return albums; + } + + @Override + public Collection getSongs() + { + if (songs == null) + { + /* + * Generate a list of songs + */ + Random random = new Random(); + StringBuilder builder; + String songTitle; + Song song; + int songNum, numSongs; + songs = new ArrayList<>(); + for (Album album : this.getAlbums()) + { + for (songNum = 0, numSongs = album.totalTracks; songNum < numSongs; songNum++) + { + builder = new StringBuilder(); + for (int i = 0, l = random.nextInt(10) + 10; i < l; i++) + { + builder.append((char) (random.nextInt(26) + 97)); + } + songTitle = builder.toString(); + + song = new Song() + { + }; + song.title = songTitle; + song.disc = 1; + song.trackNum = songNum + 1; + song.artists = album.artists.clone(); + song.album = album; + songs.add(song); + } + album.totalTracks = numSongs; + } + } + return this.songs; + } + + @Override + public Collection getArtists() + { + return this.songs.stream().flatMap(song -> Arrays.stream(song.artists)).sorted() + .collect(Collectors.toList()); + } + + @Override + public Collection getGenres() + { + return this.songs.stream().flatMap(song -> Arrays.stream(song.album.genres)).sorted() + .collect(Collectors.toList()); + } + + @Override + public Collection getAlbumArtists() + { + return this.albums.stream().flatMap(album -> Arrays.stream(album.artists)).sorted() + .collect(Collectors.toList()); + } + + @Override + public Collection getYears() + { + return this.albums.stream().map(album -> album.year).sorted() + .collect(Collectors.toList()); + } + + @Override + public Collection getSongsFromAlbum(Album album) + { + return this.songs.stream().filter(song -> song.album == album).sorted() + .collect(Collectors.toList()); + } + + @Override + public Collection getSongsFromArtist(String artist) + { + return this.songs.stream().filter(song -> Arrays.asList(song.artists).contains(artist)).sorted() + .collect(Collectors.toList()); + } + + @Override + public Album getAlbumByName(String name) + { + return this.albums.stream().filter(album -> album.name.equals(name)).findFirst().orElse(null); + } + + @Override + public Collection getAlbumsFromArtist(String artist) + { + return this.albums.stream().filter(album -> Arrays.asList(album.artists).contains(artist)) + .sorted().collect(Collectors.toList()); + } + + @Override + public Collection getAlbumsFromGenre(String genre) + { + return this.albums.stream().filter(album -> Arrays.asList(album.genres).contains(genre)) + .sorted().collect(Collectors.toList()); + } + + @Override + public Collection getAlbumsFromYear(int year) + { + return this.albums.stream().filter(album -> album.year == year) + .sorted().collect(Collectors.toList()); + } +} diff --git a/interface/src/main/java/edu/regis/universe_player/data/Song.java b/interface/src/main/java/edu/regis/universe_player/data/Song.java new file mode 100644 index 0000000..27fb773 --- /dev/null +++ b/interface/src/main/java/edu/regis/universe_player/data/Song.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021 William Hubbard. All Rights Reserved. + */ + +package edu.regis.universe_player.data; + +/** + * Contains data for a song. + */ +public abstract class Song implements Comparable +{ + public String title; + public String[] artists; + public int trackNum; + public int disc; + /** + * A reference to the album this song is part of. + */ + public Album album; + + @Override + public int compareTo(Song o) + { + if (o != null) + { + int comp = this.album.compareTo(o.album); + if (comp == 0) + { + comp = Integer.compare(this.disc, o.disc); + if (comp == 0) + { + comp = Integer.compare(this.trackNum, o.trackNum); + if (comp == 0) + { + comp = this.title.compareTo(o.title); + } + } + } + return comp; + } + else + { + return -1; + } + } +} diff --git a/interface/src/main/java/edu/regis/universe_player/data/SongProvider.java b/interface/src/main/java/edu/regis/universe_player/data/SongProvider.java new file mode 100644 index 0000000..91b5545 --- /dev/null +++ b/interface/src/main/java/edu/regis/universe_player/data/SongProvider.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2021 William Hubbard. All Rights Reserved. + */ + +package edu.regis.universe_player.data; + +import java.util.Collection; + +/** + * The song provider interface serves to give the application access to any form of song database as needed. + * + * @author William Hubbard + * @version 0.1 + */ +public interface SongProvider +{ + /** + * A SongProvider instance designed to + */ + CompiledSongProvider INSTANCE = new CompiledSongProvider(new SimpleSongProvider()); + + /** + * Obtains all albums within the collection. + * + * @return A list of albums. + */ + Collection getAlbums(); + + /** + * Obtains all songs within the collection. + * + * @return A list of songs. + */ + Collection getSongs(); + + /** + * Obtains a list of all artists. + * + * @return All artists. + */ + Collection getArtists(); + + /** + * Obtains a list of all album artists. + * + * @return All album artists. + */ + Collection getAlbumArtists(); + + /** + * Obtains a list of all genres. + * + * @return All genres. + */ + Collection getGenres(); + + /** + * Obtains a list of all years that have albums. + * + * @return All years. + */ + Collection getYears(); + + /** + * Obtains all songs from an album. + * + * @param album - The album to obtain + * @return All songs from the requested album, or null if that album is not in the database. + */ + Collection getSongsFromAlbum(Album album); + + /** + * Obtains all songs written by a given artist. + * + * @param artist - The artist to search for + * @return A list of all songs from the specified artist, or null if that artist is not in the + * database. + */ + Collection getSongsFromArtist(String artist); + + /** + * Obtains an album by a specific name. + * + * @param name - The name to search for. + * @return - The first album that matches the given name, or null if that album name is not in + * the database. + */ + Album getAlbumByName(String name); + + /** + * Obtains all albums that were written by a certain artist. + * + * @param artist - The artist to search for. + * @return - The collection on matching albums. + */ + Collection getAlbumsFromArtist(String artist); + + /** + * Obtains all albums that match a certain genre + * + * @param genre - The genre to search for. + * @return - The collection on matching albums. + */ + Collection getAlbumsFromGenre(String genre); + + /** + * Obtains all albums that were released a certain year. + * + * @param year - The year to search for. + * @return - The collection on matching albums. + */ + Collection getAlbumsFromYear(int year); +} diff --git a/interface/src/main/java/edu/regis/universe_player/player/AlbumInfo.java b/interface/src/main/java/edu/regis/universe_player/player/AlbumInfo.java new file mode 100644 index 0000000..fd81e3c --- /dev/null +++ b/interface/src/main/java/edu/regis/universe_player/player/AlbumInfo.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2021 William Hubbard. All Rights Reserved. + */ + +package edu.regis.universe_player.player; + +import javax.swing.ImageIcon; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SpringLayout; + +import edu.regis.universe_player.data.Album; + +/** + * This panel will display information on an album. + */ +public class AlbumInfo extends JPanel +{ + private Album album; + private JLabel artLabel; + private JLabel albumName; + private JLabel artists; + private JLabel genres; + private JLabel year; + + public AlbumInfo() + { + SpringLayout infoLayout = new SpringLayout(); + this.setLayout(infoLayout); + + this.artLabel = new JLabel(); + this.add(this.artLabel); + this.albumName = new JLabel("Album"); + this.add(this.albumName); + this.artists = new JLabel("Artists"); + this.add(this.artists); + this.genres = new JLabel("Genres"); + this.add(this.genres); + this.year = new JLabel("20XX"); + this.add(this.year); + + /* + * Set the layout information + */ + infoLayout.putConstraint(SpringLayout.NORTH, artLabel, 5, SpringLayout.NORTH, this); + infoLayout.putConstraint(SpringLayout.WEST, artLabel, 5, SpringLayout.WEST, this); + infoLayout.putConstraint(SpringLayout.NORTH, albumName, 5, SpringLayout.NORTH, this); + infoLayout.putConstraint(SpringLayout.WEST, albumName, 5, SpringLayout.EAST, artLabel); + infoLayout.putConstraint(SpringLayout.NORTH, artists, 5, SpringLayout.SOUTH, albumName); + infoLayout.putConstraint(SpringLayout.WEST, artists, 5, SpringLayout.EAST, artLabel); + infoLayout.putConstraint(SpringLayout.NORTH, genres, 5, SpringLayout.SOUTH, artists); + infoLayout.putConstraint(SpringLayout.WEST, genres, 5, SpringLayout.EAST, artLabel); + infoLayout.putConstraint(SpringLayout.NORTH, year, 5, SpringLayout.SOUTH, genres); + infoLayout.putConstraint(SpringLayout.WEST, year, 5, SpringLayout.EAST, artLabel); +// infoLayout.putConstraint(SpringLayout.EAST, this, 0, SpringLayout.EAST, albumName); + infoLayout.putConstraint(SpringLayout.EAST, this, 0, SpringLayout.EAST, artists); +// infoLayout.putConstraint(SpringLayout.EAST, this, 0, SpringLayout.EAST, genres); +// infoLayout.putConstraint(SpringLayout.EAST, this, 0, SpringLayout.EAST, year); + infoLayout.putConstraint(SpringLayout.SOUTH, this, 5, SpringLayout.EAST, artLabel); + } + + public AlbumInfo(Album album) + { + this(); + this.updateInfo(album); + } + + public void updateInfo(Album album) + { + final int ART_SIZE = 128; + ImageIcon icon; + StringBuilder builder; + + this.album = album; + + if (album.art != null) + { + icon = album.art; + } + else + { + icon = new ImageIcon(this.getClass() + .getResource("/gui/icons/defaultart.png"), "Default"); + } + icon.setImage(icon.getImage().getScaledInstance(ART_SIZE, ART_SIZE, 0)); + this.artLabel.setIcon(icon); + + this.albumName.setText(album.name); + + builder = new StringBuilder(); + if (album.artists != null && album.artists.length >= 1) + { + builder.append(album.artists[0]); + for (int i = 1, l = album.artists.length - 1; i < l; i++) + { + builder.append(", "); + builder.append(album.artists[i]); + } + if (album.artists.length > 1) + { + builder.append(" & "); + builder.append(album.artists[album.artists.length - 1]); + } + } + this.artists.setText(builder.toString()); + + builder = new StringBuilder(); + if (album.genres != null && album.genres.length >= 1) + { + builder.append(album.genres[0]); + for (int i = 1, l = album.genres.length - 1; i < l; i++) + { + builder.append(", "); + builder.append(album.genres[i]); + } + if (album.genres.length > 1) + { + builder.append(" & "); + builder.append(album.genres[album.genres.length - 1]); + } + } + this.genres.setText(builder.toString()); + + this.year.setText(String.valueOf(album.year)); + } +} diff --git a/interface/src/main/java/edu/regis/universe_player/player/Interface.java b/interface/src/main/java/edu/regis/universe_player/player/Interface.java index 5bebc79..d4b0370 100644 --- a/interface/src/main/java/edu/regis/universe_player/player/Interface.java +++ b/interface/src/main/java/edu/regis/universe_player/player/Interface.java @@ -7,6 +7,7 @@ package edu.regis.universe_player.player; import java.awt.BorderLayout; import javax.swing.JFrame; +import javax.swing.JScrollPane; /** * The Interface class serves as the primary GUI that the player interacts with. @@ -29,6 +30,10 @@ public class Interface extends JFrame this.getContentPane().setLayout(new BorderLayout()); this.getContentPane().add(new Collections(), BorderLayout.LINE_START); this.getContentPane().add(new PlayerControls(), BorderLayout.PAGE_END); + + JScrollPane songList = new JScrollPane(new SongList()); + this.getContentPane().add(songList, BorderLayout.CENTER); + this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } } \ No newline at end of file diff --git a/interface/src/main/java/edu/regis/universe_player/player/SongList.java b/interface/src/main/java/edu/regis/universe_player/player/SongList.java new file mode 100644 index 0000000..931757f --- /dev/null +++ b/interface/src/main/java/edu/regis/universe_player/player/SongList.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2021 William Hubbard. All Rights Reserved. + */ + +package edu.regis.universe_player.player; + +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.GridLayout; +import java.awt.Insets; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SpringLayout; + +import edu.regis.universe_player.data.Album; +import edu.regis.universe_player.data.SimpleSongProvider; +import edu.regis.universe_player.data.Song; +import edu.regis.universe_player.data.SongProvider; + +/** + * This panel will list all the songs that are to be currently displayed. + */ +public class SongList extends JPanel +{ + private Map> currentAlbums; + private Map labelMap = new HashMap<>(); + private Map artMap = new HashMap<>(); + + public SongList() + { + super(); + + GridBagLayout layout = new GridBagLayout(); + this.setLayout(layout); + + SongProvider provider = SongProvider.INSTANCE; + this.listAlbums(provider.getSongs()); + } + + /** + * Updates the songs currently listed, sorted by album. + * + * @param songs - The songs to display. + */ + public void listAlbums(Collection songs) + { + Map> albums = songs.stream().sorted().collect(Collectors + .groupingBy(song -> song.album, Collectors + .mapping(song -> song, Collectors.toList()))); + GridBagConstraints c = new GridBagConstraints(), c2 = new GridBagConstraints(); + c.fill = GridBagConstraints.NONE; + c.insets = new Insets(0, 0, 20, 0); + int i = 0, j; + AlbumInfo albumInfo; + List songCollection; + JPanel songList; + JLabel songNum, songTitle; + + this.labelMap.clear(); + this.artMap.clear(); + this.removeAll(); + this.currentAlbums = albums; + + for (Album album : albums.keySet()) + { + songCollection = albums.get(album); + + albumInfo = new AlbumInfo(album); + c.gridx = 0; + c.gridy = i; + c.anchor = GridBagConstraints.WEST; + this.add(albumInfo, c); + this.artMap.put(albumInfo, album); + + songList = new JPanel(new GridBagLayout()); + j = 0; + for (Song song : songCollection) + { + songNum = new JLabel(String.valueOf(song.trackNum)); + c2.gridx = 0; + c2.gridy = j; + c2.anchor = GridBagConstraints.EAST; + c2.insets = new Insets(0, 0, 0, 0); + songList.add(songNum, c2); + this.labelMap.put(songNum, song); + + songTitle = new JLabel(song.title); + c2.gridx = 1; + c2.gridy = j; + c2.anchor = GridBagConstraints.WEST; + c2.insets = new Insets(0, 10, 0, 0); + songList.add(songTitle, c2); + this.labelMap.put(songTitle, song); + // TODO - Add song length or something + + j++; + } + c.gridx = 1; + c.anchor = GridBagConstraints.WEST; + this.add(songList, c); +// this.add(new JLabel(new ImageIcon(this.getClass().getResource("/gui/icons/defaultart.png"), "Default")), c); + + i++; + } + } +} diff --git a/interface/src/main/resources/gui/icons/defaultart.png b/interface/src/main/resources/gui/icons/defaultart.png new file mode 100755 index 0000000000000000000000000000000000000000..a6a4583471d42b37084bc75ee962660727bb812d GIT binary patch literal 4222 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