Adds working links for the collections and such.

This commit is contained in:
Markil3
2021-07-09 13:26:05 -06:00
parent b0c3f5e6ff
commit 2bc005f031
10 changed files with 667 additions and 19 deletions

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2021 William Hubbard. All Rights Reserved.
*/
package edu.regis.universe_player;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
/**
* A utility class designed to shortcut adding click listeners to AWT objects.
*
* @author William Hubbard
* @version 0.1
*/
public interface ClickListener extends MouseListener
{
default void mousePressed(MouseEvent var1)
{
}
default void mouseReleased(MouseEvent var1)
{
}
default void mouseEntered(MouseEvent var1)
{
}
default void mouseExited(MouseEvent var1)
{
}
}

View File

@@ -4,8 +4,6 @@
package edu.regis.universe_player.data;
import java.awt.Image;
import javax.swing.ImageIcon;
public class Album implements Comparable<Album>

View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) 2021 William Hubbard. All Rights Reserved.
*/
package edu.regis.universe_player.data;
/**
* Lists all of the type of collections possible.
*/
public enum CollectionType
{
album(Album.class), artist(String.class), albumArtist(String.class), genre(String.class), year(Integer.class);
/**
* The object class for this type.
*/
public Class<?> objectType;
/**
* Creates a collection type.
*
* @param type - The class this type uses.
*/
CollectionType(Class<?> type)
{
this.objectType = type;
}
}

View File

@@ -32,7 +32,7 @@ public class SimpleSongProvider implements SongProvider
String albumName, albumArtist;
Album album;
for (int albumNum = 0, numAlbums = random
.nextInt(5) + 5; albumNum < numAlbums; albumNum++)
.nextInt(20) + 20; albumNum < numAlbums; albumNum++)
{
builder = new StringBuilder();
for (int i = 0, l = random.nextInt(10) + 10; i < l; i++)

View File

@@ -0,0 +1,315 @@
/*
* 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.awt.event.MouseEvent;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import edu.regis.universe_player.ClickListener;
import edu.regis.universe_player.data.Album;
import edu.regis.universe_player.data.CollectionType;
import edu.regis.universe_player.data.Song;
import edu.regis.universe_player.data.SongProvider;
/**
* This panel will list all the song collections on display (albums, artists, genres, etc.)
*
* @author William Hubbard
* @version 0.1
*/
public class CollectionList extends JPanel
{
/**
* The type of collections being displayed.
*/
private CollectionType type;
/**
* A link between the JLabel and the object they point towards.
*/
private Map<JLabel, Object> labelMap = new HashMap<>();
/**
* A list of all things interested in knowing when we click a collection.
*/
private LinkedList<SongDisplayListener> listeners = new LinkedList<>();
/**
* Creates a collections list view.
*/
public CollectionList()
{
super();
FlowLayout layout = new FlowLayout();
this.setLayout(layout);
}
/**
* Updates the collections currently listed, sorted by album.
*
* @param type - The type of collection we are displaying.
* @param objects - The collection to display.
*/
public void listCollection(CollectionType type, Collection<?> objects)
{
Class<?> fType = objects.stream().filter(Objects::nonNull).map(Object::getClass).findFirst()
.orElse(null);
if (objects.isEmpty() || fType == null)
{
/*
* We really don't need error checking here, and we couldn't get it working anyway.
*/
this.labelMap.clear();
this.removeAll();
return;
}
if (!type.objectType.isAssignableFrom(fType))
{
throw new ClassCastException("Can't assign " + type.objectType
.getName() + " from " + fType
.getName());
}
this.labelMap.clear();
this.removeAll();
this.type = type;
switch (type)
{
case album:
this.addAlbums(objects.stream().sorted().map(ob -> (Album) ob)
.collect(Collectors.toList()));
break;
case artist:
this.addArtists(objects.stream().sorted().map(ob -> (String) ob)
.collect(Collectors.toList()), false);
break;
case albumArtist:
this.addArtists(objects.stream().sorted().map(ob -> (String) ob)
.collect(Collectors.toList()), true);
break;
case genre:
this.addGenres(objects.stream().sorted().map(ob -> (String) ob)
.collect(Collectors.toList()));
break;
case year:
this.addYears(objects.stream().sorted().map(ob -> (Integer) ob)
.collect(Collectors.toList()));
break;
}
}
/**
* Updates the display to show a list of artists
*
* @param artists - The list of artists to display.
* @param album - Whether the list should be treated as song artists or album artists.
*/
private void addArtists(List<String> artists, boolean album)
{
final int ART_SIZE = 128;
JLabel artistLabel;
ImageIcon icon;
for (String artist : artists)
{
artistLabel = new JLabel();
// TODO - Maybe add some sort of artist image lookup?
// if (album.art != null)
// {
// icon = album.art;
// }
// else
// {
icon = new ImageIcon(this.getClass()
.getResource("/gui/icons/artist.png"), "Default");
// }
icon.setImage(icon.getImage().getScaledInstance(ART_SIZE, ART_SIZE, 0));
artistLabel.setIcon(icon);
artistLabel.setText(artist);
artistLabel.setHorizontalTextPosition(JLabel.CENTER);
artistLabel.setVerticalTextPosition(JLabel.BOTTOM);
artistLabel.addMouseListener((ClickListener) mouseEvent -> {
if (album)
{
this.triggerSongDisplayListeners(SongProvider.INSTANCE
.getAlbumsFromArtist(artist).stream()
.flatMap(album2 -> SongProvider.INSTANCE.getSongsFromAlbum(album2)
.stream())
.collect(Collectors.toList()));
}
else
{
this.triggerSongDisplayListeners(SongProvider.INSTANCE
.getSongsFromArtist(artist));
}
});
this.add(artistLabel);
this.labelMap.put(artistLabel, artist);
}
}
/**
* Updates the display to show a list of albums.
*
* @param albums - The list of albums to display.
*/
private void addAlbums(List<Album> albums)
{
final int ART_SIZE = 128;
JLabel albumLabel;
ImageIcon icon;
for (Album album : albums)
{
albumLabel = new JLabel();
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));
albumLabel.setIcon(icon);
albumLabel.setText(album.name);
albumLabel.setHorizontalTextPosition(JLabel.CENTER);
albumLabel.setVerticalTextPosition(JLabel.BOTTOM);
albumLabel.addMouseListener((ClickListener) mouseEvent -> this.triggerSongDisplayListeners(SongProvider.INSTANCE
.getSongsFromAlbum(album)));
this.add(albumLabel);
this.labelMap.put(albumLabel, album);
}
}
/**
* Updates the display to show a list of genres.
*
* @param genres - The list of genres to display.
*/
private void addGenres(List<String> genres)
{
// final int ART_SIZE = 128;
JLabel genreLabel;
// ImageIcon icon;
for (String genre : genres)
{
genreLabel = new JLabel();
// TODO - Maybe add some sort of artist image lookup?
// 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));
// albumLabel.setIcon(icon);
genreLabel.setText(genre);
genreLabel.setHorizontalTextPosition(JLabel.CENTER);
genreLabel.setVerticalTextPosition(JLabel.BOTTOM);
genreLabel.addMouseListener((ClickListener) mouseEvent -> this.triggerSongDisplayListeners(SongProvider.INSTANCE
.getAlbumsFromGenre(genre).stream()
.flatMap(album2 -> SongProvider.INSTANCE.getSongsFromAlbum(album2)
.stream())
.collect(Collectors.toList())));
this.add(genreLabel);
this.labelMap.put(genreLabel, genre);
}
}
/**
* Updates the display to show a list of release years.
*
* @param years - The list of genres to display.
*/
private void addYears(List<Integer> years)
{
// final int ART_SIZE = 128;
JLabel yearLabel;
// ImageIcon icon;
for (Integer year : years)
{
yearLabel = new JLabel();
// TODO - Maybe add some sort of artist image lookup?
// 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));
// albumLabel.setIcon(icon);
yearLabel.setText(year.toString());
yearLabel.setHorizontalTextPosition(JLabel.CENTER);
yearLabel.setVerticalTextPosition(JLabel.BOTTOM);
yearLabel.addMouseListener((ClickListener) mouseEvent -> this.triggerSongDisplayListeners(SongProvider.INSTANCE
.getAlbumsFromYear(year).stream()
.flatMap(album2 -> SongProvider.INSTANCE.getSongsFromAlbum(album2)
.stream())
.collect(Collectors.toList())));
this.add(yearLabel);
this.labelMap.put(yearLabel, year);
}
}
/**
* Adds a listener for when the displayed songs should change.
*
* @param listener - The listener to add.
*/
public void addSongDisplayListener(SongDisplayListener listener)
{
this.listeners.add(listener);
}
/**
* Adds a listener for when the displayed songs should change.
*
* @param listener - The listener to add.
*/
public void removeSongDisplayListener(SongDisplayListener listener)
{
this.listeners.remove(listener);
}
/**
* Triggers all the song display listeners.
*/
protected void triggerSongDisplayListeners(Collection<Song> songs)
{
for (SongDisplayListener listener : this.listeners)
{
listener.updateSongs(songs);
}
}
}

View File

@@ -5,11 +5,21 @@
package edu.regis.universe_player.player;
import java.awt.Color;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import edu.regis.universe_player.ClickListener;
import edu.regis.universe_player.data.CollectionType;
import edu.regis.universe_player.data.Song;
import edu.regis.universe_player.data.SongProvider;
/**
* This panel links to various song collections the player has set up.
*
@@ -18,31 +28,88 @@ import javax.swing.JPanel;
*/
public class Collections extends JPanel
{
JLabel allSongs;
JLabel artists;
JLabel albums;
JLabel genres;
JLabel years;
JLabel playlists;
/**
* A list of all things interested in knowing when we click a collection.
*/
private LinkedList<SongDisplayListener> listeners = new LinkedList<>();
/**
* Creates a collections list view.
*/
public Collections()
{
JLabel label;
BoxLayout layout = new BoxLayout(this, BoxLayout.Y_AXIS);
this.setLayout(layout);
this.add(this.allSongs = label = new JLabel("All Songs"));
this.add(label = new JLabel("All Songs"));
label.setForeground(Color.BLUE);
this.add(this.artists = label = new JLabel("Artists"));
label.addMouseListener((ClickListener) mouseEvent -> this
.triggerSongDisplayListeners(SongProvider.INSTANCE.getSongs()));
this.add(label = new JLabel("Artists"));
label.setForeground(Color.BLUE);
this.add(this.albums = label = new JLabel("Albums"));
label.addMouseListener((ClickListener) mouseEvent -> this
.triggerCollectionDisplayListeners(CollectionType.albumArtist, SongProvider.INSTANCE
.getAlbumArtists()));
this.add(label = new JLabel("Albums"));
label.setForeground(Color.BLUE);
this.add(this.genres = label = new JLabel("Genres"));
label.addMouseListener((ClickListener) mouseEvent -> this
.triggerCollectionDisplayListeners(CollectionType.album, SongProvider.INSTANCE
.getAlbums()));
this.add(label = new JLabel("Genres"));
label.setForeground(Color.BLUE);
this.add(this.years = label = new JLabel("Years"));
label.addMouseListener((ClickListener) mouseEvent -> this
.triggerCollectionDisplayListeners(CollectionType.genre, SongProvider.INSTANCE
.getGenres()));
this.add(label = new JLabel("Years"));
label.setForeground(Color.BLUE);
label.addMouseListener((ClickListener) mouseEvent -> this
.triggerCollectionDisplayListeners(CollectionType.year, SongProvider.INSTANCE
.getYears()));
this.add(new JLabel("\u23AF\u23AF\u23AF\u23AF\u23AF\u23AF"));
this.add(this.playlists = label = new JLabel("Playlists"));
this.add(label = new JLabel("Playlists"));
label.setForeground(Color.BLUE);
}
/**
* Adds a listener for when the displayed songs should change.
*
* @param listener - The listener to add.
*/
public void addSongDisplayListener(SongDisplayListener listener)
{
this.listeners.add(listener);
}
/**
* Adds a listener for when the displayed songs should change.
*
* @param listener - The listener to add.
*/
public void removeSongDisplayListener(SongDisplayListener listener)
{
this.listeners.remove(listener);
}
/**
* Triggers all the song display listeners.
*/
protected void triggerSongDisplayListeners(Collection<Song> songs)
{
for (SongDisplayListener listener : this.listeners)
{
listener.updateSongs(songs);
}
}
/**
* Triggers all the song display listeners.
*/
protected void triggerCollectionDisplayListeners(CollectionType type, Collection<?> collection)
{
for (SongDisplayListener listener : this.listeners)
{
listener.updateCollections(type, collection);
}
}
}

View File

@@ -5,17 +5,42 @@
package edu.regis.universe_player.player;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.util.Collection;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import edu.regis.universe_player.data.CollectionType;
import edu.regis.universe_player.data.Song;
/**
* The Interface class serves as the primary GUI that the player interacts with.
*
* @author William Hubbard
* @version 0.1
*/
public class Interface extends JFrame
public class Interface extends JFrame implements SongDisplayListener, ComponentListener
{
/**
* A reference to the panel containing links to different collection views.
*/
private Collections collectionTypes;
/**
* A reference to the central view showing a list of songs.
*/
private SongList songList;
/**
* A reference to the central view showing a list of collections.
*/
private CollectionList collectionList;
/**
* A reference to the central view scroll pane.
*/
private JScrollPane centerView;
public static void main(String[] args)
{
Interface inter = new Interface();
@@ -23,17 +48,86 @@ public class Interface extends JFrame
inter.setVisible(true);
}
/**
* Creates an interface
*/
public Interface()
{
super();
this.setTitle("Universal Music Player");
this.getContentPane().setLayout(new BorderLayout());
this.getContentPane().add(new Collections(), BorderLayout.LINE_START);
this.getContentPane()
.add(this.collectionTypes = new Collections(), BorderLayout.LINE_START);
this.collectionTypes.addSongDisplayListener(this);
this.getContentPane().add(new PlayerControls(), BorderLayout.PAGE_END);
JScrollPane songList = new JScrollPane(new SongList());
this.getContentPane().add(songList, BorderLayout.CENTER);
this.songList = new SongList();
this.collectionList = new CollectionList();
this.collectionList.addSongDisplayListener(this);
this.centerView = new JScrollPane(this.songList);
this.getContentPane().add(this.centerView, BorderLayout.CENTER);
this.componentResized(null);
this.addComponentListener(this);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
@Override
public void updateSongs(Collection<Song> songs)
{
this.songList.listAlbums(songs);
this.centerView.setViewportView(this.songList);
this.songList.setPreferredSize(new Dimension(this.centerView.getViewport()
.getExtentSize().width, Integer.MAX_VALUE));
this.songList.setPreferredSize(new Dimension(this.centerView.getViewport()
.getExtentSize().width, this.songList
.getMinimumSize().height));
}
@Override
public void updateCollections(CollectionType type, Collection<?> collections)
{
this.collectionList.listCollection(type, collections);
this.centerView.setViewportView(this.collectionList);
this.collectionList.setPreferredSize(new Dimension(this.centerView.getViewport()
.getExtentSize().width, Integer.MAX_VALUE));
this.collectionList.setPreferredSize(new Dimension(this.centerView.getViewport()
.getExtentSize().width, this.collectionList
.getMinimumSize().height));
}
@Override
public void componentResized(ComponentEvent event)
{
this.songList.setPreferredSize(new Dimension(this.centerView.getViewport()
.getExtentSize().width, Integer.MAX_VALUE));
this.songList.setPreferredSize(new Dimension(this.centerView.getViewport()
.getExtentSize().width, this.songList
.getMinimumSize().height));
this.collectionList.setPreferredSize(new Dimension(this.centerView.getViewport()
.getExtentSize().width, Integer.MAX_VALUE));
this.collectionList.setPreferredSize(new Dimension(this.centerView.getViewport()
.getExtentSize().width, this.collectionList
.getMinimumSize().height));
}
@Override
public void componentMoved(ComponentEvent event)
{
}
@Override
public void componentShown(ComponentEvent event)
{
}
@Override
public void componentHidden(ComponentEvent event)
{
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (c) 2021 William Hubbard. All Rights Reserved.
*/
package edu.regis.universe_player.player;
import java.util.Collection;
import java.util.EventListener;
import edu.regis.universe_player.data.CollectionType;
import edu.regis.universe_player.data.Song;
/**
* A callback that is triggered whenever one element believes that the interface center display needs to be updated.
*
* @author William Hubbard
* @version 0.1
*/
public interface SongDisplayListener extends EventListener
{
/**
* Called to display a list of songs, sorted by album.
*
* @param songs - The songs to display.
*/
void updateSongs(Collection<Song> songs);
/**
* Called to display a list of collections
*
* @param type - The type of collections to display.
* @param collections - The collections to display
*/
void updateCollections(CollectionType type, Collection<?> collections);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="512"
height="512"
viewBox="0 0 135.46666 135.46667"
version="1.1"
id="svg8"
inkscape:version="1.0.2 (e86c870879, 2021-01-15)"
sodipodi:docname="artist.svg"
inkscape:export-filename="/home/markil3/Projects/UniversalMusicPlayer/interface/src/main/resources/gui/icons/artist.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.78888252"
inkscape:cx="-23.809983"
inkscape:cy="378.54032"
inkscape:document-units="px"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
units="px"
inkscape:pagecheckerboard="true"
inkscape:window-width="1343"
inkscape:window-height="846"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<circle
style="fill:#000000;stroke-width:2.02815"
id="path10"
cx="66.765106"
cy="48.744423"
r="35.108318" />
<path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.32291665;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 85.721431,71.175093 c 0,47.470047 31.875489,47.279547 31.875489,47.279547 H 66.594158 V 78.902854 Z"
id="path12" />
<path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.32291665;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 47.466889,71.175093 c 0,47.470047 -31.875497,47.279547 -31.875497,47.279547 H 66.594158 V 78.902854 Z"
id="path12-3" />
<path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.32291665;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 15.591392,118.45464 H 0.00350819 V 135.4101 H 135.22075 v -17.04947 l -17.62383,0.094 z"
id="path863" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB