diff --git a/.gitignore b/.gitignore index 70ee542..ed20917 100644 --- a/.gitignore +++ b/.gitignore @@ -68,3 +68,5 @@ buildNumber.properties .mvn/timing.properties # Created by .ignore support plugin (hsz.mobi) + +settings.cfg \ No newline at end of file diff --git a/src/main/java/musicplayer/LibraryConfigGUI.java b/src/main/java/musicplayer/LibraryConfigGUI.java new file mode 100644 index 0000000..453c8f8 --- /dev/null +++ b/src/main/java/musicplayer/LibraryConfigGUI.java @@ -0,0 +1,71 @@ +package musicplayer; + +import musicplayer.swingmodels.LibraryListModel; + +import javax.swing.*; +import java.awt.BorderLayout; +import java.io.File; +import java.util.List; + +public class LibraryConfigGUI { + private JList listLibraryFolders; + private LibraryListModel listModel = new LibraryListModel(); + private JPanel mainPanel; + + public LibraryConfigGUI(){ + JFrame frame = new JFrame(); + frame.setContentPane(createUI()); + frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + frame.pack(); + frame.setVisible(true); + updateLibraryListContents(); + } + + private JPanel createUI() { + mainPanel = new JPanel(); + mainPanel.setLayout(new BorderLayout(0, 0)); + listLibraryFolders = new JList(); + listLibraryFolders.setModel(listModel); + mainPanel.add(listLibraryFolders, BorderLayout.CENTER); + final JPanel panel2 = new JPanel(); + panel2.setLayout(new BoxLayout(panel2, BoxLayout.PAGE_AXIS)); + mainPanel.add(panel2, BorderLayout.EAST); + JButton addNewButton = new JButton(); + addNewButton.setText("Add New"); + addNewButton.addActionListener(e -> addNew()); + panel2.add(addNewButton); + JButton removeButton = new JButton(); + removeButton.setText("Remove"); + removeButton.addActionListener(e -> removeSelected()); + panel2.add(removeButton); + return mainPanel; + } + + private void updateLibraryListContents(){ + listModel.setFolderList(LibraryUtils.getLibraryDirectories()); + } + + private void saveLibraryList(){ + List folders = listModel.currentFolderList(); + LibraryUtils.saveLibrarySettings(folders); + } + + private void addNew(){ + JFileChooser fileChooser = new JFileChooser(); + fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + fileChooser.setAcceptAllFileFilterUsed(false); + if (fileChooser.showOpenDialog(mainPanel) == JFileChooser.APPROVE_OPTION) { + File targetFile = fileChooser.getSelectedFile(); + if(!listModel.contains(targetFile)) { + listModel.addFolder(targetFile); + saveLibraryList(); + } + } + } + + public void removeSelected(){ + List files = listLibraryFolders.getSelectedValuesList(); + files.forEach(listModel::removeFile); + saveLibraryList(); + } +} diff --git a/src/main/java/musicplayer/LibraryUtils.java b/src/main/java/musicplayer/LibraryUtils.java index 5028959..fe3a3d1 100644 --- a/src/main/java/musicplayer/LibraryUtils.java +++ b/src/main/java/musicplayer/LibraryUtils.java @@ -10,15 +10,52 @@ import org.jaudiotagger.audio.exceptions.ReadOnlyFileException; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.TagException; -import java.io.IOException; +import java.io.*; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Arrays; import java.util.List; import java.util.Optional; +import java.util.Properties; +import java.util.stream.Collectors; public final class LibraryUtils { - static final String musicFileExtensionRegex = ".*\\.(mp3|mp4|flac)"; + static final String musicFileExtensionRegex = ".*\\.(mp3|mp4|flac|ogg)"; + static final Properties librarySettings = new Properties(); + static final String settingsFilename = "settings.cfg"; + static final File propertiesFile = new File(settingsFilename); + private static List libraryDirectories; + static final String foldersKey = "libraryFolders"; + + public static List getLibraryDirectories(){ + loadLibrarySettings(); // Make sure libraryDirectories matches the stored version. + return libraryDirectories; + } + + public static void loadLibrarySettings(){ + try(FileInputStream inputStream = new FileInputStream(propertiesFile)){ + librarySettings.load(inputStream); + if(librarySettings.containsKey(foldersKey)){ + libraryDirectories = Arrays.asList(librarySettings.getProperty(foldersKey).split(",")) + .stream().map(File::new).filter(File::exists).collect(Collectors.toList()); + } + } catch (IOException ex) { + propertiesFile.getParentFile().mkdirs(); + try { + propertiesFile.createNewFile(); + } catch (IOException ignored) {} + } + } + + public static void saveLibrarySettings(List folderList){ + librarySettings.setProperty(foldersKey, folderList.stream().map(File::toString).collect(Collectors.joining(","))); + try(FileWriter fileWriter = new FileWriter(settingsFilename)){ + librarySettings.store(fileWriter, ""); + } catch (IOException e) { + e.printStackTrace(); + } + } public static void processSongsWithCallback(List rootDirectory, LibraryCallbackInterface callbackInterface){ Thread thread = new Thread(() -> { diff --git a/src/main/java/musicplayer/PlayerGUI.java b/src/main/java/musicplayer/PlayerGUI.java index 63a47c9..76c13e7 100644 --- a/src/main/java/musicplayer/PlayerGUI.java +++ b/src/main/java/musicplayer/PlayerGUI.java @@ -6,6 +6,7 @@ import musicplayer.db.DatabaseManager; import musicplayer.db.Gateway; import musicplayer.model.Album; import musicplayer.model.Song; +import musicplayer.swingmodels.PlaylistTableModel; import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; @@ -15,8 +16,11 @@ import java.awt.*; import java.awt.event.ItemEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.io.File; +import java.nio.file.Path; import java.util.*; import java.util.List; +import java.util.stream.Collectors; public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterface { public JPanel mainPanel; @@ -195,10 +199,20 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf populateThread.start(); } + private void updateLibrary(){ + DefaultTreeModel model = new DefaultTreeModel(new DefaultMutableTreeNode()); + DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) model.getRoot(); + DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("Updating Library..."); + addNodeToTreeModel(model, parentNode, newNode); + libraryView.setModel(model); + List dirs = LibraryUtils.getLibraryDirectories().stream().map(File::toPath).collect(Collectors.toList()); + LibraryUtils.processSongsWithCallback(dirs, this); + } + @Override public void libraryUpdated(boolean successful) { if (successful) - libraryDisplayVariants.get(libraryDisplayType.getSelectedItem().toString()).run(); + refreshLibrary(); } private Map createDisplayVariantMap() { @@ -342,7 +356,11 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf menuItem = new JMenuItem("Update Library"); menuItem.setToolTipText("Reindex and refresh library."); + menuItem.addActionListener(e -> updateLibrary()); + tools.add(menuItem); + menuItem = new JMenuItem("Library Settings"); + menuItem.addActionListener(e -> new LibraryConfigGUI()); tools.add(menuItem); // Add everything to the menu bar itself diff --git a/src/main/java/musicplayer/swingmodels/LibraryListModel.java b/src/main/java/musicplayer/swingmodels/LibraryListModel.java new file mode 100644 index 0000000..4a0c78e --- /dev/null +++ b/src/main/java/musicplayer/swingmodels/LibraryListModel.java @@ -0,0 +1,49 @@ +package musicplayer.swingmodels; + +import javax.swing.*; +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class LibraryListModel extends AbstractListModel { + + private List libraryFolders = new ArrayList<>(); + + @Override + public int getSize() { + return libraryFolders.size(); + } + + @Override + public Object getElementAt(int index) { + return libraryFolders.get(index); + } + + public void addFolder(File folder){ + if(folder.exists() && folder.isDirectory()) { + libraryFolders.add(folder); + fireContentsChanged(this, 0, libraryFolders.size() == 0 ? 0 : libraryFolders.size() - 1); + } + } + + public List currentFolderList(){ + return new ArrayList<>(libraryFolders); // Copy? Don't want modification via here. + } + + public boolean contains(File file){ + return libraryFolders.contains(file); + } + + public void setFolderList(List folderList){ + if(folderList != null && folderList.size() > 0) + libraryFolders = new ArrayList<>(folderList); + else + libraryFolders = new ArrayList<>(); + fireContentsChanged(this, 0, libraryFolders.size() == 0 ? 0 : libraryFolders.size() - 1); + } + + public void removeFile(File file){ + libraryFolders.remove(file); + fireContentsChanged(this, 0, libraryFolders.size() == 0 ? 0 : libraryFolders.size() - 1); + } +} diff --git a/src/main/java/musicplayer/PlaylistTableModel.java b/src/main/java/musicplayer/swingmodels/PlaylistTableModel.java similarity index 98% rename from src/main/java/musicplayer/PlaylistTableModel.java rename to src/main/java/musicplayer/swingmodels/PlaylistTableModel.java index a3a52ee..11809be 100644 --- a/src/main/java/musicplayer/PlaylistTableModel.java +++ b/src/main/java/musicplayer/swingmodels/PlaylistTableModel.java @@ -1,4 +1,4 @@ -package musicplayer; +package musicplayer.swingmodels; import musicplayer.model.Song;