Adds some integration with firefox.
This is still rather unstable, but it runs.
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright (c) 2021 William Hubbard. All Rights Reserved.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'application'
|
||||
}
|
||||
|
||||
/*
|
||||
* Copyright (c) 2021 William Hubbard. All Rights Reserved.
|
||||
*/
|
||||
|
||||
// In this section you declare where to find the dependencies of your project
|
||||
repositories {
|
||||
mavenCentral()
|
||||
@@ -16,6 +16,7 @@ repositories {
|
||||
dependencies {
|
||||
// The production code uses the SLF4J logging API at compile time
|
||||
implementation 'org.slf4j:slf4j-api:1.7.25'
|
||||
implementation 'com.google.code.gson:gson:2.8.7'
|
||||
|
||||
// Declare the dependency for your favourite test framework you want to use in your tests.
|
||||
// TestNG is also supported by the Gradle Test task. Just change the
|
||||
@@ -25,4 +26,6 @@ dependencies {
|
||||
}
|
||||
|
||||
// Define the main class for the application
|
||||
mainClassName = defaultPackage + '.player.Interface'
|
||||
mainClassName = defaultPackage + '.player.Interface'
|
||||
|
||||
compileJava.dependsOn rootProject.bundleAddOn
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2021 William Hubbard. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package edu.regis.universe_player;
|
||||
|
||||
import edu.regis.universe_player.data.Song;
|
||||
|
||||
/**
|
||||
* This interface serves as the connection to a music player of some sort, whether it be
|
||||
* browser-based or from a file.
|
||||
*
|
||||
* @param <T> - The type of songs supported.
|
||||
* @author William Hubbard
|
||||
* @since 0.1
|
||||
*/
|
||||
public interface Player<T extends Song>
|
||||
{
|
||||
/**
|
||||
* Obtains the song currently playing.
|
||||
*
|
||||
* @return The current song, or null if none is playing.
|
||||
*/
|
||||
Song getCurrentSong();
|
||||
|
||||
/**
|
||||
* Loads up a song
|
||||
*
|
||||
* @param song - The song to load.
|
||||
*/
|
||||
void play(T song);
|
||||
|
||||
/**
|
||||
* Enables playback of the current song, if one is active.
|
||||
*/
|
||||
void play();
|
||||
|
||||
/**
|
||||
* Pauses playback of the current song.
|
||||
*/
|
||||
void pause();
|
||||
|
||||
/**
|
||||
* Toggles between playing and pausing the current song.
|
||||
*/
|
||||
void togglePlayback();
|
||||
|
||||
/**
|
||||
* Sets the current song time to the specified position.
|
||||
*
|
||||
* @param time - The specified time in the song, in seconds.
|
||||
*/
|
||||
void seek(float time);
|
||||
|
||||
/**
|
||||
* Checks to see if the song is paused.
|
||||
*
|
||||
* @return Whether or not the song is paused.
|
||||
*/
|
||||
boolean isPaused();
|
||||
|
||||
/**
|
||||
* Obtains the time we are currently at in the current song.
|
||||
*
|
||||
* @return - The current song position in seconds, or -1 if no song is playing.
|
||||
*/
|
||||
float getCurrentTime();
|
||||
|
||||
/**
|
||||
* Gets the length of the current song.
|
||||
*
|
||||
* @return The song length, in seconds.
|
||||
*/
|
||||
float getLength();
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) 2021 William Hubbard. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package edu.regis.universe_player.browser;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* This serves as a central point for controlling the browser process.
|
||||
*
|
||||
* @author William Hubbard
|
||||
* @since 0.1
|
||||
*/
|
||||
public class Browser
|
||||
{
|
||||
private static Process process;
|
||||
|
||||
/**
|
||||
* Utility method for launching a browser instance
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void launchBrowser() throws IOException
|
||||
{
|
||||
String os = System.getProperty("os.name").toLowerCase();
|
||||
String arch = System.getProperty("os.arch").toLowerCase();
|
||||
String args = " -profile browser/profile";
|
||||
if (process != null && process.isAlive())
|
||||
{
|
||||
process.destroy();
|
||||
}
|
||||
|
||||
if (os.contains("windows"))
|
||||
{
|
||||
setupWindows();
|
||||
process = Runtime.getRuntime().exec("browser/windows/FirefoxPortable.exe" + args);
|
||||
}
|
||||
else if (os.contains("linux"))
|
||||
{
|
||||
setupLinux();
|
||||
if (arch.contains("64"))
|
||||
{
|
||||
process = Runtime.getRuntime().exec("./browser/linux64/firefox" + args);
|
||||
}
|
||||
else
|
||||
{
|
||||
process = Runtime.getRuntime().exec("./browser/linux32/firefox" + args);
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println(os);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs first-time setup for Windows applications.
|
||||
*/
|
||||
private static void setupWindows()
|
||||
{
|
||||
try
|
||||
{
|
||||
Runtime.getRuntime()
|
||||
.exec("REG ADD HKEY_CURRENT_USER\\SOFTWARE\\Mozilla\\NativeMessagingHosts /v universal_music /d \"" + System
|
||||
.getProperty("user.dir") + "\\bin\\interface.bat\" ");
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
System.err.println("Could not set Windows registry key.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs first-time setup for OSX applications.
|
||||
*/
|
||||
private static void setupMac()
|
||||
{
|
||||
Gson gson = new Gson();
|
||||
try (JsonWriter writer = gson.newJsonWriter(new FileWriter(new File(System
|
||||
.getProperty("user.home"), "Library/Application Support/Mozilla/NativeMessagingHosts/universal_music.json"))))
|
||||
{
|
||||
writeManifest(writer, System.getProperty("user.dir") + "/bin/interface");
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
System.err.println("Could not set Mac application manifest.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs first-time setup for Linux applications.
|
||||
*/
|
||||
private static void setupLinux()
|
||||
{
|
||||
Gson gson = new Gson();
|
||||
try (JsonWriter writer = gson.newJsonWriter(new FileWriter(new File(System
|
||||
.getProperty("user.home"), ".mozilla/native-messaging-hosts/universal_music.json"))))
|
||||
{
|
||||
writeManifest(writer, System.getProperty("user.dir") + "/bin/interface");
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
System.err.println("Could not set Linux application manifest.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeManifest(JsonWriter writer, String path) throws IOException
|
||||
{
|
||||
writer.beginObject();
|
||||
|
||||
writer.name("name");
|
||||
writer.value("universal_music");
|
||||
writer.name("description");
|
||||
writer.value("Universal Music Player");
|
||||
writer.name("path");
|
||||
writer.value(path);
|
||||
writer.name("type");
|
||||
writer.value("stdio");
|
||||
|
||||
writer.name("allowed_extensions");
|
||||
writer.beginArray();
|
||||
writer.value("universal_music@regis.edu");
|
||||
writer.endArray();
|
||||
|
||||
writer.endObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the browser process to shut down.
|
||||
*/
|
||||
public static void closeBrowser()
|
||||
{
|
||||
if (process != null && process.isAlive())
|
||||
{
|
||||
process.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2021 William Hubbard. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package edu.regis.universe_player.browser;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintStream;
|
||||
import java.io.Reader;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* This class will send messages to the
|
||||
*/
|
||||
public class MessageManager implements Closeable
|
||||
{
|
||||
private final JsonReader in;
|
||||
private final JsonWriter out;
|
||||
private final Gson gson;
|
||||
|
||||
public MessageManager() throws IOException
|
||||
{
|
||||
this.gson = new Gson();
|
||||
this.in = this.gson.newJsonReader(new InputStreamReader(System.in));
|
||||
this.out = this.gson.newJsonWriter(new OutputStreamWriter(System.out));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an object from the browser.
|
||||
*
|
||||
* @return - A parsed object. What it is depends on the browser.
|
||||
*/
|
||||
public Object getMessage() throws IOException
|
||||
{
|
||||
Object value = null;
|
||||
this.in.beginObject();
|
||||
while (this.in.hasNext())
|
||||
{
|
||||
switch (this.in.nextName())
|
||||
{
|
||||
case "response":
|
||||
switch (this.in.peek())
|
||||
{
|
||||
case STRING:
|
||||
value = this.in.nextString();
|
||||
break;
|
||||
case NUMBER:
|
||||
value = this.in.nextDouble();
|
||||
break;
|
||||
case BOOLEAN:
|
||||
value = this.in.nextBoolean();
|
||||
break;
|
||||
case NULL:
|
||||
this.in.nextNull();
|
||||
break;
|
||||
default:
|
||||
throw new IOException("Unexpected JSON type" + this.in.peek());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.in.endObject();
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a string message to the browser.
|
||||
*
|
||||
* @param message - The message to send.
|
||||
*/
|
||||
public void writeMessage(String message)
|
||||
{
|
||||
String value = null;
|
||||
String type = null;
|
||||
try
|
||||
{
|
||||
this.out.beginObject();
|
||||
this.out.name("message");
|
||||
this.out.value(message);
|
||||
this.out.endObject();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pings the browser.
|
||||
*/
|
||||
public void ping()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.out.beginObject();
|
||||
this.out.name("command");
|
||||
this.out.value("ping");
|
||||
this.out.endObject();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException
|
||||
{
|
||||
this.in.close();
|
||||
this.out.close();
|
||||
}
|
||||
}
|
||||
@@ -8,11 +8,17 @@ import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.ComponentListener;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.event.WindowListener;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JScrollPane;
|
||||
|
||||
import edu.regis.universe_player.browser.Browser;
|
||||
import edu.regis.universe_player.browser.MessageManager;
|
||||
import edu.regis.universe_player.data.CollectionType;
|
||||
import edu.regis.universe_player.data.Song;
|
||||
|
||||
@@ -22,7 +28,7 @@ import edu.regis.universe_player.data.Song;
|
||||
* @author William Hubbard
|
||||
* @version 0.1
|
||||
*/
|
||||
public class Interface extends JFrame implements SongDisplayListener, ComponentListener
|
||||
public class Interface extends JFrame implements SongDisplayListener, ComponentListener, WindowListener, PlaybackCommandListener
|
||||
{
|
||||
/**
|
||||
* A reference to the panel containing links to different collection views.
|
||||
@@ -41,9 +47,32 @@ public class Interface extends JFrame implements SongDisplayListener, ComponentL
|
||||
*/
|
||||
private JScrollPane centerView;
|
||||
|
||||
/**
|
||||
* A link to the browser.
|
||||
*/
|
||||
private MessageManager browser;
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
Browser.launchBrowser();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
JOptionPane.showMessageDialog(null, e, "Could not open browser background", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
Interface inter = new Interface();
|
||||
try
|
||||
{
|
||||
inter.browser = new MessageManager();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
JOptionPane.showMessageDialog(null, e, "Could not open browser communication", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
inter.pack();
|
||||
inter.setVisible(true);
|
||||
}
|
||||
@@ -54,12 +83,16 @@ public class Interface extends JFrame implements SongDisplayListener, ComponentL
|
||||
public Interface()
|
||||
{
|
||||
super();
|
||||
PlayerControls controls;
|
||||
|
||||
this.setTitle("Universal Music Player");
|
||||
this.getContentPane().setLayout(new BorderLayout());
|
||||
this.getContentPane()
|
||||
.add(this.collectionTypes = new Collections(), BorderLayout.LINE_START);
|
||||
this.collectionTypes.addSongDisplayListener(this);
|
||||
this.getContentPane().add(new PlayerControls(), BorderLayout.PAGE_END);
|
||||
controls = new PlayerControls();
|
||||
controls.addCommandListener(this);
|
||||
this.getContentPane().add(controls, BorderLayout.PAGE_END);
|
||||
|
||||
this.songList = new SongList();
|
||||
this.collectionList = new CollectionList();
|
||||
@@ -70,6 +103,7 @@ public class Interface extends JFrame implements SongDisplayListener, ComponentL
|
||||
this.componentResized(null);
|
||||
|
||||
this.addComponentListener(this);
|
||||
this.addWindowListener(this);
|
||||
|
||||
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
}
|
||||
@@ -130,4 +164,91 @@ public class Interface extends JFrame implements SongDisplayListener, ComponentL
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowOpened(WindowEvent windowEvent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowClosing(WindowEvent windowEvent)
|
||||
{
|
||||
Browser.closeBrowser();
|
||||
if (this.browser != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.browser.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowClosed(WindowEvent windowEvent)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowIconified(WindowEvent windowEvent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowDeiconified(WindowEvent windowEvent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowActivated(WindowEvent windowEvent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowDeactivated(WindowEvent windowEvent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a playback command is issued.
|
||||
*
|
||||
* @param command - The command issued.
|
||||
* @param data - Additional data relevent to the command.
|
||||
*/
|
||||
@Override
|
||||
public void onCommand(PlaybackCommand command, Object data)
|
||||
{
|
||||
Object message = null;
|
||||
if (this.browser != null)
|
||||
{
|
||||
synchronized (this.browser)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.browser.ping();
|
||||
message = this.browser.getMessage();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
JOptionPane.showMessageDialog(this, e, "Could not send message to browser", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (message != null)
|
||||
{
|
||||
if ("ping".equals(message))
|
||||
{
|
||||
JOptionPane.showMessageDialog(this, "Ping received!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2021 William Hubbard. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package edu.regis.universe_player.player;
|
||||
|
||||
/**
|
||||
* Contains possible playback commands that the play can send.
|
||||
*
|
||||
* @author William Hubbard
|
||||
* @version 0.1
|
||||
*/
|
||||
public enum PlaybackCommand
|
||||
{
|
||||
PLAY, PAUSE, NEXT, PREVIOUS, SEEK
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2021 William Hubbard. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package edu.regis.universe_player.player;
|
||||
|
||||
import java.util.EventListener;
|
||||
|
||||
/**
|
||||
* A listener that allows objects to observe when playback commands are triggered.
|
||||
*
|
||||
* @author William Hubbard
|
||||
* @version 0.1
|
||||
*/
|
||||
public interface PlaybackCommandListener extends EventListener
|
||||
{
|
||||
/**
|
||||
* Called when a playback command is issued.
|
||||
*
|
||||
* @param command - The command issued.
|
||||
* @param data - Additional data relevent to the command.
|
||||
*/
|
||||
void onCommand(PlaybackCommand command, Object data);
|
||||
}
|
||||
@@ -6,6 +6,7 @@ package edu.regis.universe_player.player;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FlowLayout;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
@@ -26,12 +27,16 @@ public class PlayerControls extends JPanel
|
||||
private JButton prevButton;
|
||||
private JSlider progress;
|
||||
|
||||
/**
|
||||
* A list of all things interested in knowing when we trigger a command.
|
||||
*/
|
||||
private LinkedList<PlaybackCommandListener> listeners = new LinkedList<>();
|
||||
|
||||
public PlayerControls()
|
||||
{
|
||||
final Dimension BUTTON_SIZE = new Dimension(32, 32);
|
||||
final Dimension ICON_SIZE = new Dimension(16, 16);
|
||||
ImageIcon icon;
|
||||
JButton button;
|
||||
JPanel buttonCont, progressCont;
|
||||
FlowLayout buttonLayout;
|
||||
SpringLayout progressLayout;
|
||||
@@ -43,36 +48,45 @@ public class PlayerControls extends JPanel
|
||||
buttonCont = new JPanel(buttonLayout);
|
||||
this.add(buttonCont);
|
||||
|
||||
button = new JButton();
|
||||
this.prevButton = new JButton();
|
||||
icon = new ImageIcon(this.getClass()
|
||||
.getResource("/gui/icons/skipPrev.png"), "Previous Button");
|
||||
icon.setImage(icon.getImage().getScaledInstance(ICON_SIZE.width, ICON_SIZE.height, 0));
|
||||
button.setIcon(icon);
|
||||
button.setPreferredSize(BUTTON_SIZE);
|
||||
buttonCont.add(button);
|
||||
this.prevButton = button;
|
||||
this.prevButton.setIcon(icon);
|
||||
this.prevButton.setPreferredSize(BUTTON_SIZE);
|
||||
this.prevButton.addActionListener(actionEvent -> {
|
||||
this.triggerCommandListeners(PlaybackCommand.PREVIOUS, null);
|
||||
});
|
||||
buttonCont.add(this.prevButton);
|
||||
|
||||
button = new JButton();
|
||||
this.playButton = new JButton();
|
||||
icon = new ImageIcon(this.getClass().getResource("/gui/icons/play.png"), "Play Button");
|
||||
icon.setImage(icon.getImage().getScaledInstance(ICON_SIZE.width, ICON_SIZE.height, 0));
|
||||
button.setIcon(icon);
|
||||
button.setPreferredSize(BUTTON_SIZE);
|
||||
buttonCont.add(button);
|
||||
this.playButton = button;
|
||||
this.playButton.setIcon(icon);
|
||||
this.playButton.setPreferredSize(BUTTON_SIZE);
|
||||
this.playButton.addActionListener(actionEvent -> {
|
||||
this.triggerCommandListeners(PlaybackCommand.PLAY, null);
|
||||
});
|
||||
buttonCont.add(this.playButton);
|
||||
|
||||
button = new JButton();
|
||||
this.nextButton = new JButton();
|
||||
icon = new ImageIcon(this.getClass().getResource("/gui/icons/skipNext.png"), "Next Button");
|
||||
icon.setImage(icon.getImage().getScaledInstance(ICON_SIZE.width, ICON_SIZE.height, 0));
|
||||
button.setIcon(icon);
|
||||
button.setPreferredSize(BUTTON_SIZE);
|
||||
buttonCont.add(button);
|
||||
this.nextButton = button;
|
||||
this.nextButton.setIcon(icon);
|
||||
this.nextButton.setPreferredSize(BUTTON_SIZE);
|
||||
this.nextButton.addActionListener(actionEvent -> {
|
||||
this.triggerCommandListeners(PlaybackCommand.NEXT, null);
|
||||
});
|
||||
buttonCont.add(this.nextButton);
|
||||
|
||||
progressLayout = new SpringLayout();
|
||||
progressCont = new JPanel(progressLayout);
|
||||
this.add(progressCont);
|
||||
|
||||
this.progress = new JSlider();
|
||||
this.progress.addChangeListener(changeEvent -> {
|
||||
this.triggerCommandListeners(PlaybackCommand.SEEK, this.progress.getValue());
|
||||
});
|
||||
this.add(this.progress);
|
||||
|
||||
layout.putConstraint(SpringLayout.NORTH, buttonCont, 0, SpringLayout.NORTH, this);
|
||||
@@ -83,4 +97,38 @@ public class PlayerControls extends JPanel
|
||||
layout.putConstraint(SpringLayout.SOUTH, this, 5, SpringLayout.SOUTH, this.progress);
|
||||
layout.putConstraint(SpringLayout.EAST, buttonCont, 0, SpringLayout.EAST, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener for playback commands.
|
||||
*
|
||||
* @param listener - The listener to add.
|
||||
*/
|
||||
public void addCommandListener(PlaybackCommandListener listener)
|
||||
{
|
||||
this.listeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a playback listener.
|
||||
*
|
||||
* @param listener - The listener to remove.
|
||||
*/
|
||||
public void removeCommandListener(PlaybackCommandListener listener)
|
||||
{
|
||||
this.listeners.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers all the command listeners.
|
||||
*
|
||||
* @param command - The command to trigger.
|
||||
* @param data - Extra command data.
|
||||
*/
|
||||
protected void triggerCommandListeners(PlaybackCommand command, Object data)
|
||||
{
|
||||
for (PlaybackCommandListener listener : this.listeners)
|
||||
{
|
||||
listener.onCommand(command, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
242
interface/src/main/resources/gui/icons/icon.svg
Normal file
|
After Width: | Height: | Size: 114 KiB |
BIN
interface/src/main/resources/gui/icons/icon128.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
interface/src/main/resources/gui/icons/icon16.png
Normal file
|
After Width: | Height: | Size: 527 B |
BIN
interface/src/main/resources/gui/icons/icon256.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
interface/src/main/resources/gui/icons/icon32.png
Normal file
|
After Width: | Height: | Size: 974 B |
BIN
interface/src/main/resources/gui/icons/icon512.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
interface/src/main/resources/gui/icons/icon64.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |