diff --git a/lib/chessh/schema/chat.ex b/lib/chessh/schema/chat.ex new file mode 100644 index 0000000..11d9f28 --- /dev/null +++ b/lib/chessh/schema/chat.ex @@ -0,0 +1,19 @@ +defmodule Chessh.Chat do + use Ecto.Schema + import Ecto.Changeset + alias Chessh.Player + + schema "chats" do + field(:message, :string) + belongs_to(:chatter, Player, foreign_key: :chatter_id) + timestamps() + end + + def changeset(chat, attrs) do + chat + |> cast(attrs, [ + :message, + :chatter_id + ]) + end +end diff --git a/lib/chessh/ssh/client/client.ex b/lib/chessh/ssh/client/client.ex index 5a0ea1e..1d33dd2 100644 --- a/lib/chessh/ssh/client/client.ex +++ b/lib/chessh/ssh/client/client.ex @@ -111,7 +111,7 @@ defmodule Chessh.SSH.Client do {:noreply, state} action -> - send(screen_pid, {:input, width, height, action}) + send(screen_pid, {:input, width, height, action, data}) {:noreply, state} end end @@ -172,6 +172,7 @@ defmodule Chessh.SSH.Client do "\eOD" -> :left "\eOC" -> :right "\r" -> :return + "\d" -> :backspace x -> x end end diff --git a/lib/chessh/ssh/client/game/game.ex b/lib/chessh/ssh/client/game/game.ex index 738832e..6103439 100644 --- a/lib/chessh/ssh/client/game/game.ex +++ b/lib/chessh/ssh/client/game/game.ex @@ -221,6 +221,7 @@ defmodule Chessh.SSH.Client.Game do _width, _height, action, + _data, %State{ move_from: move_from, cursor: %{x: cursor_x, y: cursor_y} = cursor, diff --git a/lib/chessh/ssh/client/game/previous_game.ex b/lib/chessh/ssh/client/game/previous_game.ex index 73de868..3582cc9 100644 --- a/lib/chessh/ssh/client/game/previous_game.ex +++ b/lib/chessh/ssh/client/game/previous_game.ex @@ -57,6 +57,7 @@ defmodule Chessh.SSH.Client.PreviousGame do _width, _height, action, + _data, %State{ move_idx: move_idx, flipped: flipped, diff --git a/lib/chessh/ssh/client/game/promotion.ex b/lib/chessh/ssh/client/game/promotion.ex index c4cece6..693ec3f 100644 --- a/lib/chessh/ssh/client/game/promotion.ex +++ b/lib/chessh/ssh/client/game/promotion.ex @@ -47,11 +47,12 @@ defmodule Chessh.SSH.Client.Game.PromotionScreen do def input( _, _, - action, + _, + data, %State{client_pid: client_pid, game_pid: game_pid, game_state: %Game.State{} = game_state} = state ) do - promotion = if Enum.member?(["q", "b", "n", "r"], action), do: action, else: nil + promotion = if Enum.member?(["q", "b", "n", "r"], data), do: data, else: nil if promotion do send(client_pid, {:go_back_one_screen, game_state}) diff --git a/lib/chessh/ssh/client/menus/main_menu.ex b/lib/chessh/ssh/client/menus/main_menu.ex index 7b83b76..43f916e 100644 --- a/lib/chessh/ssh/client/menus/main_menu.ex +++ b/lib/chessh/ssh/client/menus/main_menu.ex @@ -34,7 +34,10 @@ defmodule Chessh.SSH.Client.MainMenu do %Chessh.SSH.Client.SelectPaginatePoller.State{player_session: player_session}}}, {"Previous Games", {Chessh.SSH.Client.SelectPreviousGame, - %Chessh.SSH.Client.SelectPaginatePoller.State{player_session: player_session}}} + %Chessh.SSH.Client.SelectPaginatePoller.State{player_session: player_session}}}, + {"TrongleChat", + {Chessh.SSH.Client.TrongleChat, + %Chessh.SSH.Client.TrongleChat.State{player_session: player_session}}} ] end diff --git a/lib/chessh/ssh/client/menus/select_paginate_poller.ex b/lib/chessh/ssh/client/menus/select_paginate_poller.ex index 23808b5..5c668a0 100644 --- a/lib/chessh/ssh/client/menus/select_paginate_poller.ex +++ b/lib/chessh/ssh/client/menus/select_paginate_poller.ex @@ -119,6 +119,7 @@ defmodule Chessh.SSH.Client.SelectPaginatePoller do width, height, action, + _data, %State{ client_pid: client_pid, options: options, diff --git a/lib/chessh/ssh/client/screen.ex b/lib/chessh/ssh/client/screen.ex index 0437b23..20273a5 100644 --- a/lib/chessh/ssh/client/screen.ex +++ b/lib/chessh/ssh/client/screen.ex @@ -1,6 +1,12 @@ defmodule Chessh.SSH.Client.Screen do @callback render(width :: integer(), height :: integer(), state :: any()) :: any() - @callback input(width :: integer(), height :: integer(), action :: any(), state :: any()) :: + @callback input( + width :: integer(), + height :: integer(), + action :: any(), + data :: String.t(), + state :: any() + ) :: any() defmacro __using__(_) do @@ -11,8 +17,8 @@ defmodule Chessh.SSH.Client.Screen do def handle_info({:render, width, height}, state), do: {:noreply, render(width, height, state)} - def handle_info({:input, width, height, action}, state), - do: {:noreply, input(width, height, action, state)} + def handle_info({:input, width, height, action, data}, state), + do: {:noreply, input(width, height, action, data, state)} end end end diff --git a/lib/chessh/ssh/client/trongle_chat.ex b/lib/chessh/ssh/client/trongle_chat.ex new file mode 100644 index 0000000..30c1ec2 --- /dev/null +++ b/lib/chessh/ssh/client/trongle_chat.ex @@ -0,0 +1,75 @@ +defmodule Chessh.SSH.Client.TrongleChat do + require Logger + alias Chessh.{Player, Chat, Utils, Repo, PlayerSession} + import Ecto.Query + + defmodule State do + defstruct client_pid: nil, + message: "", + player_session: nil, + chats: [] + end + + use Chessh.SSH.Client.Screen + + defp get_initial_chats() do + from(c in Chat, + order_by: [desc: c.id], + limit: 100 + ) + |> Repo.all() + |> Repo.preload([:chatter]) + end + + def get_player(%PlayerSession{player_id: player_id} = player_session) do + Repo.get!(Player, player_id) + end + + def init([%State{client_pid: client_pid, player_session: player_session} = state]) do + :syn.add_node_to_scopes([:chat]) + :ok = :syn.join(:chat, {:tronglechat}, self()) + + send(client_pid, {:send_to_ssh, Utils.clear_codes()}) + + chats = get_initial_chats() + + {:ok, + %State{ + state + | chats: chats, + player_session: %PlayerSession{player_session | player: get_player(player_session)} + }} + end + + def render( + width, + height, + %State{ + client_pid: client_pid, + chats: chats, + message: message, + player_session: %PlayerSession{player: %Player{username: username}} = player_session + } = state + ) do + send(client_pid, {:send_to_ssh, [Utils.clear_codes(), username <> "> " <> message]}) + + state + end + + def input(width, height, action, data, %State{message: message} = state) do + appended_message = + case action do + :backspace -> + %State{state | message: String.slice(message, 0..-2)} + + _ -> + if String.match?(data, ~r/[a-zA-Z \.-]/) do + %State{state | message: message <> data} + else + state + end + end + + render(width, height, appended_message) + end +end diff --git a/priv/repo/migrations/20231004233032_add_trongle_chat.exs b/priv/repo/migrations/20231004233032_add_trongle_chat.exs new file mode 100644 index 0000000..2a3c8ae --- /dev/null +++ b/priv/repo/migrations/20231004233032_add_trongle_chat.exs @@ -0,0 +1,12 @@ +defmodule Chessh.Repo.Migrations.AddTrongleChat do + use Ecto.Migration + + def change do + create table(:chats) do + add(:message, :string, null: false) + add(:chatter_id, references(:players), null: false) + + timestamps() + end + end +end