From 97daf734038f6e53d3d00323b8ac50fc465a771c Mon Sep 17 00:00:00 2001 From: Evgeny Varnakov Date: Mon, 31 Jul 2023 11:43:42 +0300 Subject: [PATCH] solution: day 3 - task 1 --- Gemfile | 2 ++ Gemfile.lock | 3 ++ app/controllers/live_stations_controller.rb | 13 ++++++++ app/javascript/application.js | 3 ++ .../controllers/player_controller.js | 30 +++++++++++++++++-- app/views/player/_player.html.erb | 5 +++- config/importmap.rb | 1 + config/routes.rb | 2 ++ 8 files changed, 56 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index e1be030..121b61c 100644 --- a/Gemfile +++ b/Gemfile @@ -67,3 +67,5 @@ gem "bcrypt", "~> 3.1.7" group :development do eval_gemfile "gemfiles/rubocop.gemfile" end + +gem "turbo_power", "~> 0.3.1" diff --git a/Gemfile.lock b/Gemfile.lock index 1420b9c..30f1409 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -315,6 +315,8 @@ GEM turbo_boost-streams (0.0.8) rails (>= 6.1) turbo-rails (>= 1.1) + turbo_power (0.3.1) + turbo-rails (~> 1.3) tzinfo (2.0.6) concurrent-ruby (~> 1.0) unicode-display_width (2.4.2) @@ -362,6 +364,7 @@ DEPENDENCIES tailwindcss-rails turbo-rails turbo_boost-commands + turbo_power (~> 0.3.1) web-console RUBY VERSION diff --git a/app/controllers/live_stations_controller.rb b/app/controllers/live_stations_controller.rb index ecaca98..317f5a8 100644 --- a/app/controllers/live_stations_controller.rb +++ b/app/controllers/live_stations_controller.rb @@ -79,6 +79,19 @@ def play render turbo_stream: turbo_stream.update("player", partial: "player/player", locals: {station:, track: station.current_track}) end + def pause + station = current_user.live_station + station.update!(live: false) + Turbo::StreamsChannel.broadcast_stream_to station, content: turbo_stream.set_attribute(".player", "data-player-state-value", "paused") + end + + + def resume + station = current_user.live_station + station.update!(live: true) + Turbo::StreamsChannel.broadcast_stream_to station, content: turbo_stream.set_attribute(".player", "data-player-state-value", "playing") + end + private def station_params diff --git a/app/javascript/application.js b/app/javascript/application.js index 4fdc39a..5fa4cd6 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -6,6 +6,9 @@ import "controllers"; import { createCable } from "@anycable/web"; import { start } from "@anycable/turbo-stream"; +import TurboPower from 'turbo_power' +TurboPower.initialize(Turbo.StreamActions) + const logLevel = document.documentElement.classList.contains("debug") ? "debug" : "error"; diff --git a/app/javascript/controllers/player_controller.js b/app/javascript/controllers/player_controller.js index 6d8e4ff..7d009c3 100644 --- a/app/javascript/controllers/player_controller.js +++ b/app/javascript/controllers/player_controller.js @@ -14,7 +14,7 @@ function secondsToDuration(num) { export default class extends Controller { static targets = ["progress", "time"]; static outlets = ["track"]; - static values = { duration: Number, track: String, nextTrackUrl: String }; + static values = { duration: Number, track: String, nextTrackUrl: String, state: String, pauseUrl: String , resumeUrl: String }; static classes = ["playing"]; initialize() { @@ -36,6 +36,18 @@ export default class extends Controller { } } + stateValueChanged() { + if (this.pauseUrlValue) { + return; + } + + if (this.playing && this.stateValue === "paused") { + this.pause(false); + } else if (!this.playing && this.stateValue === "playing") { + this.play(false); + } + } + trackOutletConnected(outlet, el) { outlet.togglePlayingIfMatch(this.trackValue); } @@ -46,7 +58,7 @@ export default class extends Controller { this.setupAudioListeners(); } - if (this.playing) { + if (this.playing || this.stateValue === "playing") { this.play(); } } @@ -61,12 +73,16 @@ export default class extends Controller { this.element.classList.add(this.playingClass); this.audio.play(); this.playing = true; + + if (this.resumeUrlValue) this.broadcastStateChange(this.resumeUrlValue); } pause() { this.element.classList.remove(this.playingClass); this.audio.pause(); this.playing = false; + + if (this.pauseUrlValue) this.broadcastStateChange(this.pauseUrlValue); } seek(e) { @@ -99,6 +115,16 @@ export default class extends Controller { } } + async broadcastStateChange(url) { + const request = new FetchRequest("POST", url, { + responseKind: "turbo-stream", + }); + const response = await request.perform(); + if (!response.ok) { + console.error("Failed to broadcast pause/resume", response.status); + } + } + updateProgress(currentTime) { const percent = (currentTime * 100) / this.durationValue; diff --git a/app/views/player/_player.html.erb b/app/views/player/_player.html.erb index 6d47d6a..b999aab 100644 --- a/app/views/player/_player.html.erb +++ b/app/views/player/_player.html.erb @@ -4,7 +4,10 @@ data-player-duration-value="<%= track&.duration %>" data-player-track-value="<%= track&.id %>" data-player-playing-class="player-playing" + data-player-state-value="playing" data-player-next-track-url-value="<%= live ? play_next_live_station_path : (!station && play_next_track_path(track))%>" + data-player-pause-url-value="<%= pause_live_station_path if live %>" + data-player-resume-url-value="<%= resume_live_station_path if live %>" data-player-track-outlet=".track" > <% if track %> @@ -12,7 +15,7 @@
<% end %> - <% unless station %> + <% if !station || live %>
<%= render "icons/play" %> diff --git a/config/importmap.rb b/config/importmap.rb index ca7fc2a..d76f3a4 100644 --- a/config/importmap.rb +++ b/config/importmap.rb @@ -16,3 +16,4 @@ pin "nanoevents", to: "https://ga.jspm.io/npm:nanoevents@7.0.1/index.js" pin "@anycable/web", to: "https://ga.jspm.io/npm:@anycable/web@0.7.0/index.js" pin "@turbo-boost/commands", to: "https://ga.jspm.io/npm:@turbo-boost/commands@0.0.11/app/assets/builds/@turbo-boost/commands.js" +pin "turbo_power", to: "https://ga.jspm.io/npm:turbo_power@0.3.1/dist/turbo_power.js" diff --git a/config/routes.rb b/config/routes.rb index 5ae29ea..dc63706 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -14,6 +14,8 @@ patch :start, on: :member patch :stop, on: :member post :play_next, on: :member + post :pause, on: :member + post :resume, on: :member resources :tracks, only: [:create, :destroy], module: :live_station do post :play, on: :member