defmodule LivebookWeb.Output.ImageInputComponent do use LivebookWeb, :live_component @impl true def mount(socket) do {:ok, socket |> assign(value: nil, value: nil, image_url: nil) |> allow_upload(:file, accept: :any, max_entries: 1, max_file_size: 100_000_000_000, progress: &handle_progress/3, auto_upload: true )} end @impl true def update(assigns, socket) do {value, assigns} = Map.pop!(assigns, :value) socket = assign(socket, assigns) socket = cond do value == socket.assigns.value -> socket value == nil -> assign(socket, value: value, image_url: nil) true -> assign(socket, value: value, image_url: image_url(socket.assigns.input_id)) end {:ok, socket} end defp image_url(input_id) do # For the client-side image preview, we serve the original binary # value from a separate endpoint. To do that, we encode information # in a token and then the controller fetches input value from the # LV. This is especially important for client-specific inputs in # forms. token = LivebookWeb.SessionHelpers.generate_input_token(self(), input_id) ~p"/public/sessions/image-input/#{token}" end @impl true def render(assigns) do ~H"""
Drag an image file
<.menu id={"#{@id}-camera-select-menu"} position={:bottom_left}> <:toggle> <.button color="gray" data-btn-open-camera> <.remix_icon icon="camera-line" /> Open camera
<.menu_item>
<.button color="gray" class="hidden" data-btn-capture-camera> <.remix_icon icon="camera-line" /> Take photo <.button color="gray" class="hidden" data-btn-cancel> <.remix_icon icon="close-circle-line" /> Cancel <.button color="gray" data-btn-upload> <.remix_icon icon="upload-2-line" /> Upload
<.file_entry name="Image" entry={entry} on_clear={JS.push("clear_file", target: @myself)} />
""" end @impl true def handle_event("validate", %{}, socket) do {:noreply, socket} end def handle_event("clear_file", %{"ref" => ref}, socket) do {:noreply, cancel_upload(socket, :file, ref)} end defp handle_progress(:file, entry, socket) do if entry.done? do file_ref = consume_uploaded_entry(socket, entry, fn %{path: path} -> {:ok, file_ref} = LivebookWeb.SessionHelpers.register_input_file( socket.assigns.session_pid, path, socket.assigns.input_id, socket.assigns.local, socket.assigns.client_id ) {:ok, file_ref} end) %{"height" => height, "width" => width} = entry.client_meta value = %{ file_ref: file_ref, height: height, width: width, format: socket.assigns.format } send_update(LivebookWeb.Output.InputComponent, id: socket.assigns.input_component_id, event: :change, value: value ) end {:noreply, socket} end end