mirror of
https://codeberg.org/JasterV/intisync.ex.git
synced 2026-04-26 18:10:07 +00:00
develop remote page and test it
This commit is contained in:
parent
adba07c752
commit
643ec77f0b
4 changed files with 257 additions and 0 deletions
109
lib/intisync_web/live/remote_live.ex
Normal file
109
lib/intisync_web/live/remote_live.ex
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
defmodule IntisyncWeb.RemoteLive do
|
||||
alias Intisync.SessionPubSub
|
||||
use IntisyncWeb, :live_view
|
||||
|
||||
alias IntisyncWeb.LiveViewMonitor
|
||||
alias Intisync.SessionsSupervisor
|
||||
alias Intisync.SessionServer
|
||||
|
||||
def mount(_params, _session, socket) do
|
||||
{:ok, assign(socket, :devices, %{})}
|
||||
end
|
||||
|
||||
def handle_params(%{"id" => session_id}, _uri, socket) do
|
||||
if connected?(socket),
|
||||
do: handle_connected(session_id, socket),
|
||||
else: {:noreply, socket}
|
||||
end
|
||||
|
||||
def unmount(_reason, {session_server_pid}) do
|
||||
SessionServer.remote_disconnected(session_server_pid)
|
||||
end
|
||||
|
||||
defp handle_connected(session_id, socket) do
|
||||
case lookup_session_server(session_id) do
|
||||
{:error, :not_found} ->
|
||||
socket = socket |> put_flash(:error, "This session expired!") |> redirect(to: "/")
|
||||
{:noreply, socket}
|
||||
|
||||
{:error, :unauthorized} ->
|
||||
socket = socket |> put_flash(:error, "Unauthorized") |> redirect(to: "/")
|
||||
{:noreply, socket}
|
||||
|
||||
{:ok, pid} ->
|
||||
enable_subscriptions(session_id)
|
||||
LiveViewMonitor.monitor(self(), __MODULE__, {pid})
|
||||
SessionServer.remote_connected(pid)
|
||||
devices = SessionServer.get_devices(pid)
|
||||
|
||||
socket =
|
||||
socket
|
||||
|> assign(:session_id, session_id)
|
||||
|> assign(:session_server_pid, pid)
|
||||
|> assign(:devices, devices)
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
end
|
||||
|
||||
defp lookup_session_server(session_id) do
|
||||
case SessionsSupervisor.whereis(session_id) do
|
||||
nil ->
|
||||
{:error, :not_found}
|
||||
|
||||
pid ->
|
||||
if SessionServer.is_full?(pid) do
|
||||
{:error, :unauthorized}
|
||||
else
|
||||
{:ok, pid}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp enable_subscriptions(session_id) do
|
||||
SessionPubSub.subscribe!(session_id, "session", "closed")
|
||||
SessionPubSub.subscribe!(session_id, "devices", "connected")
|
||||
SessionPubSub.subscribe!(session_id, "devices", "disconnected")
|
||||
SessionPubSub.subscribe!(session_id, "devices", "empty")
|
||||
end
|
||||
|
||||
##############
|
||||
# Hub events #
|
||||
##############
|
||||
def handle_info(%{topic: "session:closed:" <> _session_id}, socket) do
|
||||
socket = socket |> put_flash(:info, "The host terminated the session") |> redirect(to: "/")
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_info(%{topic: "devices:empty:" <> _session_id}, socket) do
|
||||
{:noreply, assign(socket, :devices, %{})}
|
||||
end
|
||||
|
||||
def handle_info(%{topic: "devices:connected:" <> _session_id}, socket) do
|
||||
devices = SessionServer.get_devices(socket.assigns.session_server_pid)
|
||||
{:noreply, assign(socket, :devices, devices)}
|
||||
end
|
||||
|
||||
def handle_info(%{topic: "devices:disconnected:" <> _session_id}, socket) do
|
||||
devices = SessionServer.get_devices(socket.assigns.session_server_pid)
|
||||
{:noreply, assign(socket, :devices, devices)}
|
||||
end
|
||||
|
||||
##############
|
||||
# UI events #
|
||||
##############
|
||||
|
||||
def handle_event(
|
||||
"vibrate_device:" <> index,
|
||||
%{"vibration" => vibration},
|
||||
socket
|
||||
) do
|
||||
vibration = String.to_integer(vibration)
|
||||
index = String.to_integer(index)
|
||||
|
||||
:ok = SessionServer.vibrate_device(socket.assigns.session_server_pid, index, vibration)
|
||||
devices = SessionServer.get_devices(socket.assigns.session_server_pid)
|
||||
|
||||
{:noreply, assign(socket, :devices, devices)}
|
||||
end
|
||||
end
|
||||
30
lib/intisync_web/live/remote_live.html.heex
Normal file
30
lib/intisync_web/live/remote_live.html.heex
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<header class="mb-10">
|
||||
<h1 class="text-5xl mb-4 font-bold text-indigo-500">
|
||||
IntiSync Controller
|
||||
</h1>
|
||||
<p class="text-2xl mt-2 text-zinc-600 font-semibold">
|
||||
You are controlling a remote device, be careful!
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<section>
|
||||
<h2 class="text-3xl mb-4 font-bold text-indigo-500">
|
||||
Connected devices
|
||||
</h2>
|
||||
|
||||
<p :if={Enum.empty?(@devices)} class="text-lg text-amber-500 font-semibold">
|
||||
<.icon name="hero-signal-slash" class="mr-1.5" /> No devices connected yet
|
||||
</p>
|
||||
|
||||
<div class="flex flex-col gap-4 mt-2">
|
||||
<%= for {index, device} <- @devices do %>
|
||||
<form phx-change={"vibrate_device:#{index}"}>
|
||||
<IntisyncWeb.DeviceCardComponent.view
|
||||
id={"device-#{index}"}
|
||||
device={device}
|
||||
disabled={false}
|
||||
/>
|
||||
</form>
|
||||
<% end %>
|
||||
</div>
|
||||
</section>
|
||||
|
|
@ -18,6 +18,7 @@ defmodule IntisyncWeb.Router do
|
|||
pipe_through :browser
|
||||
|
||||
live "/", LobbyLive
|
||||
live "/sessions/:id/remote", RemoteLive
|
||||
|
||||
live_session :hub, root_layout: {IntisyncWeb.Layouts, :hub_root} do
|
||||
live "/sessions/:id", HubLive
|
||||
|
|
|
|||
117
test/intisync_web/live/remote_live_test.exs
Normal file
117
test/intisync_web/live/remote_live_test.exs
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
defmodule IntisyncWeb.RemoteLiveTest do
|
||||
use IntisyncWeb.ConnCase
|
||||
import Phoenix.LiveViewTest
|
||||
|
||||
defp generate_session_id(_) do
|
||||
%{session_id: Intisync.Puid.generate()}
|
||||
end
|
||||
|
||||
setup [:generate_session_id]
|
||||
|
||||
test "A remote can join a fresh new session", %{conn: conn, session_id: session_id} do
|
||||
{:ok, _hub_view, _html} = live(conn, ~p"/sessions/#{session_id}")
|
||||
{:ok, _view, _html} = live(conn, ~p"/sessions/#{session_id}/remote")
|
||||
end
|
||||
|
||||
test "A remote can't join a session that already has a controller", %{
|
||||
conn: conn,
|
||||
session_id: session_id
|
||||
} do
|
||||
{:ok, _hub_view, _html} = live(conn, ~p"/sessions/#{session_id}")
|
||||
{:ok, _view, _html} = live(conn, ~p"/sessions/#{session_id}/remote")
|
||||
|
||||
assert {:error, {:redirect, %{to: "/"}}} = live(conn, ~p"/sessions/#{session_id}/remote")
|
||||
end
|
||||
|
||||
test "A remote can't join a non existing session", %{conn: conn, session_id: session_id} do
|
||||
assert {:error, {:redirect, %{to: "/"}}} = live(conn, ~p"/sessions/#{session_id}/remote")
|
||||
end
|
||||
|
||||
test "Renders a device card when a device connected event is received", %{
|
||||
conn: conn,
|
||||
session_id: session_id
|
||||
} do
|
||||
{:ok, hub_view, _html} = live(conn, ~p"/sessions/#{session_id}")
|
||||
{:ok, view, _html} = live(conn, ~p"/sessions/#{session_id}/remote")
|
||||
|
||||
render_click(hub_view, "connected", %{})
|
||||
|
||||
render_click(hub_view, "device_connected", %{index: 0, name: "My dummy device"})
|
||||
|
||||
assert view |> element("#device-0") |> render() =~ "My dummy device"
|
||||
end
|
||||
|
||||
test "Removes a device card when a device disconnected event is received", %{
|
||||
conn: conn,
|
||||
session_id: session_id
|
||||
} do
|
||||
{:ok, hub_view, _html} = live(conn, ~p"/sessions/#{session_id}")
|
||||
{:ok, view, _html} = live(conn, ~p"/sessions/#{session_id}/remote")
|
||||
|
||||
render_click(hub_view, "connected", %{})
|
||||
|
||||
render_click(hub_view, "device_connected", %{index: 0, name: "My dummy device"})
|
||||
|
||||
assert view |> element("#device-0") |> has_element?()
|
||||
|
||||
render_click(hub_view, "device_disconnected", %{index: 0})
|
||||
|
||||
refute view |> element("#device-0") |> has_element?()
|
||||
end
|
||||
|
||||
test "Updates device vibration when sliding the device vibration bar", %{
|
||||
conn: conn,
|
||||
session_id: session_id
|
||||
} do
|
||||
{:ok, hub_view, _html} = live(conn, ~p"/sessions/#{session_id}")
|
||||
{:ok, view, _html} = live(conn, ~p"/sessions/#{session_id}/remote")
|
||||
|
||||
render_click(hub_view, "connected", %{})
|
||||
|
||||
render_click(hub_view, "device_connected", %{index: 0, name: "My dummy device"})
|
||||
|
||||
assert view |> element("#device-0") |> has_element?()
|
||||
|
||||
render_change(view, "vibrate_device:0", %{"vibration" => "45"})
|
||||
|
||||
assert view |> element("#device-0") |> render() =~ "value=\"45\""
|
||||
end
|
||||
|
||||
test "When a devices empty event is received, all devices are removed from the view", %{
|
||||
conn: conn,
|
||||
session_id: session_id
|
||||
} do
|
||||
{:ok, hub_view, _html} = live(conn, ~p"/sessions/#{session_id}")
|
||||
{:ok, view, _html} = live(conn, ~p"/sessions/#{session_id}/remote")
|
||||
|
||||
render_click(hub_view, "connected", %{})
|
||||
|
||||
render_click(hub_view, "device_connected", %{index: 0, name: "My dummy device"})
|
||||
render_click(hub_view, "device_connected", %{index: 1, name: "My dummy device"})
|
||||
|
||||
assert view |> element("#device-0") |> has_element?()
|
||||
assert view |> element("#device-1") |> has_element?()
|
||||
|
||||
render_click(hub_view, "disconnected", %{})
|
||||
|
||||
refute view |> element("#device-0") |> has_element?()
|
||||
refute view |> element("#device-1") |> has_element?()
|
||||
end
|
||||
|
||||
test "Shows all the connected devices when joining a session with already connected devices", %{
|
||||
conn: conn,
|
||||
session_id: session_id
|
||||
} do
|
||||
{:ok, hub_view, _html} = live(conn, ~p"/sessions/#{session_id}")
|
||||
|
||||
render_click(hub_view, "connected", %{})
|
||||
|
||||
render_click(hub_view, "device_connected", %{index: 0, name: "My dummy device"})
|
||||
render_click(hub_view, "device_connected", %{index: 1, name: "My dummy device"})
|
||||
|
||||
{:ok, view, _html} = live(conn, ~p"/sessions/#{session_id}/remote")
|
||||
|
||||
assert view |> element("#device-0") |> has_element?()
|
||||
assert view |> element("#device-1") |> has_element?()
|
||||
end
|
||||
end
|
||||
Loading…
Reference in a new issue