Implemented seek functionality.
This commit is contained in:
parent
587324d5ef
commit
bc53f088cf
@ -2,6 +2,7 @@ package musicplayer;
|
|||||||
|
|
||||||
import musicplayer.callbacks.PlayerCallbackInterface;
|
import musicplayer.callbacks.PlayerCallbackInterface;
|
||||||
import musicplayer.model.Song;
|
import musicplayer.model.Song;
|
||||||
|
import org.gstreamer.ClockTime;
|
||||||
import org.gstreamer.ElementFactory;
|
import org.gstreamer.ElementFactory;
|
||||||
import org.gstreamer.Gst;
|
import org.gstreamer.Gst;
|
||||||
import org.gstreamer.State;
|
import org.gstreamer.State;
|
||||||
@ -115,7 +116,7 @@ public class Player {
|
|||||||
* @return Current playback position in seconds.
|
* @return Current playback position in seconds.
|
||||||
*/
|
*/
|
||||||
public int currentSongPosition(){
|
public int currentSongPosition(){
|
||||||
return playBin.isPlaying() || playBin.getState() == State.PAUSED ? (int) (playBin.getClock().getTime().toSeconds() - playBin.getBaseTime().toSeconds()) : 0;
|
return playBin.isPlaying() || playBin.getState() == State.PAUSED ? (int) playBin.queryPosition().toSeconds() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -134,6 +135,14 @@ public class Player {
|
|||||||
return playBin.getVolumePercent();
|
return playBin.getVolumePercent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Seek to a position in the song.
|
||||||
|
* @param position Position (in seconds) to seek to.
|
||||||
|
*/
|
||||||
|
public void seek(int position){
|
||||||
|
playBin.seek(ClockTime.fromSeconds(position));
|
||||||
|
}
|
||||||
|
|
||||||
private class InternalThread implements Runnable {
|
private class InternalThread implements Runnable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -16,10 +16,12 @@ import java.awt.*;
|
|||||||
import java.awt.event.ItemEvent;
|
import java.awt.event.ItemEvent;
|
||||||
import java.awt.event.MouseAdapter;
|
import java.awt.event.MouseAdapter;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.awt.event.MouseListener;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterface {
|
public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterface {
|
||||||
@ -32,6 +34,7 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf
|
|||||||
private PlaylistTableModel playlistTableModel = new PlaylistTableModel(new ArrayList<>());
|
private PlaylistTableModel playlistTableModel = new PlaylistTableModel(new ArrayList<>());
|
||||||
private static DefaultMutableTreeNode updatingNode = new DefaultMutableTreeNode();
|
private static DefaultMutableTreeNode updatingNode = new DefaultMutableTreeNode();
|
||||||
private boolean libraryUpdating = false;
|
private boolean libraryUpdating = false;
|
||||||
|
private AtomicBoolean seeking = new AtomicBoolean(false);
|
||||||
|
|
||||||
private Map<String, Runnable> libraryDisplayVariants = createDisplayVariantMap();
|
private Map<String, Runnable> libraryDisplayVariants = createDisplayVariantMap();
|
||||||
|
|
||||||
@ -69,7 +72,10 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf
|
|||||||
* @param position New seekBar value.
|
* @param position New seekBar value.
|
||||||
*/
|
*/
|
||||||
public void setSeekBarPosition(int position) {
|
public void setSeekBarPosition(int position) {
|
||||||
SwingUtilities.invokeLater(() -> seekBar.setValue(position));
|
SwingUtilities.invokeLater(() -> {
|
||||||
|
if(!seeking.get())
|
||||||
|
seekBar.setValue(position);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -153,6 +159,9 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf
|
|||||||
player.playSong(playlistTableModel.nextSong(player.getCurrentSong()));
|
player.playSong(playlistTableModel.nextSong(player.getCurrentSong()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the previous song in the playlist and dispatch it to the Player to be played.
|
||||||
|
*/
|
||||||
public void playPreviousSong() {
|
public void playPreviousSong() {
|
||||||
SwingUtilities.invokeLater(() -> seekBar.setValue(0));
|
SwingUtilities.invokeLater(() -> seekBar.setValue(0));
|
||||||
player.playSong(playlistTableModel.previous(player.getCurrentSong()));
|
player.playSong(playlistTableModel.previous(player.getCurrentSong()));
|
||||||
@ -222,6 +231,9 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf
|
|||||||
((DefaultTreeModel)libraryView.getModel()).nodeChanged(updatingNode);
|
((DefaultTreeModel)libraryView.getModel()).nodeChanged(updatingNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Map of display types for the library paired code to populate the library with data in the correct format.
|
||||||
|
*/
|
||||||
private Map<String, Runnable> createDisplayVariantMap() {
|
private Map<String, Runnable> createDisplayVariantMap() {
|
||||||
Map<String, Runnable> value = new HashMap<>();
|
Map<String, Runnable> value = new HashMap<>();
|
||||||
value.put("Song", () -> Gateway.listAllSongs().ifPresent(this::populateLibrary));
|
value.put("Song", () -> Gateway.listAllSongs().ifPresent(this::populateLibrary));
|
||||||
@ -272,11 +284,15 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf
|
|||||||
seekBar = new JSlider();
|
seekBar = new JSlider();
|
||||||
seekBar.setMinorTickSpacing(1);
|
seekBar.setMinorTickSpacing(1);
|
||||||
seekBar.setValue(0);
|
seekBar.setValue(0);
|
||||||
|
seekBar.addMouseListener(new SeekbarMouseListener());
|
||||||
controlPane.add(seekBar, BorderLayout.NORTH);
|
controlPane.add(seekBar, BorderLayout.NORTH);
|
||||||
controlPane.add(createControlButtons(), BorderLayout.SOUTH);
|
controlPane.add(createControlButtons(), BorderLayout.SOUTH);
|
||||||
mainPanel.add(createMenuBar(), BorderLayout.NORTH);
|
mainPanel.add(createMenuBar(), BorderLayout.NORTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Area containing the library.
|
||||||
|
*/
|
||||||
private JTree createLibraryArea() {
|
private JTree createLibraryArea() {
|
||||||
libraryView.setRootVisible(false);
|
libraryView.setRootVisible(false);
|
||||||
libraryView.setToggleClickCount(1);
|
libraryView.setToggleClickCount(1);
|
||||||
@ -285,6 +301,9 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf
|
|||||||
return libraryView;
|
return libraryView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Area containing the playlist.
|
||||||
|
*/
|
||||||
private JScrollPane createPlaylistArea() {
|
private JScrollPane createPlaylistArea() {
|
||||||
JScrollPane playlistScroll = new JScrollPane();
|
JScrollPane playlistScroll = new JScrollPane();
|
||||||
playList.setRowSelectionAllowed(true);
|
playList.setRowSelectionAllowed(true);
|
||||||
@ -308,6 +327,9 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf
|
|||||||
return playlistScroll;
|
return playlistScroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Playback control buttons (play, stop, etc.)
|
||||||
|
*/
|
||||||
private JToolBar createControlButtons() {
|
private JToolBar createControlButtons() {
|
||||||
JToolBar toolBar = new JToolBar();
|
JToolBar toolBar = new JToolBar();
|
||||||
toolBar.setFloatable(false);
|
toolBar.setFloatable(false);
|
||||||
@ -345,6 +367,9 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf
|
|||||||
return toolBar;
|
return toolBar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Volume controls.
|
||||||
|
*/
|
||||||
private JPanel createVolumeControls() {
|
private JPanel createVolumeControls() {
|
||||||
JPanel panel = new JPanel();
|
JPanel panel = new JPanel();
|
||||||
panel.setLayout(new FlowLayout());
|
panel.setLayout(new FlowLayout());
|
||||||
@ -410,4 +435,29 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MouseListener implementation for the seekbar.
|
||||||
|
* Using this instead of the ChangeListener so that the polling for the current song position
|
||||||
|
* doesn't repeatedly fire seek events.
|
||||||
|
*/
|
||||||
|
private class SeekbarMouseListener implements MouseListener {
|
||||||
|
@Override
|
||||||
|
public void mouseClicked(MouseEvent e) { seeking.set(true); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mousePressed(MouseEvent e) { seeking.set(true); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseReleased(MouseEvent e) {
|
||||||
|
player.seek(seekBar.getValue());
|
||||||
|
seeking.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseEntered(MouseEvent e) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseExited(MouseEvent e) {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,15 @@ package musicplayer.callbacks;
|
|||||||
|
|
||||||
public interface LibraryCallbackInterface {
|
public interface LibraryCallbackInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this after performing library updates so the front-end knows that updating has completed.
|
||||||
|
* @param successful Was the update function successful.
|
||||||
|
*/
|
||||||
void libraryUpdated(boolean successful);
|
void libraryUpdated(boolean successful);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the current display with the file/folder currently being parsed.
|
||||||
|
* @param name Data about the file/folder to be shown to the user.
|
||||||
|
*/
|
||||||
void currentlyUpdating(String name);
|
void currentlyUpdating(String name);
|
||||||
}
|
}
|
||||||
|
@ -6,14 +6,32 @@ import java.util.Optional;
|
|||||||
|
|
||||||
public interface PlayerCallbackInterface {
|
public interface PlayerCallbackInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the song currently shown to the user as playing.
|
||||||
|
* @param playingSong Song currently playing.
|
||||||
|
*/
|
||||||
void setSongHighlighting(Song playingSong);
|
void setSongHighlighting(Song playingSong);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the seekbar position.
|
||||||
|
* @param seconds Position to set the seekbar to.
|
||||||
|
*/
|
||||||
void setSeekBarDuration(int seconds);
|
void setSeekBarDuration(int seconds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a song from the current playlist.
|
||||||
|
* @param invalidSong Song to remove.
|
||||||
|
*/
|
||||||
void removeInvalidSong(Song invalidSong);
|
void removeInvalidSong(Song invalidSong);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Playback has ceased.
|
||||||
|
*/
|
||||||
void playerStopped();
|
void playerStopped();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start playing the next song.
|
||||||
|
*/
|
||||||
void playNextSong();
|
void playNextSong();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user