diff --git a/assets/css/app.css b/assets/css/app.css
index a7209a8..8eb942b 100644
--- a/assets/css/app.css
+++ b/assets/css/app.css
@@ -11,9 +11,7 @@
.fade-out-scale {
animation: 0.2s ease-out 0s normal forwards 1 fade-out-scale-keys;
}
-.slide-in-right {
- animation: slide-in-right-keys 0.2s forwards;
-}
+
.fade-in {
animation: 0.2s ease-out 0s normal forwards 1 fade-in-keys;
}
@@ -75,9 +73,7 @@
display: none;
}
.invalid-feedback {
- color: #a94442;
- display: block;
- margin: -1rem 0 2rem;
+ display: inline-block;
}
/* LiveView specific classes for your customization */
diff --git a/assets/js/app.js b/assets/js/app.js
index 4b098f3..2185384 100644
--- a/assets/js/app.js
+++ b/assets/js/app.js
@@ -27,9 +27,11 @@ Hooks.AudioPlayer = {
this.duration = this.el.querySelector("#player-duration")
this.progress = this.el.querySelector("#player-progress")
let enableAudio = () => {
- document.removeEventListener("click", enableAudio)
- this.player.play().catch(error => null)
- this.player.pause()
+ if(this.player.src){
+ document.removeEventListener("click", enableAudio)
+ this.player.play().catch(error => null)
+ this.player.pause()
+ }
}
document.addEventListener("click", enableAudio)
this.el.addEventListener("js:listen_now", () => this.play({sync: true}))
diff --git a/lib/live_beats/media_library.ex b/lib/live_beats/media_library.ex
index 8cfbf8e..6c00368 100644
--- a/lib/live_beats/media_library.ex
+++ b/lib/live_beats/media_library.ex
@@ -187,7 +187,15 @@ defmodule LiveBeats.MediaLibrary do
Repo.delete(song)
end
- def change_song(%Song{} = song, attrs \\ %{}) do
- Song.changeset(song, attrs)
+ def change_song(song_or_changeset, attrs \\ %{}) do
+ song_or_changeset
+ |> recycle_changeset()
+ |> Song.changeset(attrs)
end
+
+ defp recycle_changeset(%Ecto.Changeset{} = changeset) do
+ Map.merge(changeset, %{action: nil, errors: [], valid?: true})
+ end
+
+ defp recycle_changeset(%{} = other), do: other
end
diff --git a/lib/live_beats_web/live/song_live/song_entry.ex b/lib/live_beats_web/live/song_live/song_entry_component.ex
similarity index 81%
rename from lib/live_beats_web/live/song_live/song_entry.ex
rename to lib/live_beats_web/live/song_live/song_entry_component.ex
index a737f89..9dd5ce7 100644
--- a/lib/live_beats_web/live/song_live/song_entry.ex
+++ b/lib/live_beats_web/live/song_live/song_entry_component.ex
@@ -1,8 +1,12 @@
-defmodule LiveBeatsWeb.SongLive.SongEntry do
+defmodule LiveBeatsWeb.SongLive.SongEntryComponent do
use LiveBeatsWeb, :live_component
alias LiveBeats.MP3Stat
+ def send_progress(%Phoenix.LiveView.UploadEntry{} = entry) do
+ send_update(__MODULE__, id: entry.ref, progress: entry.progress)
+ end
+
def render(assigns) do
~H"""
@@ -19,13 +23,15 @@ defmodule LiveBeatsWeb.SongLive.SongEntry do
- <%= error_tag(@errors, :title, "songs[#{@ref}][title]") %>
- <%= error_tag(@errors, :artist, "songs[#{@ref}][artist]") %>
+
+
+ <.error input_name={"songs[#{@ref}][title]"} field={:title} errors={@errors}/>
+ <.error input_name={"songs[#{@ref}][artist]"} field={:artist} errors={@errors}/>
diff --git a/lib/live_beats_web/live/song_live/upload_form_component.ex b/lib/live_beats_web/live/song_live/upload_form_component.ex
index 442da3c..4e10097 100644
--- a/lib/live_beats_web/live/song_live/upload_form_component.ex
+++ b/lib/live_beats_web/live/song_live/upload_form_component.ex
@@ -2,7 +2,7 @@ defmodule LiveBeatsWeb.SongLive.UploadFormComponent do
use LiveBeatsWeb, :live_component
alias LiveBeats.{MediaLibrary, MP3Stat}
- alias LiveBeatsWeb.SongLive.SongEntry
+ alias LiveBeatsWeb.SongLive.SongEntryComponent
@max_songs 10
@@ -12,8 +12,8 @@ defmodule LiveBeatsWeb.SongLive.UploadFormComponent do
{:ok, %MP3Stat{} = stat} ->
{:ok, put_stats(socket, entry_ref, stat)}
- _ ->
- {:ok, cancel_upload(socket, :mp3, entry_ref)}
+ {:error, _} ->
+ {:ok, cancel_changeset_upload(socket, entry_ref, :not_accepted)}
end
end
@@ -54,7 +54,7 @@ defmodule LiveBeatsWeb.SongLive.UploadFormComponent do
|> push_redirect(to: Routes.song_index_path(socket, :index))}
{:error, _reason} ->
- {:noreply, put_flash(socket, :error, "There were problems uploading your songs")}
+ {:noreply, socket}
end
end
@@ -69,7 +69,6 @@ defmodule LiveBeatsWeb.SongLive.UploadFormComponent do
new_changeset =
acc
|> get_changeset(ref)
- |> Ecto.Changeset.apply_changes()
|> MediaLibrary.change_song(song_params)
|> Map.put(:action, action)
@@ -103,8 +102,12 @@ defmodule LiveBeatsWeb.SongLive.UploadFormComponent do
update(socket, :changesets, &Map.put(&1, entry_ref, changeset))
end
+ defp drop_changeset(socket, entry_ref) do
+ update(socket, :changesets, &Map.delete(&1, entry_ref))
+ end
+
defp handle_progress(:mp3, entry, socket) do
- send_update(SongEntry, id: entry.ref, progress: entry.progress)
+ SongEntryComponent.send_progress(entry)
if entry.done? do
async_calculate_duration(socket, entry)
@@ -144,21 +147,32 @@ defmodule LiveBeatsWeb.SongLive.UploadFormComponent do
defp drop_invalid_uploads(socket) do
%{uploads: uploads} = socket.assigns
- {new_socket, error_messages, _index} =
- Enum.reduce(uploads.mp3.entries, {socket, [], 0}, fn entry, {socket, msgs, i} ->
- if i >= @max_songs do
- {cancel_upload(socket, :mp3, entry.ref), [{entry.client_name, :dropped} | msgs], i + 1}
- else
- case upload_errors(uploads.mp3, entry) do
- [first | _] ->
- {cancel_upload(socket, :mp3, entry.ref), [{entry.client_name, first} | msgs], i + 1}
+ Enum.reduce(Enum.with_index(uploads.mp3.entries), socket, fn {entry, i}, socket ->
+ if i >= @max_songs do
+ cancel_changeset_upload(socket, entry.ref, :dropped)
+ else
+ case upload_errors(uploads.mp3, entry) do
+ [first | _] ->
+ cancel_changeset_upload(socket, entry.ref, first)
- [] ->
- {socket, msgs, i + 1}
- end
+ [] ->
+ socket
end
- end)
+ end
+ end)
+ end
- assign(new_socket, error_messages: error_messages)
+ defp cancel_changeset_upload(socket, entry_ref, reason) do
+ entry = get_entry!(socket, entry_ref)
+
+ socket
+ |> cancel_upload(:mp3, entry.ref)
+ |> drop_changeset(entry.ref)
+ |> update(:error_messages, &(&1 ++ [{entry.client_name, reason}]))
+ end
+
+ defp get_entry!(socket, entry_ref) do
+ Enum.find(socket.assigns.uploads.mp3.entries, fn entry -> entry.ref == entry_ref end) ||
+ raise "no entry found for ref #{inspect(entry_ref)}"
end
end
diff --git a/lib/live_beats_web/live/song_live/upload_form_component.html.heex b/lib/live_beats_web/live/song_live/upload_form_component.html.heex
index 7ddaf3d..d0de3ab 100644
--- a/lib/live_beats_web/live/song_live/upload_form_component.html.heex
+++ b/lib/live_beats_web/live/song_live/upload_form_component.html.heex
@@ -10,57 +10,57 @@
phx-submit="save">
-
- <%= for {ref, changeset} <- @changesets do %>
- <.live_component id={ref} module={SongEntry} changeset={changeset} />
- <% end %>
+
+ <%= for {ref, changeset} <- @changesets do %>
+ <.live_component id={ref} module={SongEntryComponent} changeset={changeset} />
+ <% end %>
-
-
-
- <%= if Enum.any?(@error_messages) do %>
-
-
-
+
+
+
+ <%= if Enum.any?(@error_messages) do %>
+
+
+
<.icon name={:x_circle} class="h-5 w-5 text-red-400"/>
-
-
-
- Oops!
-
-
-
- <%= for {client_name, error} <- @error_messages do %>
- - <%= client_name %>: <.file_error kind={error} />
- <% end %>
-
-
-
-
-
- <% end %>
+
+
+
+ Oops!
+
+
+
+ <%= for {client_name, kind} <- @error_messages do %>
+ - <%= client_name %>: <.file_error kind={kind} />
+ <% end %>
+
+
+
+
+
+ <% end %>
-
-
-
-
-
-
or drag and drop
-
-
- MP3s up to 20MB
-
-
-
-
-
-
-
+
+
+
+
+
+
or drag and drop
+
+
+ MP3s up to 20MB
+
+
+
+
+
+
+
diff --git a/lib/live_beats_web/views/error_helpers.ex b/lib/live_beats_web/views/error_helpers.ex
index 4d6904e..e30f968 100644
--- a/lib/live_beats_web/views/error_helpers.ex
+++ b/lib/live_beats_web/views/error_helpers.ex
@@ -4,25 +4,38 @@ defmodule LiveBeatsWeb.ErrorHelpers do
"""
use Phoenix.HTML
+ import Phoenix.LiveView
+ import Phoenix.LiveView.Helpers
@doc """
Generates tag for inlined form input errors.
"""
def error_tag(form, field) do
- error_tag(form.errors, field, input_name(form, field))
+ error(%{errors: form.errors, field: field, input_name: input_name(form, field)})
end
- def error_tag(errors, field, input_name) do
- Enum.map(Keyword.get_values(errors, field), fn error ->
- content_tag(:div, translate_error(error),
- class: "invalid-feedback mt-0 text-sm text-red-600 text-right",
- phx_feedback_for: input_name
- )
- end)
+ def error(%{errors: errors, field: field} = assigns) do
+ assigns =
+ assigns
+ |> assign(:error_values, Keyword.get_values(errors, field))
+ |> assign_new(:class, fn -> "" end)
+
+ ~H"""
+ <%= for error <- @error_values do %>
+
+ <%= translate_error(error) %>
+
+ <% end %>
+
+ <%= if Enum.empty?(@error_values) do %>
+
+ <% end %>
+ """
end
-
-
@doc """
Translates an error message using gettext.
"""