Skip to content

Commit

Permalink
Merge pull request #3 from woutdp/add-volume-slider
Browse files Browse the repository at this point in the history
Add Volume slider
  • Loading branch information
maxence-charriere authored Sep 17, 2020
2 parents 8bcea58 + 03b2428 commit 623c81f
Show file tree
Hide file tree
Showing 8 changed files with 286 additions and 17 deletions.
1 change: 1 addition & 0 deletions bin/lofimusic/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ func main() {
"https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500&display=swap",
"https://fonts.googleapis.com/css2?family=Roboto&display=swap",
"/web/lofimusic.css",
"/web/range.css",
},

ThemeColor: backgroundColor,
Expand Down
165 changes: 153 additions & 12 deletions bin/lofimusic/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package main

import (
"fmt"
"strconv"

"github.com/maxence-charriere/go-app/v7/pkg/app"
"github.com/maxence-charriere/go-app/v7/pkg/errors"
)

var (
Expand All @@ -14,6 +16,7 @@ type player struct {
app.Compo

Channel channel
State playerState

youtube app.Value
releaseIframe func()
Expand All @@ -24,6 +27,9 @@ type player struct {
}

func (p *player) OnMount(ctx app.Context) {
p.State.load()
p.Update()

if !youtubeAPIReady {
onYouTubeIframeAPIReady := app.FuncOf(p.onYoutubeIframeAPIReady)
p.releaseIframe = onYouTubeIframeAPIReady.Release
Expand All @@ -32,7 +38,6 @@ func (p *player) OnMount(ctx app.Context) {
}

app.Dispatch(p.setupYoutubePlayer)
p.Update()
}

func (p *player) onYoutubeIframeAPIReady(this app.Value, args []app.Value) interface{} {
Expand Down Expand Up @@ -62,8 +67,26 @@ func (p *player) setupYoutubePlayer() {
})
}

func (p *player) OnDismount() {
if p.releaseIframe != nil {
p.releaseIframe()
}

if p.releaseOnPlayerReady != nil {
p.releaseOnPlayerReady()
}

if p.releasePlayerStateChange != nil {
p.releasePlayerStateChange()
}
}

func (p *player) onPlayerReady(this app.Value, args []app.Value) interface{} {
p.youtube.Call("playVideo")
app.Dispatch(func() {
p.setVolume(p.State.Volume)
p.play()
})

return nil
}

Expand Down Expand Up @@ -93,17 +116,31 @@ func (p *player) onPlayerStateChange(this app.Value, args []app.Value) interface
return nil
}

func (p *player) OnDismount() {
if p.releaseIframe != nil {
p.releaseIframe()
}
func (p *player) play() {
p.youtube.Call("playVideo")
}

if p.releaseOnPlayerReady != nil {
p.releaseOnPlayerReady()
func (p *player) setVolume(volume int) {
if volume == 0 {
p.youtube.Call("mute")
} else {
p.youtube.Call("unMute")
p.State.LastNonZeroVolume = volume
}

if p.releasePlayerStateChange != nil {
p.releasePlayerStateChange()
p.youtube.Call("setVolume", volume)
p.State.Volume = volume
p.saveState()
p.Update()

app.Dispatch(func() {
app.Window().GetElementByID("volume-bar").Set("value", volume)
})
}

func (p *player) saveState() {
if err := p.State.save(); err != nil {
app.Log("%s", errors.New("saving player state failed").Wrap(err))
}
}

Expand Down Expand Up @@ -178,6 +215,72 @@ func (p *player) Render() app.UI {
),
),
),

app.Stack().
Class("volume").
Class(hide).
Center().
Content(
app.If(p.State.Volume > 66,
app.Button().
Class("button").
Title("Mute volume.").
OnClick(p.onMute).
Body(
app.Raw(`
<svg style="width:24px;height:24px" viewBox="0 0 24 24">
<path fill="currentColor" d="M14,3.23V5.29C16.89,6.15 19,8.83 19,12C19,15.17 16.89,17.84 14,18.7V20.77C18,19.86 21,16.28 21,12C21,7.72 18,4.14 14,3.23M16.5,12C16.5,10.23 15.5,8.71 14,7.97V16C15.5,15.29 16.5,13.76 16.5,12M3,9V15H7L12,20V4L7,9H3Z" />
</svg>
`),
),
).ElseIf(p.State.Volume > 33,
app.Button().
Class("button").
Title("Mute volume.").
OnClick(p.onMute).
Body(
app.Raw(`
<svg style="width:24px;height:24px" viewBox="0 0 24 24">
<path fill="currentColor" d="M5,9V15H9L14,20V4L9,9M18.5,12C18.5,10.23 17.5,8.71 16,7.97V16C17.5,15.29 18.5,13.76 18.5,12Z" />
</svg>
`),
),
).ElseIf(p.State.Volume > 0,
app.Button().
Class("button").
Title("Mute volume.").
OnClick(p.onMute).
Body(
app.Raw(`
<svg style="width:24px;height:24px" viewBox="0 0 24 24">
<path fill="currentColor" d="M7,9V15H11L16,20V4L11,9H7Z" />
</svg>
`),
),
).Else(
app.Button().
Class("button").
Title("Unmute volume.").
OnClick(p.onUnMute).
Body(
app.Raw(`
<svg style="width:24px;height:24px" viewBox="0 0 24 24">
<path fill="currentColor" d="M3,9H7L12,4V20L7,15H3V9M16.59,12L14,9.41L15.41,8L18,10.59L20.59,8L22,9.41L19.41,12L22,14.59L20.59,16L18,13.41L15.41,16L14,14.59L16.59,12Z" />
</svg>
`),
),
),
app.Input().
ID("volume-bar").
Class("volumebar").
Type("range").
Placeholder("Volume").
Min("0").
Max("100").
Value(strconv.Itoa(p.State.Volume)).
OnChange(p.onVolumeChange).
OnInput(p.onVolumeChange),
),
),
),
)
Expand All @@ -187,8 +290,17 @@ func (p *player) onPlay(ctx app.Context, e app.Event) {
p.play()
}

func (p *player) play() {
p.youtube.Call("playVideo")
func (p *player) onVolumeChange(ctx app.Context, e app.Event) {
volume, _ := strconv.Atoi(ctx.JSSrc.Get("value").String())
p.setVolume(volume)
}

func (p *player) onMute(ctx app.Context, e app.Event) {
p.setVolume(0)
}

func (p *player) onUnMute(ctx app.Context, e app.Event) {
p.setVolume(p.State.LastNonZeroVolume)
}

func (p *player) onShuffle(ctx app.Context, e app.Event) {
Expand All @@ -200,3 +312,32 @@ func (p *player) onShuffle(ctx app.Context, e app.Event) {
}
}
}

type playerState struct {
Volume int
LastNonZeroVolume int
Muted bool
}

func (s *playerState) load() error {
if err := app.LocalStorage.Get("player.state", s); err != nil {
return errors.New("getting player status from local storage failed").
Wrap(err)
}

if *s == (playerState{}) {
s.Volume = 100
s.LastNonZeroVolume = 100
}

return nil
}

func (s *playerState) save() error {
if err := app.LocalStorage.Set("player.state", s); err != nil {
return errors.New("saving player status in local storage failed").
Wrap(err)
}

return nil
}
29 changes: 29 additions & 0 deletions bin/lofimusic/player_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package main

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestPlayerStatus(t *testing.T) {
var p playerState

err := p.load()
require.NoError(t, err)
require.Equal(t, 100, p.LastNonZeroVolume)
require.Equal(t, 100, p.Volume)
require.False(t, p.Muted)

p.Volume = 50
p.Muted = true
err = p.save()
require.NoError(t, err)

p = playerState{}
err = p.load()
require.NoError(t, err)
require.Equal(t, 100, p.LastNonZeroVolume)
require.Equal(t, 50, p.Volume)
require.True(t, p.Muted)
}
Binary file modified docs/web/app.wasm
Binary file not shown.
39 changes: 34 additions & 5 deletions docs/web/lofimusic.css
Original file line number Diff line number Diff line change
Expand Up @@ -199,29 +199,58 @@ a:hover {
margin: auto;
}

.player .controls .button {
.player .controls .button,
.player .volume .button {
background-color: transparent;
border: 1px solid currentColor;
border-radius: 50%;
color: currentColor;
width: 54px;
min-width: 54px;
height: 54px;
cursor: pointer;
outline: none;
transition: 0.2s all;
margin: 24px;
margin: 24px 0;
}

.player .controls .button:hover {
.player .volume {
position: absolute;
right: 30px;
bottom: 24px;
width: auto;
height: 54px;
}

@media (max-width: 480px) {
.player .volume {
display: none;
}
}

.player .volume .button {
width: 36px;
height: 36px;
margin: 0;
border: none;
}

.player .controls .button:hover,
.player .volume .button:hover {
color: white;
transform: scale(1.3);
}

.player .controls .button:active {
.player .controls .button:active,
.player .volume .button:active {
color: white;
transform: scale(0.98);
}

.volumebar {
min-width: 100px;
}

.blur {
filter: blur(1.5rem);
}
Expand All @@ -236,7 +265,7 @@ a:hover {
.detail {
max-width: 75%;
position: absolute;
bottom: 15%;
bottom: 18%;
right: 0;
text-shadow: 1px 1px black;
}
Expand Down
Loading

0 comments on commit 623c81f

Please sign in to comment.