live_beats/lib/live_beats_web/live/profile_live.ex

284 lines
8.7 KiB
Elixir
Raw Normal View History

2021-11-22 14:57:24 +00:00
defmodule LiveBeatsWeb.ProfileLive do
2021-10-29 16:12:23 +00:00
use LiveBeatsWeb, :live_view
2021-11-12 03:42:10 +00:00
alias LiveBeats.{Accounts, MediaLibrary, MP3Stat}
2021-11-16 16:58:22 +00:00
alias LiveBeatsWeb.{LayoutComponent, Presence}
2021-11-22 14:57:24 +00:00
alias LiveBeatsWeb.ProfileLive.{SongRowComponent, UploadFormComponent}
2021-10-29 16:12:23 +00:00
def render(assigns) do
~H"""
<.title_bar>
2021-11-16 16:58:22 +00:00
<div>
<div class="block">
<%= @profile.tagline %> <%= if @owns_profile? do %>(you)<% end %>
</div>
<.link href={@profile.external_homepage_url} _target="blank" class="block text-sm text-gray-600">
2021-11-16 20:54:40 +00:00
<.icon name={:code}/> <span class=""><%= url_text(@profile.external_homepage_url) %></span>
2021-11-16 16:58:22 +00:00
</.link>
</div>
2021-10-29 16:12:23 +00:00
<:actions>
2021-11-12 03:42:10 +00:00
<%= if @active_profile_id == @profile.user_id do %>
<.button primary
phx-click={JS.push("switch_profile", value: %{user_id: nil}, target: "#player", loading: "#player")}
>
<.icon name={:stop}/><span class="ml-2">Stop Listening</span>
</.button>
<% else %>
<.button primary
phx-click={JS.push("switch_profile", value: %{user_id: @profile.user_id}, target: "#player", loading: "#player")}
>
<.icon name={:play}/><span class="ml-2">Listen</span>
</.button>
<% end %>
<%= if @owns_profile? do %>
2021-12-14 20:19:03 +00:00
<.button id="upload-btn" primary patch={profile_path(@current_user, :new)}>
2021-11-12 03:42:10 +00:00
<.icon name={:upload}/><span class="ml-2">Upload Songs</span>
</.button>
<% end %>
2021-10-29 16:12:23 +00:00
</:actions>
</.title_bar>
2021-11-16 16:58:22 +00:00
<Presence.listening_now presences={@presences}>
<:title let={user}><%= user.username %></:title>
</Presence.listening_now>
2021-12-16 02:51:09 +00:00
<div id="dialogs" phx-update="append">
<%= for song <- if(@owns_profile?, do: @songs, else: []), id = "delete-modal-#{song.id}" do %>
<.modal
id={id}
on_confirm={JS.push("delete", value: %{id: song.id}) |> hide_modal(id) |> hide("#song-#{song.id}")}
>
Are you sure you want to delete "<%= song.title %>"?
<:cancel>Cancel</:cancel>
<:confirm>Delete</:confirm>
</.modal>
<% end %>
</div>
2021-10-29 16:12:23 +00:00
2021-11-05 00:49:19 +00:00
<.live_table
2021-12-16 02:51:09 +00:00
id="songs"
2021-11-05 19:57:33 +00:00
module={SongRowComponent}
2021-11-05 00:49:19 +00:00
rows={@songs}
row_id={fn song -> "song-#{song.id}" end}
2021-11-30 15:03:08 +00:00
owns_profile?={@owns_profile?}
2021-11-05 00:49:19 +00:00
>
<:col let={%{song: song}} label="Title"><%= song.title %></:col>
<:col let={%{song: song}} label="Artist"><%= song.artist %></:col>
<:col let={%{song: song}} label="Attribution" class="max-w-5xl break-words text-gray-600 font-light"><%= song.attribution %></:col>
2021-11-05 00:49:19 +00:00
<:col let={%{song: song}} label="Duration"><%= MP3Stat.to_mmss(song.duration) %></:col>
<:col let={%{song: song}} label="" if={@owns_profile?}>
2021-11-05 00:49:19 +00:00
<.link phx-click={show_modal("delete-modal-#{song.id}")} class="inline-flex items-center px-3 py-2 text-sm leading-4 font-medium">
2021-11-05 01:20:31 +00:00
<.icon name={:trash} class="-ml-0.5 mr-2 h-4 w-4"/>
2021-11-05 00:49:19 +00:00
Delete
</.link>
2021-10-29 16:12:23 +00:00
</:col>
2021-11-05 00:49:19 +00:00
</.live_table>
2021-10-29 16:12:23 +00:00
"""
end
2021-11-12 03:42:10 +00:00
def mount(%{"profile_username" => profile_username}, _session, socket) do
2021-11-05 19:57:33 +00:00
%{current_user: current_user} = socket.assigns
2021-11-12 03:42:10 +00:00
profile =
Accounts.get_user_by!(username: profile_username)
|> MediaLibrary.get_profile!()
2021-11-05 00:49:19 +00:00
if connected?(socket) do
MediaLibrary.subscribe_to_profile(profile)
2021-11-12 03:42:10 +00:00
Accounts.subscribe(current_user.id)
LiveBeatsWeb.Presence.subscribe(profile)
2021-12-09 05:33:29 +00:00
Phoenix.Presence.Client.track(topic(profile.user_id),
current_user.id,
2021-12-09 05:33:29 +00:00
%{}
)
2021-11-05 00:49:19 +00:00
end
2021-11-05 12:57:48 +00:00
2021-11-12 03:42:10 +00:00
active_song_id =
if song = MediaLibrary.get_current_active_song(profile) do
2021-12-16 03:03:18 +00:00
SongRowComponent.send_status(song.id, song.status)
2021-11-05 19:57:33 +00:00
song.id
end
2021-11-12 03:42:10 +00:00
socket =
socket
|> assign(
active_song_id: active_song_id,
active_profile_id: current_user.active_profile_user_id,
profile: profile,
owns_profile?: MediaLibrary.owns_profile?(current_user, profile)
)
|> list_songs()
2021-11-16 16:58:22 +00:00
|> assign_presences()
2021-11-12 03:42:10 +00:00
{:ok, socket, temporary_assigns: [songs: []]}
2021-10-29 16:12:23 +00:00
end
def handle_params(params, _url, socket) do
2021-11-18 16:50:15 +00:00
LayoutComponent.hide_modal()
{:noreply, socket |> apply_action(socket.assigns.live_action, params)}
2021-11-05 00:49:19 +00:00
end
2021-11-05 19:57:33 +00:00
def handle_event("play_or_pause", %{"id" => id}, socket) do
song = MediaLibrary.get_song!(id)
2021-11-12 03:42:10 +00:00
can_playback? = MediaLibrary.can_control_playback?(socket.assigns.current_user, song)
cond do
can_playback? and socket.assigns.active_song_id == id and MediaLibrary.playing?(song) ->
MediaLibrary.pause_song(song)
can_playback? ->
MediaLibrary.play_song(id)
true ->
:noop
2021-11-05 19:57:33 +00:00
end
2021-11-05 00:49:19 +00:00
{:noreply, socket}
end
def handle_event("delete", %{"id" => id}, socket) do
song = MediaLibrary.get_song!(id)
2021-11-12 11:42:07 +00:00
2021-11-12 03:42:10 +00:00
if song.user_id == socket.assigns.current_user.id do
2021-12-14 20:29:07 +00:00
:ok = MediaLibrary.delete_song(song)
2021-11-12 03:42:10 +00:00
end
2021-11-12 11:42:07 +00:00
2021-11-05 00:49:19 +00:00
{:noreply, socket}
end
def handle_info({LiveBeats.PresenceClient, %{user_joined: user_id}}, socket) do
new_user = Accounts.get_user!(user_id)
updated_presences =
if new_user in socket.assigns.presences do
socket.assigns.presences
else
[new_user | socket.assigns.presences]
end
{:noreply, assign(socket, :presences, updated_presences)}
end
def handle_info({LiveBeats.PresenceClient, %{user_left: user_id}}, socket) do
updated_presences = socket.assigns.presences
|> Enum.reject(fn user -> user.id == String.to_integer(user_id) end)
{:noreply, assign(socket, :presences, updated_presences)}
end
def handle_info({Accounts, %Accounts.Events.ActiveProfileChanged{} = event}, socket) do
{:noreply, assign(socket, active_profile_id: event.new_profile_user_id)}
2021-11-12 03:42:10 +00:00
end
def handle_info({MediaLibrary, %MediaLibrary.Events.PublicProfileUpdated{} = update}, socket) do
{:noreply,
socket
|> assign(profile: update.profile)
|> push_patch(to: profile_path(update.profile))}
end
def handle_info({MediaLibrary, %MediaLibrary.Events.Play{song: song}}, socket) do
2021-11-05 00:49:19 +00:00
{:noreply, play_song(socket, song)}
end
def handle_info({MediaLibrary, %MediaLibrary.Events.Pause{song: song}}, socket) do
2021-11-05 00:49:19 +00:00
{:noreply, pause_song(socket, song.id)}
end
2021-12-16 02:51:09 +00:00
def handle_info({MediaLibrary, %MediaLibrary.Events.SongsImported{songs: songs}}, socket) do
{:noreply, update(socket, :songs, &(&1 ++ songs))}
end
def handle_info({MediaLibrary, _}, socket), do: {:noreply, socket}
def handle_info({Accounts, _}, socket), do: {:noreply, socket}
2021-11-05 19:57:33 +00:00
defp stop_song(socket, song_id) do
2021-12-16 03:03:18 +00:00
SongRowComponent.send_status(song_id, :stopped)
2021-11-05 19:57:33 +00:00
2021-11-12 03:42:10 +00:00
if socket.assigns.active_song_id == song_id do
assign(socket, :active_song_id, nil)
2021-11-05 19:57:33 +00:00
else
socket
end
end
2021-11-05 00:49:19 +00:00
defp pause_song(socket, song_id) do
2021-12-16 03:03:18 +00:00
SongRowComponent.send_status(song_id, :paused)
2021-11-05 00:49:19 +00:00
socket
end
2021-11-05 19:57:33 +00:00
defp play_song(socket, %MediaLibrary.Song{} = song) do
2021-11-12 03:42:10 +00:00
%{active_song_id: active_song_id} = socket.assigns
2021-11-05 00:49:19 +00:00
2021-11-05 19:57:33 +00:00
cond do
2021-11-12 03:42:10 +00:00
active_song_id == song.id ->
2021-12-16 03:03:18 +00:00
SongRowComponent.send_status(song.id, :playing)
2021-11-05 19:57:33 +00:00
socket
2021-11-12 03:42:10 +00:00
active_song_id ->
2021-12-16 03:03:18 +00:00
SongRowComponent.send_status(song.id, :playing)
2021-11-05 19:57:33 +00:00
socket
2021-11-12 03:42:10 +00:00
|> stop_song(active_song_id)
|> assign(active_song_id: song.id)
2021-11-05 19:57:33 +00:00
true ->
2021-12-16 03:03:18 +00:00
SongRowComponent.send_status(song.id, :playing)
2021-11-12 03:42:10 +00:00
assign(socket, active_song_id: song.id)
2021-11-05 00:49:19 +00:00
end
end
2021-11-18 16:50:15 +00:00
defp apply_action(socket, :new, _params) do
if socket.assigns.owns_profile? do
socket
|> assign(:page_title, "Add Songs")
|> assign(:song, %MediaLibrary.Song{})
|> show_upload_modal()
2021-11-05 00:49:19 +00:00
else
2021-11-18 16:50:15 +00:00
socket
|> put_flash(:error, "You can't do that")
|> redirect(to: profile_path(socket.assigns.current_user))
2021-11-05 00:49:19 +00:00
end
2021-10-29 16:12:23 +00:00
end
2021-12-14 15:35:51 +00:00
defp apply_action(socket, :show, _params) do
2021-10-29 16:12:23 +00:00
socket
|> assign(:page_title, "Listing Songs")
|> assign(:song, nil)
end
2021-11-18 16:50:15 +00:00
defp show_upload_modal(socket) do
LayoutComponent.show_modal(UploadFormComponent, %{
id: :new,
confirm: {"Save", type: "submit", form: "song-form"},
2021-11-23 14:34:34 +00:00
patch: profile_path(socket.assigns.current_user),
2021-11-18 16:50:15 +00:00
song: socket.assigns.song,
title: socket.assigns.page_title,
current_user: socket.assigns.current_user
})
socket
end
2021-11-12 03:42:10 +00:00
defp list_songs(socket) do
assign(socket, songs: MediaLibrary.list_profile_songs(socket.assigns.profile, 50))
2021-10-29 16:12:23 +00:00
end
2021-11-16 16:58:22 +00:00
defp assign_presences(socket) do
presences = socket.assigns.profile.user_id
|> topic()
|> LiveBeats.PresenceClient.list()
2021-12-14 16:23:19 +00:00
|> Enum.map(fn {_key, meta} -> meta.user end)
assign(socket, presences: presences)
2021-11-16 16:58:22 +00:00
end
defp url_text(nil), do: ""
2021-11-18 16:50:15 +00:00
2021-11-16 16:58:22 +00:00
defp url_text(url_str) do
uri = URI.parse(url_str)
uri.host <> uri.path
end
defp topic(user_id) when is_integer(user_id), do: "active_profile:#{user_id}"
2021-10-29 16:12:23 +00:00
end