Files
archived-teslamate/lib/teslamate_web/live/car_live/summary.ex
2022-01-22 13:00:50 +01:00

158 lines
4.9 KiB
Elixir

defmodule TeslaMateWeb.CarLive.Summary do
use TeslaMateWeb, :live_view
import TeslaMateWeb.Gettext
alias TeslaMate.Vehicles.Vehicle.Summary
alias TeslaMate.Vehicles.Vehicle
alias TeslaMate.{Vehicles, Convert}
on_mount {TeslaMateWeb.InitAssigns, :locale}
@impl true
def mount(_params, %{"summary" => %Summary{car: car} = summary} = session, socket) do
if connected?(socket) do
send(self(), :update_duration)
send(self(), {:status, Vehicle.busy?(car.id)})
:ok = Vehicles.subscribe_to_summary(car.id)
:ok = Vehicles.subscribe_to_fetch(car.id)
end
assigns = %{
car: car,
summary: summary,
fetch_status: Vehicle.busy?(car.id),
fetch_start: 0,
fetch_timer: nil,
settings: session["settings"],
translate_state: &translate_state/1,
duration: humanize_duration(summary.since),
error: nil,
error_timeout: nil,
loading: false
}
{:ok, assign(socket, assigns)}
end
@impl true
def handle_event("suspend_logging", _val, socket) do
cancel_timer(socket.assigns.error_timeout)
send(self(), :suspend_logging)
{:noreply, assign(socket, loading: true)}
end
def handle_event("resume_logging", _val, socket) do
send(self(), :resume_logging)
{:noreply, assign(socket, loading: true)}
end
@impl true
def handle_info(:update_duration, socket) do
Process.send_after(self(), :update_duration, :timer.seconds(1))
{:noreply, assign(socket, duration: humanize_duration(socket.assigns.summary.since))}
end
def handle_info(:resume_logging, socket) do
:ok = Vehicles.resume_logging(socket.assigns.car.id)
{:noreply, socket}
end
def handle_info(:suspend_logging, socket) do
assigns =
case Vehicles.suspend_logging(socket.assigns.car.id) do
:ok ->
%{error: nil, error_timeout: nil, loading: false}
{:error, reason} ->
%{
error: error_to_str(reason),
error_timeout: Process.send_after(self(), :hide_error, 5_000),
loading: false
}
end
{:noreply, assign(socket, assigns)}
end
def handle_info(:hide_error, socket) do
{:noreply, assign(socket, error: nil, error_timeout: nil)}
end
def handle_info(%Summary{since: since} = summary, socket) do
{:noreply,
assign(socket, summary: summary, duration: humanize_duration(since), loading: false)}
end
def handle_info({:status, true}, socket) do
cancel_timer(socket.assigns.fetch_timer)
assigns = %{
fetch_status: true,
fetch_start: System.monotonic_time(),
fetch_timer: nil
}
{:noreply, assign(socket, assigns)}
end
# Note: this must be smaller than the @driving_interval
@min_spinner_visibility_ms 1000
def handle_info({:status, false}, socket) do
fetch_duration =
(System.monotonic_time() - socket.assigns.fetch_start) /
System.convert_time_unit(1, :millisecond, :native)
assigns =
case @min_spinner_visibility_ms - fetch_duration do
diff when 0 < diff ->
%{fetch_timer: Process.send_after(self(), :set_status_to_false, round(diff))}
_ ->
%{fetch_status: false}
end
{:noreply, assign(socket, assigns)}
end
def handle_info(:set_status_to_false, socket) do
{:noreply, assign(socket, fetch_status: false)}
end
defp translate_state(:start), do: ""
defp translate_state(:driving), do: gettext("driving")
defp translate_state(:charging), do: gettext("charging")
defp translate_state(:updating), do: gettext("updating")
defp translate_state(:suspended), do: gettext("falling asleep")
defp translate_state(:online), do: gettext("online")
defp translate_state(:offline), do: gettext("offline")
defp translate_state(:asleep), do: gettext("asleep")
defp translate_state(:unavailable), do: gettext("unavailable")
defp error_to_str(:unlocked), do: gettext("Car is unlocked")
defp error_to_str(:doors_open), do: gettext("Doors are open")
defp error_to_str(:trunk_open), do: gettext("Trunk is open")
defp error_to_str(:sentry_mode), do: gettext("Sentry mode is enabled")
defp error_to_str(:preconditioning), do: gettext("Preconditioning")
defp error_to_str(:user_present), do: gettext("Driver present")
defp error_to_str(:downloading_update), do: gettext("Downloading update")
defp error_to_str(:update_in_progress), do: gettext("Update in progress")
defp error_to_str(:timeout), do: gettext("Timeout")
defp error_to_str(_other), do: gettext("An error occurred")
defp cancel_timer(nil), do: :ok
defp cancel_timer(ref) when is_reference(ref), do: Process.cancel_timer(ref)
defp humanize_duration(nil), do: nil
defp humanize_duration(date) do
case DateTime.utc_now() |> DateTime.diff(date, :second) do
dur when dur < 5 -> nil
dur when dur > 60 -> dur |> Convert.sec_to_str() |> Enum.reject(&String.ends_with?(&1, "s"))
dur -> dur |> Convert.sec_to_str()
end
end
end