Modify Chat UI
This commit is contained in:
parent
9f0213865d
commit
00113848c8
10 changed files with 1663 additions and 1572 deletions
|
@ -18,15 +18,22 @@ class Room(models.Model):
|
||||||
Profile, related_name="user_two", verbose_name="user 2", on_delete=CASCADE
|
Profile, related_name="user_two", verbose_name="user 2", on_delete=CASCADE
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@cache_wrapper(prefix="Rc")
|
||||||
def contain(self, profile):
|
def contain(self, profile):
|
||||||
return self.user_one == profile or self.user_two == profile
|
return self.user_one == profile or self.user_two == profile
|
||||||
|
|
||||||
|
@cache_wrapper(prefix="Rou")
|
||||||
def other_user(self, profile):
|
def other_user(self, profile):
|
||||||
return self.user_one if profile == self.user_two else self.user_two
|
return self.user_one if profile == self.user_two else self.user_two
|
||||||
|
|
||||||
|
@cache_wrapper(prefix="Rus")
|
||||||
def users(self):
|
def users(self):
|
||||||
return [self.user_one, self.user_two]
|
return [self.user_one, self.user_two]
|
||||||
|
|
||||||
|
@cache_wrapper(prefix="Rlmb")
|
||||||
|
def last_message_body(self):
|
||||||
|
return self.message_set.first().body
|
||||||
|
|
||||||
|
|
||||||
class Message(models.Model):
|
class Message(models.Model):
|
||||||
author = models.ForeignKey(Profile, verbose_name=_("user"), on_delete=CASCADE)
|
author = models.ForeignKey(Profile, verbose_name=_("user"), on_delete=CASCADE)
|
||||||
|
|
|
@ -22,6 +22,7 @@ from django.db.models import (
|
||||||
Count,
|
Count,
|
||||||
IntegerField,
|
IntegerField,
|
||||||
F,
|
F,
|
||||||
|
Max,
|
||||||
)
|
)
|
||||||
from django.db.models.functions import Coalesce
|
from django.db.models.functions import Coalesce
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
@ -206,6 +207,7 @@ def post_message(request):
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
Room.last_message_body.dirty(room)
|
||||||
for user in room.users():
|
for user in room.users():
|
||||||
event.post(
|
event.post(
|
||||||
encrypt_channel("chat_" + str(user.id)),
|
encrypt_channel("chat_" + str(user.id)),
|
||||||
|
@ -342,15 +344,31 @@ def get_online_status(profile, other_profile_ids, rooms=None):
|
||||||
if rooms:
|
if rooms:
|
||||||
unread_count = get_unread_count(rooms, profile)
|
unread_count = get_unread_count(rooms, profile)
|
||||||
count = {}
|
count = {}
|
||||||
|
last_msg = {}
|
||||||
|
room_of_user = {}
|
||||||
for i in unread_count:
|
for i in unread_count:
|
||||||
count[i["other_user"]] = i["unread_count"]
|
room = Room.objects.get(id=i["room"])
|
||||||
|
other_profile = room.other_user(profile)
|
||||||
|
count[other_profile.id] = i["unread_count"]
|
||||||
|
for room in rooms:
|
||||||
|
room = Room.objects.get(id=room)
|
||||||
|
other_profile = room.other_user(profile)
|
||||||
|
last_msg[other_profile.id] = room.last_message_body()
|
||||||
|
room_of_user[other_profile.id] = room.id
|
||||||
|
|
||||||
for other_profile in other_profiles:
|
for other_profile in other_profiles:
|
||||||
is_online = False
|
is_online = False
|
||||||
if other_profile.last_access >= last_5_minutes:
|
if other_profile.last_access >= last_5_minutes:
|
||||||
is_online = True
|
is_online = True
|
||||||
user_dict = {"user": other_profile, "is_online": is_online}
|
user_dict = {"user": other_profile, "is_online": is_online}
|
||||||
if rooms and other_profile.id in count:
|
if rooms:
|
||||||
user_dict["unread_count"] = count[other_profile.id]
|
user_dict.update(
|
||||||
|
{
|
||||||
|
"unread_count": count.get(other_profile.id),
|
||||||
|
"last_msg": last_msg.get(other_profile.id),
|
||||||
|
"room": room_of_user.get(other_profile.id),
|
||||||
|
}
|
||||||
|
)
|
||||||
user_dict["url"] = encrypt_url(profile.id, other_profile.id)
|
user_dict["url"] = encrypt_url(profile.id, other_profile.id)
|
||||||
ret.append(user_dict)
|
ret.append(user_dict)
|
||||||
return ret
|
return ret
|
||||||
|
@ -386,17 +404,9 @@ def get_status_context(profile, include_ignored=False):
|
||||||
|
|
||||||
recent_profile_ids = [str(i["other_user"]) for i in recent_profile]
|
recent_profile_ids = [str(i["other_user"]) for i in recent_profile]
|
||||||
recent_rooms = [int(i["id"]) for i in recent_profile]
|
recent_rooms = [int(i["id"]) for i in recent_profile]
|
||||||
friend_list = (
|
|
||||||
Friend.get_friend_profiles(profile)
|
|
||||||
.exclude(id__in=recent_profile_ids)
|
|
||||||
.exclude(id__in=ignored_users)
|
|
||||||
.order_by("-last_access")
|
|
||||||
.values_list("id", flat=True)
|
|
||||||
)
|
|
||||||
|
|
||||||
admin_list = (
|
admin_list = (
|
||||||
queryset.filter(display_rank="admin")
|
queryset.filter(display_rank="admin")
|
||||||
.exclude(id__in=friend_list)
|
|
||||||
.exclude(id__in=recent_profile_ids)
|
.exclude(id__in=recent_profile_ids)
|
||||||
.values_list("id", flat=True)
|
.values_list("id", flat=True)
|
||||||
)
|
)
|
||||||
|
@ -405,7 +415,6 @@ def get_status_context(profile, include_ignored=False):
|
||||||
queryset.filter(last_access__gte=last_5_minutes)
|
queryset.filter(last_access__gte=last_5_minutes)
|
||||||
.annotate(is_online=Case(default=True, output_field=BooleanField()))
|
.annotate(is_online=Case(default=True, output_field=BooleanField()))
|
||||||
.order_by("-rating")
|
.order_by("-rating")
|
||||||
.exclude(id__in=friend_list)
|
|
||||||
.exclude(id__in=admin_list)
|
.exclude(id__in=admin_list)
|
||||||
.exclude(id__in=recent_profile_ids)
|
.exclude(id__in=recent_profile_ids)
|
||||||
.values_list("id", flat=True)[:30]
|
.values_list("id", flat=True)[:30]
|
||||||
|
@ -416,10 +425,6 @@ def get_status_context(profile, include_ignored=False):
|
||||||
"title": "Recent",
|
"title": "Recent",
|
||||||
"user_list": get_online_status(profile, recent_profile_ids, recent_rooms),
|
"user_list": get_online_status(profile, recent_profile_ids, recent_rooms),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"title": "Following",
|
|
||||||
"user_list": get_online_status(profile, friend_list),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"title": "Admin",
|
"title": "Admin",
|
||||||
"user_list": get_online_status(profile, admin_list),
|
"user_list": get_online_status(profile, admin_list),
|
||||||
|
@ -488,18 +493,9 @@ def get_or_create_room(request):
|
||||||
|
|
||||||
def get_unread_count(rooms, user):
|
def get_unread_count(rooms, user):
|
||||||
if rooms:
|
if rooms:
|
||||||
res = (
|
return UserRoom.objects.filter(
|
||||||
UserRoom.objects.filter(user=user, room__in=rooms, unread_count__gt=0)
|
user=user, room__in=rooms, unread_count__gt=0
|
||||||
.select_related("room__user_one", "room__user_two")
|
).values("unread_count", "room")
|
||||||
.values("unread_count", "room__user_one", "room__user_two")
|
|
||||||
)
|
|
||||||
for ur in res:
|
|
||||||
ur["other_user"] = (
|
|
||||||
ur["room__user_one"]
|
|
||||||
if ur["room__user_two"] == user.id
|
|
||||||
else ur["room__user_two"]
|
|
||||||
)
|
|
||||||
return res
|
|
||||||
else: # lobby
|
else: # lobby
|
||||||
user_room = UserRoom.objects.filter(user=user, room__isnull=True).first()
|
user_room = UserRoom.objects.filter(user=user, room__isnull=True).first()
|
||||||
if not user_room:
|
if not user_room:
|
||||||
|
|
|
@ -5,9 +5,10 @@ from django.db.models.query import QuerySet
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
MAX_NUM_CHAR = 15
|
MAX_NUM_CHAR = 15
|
||||||
|
NONE_RESULT = "__None__"
|
||||||
|
|
||||||
|
|
||||||
def cache_wrapper(prefix, timeout=86400):
|
def cache_wrapper(prefix, timeout=None):
|
||||||
def arg_to_str(arg):
|
def arg_to_str(arg):
|
||||||
if hasattr(arg, "id"):
|
if hasattr(arg, "id"):
|
||||||
return str(arg.id)
|
return str(arg.id)
|
||||||
|
@ -31,8 +32,11 @@ def cache_wrapper(prefix, timeout=86400):
|
||||||
cache_key = get_key(func, *args, **kwargs)
|
cache_key = get_key(func, *args, **kwargs)
|
||||||
result = cache.get(cache_key)
|
result = cache.get(cache_key)
|
||||||
if result is not None:
|
if result is not None:
|
||||||
|
if result == NONE_RESULT:
|
||||||
|
result = None
|
||||||
return result
|
return result
|
||||||
|
if result is None:
|
||||||
|
result = NONE_RESULT
|
||||||
result = func(*args, **kwargs)
|
result = func(*args, **kwargs)
|
||||||
cache.set(cache_key, result, timeout)
|
cache.set(cache_key, result, timeout)
|
||||||
return result
|
return result
|
||||||
|
|
|
@ -47,11 +47,6 @@ else:
|
||||||
"pagedown-extra/Markdown.Extra.js",
|
"pagedown-extra/Markdown.Extra.js",
|
||||||
"pagedown_init.js",
|
"pagedown_init.js",
|
||||||
]
|
]
|
||||||
css = {
|
|
||||||
"all": [
|
|
||||||
"markdown.css",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
class AdminPagedownWidget(PagedownWidget, admin_widgets.AdminTextareaWidget):
|
class AdminPagedownWidget(PagedownWidget, admin_widgets.AdminTextareaWidget):
|
||||||
class Media:
|
class Media:
|
||||||
|
@ -60,7 +55,6 @@ else:
|
||||||
"pagedown_widget.css",
|
"pagedown_widget.css",
|
||||||
"content-description.css",
|
"content-description.css",
|
||||||
"admin/css/pagedown.css",
|
"admin/css/pagedown.css",
|
||||||
"markdown.css",
|
|
||||||
"pagedown.css",
|
"pagedown.css",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -125,7 +119,6 @@ else:
|
||||||
"pygment-github.css",
|
"pygment-github.css",
|
||||||
"table.css",
|
"table.css",
|
||||||
"ranks.css",
|
"ranks.css",
|
||||||
"markdown.css",
|
|
||||||
"dmmd-preview.css",
|
"dmmd-preview.css",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,15 +39,15 @@
|
||||||
#chat-online {
|
#chat-online {
|
||||||
border-right: 1px solid #ccc;
|
border-right: 1px solid #ccc;
|
||||||
padding-bottom: 0 !important;
|
padding-bottom: 0 !important;
|
||||||
min-width: 25%;
|
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
|
font-size: 1.2em;
|
||||||
}
|
}
|
||||||
#chat-online-content {
|
#chat-online-content {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
max-height: calc(100% - 44px);
|
max-height: 100%;
|
||||||
}
|
}
|
||||||
#chat-box {
|
#chat-box {
|
||||||
/*border: 1px solid #ccc;*/
|
/*border: 1px solid #ccc;*/
|
||||||
|
@ -75,6 +75,14 @@
|
||||||
padding: 0;
|
padding: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
.selected-status-row {
|
||||||
|
background-color: lightgray;
|
||||||
|
}
|
||||||
|
.status_last_message {
|
||||||
|
color: darkgray;
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
@media (min-width: 800px) {
|
@media (min-width: 800px) {
|
||||||
#chat-container {
|
#chat-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -86,6 +94,10 @@
|
||||||
}
|
}
|
||||||
#chat-online {
|
#chat-online {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
width: 35%;
|
||||||
|
}
|
||||||
|
#chat-area {
|
||||||
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
.chat-left-panel, .chat-right-panel {
|
.chat-left-panel, .chat-right-panel {
|
||||||
display: block !important;
|
display: block !important;
|
||||||
|
@ -138,29 +150,29 @@
|
||||||
transition: 1.5s ease-in-out;
|
transition: 1.5s ease-in-out;
|
||||||
}
|
}
|
||||||
.status-pic {
|
.status-pic {
|
||||||
height: 1.3em;
|
height: 32px;
|
||||||
width: 1.3em;
|
width: 32px;
|
||||||
border-radius: 0.3em;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
.status-container {
|
.status-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
.status-circle {
|
.status-circle {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
cx: 18px;
|
cx: 27px;
|
||||||
cy: 18px;
|
cy: 27px;
|
||||||
r: 4.5px;
|
r: 4.5px;
|
||||||
stroke: white;
|
stroke: white;
|
||||||
stroke-width: 1;
|
stroke-width: 1;
|
||||||
}
|
}
|
||||||
.status-row {
|
.status-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: 15px;
|
padding: 15px;
|
||||||
padding: 0.2em 0.2em 0.2em 1em;
|
gap: 0.5em;
|
||||||
border-radius: 4px;
|
|
||||||
}
|
}
|
||||||
.status-row:hover {
|
.status-row:hover {
|
||||||
background: lightgray;
|
background: lightgray;
|
||||||
|
@ -168,6 +180,7 @@
|
||||||
}
|
}
|
||||||
.status-list {
|
.status-list {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
.status-section-title {
|
.status-section-title {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -200,6 +213,7 @@
|
||||||
background-color: darkcyan;
|
background-color: darkcyan;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
padding: 0 0.5em;
|
padding: 0 0.5em;
|
||||||
|
align-self: flex-end;
|
||||||
}
|
}
|
||||||
#setting-content {
|
#setting-content {
|
||||||
display: none;
|
display: none;
|
||||||
|
@ -225,7 +239,7 @@
|
||||||
|
|
||||||
@media (max-width: 799px) {
|
@media (max-width: 799px) {
|
||||||
#chat-area {
|
#chat-area {
|
||||||
height: 500px;
|
height: calc(100vh - 50px);
|
||||||
}
|
}
|
||||||
#emoji-button {
|
#emoji-button {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -20,7 +20,6 @@
|
||||||
window.lock = false;
|
window.lock = false;
|
||||||
window.lock_click_space = false;
|
window.lock_click_space = false;
|
||||||
window.pushed_messages = new Set();
|
window.pushed_messages = new Set();
|
||||||
let isMobile = window.matchMedia("only screen and (max-width: 799px)").matches;
|
|
||||||
|
|
||||||
window.load_dynamic_update = function (last_msg) {
|
window.load_dynamic_update = function (last_msg) {
|
||||||
var receiver = new EventReceiver(
|
var receiver = new EventReceiver(
|
||||||
|
@ -71,25 +70,20 @@
|
||||||
|
|
||||||
<div id="chat-container">
|
<div id="chat-container">
|
||||||
<div id="chat-online" class="chat-right-panel sidebox">
|
<div id="chat-online" class="chat-right-panel sidebox">
|
||||||
<h3>
|
|
||||||
<i class="fa fa-users"></i>{{_('Online Users')}}
|
|
||||||
</h3>
|
|
||||||
<div id="chat-online-content">
|
<div id="chat-online-content">
|
||||||
<div id="search-container">
|
<div id="search-container">
|
||||||
<center>
|
<form id="chat-search-form" name="form" action="{{ url('get_or_create_room') }}" method="post">
|
||||||
<form id="search-form" name="form" action="{{ url('get_or_create_room') }}" method="post">
|
{% csrf_token %}
|
||||||
{% csrf_token %}
|
<input id="search-handle" type="text" name="search"
|
||||||
<input id="search-handle" type="text" name="search"
|
placeholder="{{ _('Search by handle...') }}">
|
||||||
placeholder="{{ _('Search by handle...') }}">
|
</form>
|
||||||
</form>
|
|
||||||
</center>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="chat-online-list">
|
<div id="chat-online-list">
|
||||||
{% include "chat/online_status.html" %}
|
{% include "chat/online_status.html" %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="chat-area" class="chat-left-panel" style="width:100%">
|
<div id="chat-area" class="chat-left-panel">
|
||||||
<div id="chat-info" style="height: 10%">
|
<div id="chat-info" style="height: 10%">
|
||||||
{% include 'chat/user_online_status.html' %}
|
{% include 'chat/user_online_status.html' %}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -102,12 +102,22 @@
|
||||||
float: inherit;
|
float: inherit;
|
||||||
}
|
}
|
||||||
#search-container {
|
#search-container {
|
||||||
margin-bottom: 0.4em;
|
padding: 1em;
|
||||||
}
|
}
|
||||||
#setting {
|
#setting {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
.status-user {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-width: 0;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
.wrapline {
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
@media (min-width: 800px) {
|
@media (min-width: 800px) {
|
||||||
#page-container {
|
#page-container {
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -27,11 +27,18 @@
|
||||||
fill="{{'green' if user.is_online else 'red'}}"/>
|
fill="{{'green' if user.is_online else 'red'}}"/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<span style="padding-left:0.3em" class="username {{ user.user.css_class }}">
|
<div class="status-user">
|
||||||
{{ user.user.username }}
|
<span class="username {{ user.user.css_class }} wrapline">
|
||||||
</span>
|
{{ user.user.username }}
|
||||||
<span class="spacer">
|
</span>
|
||||||
<span class="unread-count" id="unread-count-{{user.user.id}}">{{user.unread_count if user.unread_count}}</span>
|
{% if user.last_msg %}
|
||||||
|
<span class="status_last_message wrapline" {% if user.room %}id="last_msg-{{user.room}}"{% endif %}>
|
||||||
|
{{ user.last_msg }}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<span class="unread-count" id="unread-count-{{user.user.id}}">
|
||||||
|
{{user.unread_count if user.unread_count}}
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
Loading…
Reference in a new issue