Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 2s
176 lines
5.5 KiB
Elixir
176 lines
5.5 KiB
Elixir
defmodule AprsmeWeb.MapLive.State do
|
|
@moduledoc """
|
|
Manages initial LiveView socket state assignment for the map view.
|
|
Extracted from Index to reduce module size.
|
|
"""
|
|
|
|
import Phoenix.Component, only: [assign: 2]
|
|
import Phoenix.LiveView, only: [connected?: 1, get_connect_params: 1]
|
|
|
|
alias Aprsme.Packets
|
|
alias AprsmeWeb.Live.Shared.BoundsUtils
|
|
alias AprsmeWeb.MapLive.PacketBatcher
|
|
alias AprsmeWeb.MapLive.UrlParams
|
|
alias Phoenix.LiveView.Socket
|
|
|
|
@doc """
|
|
Assign default values to a fresh socket.
|
|
"""
|
|
@spec default(Socket.t(), DateTime.t()) :: Socket.t()
|
|
def default(socket, one_day_ago) do
|
|
assign(socket,
|
|
packets: [],
|
|
visible_packets: %{},
|
|
historical_packets: %{},
|
|
page_title: "APRS Map",
|
|
station_popup_open: false,
|
|
map_bounds: %{
|
|
north: 49.0,
|
|
south: 24.0,
|
|
east: -66.0,
|
|
west: -125.0
|
|
},
|
|
map_center: UrlParams.default_center(),
|
|
map_zoom: UrlParams.default_zoom(),
|
|
packet_age_threshold: one_day_ago,
|
|
map_ready: false,
|
|
historical_loaded: false,
|
|
bounds_update_timer: nil,
|
|
pending_bounds: nil,
|
|
initial_bounds_loaded: false,
|
|
# Loading state management
|
|
historical_loading: false,
|
|
loading_generation: 0,
|
|
pending_batch_tasks: [],
|
|
# Overlay controls
|
|
overlay_callsign: "",
|
|
slideover_open: true,
|
|
# Track when last update occurred for real-time display in map sidebar
|
|
# Updated when packets are processed or map bounds change
|
|
last_update_at: DateTime.utc_now(),
|
|
# Add missing assigns for components
|
|
loading: false,
|
|
connection_status: connection_status(),
|
|
show_all_packets: true
|
|
)
|
|
end
|
|
|
|
@doc """
|
|
Finalize mount assigns with computed values.
|
|
Takes the socket after basic setup and an opts map.
|
|
"""
|
|
@spec finalize(Socket.t(), map()) :: Socket.t()
|
|
def finalize(socket, %{
|
|
initial_bounds: initial_bounds,
|
|
final_map_center: final_map_center,
|
|
final_map_zoom: final_map_zoom,
|
|
should_skip_initial_url_update: should_skip_initial_url_update,
|
|
tracked_callsign: tracked_callsign,
|
|
deployed_at: deployed_at,
|
|
one_day_ago: one_day_ago
|
|
}) do
|
|
# Don't override trail_duration and historical_hours if they're already set
|
|
trail_duration = Map.get(socket.assigns, :trail_duration, "1")
|
|
historical_hours = Map.get(socket.assigns, :historical_hours, "1")
|
|
packet_age_threshold = Map.get(socket.assigns, :packet_age_threshold, one_day_ago)
|
|
|
|
# If tracking a specific callsign, fetch their latest packet and other SSIDs
|
|
{tracked_callsign_latest_packet, other_ssids} =
|
|
if tracked_callsign == "" do
|
|
{nil, []}
|
|
else
|
|
try do
|
|
packet = Packets.get_latest_packet_for_callsign(tracked_callsign)
|
|
ssids = Packets.get_other_ssids(tracked_callsign)
|
|
{packet, ssids}
|
|
rescue
|
|
# Handle database connection errors gracefully (especially in tests)
|
|
DBConnection.OwnershipError ->
|
|
{nil, []}
|
|
|
|
_ ->
|
|
{nil, []}
|
|
end
|
|
end
|
|
|
|
# Start packet batcher for efficient updates
|
|
{:ok, batcher_pid} = PacketBatcher.start_link(self())
|
|
Process.monitor(batcher_pid)
|
|
|
|
# Determine initial slideover state from client viewport width
|
|
slideover_open = slideover_open?(socket)
|
|
|
|
assign(socket,
|
|
map_ready: false,
|
|
map_bounds: initial_bounds,
|
|
map_center: final_map_center,
|
|
map_zoom: final_map_zoom,
|
|
should_skip_initial_url_update: should_skip_initial_url_update,
|
|
overlay_callsign: "",
|
|
tracked_callsign: tracked_callsign,
|
|
tracked_callsign_latest_packet: tracked_callsign_latest_packet,
|
|
other_ssids: other_ssids,
|
|
trail_duration: trail_duration,
|
|
historical_hours: historical_hours,
|
|
packet_age_threshold: packet_age_threshold,
|
|
slideover_open: slideover_open,
|
|
deployed_at: deployed_at,
|
|
buffer_timer: nil,
|
|
batcher_pid: batcher_pid,
|
|
station_popup_open: false,
|
|
initial_bounds_loaded: false,
|
|
# Always load historical data on initial page load
|
|
needs_initial_historical_load: true,
|
|
# Loading state management
|
|
historical_loading: false,
|
|
loading_generation: 0,
|
|
pending_batch_tasks: [],
|
|
# Add missing assigns for components
|
|
loading: false,
|
|
connection_status: connection_status(),
|
|
show_all_packets: true
|
|
)
|
|
end
|
|
|
|
@doc """
|
|
Determine whether the slideover should be open on initial render.
|
|
"""
|
|
@spec slideover_open?(Socket.t()) :: boolean()
|
|
def slideover_open?(socket) do
|
|
if connected?(socket) do
|
|
viewport_width = get_connect_params(socket)["viewport_width"] || 1024
|
|
viewport_width >= 1024
|
|
else
|
|
true
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Get the initial APRS connection status.
|
|
"""
|
|
@spec connection_status() :: String.t()
|
|
def connection_status do
|
|
# Check if APRS connection is disabled
|
|
connection_disabled = Application.get_env(:aprsme, :disable_aprs_connection, false)
|
|
if connection_disabled, do: "disconnected", else: "connected"
|
|
end
|
|
|
|
@doc """
|
|
Default map center used by UrlParams.
|
|
"""
|
|
@spec default_center() :: %{lat: float(), lng: float()}
|
|
def default_center, do: UrlParams.default_center()
|
|
|
|
@doc """
|
|
Default map zoom used by UrlParams.
|
|
"""
|
|
def default_zoom, do: UrlParams.default_zoom()
|
|
|
|
@doc """
|
|
Calculate initial bounds from center and zoom.
|
|
"""
|
|
@spec initial_bounds(%{lat: float(), lng: float()}, integer()) :: map()
|
|
def initial_bounds(center, zoom) do
|
|
BoundsUtils.calculate_bounds_from_center_and_zoom(center, zoom)
|
|
end
|
|
end
|