Skip to content

Commit

Permalink
many improvements
Browse files Browse the repository at this point in the history
metro theme
albums view
fixed player not going to next track in queue for ogg
enable autoresizing columns in tables
  • Loading branch information
wakingrufus committed Nov 18, 2021
1 parent 8d9c275 commit 9b61cc9
Show file tree
Hide file tree
Showing 13 changed files with 260 additions and 133 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,7 @@ fun scan(rootDir: File): Library {

sealed class ScanResult {
class TrackSuccess(val track: Track) : ScanResult()
class PlaylistSuccess(val playlist: Playlist) : ScanResult()
class ScanFailure(val error: String) : ScanResult()
class AlbumCover() : ScanResult()
}

fun buildAlbum(track: Track): Album {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,3 @@ fun parse(libDir: File, file: File): Playlist {
)
}
}

fun resolveAbsPath(playlistFile: File, path: String): File {
val rel = playlistFile.parentFile.resolve(path)
val abs = Paths.get(path).toFile()
return if (rel.exists()) {
rel.absoluteFile
} else {
abs
}
}
18 changes: 14 additions & 4 deletions desktop/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
application
kotlin("jvm")
Expand All @@ -16,6 +18,7 @@ dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-javafx:1.4.3")
implementation("com.github.trilarion:java-vorbis-support:1.2.1")
implementation("javax.servlet:javax.servlet-api:4.0.1")
implementation("org.jfxtras:jmetro:11.6.15")

runtimeOnly("org.openjfx:javafx-graphics:${javafx.version}:win")
runtimeOnly("org.openjfx:javafx-graphics:${javafx.version}:linux")
Expand All @@ -38,6 +41,7 @@ jlink {
options.set(listOf("--strip-debug", "--compress", "2", "--no-header-files", "--no-man-pages"))
launcher {
name = "jamm"
jvmArgs = listOf("--add-opens=javafx.controls/javafx.scene.control.skin=jamm.desktop")
}
forceMerge("javafx")
//addExtraDependencies("javafx")
Expand All @@ -51,11 +55,11 @@ jlink {
requires("jdk.jfr")
requires("jdk.unsupported")
provides("javax.sound.sampled.spi.AudioFileReader")
.with ("com.github.trilarion.sound.vorbis.sampled.spi.VorbisAudioFileReader")
.with("com.github.trilarion.sound.vorbis.sampled.spi.VorbisAudioFileReader")
provides("kotlinx.coroutines.internal.MainDispatcherFactory")
.with ("kotlinx.coroutines.javafx.JavaFxDispatcherFactory")
.with("kotlinx.coroutines.javafx.JavaFxDispatcherFactory")
provides("javax.sound.sampled.spi.FormatConversionProvider")
.with ("com.github.trilarion.sound.vorbis.sampled.spi.VorbisFormatConversionProvider")
.with("com.github.trilarion.sound.vorbis.sampled.spi.VorbisFormatConversionProvider")
}
jpackage {
installerOptions = listOf("--description", project.description)
Expand All @@ -67,8 +71,14 @@ jlink {
application {
mainModule.set("jamm.desktop")
mainClass.set("com.github.wakingrufus.jamm.desktop.Main")
applicationDefaultJvmArgs = listOf("--add-opens=javafx.controls/javafx.scene.control.skin=jamm.desktop")
}

tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}

val compileKotlin: KotlinCompile by tasks
compileKotlin.kotlinOptions {
languageVersion = "1.4"
}
2 changes: 2 additions & 0 deletions desktop/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
requires kotlinx.coroutines.core.jvm;
requires kotlinx.coroutines.javafx;
requires java.logging;
requires java.prefs;
requires org.jfxtras.styles.jmetro;

exports com.github.wakingrufus.jamm.desktop;
exports com.github.wakingrufus.javafx;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import com.github.wakingrufus.javafx.*
import javafx.beans.property.ReadOnlyListWrapper
import javafx.beans.property.SimpleObjectProperty
import javafx.collections.FXCollections
import javafx.collections.ListChangeListener
import javafx.event.EventHandler
import javafx.scene.image.Image
import javafx.scene.layout.*
import java.io.ByteArrayInputStream
import java.lang.reflect.InvocationTargetException


class AlbumArtistView(val library: ObservableLibrary, val mediaPlayer: MediaPlayerController) : BorderPane(), Logging {
Expand Down Expand Up @@ -42,7 +44,7 @@ class AlbumArtistView(val library: ObservableLibrary, val mediaPlayer: MediaPlay
this.fitWidth = 256.0
}
}
label(album.name){
label(album.name) {
this.style = "-fx-font-family: 'DejaVu Sans', Arial, sans-serif;"
}
onMouseClicked = EventHandler {
Expand All @@ -52,20 +54,22 @@ class AlbumArtistView(val library: ObservableLibrary, val mediaPlayer: MediaPlay
}
}
}
bottom<VBox> {
tableView(ReadOnlyListWrapper(tracks)) {
column<Track, String>("#") { it.value.trackNumber.toString().toProperty() }
column<Track, String>("Title") { it.value.title.toProperty() }
column<Track, String>("Album") { it.value.album.toProperty() }
column<Track, String>("Album Artist") { it.value.albumArtist.name.toProperty() }
bottom<BorderPane> {
center<StackPane> {
tableView(ReadOnlyListWrapper(tracks)) {
column<Track, String>("#") { it.value.trackNumber.toString().toProperty() }
column<Track, String>("Title") { it.value.title.toProperty() }
column<Track, String>("Album") { it.value.album.toProperty() }
column<Track, String>("Album Artist") { it.value.albumArtist.name.toProperty() }
autoResize()
}
}
}
}
bottom<HBox> {

button("Play") {
action {
mediaPlayer.play(tracks)
bottom<HBox> {
button("Play") {
action {
mediaPlayer.play(tracks)
}
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.github.wakingrufus.jamm.desktop

import com.github.wakingrufus.jamm.common.AlbumKey
import com.github.wakingrufus.jamm.common.Track
import com.github.wakingrufus.javafx.*
import javafx.beans.property.ReadOnlyListWrapper
import javafx.beans.property.SimpleObjectProperty
import javafx.collections.FXCollections
import javafx.scene.layout.BorderPane
import javafx.scene.layout.HBox
import javafx.scene.layout.StackPane

class AlbumsView(val library: ObservableLibrary, val mediaPlayer: MediaPlayerController) : BorderPane(), Logging {
val tracks = FXCollections.observableArrayList<Track>()
val selectedAlbum = SimpleObjectProperty<AlbumKey>().also {
it.onChange {
tracks.clear()
tracks.setAll(library.albumTracks[it]?.sortedBy { it.trackNumber })
}
}

init {
top<HBox> {
button("Play Random Album") {
this.action {
library.albumList.random().also {
mediaPlayer.play(library.albumTracks.get(it)?.sortedBy { it.trackNumber }.orEmpty())
}
}
}
}
left<StackPane> {
listview(library.albumList) {
this.cellFactory = CustomStringCellFactory { it.albumName + " - " + it.albumArtist }
bindSelected(selectedAlbum)
}
}
center<BorderPane> {
center<BorderPane> {
center<StackPane> {
tableView(ReadOnlyListWrapper(tracks)) {
column<Track, String>("#") { it.value.trackNumber.toString().toProperty() }
column<Track, String>("Title") { it.value.title.toProperty() }
column<Track, String>("Album") { it.value.album.toProperty() }
column<Track, String>("Album Artist") { it.value.albumArtist.name.toProperty() }
autoResize()
}
}
bottom<HBox> {
button("Play") {
action {
mediaPlayer.play(tracks)
}
}
}
}
}
}
}
118 changes: 73 additions & 45 deletions desktop/src/main/kotlin/com/github/wakingrufus/jamm/desktop/Jamm.kt
Original file line number Diff line number Diff line change
@@ -1,104 +1,132 @@
package com.github.wakingrufus.jamm.desktop

import com.github.wakingrufus.jamm.common.AlbumKey
import com.github.wakingrufus.jamm.common.Track
import com.github.wakingrufus.javafx.*
import javafx.application.Application
import javafx.beans.property.SimpleStringProperty
import javafx.collections.FXCollections
import javafx.event.EventHandler
import javafx.geometry.Side
import javafx.scene.control.Tab
import javafx.scene.control.TabPane
import javafx.scene.control.TextInputDialog
import javafx.scene.layout.BorderPane
import javafx.scene.layout.HBox
import javafx.scene.layout.VBox
import javafx.stage.Stage
import jfxtras.styles.jmetro.JMetro
import jfxtras.styles.jmetro.JMetroStyleClass
import jfxtras.styles.jmetro.Style
import java.io.File
import java.nio.file.Paths
import java.util.prefs.Preferences


class Jamm : Application(), Logging {

val observableLibrary: ObservableLibrary = ObservableLibrary()
val libraryPath: SimpleStringProperty = SimpleStringProperty(
Preferences.userNodeForPackage(Jamm::class.java)
.get("library.path", File(System.getProperty("user.home")).resolve("Music").path
))

override fun start(primaryStage: Stage) {
logger().info("starting")
var artistsTab: Tab? = null
var playlistsTab: Tab? = null
val playQueue = FXCollections.observableArrayList<Track>()
// var library = Library()
val mediaPlayerView = MediaPlayerView(playQueue)
val mediaPlayerController = object : MediaPlayerController {
override fun play(tracks: List<Track>) {
logger().info("adding ${tracks.size} to queue")
playQueue.clear()
playQueue.setAll(tracks)
mediaPlayerView.play()
}

override fun queue(tracks: List<Track>) {
logger().info("adding ${tracks.size} to queue")
playQueue.addAll(tracks)
mediaPlayerView.play()
}
}


primaryStage.scene = scene<BorderPane>(width = 1920.0, height = 1080.0) {
this.styleClass.add(JMetroStyleClass.BACKGROUND)
top<VBox> {
menuBar {
menu("Settings") {
item("Music Library...") {
this.onAction = EventHandler {
val pref = Preferences.userNodeForPackage(Jamm::class.java)
val current = pref.get(
"library.path",
File(System.getProperty("user.home")).resolve("Music").path
)
val dialog: TextInputDialog = TextInputDialog(current).apply {
this.title = "Library Path"
}
dialog.contentText = "This is a sample dialog"
val path = dialog.showAndWait()
path.ifPresent {
libraryPath.set(it)
scan()
pref.put("library.path", it)
}
}
}
}
}
}
center<TabPane> {
playlistsTab = Tab("Playlists")
artistsTab = Tab("Album Artists")
this.tabs.add(playlistsTab)
this.tabs.add(artistsTab)
tab("Playlists") {
PlaylistView(observableLibrary)
}
tab("Album Artists") {
AlbumArtistView(observableLibrary, mediaPlayerController)
}
tab("Albums") {
AlbumsView(observableLibrary, mediaPlayerController)
}
this.side = Side.LEFT
}
val playNextQueue: () -> Unit = {

}
right<BorderPane> {
top<BorderPane> {
this.center = MediaPlayerView(playQueue)
this.center = mediaPlayerView
}
center<VBox> {
label("Play Queue")
add<VBox> {
this.spacing = 10.0
this.children.bind(playQueue) { track ->
VBox().apply {
style = "-fx-border-color: white; -fx-border-style: solid; -fx-border-width: 1px;"
label(track.title) { style = "-fx-text-alignment: center;" }
label(track.albumArtist.name) {
style = "-fx-font-weight: bold; -fx-text-alignment: center;"
}
label(track.album) { style = "-fx-font-style: italic; -fx-text-alignment: center;" }
}
}
}
}
}
bottom<HBox> {

buttonBar {
button("Load") {
action {
val libraryDir = File(System.getProperty("user.home"))
.resolve("Music")
if (!libraryDir.exists()) {
logger().error("Music directory not found")
} else {
// GlobalScope.launch(Dispatchers.IO) {
// library = scan(libraryDir)
// library.warnings.forEach {
// logger().warn(it)
// }
// library.errors.forEach {
// logger().error(it)
// }
observableLibrary.scan(libraryDir)
// }
// logger().info("tracks: ${observableLibrary.trackCount}")
logger().info("album artists: ${observableLibrary.albumArtistsAlbums.keys.size}")
artistsTab?.content = AlbumArtistView(observableLibrary, mediaPlayerController)
playlistsTab?.content = PlaylistView(observableLibrary)
this.children.add(HBox().apply {
label(track.albumArtist.name) {
style = "-fx-font-weight: bold; -fx-text-alignment: center;"
}
label(" - ")
label(track.album) { style = "-fx-font-style: italic; -fx-text-alignment: center;" }
})

}
}
}
}
}
}
val jMetro = JMetro(Style.DARK)
jMetro.scene = primaryStage.scene
primaryStage.show()
scan()
}

fun scan() {
val f = Paths.get(libraryPath.value).toFile()
if (!f.exists()) {
logger().error("Music directory not found")
} else {
observableLibrary.scan(f)
}
}
}

This file was deleted.

Loading

0 comments on commit 9b61cc9

Please sign in to comment.