aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shard/lib/app/chat.ex39
-rw-r--r--shardweb/assets/css/app.css5
-rw-r--r--shardweb/lib/channels/chat_channel.ex3
-rw-r--r--shardweb/lib/controllers/identity_controller.ex14
-rw-r--r--shardweb/lib/templates/chat/chat.html.eex6
-rw-r--r--shardweb/lib/templates/identity/list.html.eex5
-rw-r--r--shardweb/lib/templates/identity/view.html.eex25
-rw-r--r--shardweb/lib/templates/layout/app.html.eex101
-rw-r--r--shardweb/lib/templates/page/peer_list.html.eex7
-rw-r--r--shardweb/lib/views/layout_view.ex21
10 files changed, 157 insertions, 69 deletions
diff --git a/shard/lib/app/chat.ex b/shard/lib/app/chat.ex
index d8ba5da..8d55cda 100644
--- a/shard/lib/app/chat.ex
+++ b/shard/lib/app/chat.ex
@@ -82,7 +82,10 @@ defmodule SApp.Chat do
end
Shard.Manager.dispatch_to(id, nil, self())
{:ok, page_store} = SApp.PageStore.start_link(id, :page_store, netgroup)
- root = Shard.Manager.load_state id
+ {root, read} = case Shard.Manager.load_state id do
+ %{root: root, read: read} -> {root, read}
+ _ -> {nil, nil}
+ end
root = cond do
root == nil -> nil
GenServer.call(page_store, {:have_rec, root}) -> root
@@ -101,6 +104,7 @@ defmodule SApp.Chat do
page_store: page_store,
mst: mst,
subs: MapSet.new,
+ read: read,
}
}
:redundant ->
@@ -120,6 +124,26 @@ defmodule SApp.Chat do
{:reply, ret, state}
end
+ def handle_call(:has_unread, _from, state) do
+ if state.mst.root != state.read do
+ case MST.last(state.mst, nil, 1) do
+ [{{_, msgbin, _}, true}] ->
+ {ts, _} = SData.term_unbin msgbin
+ {:reply, ts, state}
+ [] ->
+ {:reply, nil, state}
+ end
+ else
+ {:reply, nil, state}
+ end
+ end
+
+ def handle_cast(:mark_read, state) do
+ state = %{state | read: state.mst.root}
+ save_state(state)
+ {:noreply, state}
+ end
+
@doc """
Implementation of the :chat_send handler. This is the main handler that is used
to send a message to the chat room. Puts the message in the store and syncs
@@ -133,7 +157,7 @@ defmodule SApp.Chat do
prev_root = state.mst.root
mst = MST.insert(state.mst, msgitem)
state = %{state | mst: mst}
- Shard.Manager.save_state(state.id, mst.root)
+ save_state(state)
for pid <- state.subs do
if Process.alive?(pid) do
@@ -202,7 +226,7 @@ defmodule SApp.Chat do
if mst2.root == new_root do
state = %{state | mst: mst2}
GenServer.cast(state.page_store, {:set_roots, [mst2.root]})
- Shard.Manager.save_state(state.id, mst2.root)
+ save_state(state)
msg_callback(state, msgitem)
state
else
@@ -265,8 +289,9 @@ defmodule SApp.Chat do
msg_callback(state, x)
end
GenServer.cast(state.page_store, {:set_roots, [mst.root]})
- Shard.Manager.save_state(state.id, mst.root)
- %{state | mst: mst}
+ state = %{state | mst: mst}
+ save_state(state)
+ state
else
Logger.warn("Incorrect signatures somewhere while merging, dropping merged data")
state
@@ -279,6 +304,10 @@ defmodule SApp.Chat do
{:noreply, %{ state | subs: new_subs }}
end
+ defp save_state(state) do
+ Shard.Manager.save_state(state.id, %{root: state.mst.root, read: state.read})
+ end
+
defp msg_callback(state, {pk, msgbin, sign}) do
for pid <- state.subs do
if Process.alive?(pid) do
diff --git a/shardweb/assets/css/app.css b/shardweb/assets/css/app.css
index 0676867..e8d40d2 100644
--- a/shardweb/assets/css/app.css
+++ b/shardweb/assets/css/app.css
@@ -4,3 +4,8 @@
color: #fff;
background-color: #080808;
}
+
+.have_unread {
+ color: #fff;
+ font-weight: bold;
+}
diff --git a/shardweb/lib/channels/chat_channel.ex b/shardweb/lib/channels/chat_channel.ex
index f898602..a413be1 100644
--- a/shardweb/lib/channels/chat_channel.ex
+++ b/shardweb/lib/channels/chat_channel.ex
@@ -47,6 +47,7 @@ defmodule ShardWeb.ChatChannel do
message: msg,
})
end)
+ GenServer.cast(socket.assigns.pid, :mark_read)
{:noreply, socket}
end
@@ -57,10 +58,12 @@ defmodule ShardWeb.ChatChannel do
push socket, "shout", %{"name" => nick,
"pk16" => Shard.Keys.pk_display(pk),
"message" => msg}
+ GenServer.cast(socket.assigns.pid, :mark_read)
{:noreply, socket}
end
def handle_info({:chat_send, _, _}, socket) do
+ GenServer.cast(socket.assigns.pid, :mark_read)
{:noreply, socket}
end
diff --git a/shardweb/lib/controllers/identity_controller.ex b/shardweb/lib/controllers/identity_controller.ex
index 3c04fe8..dd254bb 100644
--- a/shardweb/lib/controllers/identity_controller.ex
+++ b/shardweb/lib/controllers/identity_controller.ex
@@ -10,7 +10,19 @@ defmodule ShardWeb.IdentityController do
end
def view(conn, %{"pk" => pk}) do
- #TODO
+ {:ok, pk} = Base.decode16(pk)
+ shard = %SApp.Identity.Manifest{pk: pk} |> SData.term_hash
+ pid = Shard.Manager.find_proc shard
+
+ if pid == nil do
+ render conn, ShardWeb.ErrorView, "404.html"
+ else
+ render conn, "view.html",
+ view_pk: pk,
+ view_nick: SApp.Identity.get_nick(pk),
+ shard: shard,
+ pid: pid
+ end
end
def update(conn, params) do
diff --git a/shardweb/lib/templates/chat/chat.html.eex b/shardweb/lib/templates/chat/chat.html.eex
index 8a43acf..45609d8 100644
--- a/shardweb/lib/templates/chat/chat.html.eex
+++ b/shardweb/lib/templates/chat/chat.html.eex
@@ -18,14 +18,14 @@
<i class="fa fa-comments"></i> Chat rooms
</li>
<li class="active">
- <i class="fa fa-comments"></i> #<%= @chan %>
+ <i class="fa fa-users"></i> #<%= @chan %>
</li>
<% else %>
<li>
- <i class="fa fa-user"></i> Private chat
+ <i class="fa fa-comments"></i> Private chat
</li>
<li class="active">
- <i class="fa fa-comments"></i> <%= @nicks %>
+ <i class="fa fa-user"></i> <%= @nicks %>
</li>
<% end %>
</ol>
diff --git a/shardweb/lib/templates/identity/list.html.eex b/shardweb/lib/templates/identity/list.html.eex
index 007af3d..6437f9c 100644
--- a/shardweb/lib/templates/identity/list.html.eex
+++ b/shardweb/lib/templates/identity/list.html.eex
@@ -31,7 +31,10 @@
<% end %>
</td>
<td>
- <%= if manifest.pk != @pk do %>
+ <a class="btn btn-xs btn-info" href="<%= identity_path(@conn, :view, manifest.pk |> Base.encode16) %>"><i class="fa fa-info"></i></a>
+ <%= if manifest.pk == @pk do %>
+ <a class="btn btn-xs btn-warning" href="<%= identity_path(@conn, :self) %>"><i class="fa fa-edit"></i> Edit</a>
+ <% else %>
<a class="btn btn-xs btn-primary" href="<%= chat_path(@conn, :privchat, manifest.pk |> Base.encode16) %>"><i class="fa fa-comments"></i> PM</a>
<% end %>
</td>
diff --git a/shardweb/lib/templates/identity/view.html.eex b/shardweb/lib/templates/identity/view.html.eex
new file mode 100644
index 0000000..8bb8ca2
--- /dev/null
+++ b/shardweb/lib/templates/identity/view.html.eex
@@ -0,0 +1,25 @@
+<!-- Page Heading -->
+<div class="row">
+ <div class="col-lg-12">
+ <h1 class="page-header">
+ <%= @view_nick %> <small><%= @view_pk |> Base.encode16 %></small>
+ </h1>
+ <ol class="breadcrumb">
+ <li>
+ <i class="fa fa-users"></i> People
+ </li>
+ <li class="active">
+ <i class="fa fa-user"></i> <%= @view_nick %>
+ </li>
+ </ol>
+ </div>
+</div>
+<!-- /.row -->
+
+<%= render ShardWeb.LayoutView, "flashes.html", assigns %>
+
+<pre>
+ <%= inspect((GenServer.call(@pid, :get_info)), pretty: true, width: 40) %>
+</pre>
+
+
diff --git a/shardweb/lib/templates/layout/app.html.eex b/shardweb/lib/templates/layout/app.html.eex
index f49c8e6..067ad57 100644
--- a/shardweb/lib/templates/layout/app.html.eex
+++ b/shardweb/lib/templates/layout/app.html.eex
@@ -52,79 +52,52 @@
<!-- Top Menu Items -->
<ul class="nav navbar-right top-nav">
<li class="dropdown">
- <a href="#" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-envelope"></i> <b class="caret"></b></a>
+ <% sur = privchat_with_unread(@conn) %>
+ <a href="#" class="dropdown-toggle" data-toggle="dropdown">
+ <i class="fa fa-envelope"></i>
+ <%= if sur != [] do %>
+ <span class="badge badge-notify"><%= Enum.count sur %></span>
+ <% end %>
+ <b class="caret"></b>
+ </a>
<ul class="dropdown-menu message-dropdown">
+ <%= for {id, %SApp.Chat.PrivChat.Manifest{pk_list: pk_list}, pid} <- sur do %>
<li class="message-preview">
- <a href="#">
- <div class="media">
- <span class="pull-left">
- <img class="media-object" src="http://placehold.it/50x50" alt="">
- </span>
- <div class="media-body">
- <h5 class="media-heading"><strong>John Smith</strong>
- </h5>
- <p class="small text-muted"><i class="fa fa-clock-o"></i> Yesterday at 4:32 PM</p>
- <p>Lorem ipsum dolor sit amet, consectetur...</p>
- </div>
- </div>
- </a>
- </li>
- <li class="message-preview">
- <a href="#">
+ <a href="<%= chat_path(@conn, :privchat, str_of_pk_list(@conn, pk_list)) %>">
<div class="media">
<span class="pull-left">
<img class="media-object" src="http://placehold.it/50x50" alt="">
</span>
<div class="media-body">
- <h5 class="media-heading"><strong>John Smith</strong>
+ <h5 class="media-heading"><strong><%= nicks_of_pk_list(@conn, pk_list) %></strong>
</h5>
<p class="small text-muted"><i class="fa fa-clock-o"></i> Yesterday at 4:32 PM</p>
- <p>Lorem ipsum dolor sit amet, consectetur...</p>
+ <p><%= chat_shard_last_msg(pid) %></p>
</div>
</div>
</a>
</li>
- <li class="message-preview">
- <a href="#">
- <div class="media">
- <span class="pull-left">
- <img class="media-object" src="http://placehold.it/50x50" alt="">
- </span>
- <div class="media-body">
- <h5 class="media-heading"><strong>John Smith</strong>
- </h5>
- <p class="small text-muted"><i class="fa fa-clock-o"></i> Yesterday at 4:32 PM</p>
- <p>Lorem ipsum dolor sit amet, consectetur...</p>
- </div>
- </div>
- </a>
- </li>
- <li class="message-footer">
- <a href="#">Read All New Messages</a>
- </li>
+ <% end %>
+ <li class="message-footer">
+ <a href="<%= identity_path(@conn, :list) %>"><i class="fa fa-users"></i> People</a>
+ </li>
</ul>
</li>
<li class="dropdown">
- <a href="#" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-bell"></i> <b class="caret"></b></a>
+ <% cur = chat_with_unread(@conn) %>
+ <a href="#" class="dropdown-toggle" data-toggle="dropdown">
+ <i class="fa fa-bell"></i>
+ <%= if cur != [] do %>
+ <span class="badge badge-notify"><%= Enum.count cur %></span>
+ <% end %>
+ <b class="caret"></b>
+ </a>
<ul class="dropdown-menu alert-dropdown">
+ <%= for {_, %SApp.Chat.Manifest{channel: chan}, _} <- cur do %>
<li>
- <a href="#">Alert Name <span class="label label-default">Alert Badge</span></a>
- </li>
- <li>
- <a href="#">Alert Name <span class="label label-primary">Alert Badge</span></a>
- </li>
- <li>
- <a href="#">Alert Name <span class="label label-success">Alert Badge</span></a>
- </li>
- <li>
- <a href="#">Alert Name <span class="label label-info">Alert Badge</span></a>
- </li>
- <li>
- <a href="#">Alert Name <span class="label label-warning">Alert Badge</span></a>
- </li>
- <li>
- <a href="#">Alert Name <span class="label label-danger">Alert Badge</span></a>
+ <a href="<%= chat_path(@conn, :chat, chan) %>">#<%= chan %></a>
</li>
+ <% end %>
<li class="divider"></li>
<li>
<a href="#">View All</a>
@@ -161,9 +134,15 @@
<ul id="demo" class="<%= if not (@view_module == ShardWeb.ChatView and @view_template == "chat.html" and @public) do "collapse" else "" end %>">
- <%= for {id, %SApp.Chat.Manifest{channel: name}, _} <- shard_list() do %>
+ <%= for {id, %SApp.Chat.Manifest{channel: name}, pid} <- shard_list() do %>
<li class="<%= if @shard == id do "custom_active" else "" end %>">
- <a href="<%= chat_path(@conn, :chat, name) %>">#<%= name %></a>
+ <a href="<%= chat_path(@conn, :chat, name) %>">
+ <%= if GenServer.call(pid, :has_unread) != nil do %>
+ <span class="have_unread">#<%= name %></span>
+ <% else %>
+ #<%= name %>
+ <% end %>
+ </a>
</li>
<% end %>
<li>
@@ -177,9 +156,15 @@
<a href="<%= identity_path(@conn, :list) %>"><i class="fa fa-fw fa-users"></i> People<i class="fa fa-fw fa-caret-down"></i></a>
<%= if (@view_module == ShardWeb.IdentityView and @view_template == "list.html") or (@view_module == ShardWeb.ChatView and @view_template == "chat.html" and not @public) do %>
<ul>
- <%= for {id, %SApp.Chat.PrivChat.Manifest{pk_list: pk_list}, _} <- shard_list() do %>
+ <%= for {id, %SApp.Chat.PrivChat.Manifest{pk_list: pk_list}, pid} <- shard_list() do %>
<li class="<%= if id == @shard do "custom_active" else "" end %>">
- <a href="<%= chat_path(@conn, :privchat, str_of_pk_list(@conn, pk_list)) %>"><%= nicks_of_pk_list(@conn, pk_list) %></a>
+ <a href="<%= chat_path(@conn, :privchat, str_of_pk_list(@conn, pk_list)) %>">
+ <%= if GenServer.call(pid, :has_unread) != nil do %>
+ <span class="have_unread"><%= nicks_of_pk_list(@conn, pk_list) %></span>
+ <% else %>
+ <%= nicks_of_pk_list(@conn, pk_list) %>
+ <% end %>
+ </a>
</li>
<% end %>
</ul>
diff --git a/shardweb/lib/templates/page/peer_list.html.eex b/shardweb/lib/templates/page/peer_list.html.eex
index f385528..ff6479f 100644
--- a/shardweb/lib/templates/page/peer_list.html.eex
+++ b/shardweb/lib/templates/page/peer_list.html.eex
@@ -30,7 +30,12 @@
<td>
<%= case auth do %>
<% nil -> %>(anonymous)
- <% %SNet.Auth{his_pk: his_pk} -> %> <%= Shard.Keys.pk_display(his_pk) %>
+ <% %SNet.Auth{his_pk: his_pk} -> %>
+ <i class="fa fa-user"></i>
+ <%= SApp.Identity.get_nick(his_pk) %>
+ <a href="<%= identity_path(@conn, :view, his_pk|>Base.encode16) %>">
+ <small><%= Shard.Keys.pk_display(his_pk) %></small>
+ </a>
<% end %>
</td>
<td><%= :inet_parse.ntoa(ip) %></td>
diff --git a/shardweb/lib/views/layout_view.ex b/shardweb/lib/views/layout_view.ex
index 317d405..990df55 100644
--- a/shardweb/lib/views/layout_view.ex
+++ b/shardweb/lib/views/layout_view.ex
@@ -24,4 +24,25 @@ defmodule ShardWeb.LayoutView do
l -> Enum.join(l, ", ")
end
end
+
+ def chat_shard_last_msg(pid) do
+ [{{_, msgbin, _}, true}] = GenServer.call(pid, {:read_history, nil, 1})
+ {_, msg} = SData.term_unbin msgbin
+ msg
+ end
+
+ def privchat_with_unread(conn) do
+ for {id, %SApp.Chat.PrivChat.Manifest{pk_list: pk_list}, pid} <- shard_list(),
+ conn.assigns.pk in pk_list,
+ unread_time = GenServer.call(pid, :has_unread),
+ unread_time != nil,
+ do: {id, %SApp.Chat.PrivChat.Manifest{pk_list: pk_list}, pid}
+ end
+
+ def chat_with_unread(conn) do
+ for {id, %SApp.Chat.Manifest{channel: c}, pid} <- shard_list(),
+ unread_time = GenServer.call(pid, :has_unread),
+ unread_time != nil,
+ do: {id, %SApp.Chat.Manifest{channel: c}, pid}
+ end
end