From 9b20307f3c1edee7c54463de8a7b8765a814cc8b Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 9 Sep 2022 10:39:27 +0100 Subject: [PATCH] extend api to enable lazy setting of AudioPlayer and stream mechanise the forward and back buttons allow slider input to set player position mode the stop/play/pause buttons icons for buttons --- .../org/vaadin/addon/audio/demo/Controls.java | 262 +++++++++++++----- 1 file changed, 185 insertions(+), 77 deletions(-) diff --git a/src/test/java/org/vaadin/addon/audio/demo/Controls.java b/src/test/java/org/vaadin/addon/audio/demo/Controls.java index e53663e..56edfed 100644 --- a/src/test/java/org/vaadin/addon/audio/demo/Controls.java +++ b/src/test/java/org/vaadin/addon/audio/demo/Controls.java @@ -1,5 +1,9 @@ package org.vaadin.addon.audio.demo; +import org.vaadin.addon.audio.server.AudioPlayer; +import org.vaadin.addon.audio.server.state.PlaybackState; +import org.vaadin.addon.audio.server.state.StateChangeCallback; + import com.vaadin.flow.component.HasComponents; import com.vaadin.flow.component.HasSize; import com.vaadin.flow.component.Tag; @@ -8,13 +12,11 @@ import com.vaadin.flow.component.dependency.HtmlImport; import com.vaadin.flow.component.dependency.JsModule; import com.vaadin.flow.component.dependency.Uses; +import com.vaadin.flow.component.icon.VaadinIcon; import com.vaadin.flow.component.notification.Notification; import com.vaadin.flow.component.polymertemplate.Id; import com.vaadin.flow.component.polymertemplate.PolymerTemplate; import com.vaadin.flow.templatemodel.TemplateModel; -import org.vaadin.addon.audio.server.AudioPlayer; -import org.vaadin.addon.audio.server.state.PlaybackState; -import org.vaadin.addon.audio.server.state.StateChangeCallback; /** * A Designer generated component for the player-controls template. @@ -28,7 +30,31 @@ @Uses(SliderWithCaption.class) public class Controls extends PolymerTemplate implements HasSize, HasComponents { + private static final long serialVersionUID = 908526599880999031L; + + /** + * This model binds properties between PlayerControls and player-controls + */ + public interface PlayerControlsModel extends TemplateModel { + String getPlayerStatus(); + + void setPlayerStatus(String playerStatus); + + String getStreamStatus(); + + void setStreamStatus(String streamStatus); + + String getStreamName(); + + void setStreamName(String streamName); + + String getTime(); + + void setTime(String time); + } + private AudioPlayer player; + @Id("back5Button") private Button back5Button; @Id("stopButton") @@ -55,65 +81,58 @@ public class Controls extends PolymerTemplate impl private Button deleteButton; /** - * Creates a new PlayerControls. + * Creates a new PlayerControls with lazy setting of the AudioPlayer suitable for use in the AfterNavigationObserver callback. */ - public Controls(AudioPlayer player, String streamName) { - getModel().setStreamName("Stream " + streamName); + public Controls() { setWidthFull(); + + initButtonsAndSliders(player); + } + + /** + * Lazy setting of the AudioPlayer suitable for use in the AfterNavigationObserver callback, may need to now call @{link initPositionSlider}. + * @param player The AudioPlayer instance + * @param streamName The stream name + */ + public void setPlayer(AudioPlayer player, String streamName) { this.player = player; + getElement().appendChild(player.getElement()); - positionSlider.getSlider().addValueChangeListener(e -> { - if (e.isFromClient()) { - player.setPosition(e.getValue().intValue()); - } - }); + initListeners(player); - back5Button.addClickListener(e -> player.skip(-5000)); - stopButton.addClickListener(e -> player.stop()); - pauseButton.addClickListener(e -> { - if (player.isPaused()) { - player.resume(); - } else { - player.pause(); - } - }); - playButton.addClickListener(e -> { - if (player.isStopped()) { - player.play(); - } else if (player.isPaused()) { - player.resume(); - } else { - // player.play(0); - player.play(); - } - }); - forward5Button.addClickListener(e -> player.skip(5000)); + getModel().setStreamName("Stream " + streamName); + } - volumeSlider.getSlider().addValueChangeListener(e -> { - Notification.show("Volume: " + e.getValue()); - player.setVolume(e.getValue()); - }); - leftGainSlider.getSlider().addValueChangeListener(e -> { - Notification.show("Left gain: " + e.getValue()); - player.setVolumeOnChannel(e.getValue(), 0); - }); - rightGainSlider.getSlider().addValueChangeListener(e -> { - Notification.show("Right gain: " + e.getValue()); - player.setVolumeOnChannel(e.getValue(), 1); - }); - balanceSlider.getSlider().addValueChangeListener(e -> { - Notification.show("Balance: " + e.getValue()); - player.setBalance(e.getValue()); - }); - speedSlider.getSlider().addValueChangeListener(e -> { - Notification.show("Speed: " + e.getValue()); - player.setPlaybackSpeed(e.getValue()); - }); + /** + * Initialise the position slider. + */ + public void initPositionSlider() { + int duration = player.getDuration(); - deleteButton.addClickListener(e -> getElement().removeFromParent()); + positionSlider.getSlider().setMaxValue(duration); + positionSlider.getSlider().setMinValue(0.0); + positionSlider.getSlider().setValue(0.0); + } + /** + * Creates a new PlayerControls all in one hit, no need to call @{link initPositionSlider}. + * @param player The AudioPlayer instance + * @param streamName The stream name + */ + public Controls(AudioPlayer player, String streamName) { + getModel().setStreamName("Stream " + streamName); + setWidthFull(); + this.player = player; + getElement().appendChild(player.getElement()); + + initButtonsAndSliders(player); + initListeners(player); + } + + private void initListeners(AudioPlayer player) { final UI ui = UI.getCurrent(); + player.getStream().addStateChangeListener(newState -> { ui.access(() -> { String text = "Stream status: "; @@ -143,11 +162,17 @@ public Controls(AudioPlayer player, String streamName) { player.addStateChangeListener(new StateChangeCallback() { + { + modeButtons(PlaybackState.STOPPED); + } + @Override - public void playbackStateChanged(final PlaybackState new_state) { + public void playbackStateChanged(final PlaybackState newState) { ui.access(() -> { + modeButtons(newState); + String text = "Player status: "; - switch (new_state) { + switch (newState) { case PAUSED: text += "PAUSED"; break; @@ -165,41 +190,124 @@ public void playbackStateChanged(final PlaybackState new_state) { } @Override - public void playbackPositionChanged(final int new_position_millis) { + public void playbackPositionChanged(final int newPositionMillis) { ui.access(() -> { - // TODO: for proper slider setting, we need to know the position - // in millis and total duration of audio - int duration = player.getDuration(); - int pos = player.getPosition(); - positionSlider.getSlider().setMaxValue(duration); - positionSlider.getSlider().setMinValue(0.0); - // set value without trigger value change event - positionSlider.getSlider().setValue((double) new_position_millis); - getModel().setTime(player.getPositionString() + " / " + player.getDurationString()); + // TODO for proper slider setting, we need to know the position in millis and total duration of audio + updateSlider(newPositionMillis); }); } - }); + private void modeButtons(PlaybackState newState) { + switch (newState) { + case PAUSED: + stopButton.setEnabled(true); + playButton.setEnabled(false); + pauseButton.setEnabled(true); + break; + case PLAYING: + stopButton.setEnabled(true); + playButton.setEnabled(false); + pauseButton.setEnabled(true); + break; + case STOPPED: + stopButton.setEnabled(false); + playButton.setEnabled(true); + pauseButton.setEnabled(false); + break; + default: + break; + } + } + }); } - /** - * This model binds properties between PlayerControls and player-controls - */ - public interface PlayerControlsModel extends TemplateModel { - String getPlayerStatus(); + private void initButtonsAndSliders(AudioPlayer player) { + positionSlider.getSlider().addValueChangeListener(e -> { + if (e.isFromClient()) { + player.setPosition(e.getValue().intValue()); + getModel().setTime(player.getPositionString() + " / " + player.getDurationString()); + } + }); - void setPlayerStatus(String playerStatus); + back5Button.addClickListener(e -> { + //player.skip(-5000); + int pos = Math.max(0, player.getPosition() - 5_000); + player.setPosition(pos); + updateSlider(pos); + }); + back5Button.setIcon(VaadinIcon.FAST_BACKWARD.create()); - String getStreamStatus(); + stopButton.addClickListener(e -> { + player.stop(); + // not sure why this is needed + int pos = 0; + player.setPosition(pos); + updateSlider(pos); + }); + stopButton.setIcon(VaadinIcon.STOP.create()); - void setStreamStatus(String streamStatus); + pauseButton.addClickListener(e -> { + if (player.isPaused()) { + player.resume(); + } else { + player.pause(); + } + }); + pauseButton.setIcon(VaadinIcon.PAUSE.create()); - String getStreamName(); + playButton.addClickListener(e -> { + if (player.isStopped()) { + player.play(); + } else if (player.isPaused()) { + player.resume(); + } else { + // player.play(0); + player.play(); + } + }); + playButton.setIcon(VaadinIcon.PLAY.create()); - void setStreamName(String streamName); + forward5Button.addClickListener(e -> { + //player.skip(5000); + int pos = Math.min(player.getDuration(), player.getPosition() + 5_000); + player.setPosition(pos); + updateSlider(pos); + }); + forward5Button.setIcon(VaadinIcon.FAST_FORWARD.create()); - String getTime(); + volumeSlider.getSlider().addValueChangeListener(e -> { + Notification.show("Volume: " + e.getValue()); + player.setVolume(e.getValue()); + }); + leftGainSlider.getSlider().addValueChangeListener(e -> { + Notification.show("Left gain: " + e.getValue()); + player.setVolumeOnChannel(e.getValue(), 0); + }); + rightGainSlider.getSlider().addValueChangeListener(e -> { + Notification.show("Right gain: " + e.getValue()); + player.setVolumeOnChannel(e.getValue(), 1); + }); + balanceSlider.getSlider().addValueChangeListener(e -> { + Notification.show("Balance: " + e.getValue()); + player.setBalance(e.getValue()); + }); + speedSlider.getSlider().addValueChangeListener(e -> { + Notification.show("Speed: " + e.getValue()); + player.setPlaybackSpeed(e.getValue()); + }); - void setTime(String time); + deleteButton.addClickListener(e -> getElement().removeFromParent()); } + + private void updateSlider(int newPositionMillis) { + int duration = player.getDuration(); + + positionSlider.getSlider().setMaxValue(duration); + positionSlider.getSlider().setMinValue(0.0); + // set value without trigger value change event + positionSlider.getSlider().setValue((double) newPositionMillis); + + getModel().setTime(player.getPositionString() + " / " + player.getDurationString()); + } + }