chat 0.2.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +11 -8
- data/Rakefile +2 -0
- data/app/assets/javascripts/chat/channels/message.coffee +33 -43
- data/app/assets/javascripts/chat/channels/status.coffee +2 -2
- data/app/assets/javascripts/chat/messages.coffee +12 -11
- data/app/assets/stylesheets/chat/avatar_grid.sass +40 -0
- data/app/assets/stylesheets/chat/chat.sass +9 -4
- data/app/assets/stylesheets/chat/checkbox.sass +3 -3
- data/app/assets/stylesheets/chat/emojionearea.min.css +1 -1
- data/app/assets/stylesheets/chat/header.sass +25 -8
- data/app/assets/stylesheets/chat/launch.sass +39 -3
- data/app/assets/stylesheets/chat/list.sass +56 -23
- data/app/assets/stylesheets/chat/message_form.sass +7 -4
- data/app/assets/stylesheets/chat/new.sass +27 -22
- data/app/assets/stylesheets/chat/transcript.sass +60 -64
- data/app/channels/chat/messages_channel.rb +3 -2
- data/app/channels/chat/notification_channel.rb +2 -0
- data/app/channels/chat/status_channel.rb +12 -10
- data/app/controllers/chat/application_controller.rb +5 -1
- data/app/controllers/chat/conversations_controller.rb +24 -2
- data/app/controllers/chat/messages_controller.rb +8 -2
- data/app/helpers/chat/application_helper.rb +35 -24
- data/app/jobs/chat/application_job.rb +9 -1
- data/app/jobs/chat/message_relay_job.rb +5 -13
- data/app/jobs/chat/notification_relay_job.rb +10 -4
- data/app/jobs/chat/status_relay_job.rb +3 -3
- data/app/mailers/chat/application_mailer.rb +2 -0
- data/app/models/chat/application_record.rb +2 -0
- data/app/models/chat/conversation.rb +12 -0
- data/app/models/chat/dot_command.rb +2 -0
- data/app/models/chat/dot_command/gif.rb +2 -0
- data/app/models/chat/dot_command/shrug.rb +3 -1
- data/app/models/chat/dot_command/validator.rb +3 -1
- data/app/models/chat/message.rb +10 -2
- data/app/models/chat/session.rb +3 -3
- data/app/views/chat/_chat.html.haml +10 -6
- data/app/views/chat/conversations/_conversation.html.haml +23 -0
- data/app/views/chat/conversations/_index.html.haml +1 -6
- data/app/views/chat/conversations/_new.html.haml +2 -4
- data/app/views/chat/conversations/_show.html.haml +8 -7
- data/app/views/chat/conversations/create.js.erb +14 -10
- data/app/views/chat/conversations/show.js.erb +8 -5
- data/app/views/chat/messages/_message.haml +9 -12
- data/config/routes.rb +4 -2
- data/lib/chat.rb +5 -1
- data/lib/chat/engine.rb +2 -0
- data/lib/chat/user.rb +7 -12
- data/lib/chat/version.rb +3 -1
- data/lib/generators/chat/install/install_generator.rb +2 -0
- data/lib/generators/chat/install/templates/add_chat_to_users.rb +3 -1
- data/lib/generators/chat/install/templates/chat.rb +2 -0
- data/lib/generators/chat/install/templates/create_chat.rb +19 -7
- data/lib/tasks/chat_tasks.rake +1 -0
- metadata +15 -48
- data/app/models/chat/dot_command/leave.rb +0 -16
@@ -1,7 +1,7 @@
|
|
1
|
-
@import "https://fonts.googleapis.com/css?family=Lato:300
|
1
|
+
@import "https://fonts.googleapis.com/css?family=Lato:300,400,700,900"
|
2
2
|
|
3
3
|
#chat .new_message
|
4
|
-
margin: 0px
|
4
|
+
margin: 0px 20px 25px 20px
|
5
5
|
flex-direction: column
|
6
6
|
display: flex
|
7
7
|
position: relative
|
@@ -15,7 +15,7 @@
|
|
15
15
|
cursor: pointer
|
16
16
|
font-size: 22px
|
17
17
|
&:hover
|
18
|
-
color: #
|
18
|
+
color: #fff
|
19
19
|
input[type='text'], textarea
|
20
20
|
font-size: 17px
|
21
21
|
font-family: "Lato" !important
|
@@ -35,7 +35,7 @@
|
|
35
35
|
width: 0
|
36
36
|
bottom: 0px
|
37
37
|
position: absolute
|
38
|
-
background: #
|
38
|
+
background: #fff
|
39
39
|
transition: 0.2s ease all
|
40
40
|
-moz-transition: 0.2s ease all
|
41
41
|
-webkit-transition: 0.2s ease all
|
@@ -48,3 +48,6 @@
|
|
48
48
|
width: 50%
|
49
49
|
input[type='file']
|
50
50
|
display: none !important
|
51
|
+
.emojionearea .emojionearea-editor
|
52
|
+
border-bottom: 1px solid #bdbdbd !important
|
53
|
+
color: #fff !important
|
@@ -1,52 +1,57 @@
|
|
1
|
-
@import "https://fonts.googleapis.com/css?family=Lato:300
|
1
|
+
@import "https://fonts.googleapis.com/css?family=Lato:300,400,700,900"
|
2
2
|
|
3
3
|
#chat .new_conversation
|
4
|
-
height: calc(100% -
|
5
|
-
|
4
|
+
height: calc(100% - 50px)
|
5
|
+
overflow-y: scroll
|
6
|
+
position: absolute
|
7
|
+
right: 100%
|
8
|
+
transition: 0.5s
|
9
|
+
width: 100%
|
10
|
+
z-index: 13
|
11
|
+
display: flex
|
6
12
|
flex-direction: column
|
7
|
-
|
8
|
-
|
9
|
-
display: flex
|
10
|
-
flex-direction: column
|
11
|
-
height: calc(100% - 48px)
|
12
|
-
overflow-y: auto
|
13
|
-
&::-webkit-scrollbar
|
14
|
-
display: none
|
13
|
+
&::-webkit-scrollbar
|
14
|
+
visibility: hidden
|
15
15
|
label
|
16
16
|
position: relative
|
17
17
|
margin: 1rem
|
18
|
-
line-height: 135%
|
19
18
|
cursor: pointer
|
20
|
-
font-size: 18px
|
21
19
|
font-family: "Lato" !important
|
22
20
|
letter-spacing: 1.5px !important
|
23
21
|
padding-left: 40px
|
22
|
+
color: #fff
|
23
|
+
width: calc(100% - 40px - 1rem)
|
24
24
|
.chat__status
|
25
25
|
&:after
|
26
26
|
content: "\2022"
|
27
27
|
&.offline
|
28
28
|
&:after
|
29
|
-
color:
|
29
|
+
color: hsl(355, 65%, 65%)
|
30
30
|
&.online
|
31
31
|
&:after
|
32
32
|
color: #AED581
|
33
33
|
|
34
|
+
.chat__submit-container
|
35
|
+
margin: 1rem
|
36
|
+
padding: 10px 0
|
37
|
+
width: calc(100% - 1rem)
|
38
|
+
display: flex
|
39
|
+
flex-direction: column
|
40
|
+
justify-content: center
|
41
|
+
align-items: center
|
42
|
+
|
34
43
|
input[type='submit']
|
35
|
-
border
|
36
|
-
border-left: none
|
37
|
-
border-bottom: none
|
38
|
-
border-right: none
|
44
|
+
border: none
|
39
45
|
font-family: "Lato" !important
|
40
46
|
letter-spacing: 1.5px !important
|
41
47
|
font-size: 17px
|
42
48
|
background: transparent
|
43
|
-
|
44
|
-
padding: 10px 0 10px 0
|
49
|
+
padding: 0
|
45
50
|
cursor: pointer
|
46
51
|
transition: all 0.3s ease
|
47
52
|
z-index: 10
|
48
|
-
|
49
|
-
|
53
|
+
color: #fff
|
54
|
+
margin: 0px
|
50
55
|
|
51
56
|
#chat .chat__errors
|
52
57
|
text-align: center
|
@@ -1,76 +1,72 @@
|
|
1
1
|
#chat .current_chat
|
2
|
-
|
2
|
+
display: flex
|
3
3
|
flex-direction: column
|
4
|
+
overflow-y: scroll
|
5
|
+
position: absolute
|
6
|
+
width: 100%
|
7
|
+
height: calc(100% - 50px)
|
8
|
+
left: 100%
|
9
|
+
opacity: 1
|
10
|
+
transition: 0.5s
|
11
|
+
z-index: 13
|
12
|
+
&::-webkit-scrollbar
|
13
|
+
visibility: hidden
|
4
14
|
img.chat__user-avatar
|
5
15
|
width: 50px
|
6
16
|
height: 50px
|
7
17
|
object-fit: cover
|
8
18
|
border-radius: 50%
|
19
|
+
.transcript_placeholder_avatar
|
20
|
+
width: 50px
|
21
|
+
height: 50px
|
9
22
|
i.chat__user-avatar
|
10
23
|
font-size: 50px
|
11
24
|
.chat__transcript
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
display:
|
16
|
-
|
17
|
-
width: 100%
|
18
|
-
padding-top: 10px
|
19
|
-
padding-bottom: 10px
|
20
|
-
img
|
21
|
-
width: 100%
|
22
|
-
border-bottom: 4px solid #C8E6C9
|
23
|
-
&.current img
|
24
|
-
border-bottom: 4px solid #B2EBF2
|
25
|
-
.chat__message
|
26
|
-
padding: 10px
|
27
|
-
display: flex
|
28
|
-
flex-direction: row
|
29
|
-
img
|
30
|
-
font-size: inherit
|
31
|
-
height: 2ex
|
32
|
-
width: 2.1ex
|
33
|
-
min-height: 20px
|
34
|
-
min-width: 20px
|
35
|
-
display: inline-block
|
36
|
-
margin: -.2ex .15em .2ex
|
37
|
-
line-height: normal
|
38
|
-
vertical-align: middle
|
39
|
-
max-width: 100%
|
40
|
-
top: 0
|
41
|
-
.text
|
42
|
-
padding: 5px
|
43
|
-
flex: 1
|
44
|
-
position: relative
|
25
|
+
margin-left: 25px
|
26
|
+
margin-right: 25px
|
27
|
+
.message-container
|
28
|
+
display: flex
|
29
|
+
flex-direction: row
|
45
30
|
&.right
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
background: #C8E6C9
|
65
|
-
border: none
|
66
|
-
&:after
|
67
|
-
content: ""
|
68
|
-
position: absolute
|
69
|
-
border-style: solid
|
70
|
-
border-width: 0px 15px 13px 0px
|
71
|
-
border-color: transparent #C8E6C9
|
31
|
+
text-align: right
|
32
|
+
flex-direction: row-reverse
|
33
|
+
.message
|
34
|
+
flex-direction: row-reverse
|
35
|
+
.content
|
36
|
+
border-top-right-radius: 0 !important
|
37
|
+
border-top-left-radius: 10px !important
|
38
|
+
&.image img
|
39
|
+
border-top-right-radius: 0 !important
|
40
|
+
border-top-left-radius: 10px !important
|
41
|
+
.message
|
42
|
+
min-height: 50px
|
43
|
+
display: flex
|
44
|
+
margin: 0 10px 5px 10px
|
45
|
+
flex: 1
|
46
|
+
flex-direction: row
|
47
|
+
max-width: 100%
|
48
|
+
&.image
|
72
49
|
display: block
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
50
|
+
img
|
51
|
+
max-width: 100%
|
52
|
+
border-radius: 10px
|
53
|
+
border-top-left-radius: 0
|
54
|
+
.content
|
55
|
+
background: #fff
|
56
|
+
padding: 10px
|
57
|
+
border-radius: 10px
|
58
|
+
color: #212121
|
59
|
+
border-top-left-radius: 0
|
60
|
+
word-break: break-all
|
61
|
+
img
|
62
|
+
font-size: inherit
|
63
|
+
height: 2ex
|
64
|
+
width: 2.1ex
|
65
|
+
min-height: 20px
|
66
|
+
min-width: 20px
|
67
|
+
display: inline-block
|
68
|
+
margin: -.2ex .15em .2ex
|
69
|
+
line-height: normal
|
70
|
+
vertical-align: middle
|
71
|
+
max-width: 100%
|
72
|
+
top: 0
|
@@ -1,11 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Chat::MessagesChannel < ApplicationCable::Channel
|
2
4
|
def follow(data)
|
3
5
|
stop_all_streams
|
4
6
|
stream_from "chats::#{data['chat_id']}::messages"
|
5
7
|
end
|
6
8
|
|
7
|
-
def
|
9
|
+
def unsubscribed
|
8
10
|
stop_all_streams
|
9
11
|
end
|
10
|
-
alias unsubscribed unfollow
|
11
12
|
end
|
@@ -1,12 +1,14 @@
|
|
1
|
-
|
2
|
-
def online
|
3
|
-
stop_all_streams
|
4
|
-
stream_from "chat::status"
|
5
|
-
current_user.online
|
6
|
-
end
|
1
|
+
# frozen_string_literal: true
|
7
2
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
3
|
+
class Chat::StatusChannel < ApplicationCable::Channel
|
4
|
+
def online
|
5
|
+
stop_all_streams
|
6
|
+
stream_from "chat::status"
|
7
|
+
current_user.online
|
12
8
|
end
|
9
|
+
|
10
|
+
def unsubscribed
|
11
|
+
current_user.offline
|
12
|
+
stop_all_streams
|
13
|
+
end
|
14
|
+
end
|
@@ -1,6 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Chat
|
2
4
|
class ConversationsController < ApplicationController
|
3
|
-
before_action Chat.logged_in_check
|
4
5
|
before_action :set_conversation, only: :show
|
5
6
|
|
6
7
|
def show
|
@@ -8,6 +9,14 @@ module Chat
|
|
8
9
|
|
9
10
|
def create
|
10
11
|
@conversation = Chat::Conversation.create(conversation_params)
|
12
|
+
|
13
|
+
if @conversation.persisted? ||
|
14
|
+
@conversation.errors.messages[:sessions].present?
|
15
|
+
render template: :create
|
16
|
+
else
|
17
|
+
@conversation = find_existing_conversation
|
18
|
+
render template: "chat/conversations/show"
|
19
|
+
end
|
11
20
|
end
|
12
21
|
|
13
22
|
private
|
@@ -20,11 +29,24 @@ module Chat
|
|
20
29
|
|
21
30
|
def conversation_params
|
22
31
|
chat_params = params.require(:conversation).permit(user_ids: [])
|
23
|
-
if chat_params[:user_ids].reject(&:blank?).present?
|
32
|
+
if chat_params[:user_ids].reject!(&:blank?).present?
|
24
33
|
chat_params[:user_ids] << current_user.id
|
34
|
+
chat_params[:user_ids].map!(&:to_i)
|
25
35
|
end
|
26
36
|
|
27
37
|
chat_params
|
28
38
|
end
|
39
|
+
|
40
|
+
def find_existing_conversation
|
41
|
+
Chat::Conversation.includes(
|
42
|
+
:users, messages: :user
|
43
|
+
).find(
|
44
|
+
Chat::Conversation.joins(:users).having(
|
45
|
+
"COUNT(DISTINCT users.id) = ?", conversation_params[:user_ids].count
|
46
|
+
).group(:id).find_by(
|
47
|
+
users: { id: conversation_params[:user_ids] }
|
48
|
+
).id
|
49
|
+
)
|
50
|
+
end
|
29
51
|
end
|
30
52
|
end
|
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Chat
|
2
4
|
class MessagesController < ApplicationController
|
3
|
-
before_action Chat.logged_in_check
|
4
5
|
before_action :set_conversation
|
6
|
+
before_action :set_session
|
5
7
|
|
6
8
|
def create
|
7
9
|
@conversation.messages.create(message_params)
|
@@ -19,9 +21,13 @@ module Chat
|
|
19
21
|
@conversation = Chat::Conversation.find(params[:conversation_id])
|
20
22
|
end
|
21
23
|
|
24
|
+
def set_session
|
25
|
+
@session = @conversation.sessions.find_by(user: current_user)
|
26
|
+
end
|
27
|
+
|
22
28
|
def message_params
|
23
29
|
params.require(:message).permit(:text, :image).merge(
|
24
|
-
user_id: current_user.id
|
30
|
+
user_id: current_user.id, session_id: @session.id
|
25
31
|
)
|
26
32
|
end
|
27
33
|
end
|
@@ -1,18 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Chat
|
2
4
|
module ApplicationHelper
|
3
|
-
def render_chat
|
5
|
+
def render_chat
|
4
6
|
return unless send Chat.signed_in
|
5
7
|
|
6
|
-
render "chat/chat"
|
8
|
+
render "chat/chat"
|
7
9
|
end
|
8
10
|
|
9
|
-
def launch_chat_fab
|
11
|
+
def launch_chat_fab
|
10
12
|
attrs = {
|
11
|
-
class: "chat__launch",
|
12
|
-
data: { "current-user" => current_user.id }
|
13
|
+
class: "chat__launch", data: { "current-user" => current_user.id }
|
13
14
|
}
|
14
15
|
button_tag(attrs) do
|
15
|
-
material_icon.forum.css_class("md
|
16
|
+
material_icon.forum.css_class("md-dark").to_s.html_safe
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
@@ -32,31 +33,41 @@ module Chat
|
|
32
33
|
end
|
33
34
|
|
34
35
|
def chat_avatar(user)
|
35
|
-
if user.
|
36
|
-
image_tag(user.
|
36
|
+
if user.chat_avatar?
|
37
|
+
image_tag(user.chat_avatar, class: "chat__user-avatar")
|
37
38
|
else
|
38
39
|
MaterialIcon.new.css_class("chat__user-avatar").person
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
42
43
|
def chat_list
|
43
|
-
@chat_list ||=
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
private
|
52
|
-
|
53
|
-
def group_concat
|
54
|
-
if ActiveRecord::Base.connection.adapter_name == "SQLite"
|
55
|
-
"GROUP_CONCAT(users.#{::User.first_name} || ' ' || users.#{::User.last_name}, ', ') as names"
|
56
|
-
elsif ActiveRecord::Base.connection.adapter_name == "MySQL"
|
57
|
-
"GROUP_CONCAT(CONCAT(\"users.#{User.first_name}\",\" \", \"users.#{User.last_name}\") "\
|
58
|
-
"SEPARATOR ', ') as names"
|
44
|
+
@chat_list ||= current_user.conversations.includes(:users).order(
|
45
|
+
"chat_conversations.created_at desc"
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
def chat_avatars(conversation)
|
50
|
+
(conversation.users - [current_user]).first(2).map do |u|
|
51
|
+
chat_avatar(u)
|
59
52
|
end
|
60
53
|
end
|
54
|
+
|
55
|
+
def chat_avatar_count(conversation)
|
56
|
+
if (count = conversation_user_count(conversation)) <= 2
|
57
|
+
"count_#{count}"
|
58
|
+
else
|
59
|
+
"count_default"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def conversation_user_count(conversation)
|
64
|
+
conversation.users.to_a.size - 1
|
65
|
+
end
|
66
|
+
|
67
|
+
def message_classes(message)
|
68
|
+
css_class = message.user == current_user ? "right" : "left"
|
69
|
+
css_class += message.image? ? " image" : ""
|
70
|
+
css_class
|
71
|
+
end
|
61
72
|
end
|
62
73
|
end
|