Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
AloqaIM-Android
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
AloqaIM-Android
Commits
4e3936ca
Unverified
Commit
4e3936ca
authored
Aug 29, 2018
by
Filipe de Lima Brito
Committed by
GitHub
Aug 29, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'develop' into new/google-analytics-for-firebase
parents
8ce5d9d3
9e631abd
Changes
44
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
44 changed files
with
958 additions
and
163 deletions
+958
-163
build.gradle
app/build.gradle
+2
-0
RocketChatApplication.kt
...ain/java/chat/rocket/android/app/RocketChatApplication.kt
+0
-2
ActionsAttachmentViewHolder.kt
...t/android/chatroom/adapter/ActionsAttachmentViewHolder.kt
+43
-0
ActionsListAdapter.kt
...hat/rocket/android/chatroom/adapter/ActionsListAdapter.kt
+73
-0
ChatRoomAdapter.kt
...a/chat/rocket/android/chatroom/adapter/ChatRoomAdapter.kt
+39
-3
MessageViewHolder.kt
...chat/rocket/android/chatroom/adapter/MessageViewHolder.kt
+39
-13
ChatRoomView.kt
...chat/rocket/android/chatroom/presentation/ChatRoomView.kt
+0
-5
ChatRoomFragment.kt
.../java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
+37
-11
ActionsAttachmentUiModel.kt
...cket/android/chatroom/uimodel/ActionsAttachmentUiModel.kt
+29
-0
BaseUiModel.kt
.../java/chat/rocket/android/chatroom/uimodel/BaseUiModel.kt
+2
-1
UiModelMapper.kt
...ava/chat/rocket/android/chatroom/uimodel/UiModelMapper.kt
+18
-1
MessageParser.kt
...src/main/java/chat/rocket/android/helper/MessageParser.kt
+21
-8
MainPresenter.kt
...va/chat/rocket/android/main/presentation/MainPresenter.kt
+38
-0
MainActivity.kt
...src/main/java/chat/rocket/android/main/ui/MainActivity.kt
+1
-0
Text.kt
...src/main/java/chat/rocket/android/util/extensions/Text.kt
+3
-2
item_action_button.xml
app/src/main/res/layout/item_action_button.xml
+29
-0
item_actions_attachment.xml
app/src/main/res/layout/item_actions_attachment.xml
+57
-0
dimens.xml
app/src/main/res/values/dimens.xml
+1
-0
build.gradle
build.gradle
+1
-1
dependencies.gradle
dependencies.gradle
+4
-1
build.gradle
emoji/build.gradle
+10
-0
proguard-rules.pro
emoji/proguard-rules.pro
+9
-0
ComposerEditText.kt
...c/main/java/chat/rocket/android/emoji/ComposerEditText.kt
+22
-3
Emoji.kt
emoji/src/main/java/chat/rocket/android/emoji/Emoji.kt
+17
-9
EmojiDao.kt
emoji/src/main/java/chat/rocket/android/emoji/EmojiDao.kt
+45
-0
EmojiKeyboardPopup.kt
...main/java/chat/rocket/android/emoji/EmojiKeyboardPopup.kt
+15
-9
EmojiParser.kt
emoji/src/main/java/chat/rocket/android/emoji/EmojiParser.kt
+78
-8
EmojiPickerPopup.kt
...c/main/java/chat/rocket/android/emoji/EmojiPickerPopup.kt
+7
-3
EmojiRepository.kt
...rc/main/java/chat/rocket/android/emoji/EmojiRepository.kt
+150
-61
EmojiCategory.kt
.../java/chat/rocket/android/emoji/internal/EmojiCategory.kt
+7
-2
EmojiGlideModule.kt
...va/chat/rocket/android/emoji/internal/EmojiGlideModule.kt
+15
-0
EmojiPagerAdapter.kt
...a/chat/rocket/android/emoji/internal/EmojiPagerAdapter.kt
+58
-17
Extensions.kt
...ain/java/chat/rocket/android/emoji/internal/Extensions.kt
+5
-0
EmojiDatabase.kt
...va/chat/rocket/android/emoji/internal/db/EmojiDatabase.kt
+48
-0
StringListConverter.kt
...t/rocket/android/emoji/internal/db/StringListConverter.kt
+16
-0
ic_emoji_custom.png
emoji/src/main/res/drawable-hdpi/ic_emoji_custom.png
+0
-0
ic_emoji_custom.png
emoji/src/main/res/drawable-mdpi/ic_emoji_custom.png
+0
-0
ic_emoji_custom.png
emoji/src/main/res/drawable-xhdpi/ic_emoji_custom.png
+0
-0
ic_emoji_custom.png
emoji/src/main/res/drawable-xxhdpi/ic_emoji_custom.png
+0
-0
ic_emoji_custom.png
emoji/src/main/res/drawable-xxxhdpi/ic_emoji_custom.png
+0
-0
emoji_image_row_item.xml
emoji/src/main/res/layout/emoji_image_row_item.xml
+14
-0
emoji_row_item.xml
emoji/src/main/res/layout/emoji_row_item.xml
+1
-0
dimens.xml
emoji/src/main/res/values/dimens.xml
+3
-2
gradle-wrapper.properties
gradle/wrapper/gradle-wrapper.properties
+1
-1
No files found.
app/build.gradle
View file @
4e3936ca
...
@@ -134,6 +134,8 @@ dependencies {
...
@@ -134,6 +134,8 @@ dependencies {
implementation
libraries
.
frescoWebP
implementation
libraries
.
frescoWebP
implementation
libraries
.
frescoAnimatedWebP
implementation
libraries
.
frescoAnimatedWebP
implementation
libraries
.
glide
kapt
libraries
.
kotshiCompiler
kapt
libraries
.
kotshiCompiler
implementation
libraries
.
kotshiApi
implementation
libraries
.
kotshiApi
...
...
app/src/main/java/chat/rocket/android/app/RocketChatApplication.kt
View file @
4e3936ca
...
@@ -18,7 +18,6 @@ import chat.rocket.android.server.domain.GetCurrentServerInteractor
...
@@ -18,7 +18,6 @@ import chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.domain.GetSettingsInteractor
import
chat.rocket.android.server.domain.GetSettingsInteractor
import
chat.rocket.android.server.domain.SITE_URL
import
chat.rocket.android.server.domain.SITE_URL
import
chat.rocket.android.server.domain.TokenRepository
import
chat.rocket.android.server.domain.TokenRepository
import
chat.rocket.android.emoji.EmojiRepository
import
chat.rocket.android.util.setupFabric
import
chat.rocket.android.util.setupFabric
import
com.facebook.drawee.backends.pipeline.DraweeConfig
import
com.facebook.drawee.backends.pipeline.DraweeConfig
import
com.facebook.drawee.backends.pipeline.Fresco
import
com.facebook.drawee.backends.pipeline.Fresco
...
@@ -84,7 +83,6 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje
...
@@ -84,7 +83,6 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje
context
=
WeakReference
(
applicationContext
)
context
=
WeakReference
(
applicationContext
)
AndroidThreeTen
.
init
(
this
)
AndroidThreeTen
.
init
(
this
)
EmojiRepository
.
load
(
this
)
setupFabric
(
this
)
setupFabric
(
this
)
setupFresco
()
setupFresco
()
...
...
app/src/main/java/chat/rocket/android/chatroom/adapter/ActionsAttachmentViewHolder.kt
0 → 100644
View file @
4e3936ca
package
chat.rocket.android.chatroom.adapter
import
android.view.View
import
chat.rocket.android.chatroom.uimodel.ActionsAttachmentUiModel
import
chat.rocket.android.emoji.EmojiReactionListener
import
chat.rocket.core.model.attachment.actions.Action
import
chat.rocket.core.model.attachment.actions.ButtonAction
import
kotlinx.android.synthetic.main.item_actions_attachment.view.*
import
androidx.recyclerview.widget.LinearLayoutManager
import
timber.log.Timber
class
ActionsAttachmentViewHolder
(
itemView
:
View
,
listener
:
ActionsListener
,
reactionListener
:
EmojiReactionListener
?
=
null
,
var
actionAttachmentOnClickListener
:
ActionAttachmentOnClickListener
)
:
BaseViewHolder
<
ActionsAttachmentUiModel
>(
itemView
,
listener
,
reactionListener
)
{
init
{
with
(
itemView
)
{
setupActionMenu
(
actions_attachment_container
)
}
}
override
fun
bindViews
(
data
:
ActionsAttachmentUiModel
)
{
val
actions
=
data
.
actions
val
alignment
=
data
.
buttonAlignment
Timber
.
d
(
"no of actions : ${actions.size} : $actions"
)
with
(
itemView
)
{
title
.
text
=
data
.
title
?:
""
actions_list
.
layoutManager
=
LinearLayoutManager
(
itemView
.
context
,
when
(
alignment
)
{
"horizontal"
->
LinearLayoutManager
.
HORIZONTAL
else
->
LinearLayoutManager
.
VERTICAL
//Default
},
false
)
actions_list
.
adapter
=
ActionsListAdapter
(
actions
,
actionAttachmentOnClickListener
)
}
}
}
interface
ActionAttachmentOnClickListener
{
fun
onActionClicked
(
view
:
View
,
action
:
Action
)
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/adapter/ActionsListAdapter.kt
0 → 100644
View file @
4e3936ca
package
chat.rocket.android.chatroom.adapter
import
android.view.View
import
android.view.ViewGroup
import
androidx.core.view.isVisible
import
androidx.recyclerview.widget.RecyclerView
import
chat.rocket.android.R
import
chat.rocket.android.util.extensions.inflate
import
chat.rocket.core.model.attachment.actions.Action
import
chat.rocket.core.model.attachment.actions.ButtonAction
import
com.facebook.drawee.backends.pipeline.Fresco
import
kotlinx.android.synthetic.main.item_action_button.view.*
import
timber.log.Timber
class
ActionsListAdapter
(
actions
:
List
<
Action
>,
var
actionAttachmentOnClickListener
:
ActionAttachmentOnClickListener
)
:
RecyclerView
.
Adapter
<
ActionsListAdapter
.
ViewHolder
>()
{
var
actions
:
List
<
Action
>
=
actions
inner
class
ViewHolder
(
var
layout
:
View
)
:
RecyclerView
.
ViewHolder
(
layout
)
{
lateinit
var
action
:
ButtonAction
private
val
onClickListener
=
View
.
OnClickListener
{
actionAttachmentOnClickListener
.
onActionClicked
(
it
,
action
)
}
init
{
with
(
itemView
)
{
action_button
.
setOnClickListener
(
onClickListener
)
action_image_button
.
setOnClickListener
(
onClickListener
)
}
}
fun
bindAction
(
action
:
Action
)
{
with
(
itemView
)
{
Timber
.
d
(
"action : $action"
)
this
@ViewHolder
.
action
=
action
as
ButtonAction
if
(
action
.
imageUrl
!=
null
)
{
action_button
.
isVisible
=
false
action_image_button
.
isVisible
=
true
//Image button
val
controller
=
Fresco
.
newDraweeControllerBuilder
().
apply
{
setUri
(
action
.
imageUrl
)
autoPlayAnimations
=
true
oldController
=
action_image_button
.
controller
}.
build
()
action_image_button
.
controller
=
controller
}
else
if
(
action
.
text
!=
null
)
{
action_button
.
isVisible
=
true
action_image_button
.
isVisible
=
false
this
.
action_button
.
setText
(
action
.
text
)
}
}
}
}
override
fun
onCreateViewHolder
(
parent
:
ViewGroup
,
viewType
:
Int
):
ViewHolder
{
val
view
=
parent
.
inflate
(
R
.
layout
.
item_action_button
)
return
ViewHolder
(
view
)
}
override
fun
getItemCount
():
Int
{
return
actions
.
size
}
override
fun
onBindViewHolder
(
holder
:
ViewHolder
,
position
:
Int
)
{
val
action
=
actions
[
position
]
holder
.
bindAction
(
action
)
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/adapter/ChatRoomAdapter.kt
View file @
4e3936ca
package
chat.rocket.android.chatroom.adapter
package
chat.rocket.android.chatroom.adapter
import
android.app.AlertDialog
import
android.content.Context
import
androidx.recyclerview.widget.RecyclerView
import
androidx.recyclerview.widget.RecyclerView
import
android.view.MenuItem
import
android.view.MenuItem
import
android.view.View
import
android.view.ViewGroup
import
android.view.ViewGroup
import
chat.rocket.android.R
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.presentation.ChatRoomPresenter
import
chat.rocket.android.chatroom.uimodel.*
import
chat.rocket.android.chatroom.uimodel.*
import
chat.rocket.android.util.extensions.inflate
import
chat.rocket.android.util.extensions.inflate
import
chat.rocket.android.emoji.EmojiReactionListener
import
chat.rocket.android.emoji.EmojiReactionListener
import
chat.rocket.android.util.extensions.openTabbedUrl
import
chat.rocket.core.model.attachment.actions.Action
import
chat.rocket.core.model.attachment.actions.ButtonAction
import
chat.rocket.core.model.Message
import
chat.rocket.core.model.Message
import
chat.rocket.core.model.isSystemMessage
import
chat.rocket.core.model.isSystemMessage
import
timber.log.Timber
import
timber.log.Timber
import
java.security.InvalidParameterException
import
java.security.InvalidParameterException
class
ChatRoomAdapter
(
class
ChatRoomAdapter
(
private
val
roomId
:
String
?
=
null
,
private
val
roomType
:
String
?
=
null
,
private
val
roomType
:
String
?
=
null
,
private
val
roomName
:
String
?
=
null
,
private
val
roomName
:
String
?
=
null
,
private
val
actionSelectListener
:
OnActionSelected
?
=
null
,
private
val
actionSelectListener
:
OnActionSelected
?
=
null
,
...
@@ -72,6 +74,10 @@ class ChatRoomAdapter(
...
@@ -72,6 +74,10 @@ class ChatRoomAdapter(
actionSelectListener
?.
openDirectMessage
(
roomName
,
permalink
)
actionSelectListener
?.
openDirectMessage
(
roomName
,
permalink
)
}
}
}
}
BaseUiModel
.
ViewType
.
ACTIONS_ATTACHMENT
->
{
val
view
=
parent
.
inflate
(
R
.
layout
.
item_actions_attachment
)
ActionsAttachmentViewHolder
(
view
,
actionsListener
,
reactionListener
,
actionAttachmentOnClickListener
)
}
else
->
{
else
->
{
throw
InvalidParameterException
(
"TODO - implement for ${viewType.toViewType()}"
)
throw
InvalidParameterException
(
"TODO - implement for ${viewType.toViewType()}"
)
}
}
...
@@ -125,6 +131,8 @@ class ChatRoomAdapter(
...
@@ -125,6 +131,8 @@ class ChatRoomAdapter(
holder
.
bind
(
dataSet
[
position
]
as
GenericFileAttachmentUiModel
)
holder
.
bind
(
dataSet
[
position
]
as
GenericFileAttachmentUiModel
)
is
MessageReplyViewHolder
->
is
MessageReplyViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
MessageReplyUiModel
)
holder
.
bind
(
dataSet
[
position
]
as
MessageReplyUiModel
)
is
ActionsAttachmentViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
ActionsAttachmentUiModel
)
}
}
}
}
...
@@ -203,6 +211,33 @@ class ChatRoomAdapter(
...
@@ -203,6 +211,33 @@ class ChatRoomAdapter(
}
}
}
}
private
val
actionAttachmentOnClickListener
=
object
:
ActionAttachmentOnClickListener
{
override
fun
onActionClicked
(
view
:
View
,
action
:
Action
)
{
val
temp
=
action
as
ButtonAction
if
(
temp
.
url
!=
null
&&
temp
.
isWebView
!=
null
)
{
if
(
temp
.
isWebView
==
true
)
{
//TODO: Open in a configurable sizable webview
Timber
.
d
(
"Open in a configurable sizable webview"
)
}
else
{
//Open in chrome custom tab
temp
.
url
?.
let
{
view
.
openTabbedUrl
(
it
)
}
}
}
else
if
(
temp
.
message
!=
null
&&
temp
.
isMessageInChatWindow
!=
null
)
{
if
(
temp
.
isMessageInChatWindow
==
true
)
{
//Send to chat window
temp
.
message
?.
let
{
if
(
roomId
!=
null
)
{
actionSelectListener
?.
sendMessage
(
roomId
,
it
)
}
}
}
else
{
//TODO: Send to bot but not in chat window
Timber
.
d
(
"Send to bot but not in chat window"
)
}
}
}
}
private
val
actionsListener
=
object
:
BaseViewHolder
.
ActionsListener
{
private
val
actionsListener
=
object
:
BaseViewHolder
.
ActionsListener
{
override
fun
isActionsEnabled
():
Boolean
=
enableActions
override
fun
isActionsEnabled
():
Boolean
=
enableActions
...
@@ -259,5 +294,6 @@ class ChatRoomAdapter(
...
@@ -259,5 +294,6 @@ class ChatRoomAdapter(
fun
deleteMessage
(
roomId
:
String
,
id
:
String
)
fun
deleteMessage
(
roomId
:
String
,
id
:
String
)
fun
showReactions
(
id
:
String
)
fun
showReactions
(
id
:
String
)
fun
openDirectMessage
(
roomName
:
String
,
message
:
String
)
fun
openDirectMessage
(
roomName
:
String
,
message
:
String
)
fun
sendMessage
(
chatRoomId
:
String
,
text
:
String
)
}
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/adapter/MessageViewHolder.kt
View file @
4e3936ca
package
chat.rocket.android.chatroom.adapter
package
chat.rocket.android.chatroom.adapter
import
android.graphics.Color
import
android.graphics.Color
import
android.graphics.drawable.Drawable
import
android.text.Spannable
import
android.text.method.LinkMovementMethod
import
android.text.method.LinkMovementMethod
import
android.text.style.ImageSpan
import
android.view.View
import
android.view.View
import
androidx.core.view.isVisible
import
androidx.core.view.isVisible
import
chat.rocket.android.R
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.uimodel.MessageUiModel
import
chat.rocket.android.chatroom.uimodel.MessageUiModel
import
chat.rocket.android.emoji.EmojiReactionListener
import
chat.rocket.android.emoji.EmojiReactionListener
import
chat.rocket.core.model.isSystemMessage
import
chat.rocket.core.model.isSystemMessage
import
com.bumptech.glide.load.resource.gif.GifDrawable
import
kotlinx.android.synthetic.main.avatar.view.*
import
kotlinx.android.synthetic.main.avatar.view.*
import
kotlinx.android.synthetic.main.item_message.view.*
import
kotlinx.android.synthetic.main.item_message.view.*
...
@@ -15,7 +19,7 @@ class MessageViewHolder(
...
@@ -15,7 +19,7 @@ class MessageViewHolder(
itemView
:
View
,
itemView
:
View
,
listener
:
ActionsListener
,
listener
:
ActionsListener
,
reactionListener
:
EmojiReactionListener
?
=
null
reactionListener
:
EmojiReactionListener
?
=
null
)
:
BaseViewHolder
<
MessageUiModel
>(
itemView
,
listener
,
reactionListener
)
{
)
:
BaseViewHolder
<
MessageUiModel
>(
itemView
,
listener
,
reactionListener
)
,
Drawable
.
Callback
{
init
{
init
{
with
(
itemView
)
{
with
(
itemView
)
{
...
@@ -26,22 +30,26 @@ class MessageViewHolder(
...
@@ -26,22 +30,26 @@ class MessageViewHolder(
override
fun
bindViews
(
data
:
MessageUiModel
)
{
override
fun
bindViews
(
data
:
MessageUiModel
)
{
with
(
itemView
)
{
with
(
itemView
)
{
day_marker_layout
.
visibility
=
if
(
data
.
showDayMarker
)
{
day
.
text
=
data
.
currentDayMarkerText
day
.
text
=
data
.
currentDayMarkerText
View
.
VISIBLE
day_marker_layout
.
isVisible
=
data
.
showDayMarker
}
else
{
View
.
GONE
}
if
(
data
.
isFirstUnread
)
{
new_messages_notif
.
isVisible
=
data
.
isFirstUnread
new_messages_notif
.
visibility
=
View
.
VISIBLE
}
else
{
new_messages_notif
.
visibility
=
View
.
GONE
}
text_message_time
.
text
=
data
.
time
text_message_time
.
text
=
data
.
time
text_sender
.
text
=
data
.
senderName
text_sender
.
text
=
data
.
senderName
text_content
.
text
=
data
.
content
if
(
data
.
content
is
Spannable
)
{
val
spans
=
data
.
content
.
getSpans
(
0
,
data
.
content
.
length
,
ImageSpan
::
class
.
java
)
spans
.
forEach
{
if
(
it
.
drawable
is
GifDrawable
)
{
it
.
drawable
.
callback
=
this
@MessageViewHolder
(
it
.
drawable
as
GifDrawable
).
start
()
}
}
}
text_content
.
text_content
.
text
=
data
.
content
image_avatar
.
setImageURI
(
data
.
avatar
)
image_avatar
.
setImageURI
(
data
.
avatar
)
text_content
.
setTextColor
(
if
(
data
.
isTemporary
)
Color
.
GRAY
else
Color
.
BLACK
)
text_content
.
setTextColor
(
if
(
data
.
isTemporary
)
Color
.
GRAY
else
Color
.
BLACK
)
...
@@ -64,4 +72,22 @@ class MessageViewHolder(
...
@@ -64,4 +72,22 @@ class MessageViewHolder(
}
}
}
}
}
}
override
fun
unscheduleDrawable
(
who
:
Drawable
?,
what
:
Runnable
?)
{
with
(
itemView
)
{
text_content
.
removeCallbacks
(
what
)
}
}
override
fun
invalidateDrawable
(
p0
:
Drawable
?)
{
with
(
itemView
)
{
text_content
.
invalidate
()
}
}
override
fun
scheduleDrawable
(
who
:
Drawable
?,
what
:
Runnable
?,
w
:
Long
)
{
with
(
itemView
)
{
text_content
.
postDelayed
(
what
,
w
)
}
}
}
}
app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomView.kt
View file @
4e3936ca
...
@@ -148,9 +148,4 @@ interface ChatRoomView : LoadingView, MessageView {
...
@@ -148,9 +148,4 @@ interface ChatRoomView : LoadingView, MessageView {
*/
*/
fun
onRoomUpdated
(
userCanPost
:
Boolean
,
channelIsBroadcast
:
Boolean
,
userCanMod
:
Boolean
)
fun
onRoomUpdated
(
userCanPost
:
Boolean
,
channelIsBroadcast
:
Boolean
,
userCanMod
:
Boolean
)
/**
* Open a DM with the user in the given [chatRoom] and pass the [permalink] for the message
* to reply.
*/
fun
openDirectMessage
(
chatRoom
:
ChatRoom
,
permalink
:
String
)
}
}
app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
View file @
4e3936ca
...
@@ -6,9 +6,13 @@ import android.content.ClipData
...
@@ -6,9 +6,13 @@ import android.content.ClipData
import
android.content.ClipboardManager
import
android.content.ClipboardManager
import
android.content.Context
import
android.content.Context
import
android.content.Intent
import
android.content.Intent
import
android.graphics.drawable.Drawable
import
android.os.Bundle
import
android.os.Bundle
import
android.os.Handler
import
android.os.Handler
import
android.os.SystemClock
import
android.text.Spannable
import
android.text.SpannableStringBuilder
import
android.text.SpannableStringBuilder
import
android.text.style.ImageSpan
import
android.view.KeyEvent
import
android.view.KeyEvent
import
android.view.LayoutInflater
import
android.view.LayoutInflater
import
android.view.Menu
import
android.view.Menu
...
@@ -53,11 +57,13 @@ import chat.rocket.android.emoji.EmojiKeyboardPopup
...
@@ -53,11 +57,13 @@ import chat.rocket.android.emoji.EmojiKeyboardPopup
import
chat.rocket.android.emoji.EmojiParser
import
chat.rocket.android.emoji.EmojiParser
import
chat.rocket.android.emoji.EmojiPickerPopup
import
chat.rocket.android.emoji.EmojiPickerPopup
import
chat.rocket.android.emoji.EmojiReactionListener
import
chat.rocket.android.emoji.EmojiReactionListener
import
chat.rocket.android.emoji.internal.isCustom
import
chat.rocket.android.helper.EndlessRecyclerViewScrollListener
import
chat.rocket.android.helper.EndlessRecyclerViewScrollListener
import
chat.rocket.android.helper.ImageHelper
import
chat.rocket.android.helper.ImageHelper
import
chat.rocket.android.helper.KeyboardHelper
import
chat.rocket.android.helper.KeyboardHelper
import
chat.rocket.android.helper.MessageParser
import
chat.rocket.android.helper.MessageParser
import
chat.rocket.android.util.extension.asObservable
import
chat.rocket.android.util.extension.asObservable
import
chat.rocket.android.util.extension.launchUI
import
chat.rocket.android.util.extensions.circularRevealOrUnreveal
import
chat.rocket.android.util.extensions.circularRevealOrUnreveal
import
chat.rocket.android.util.extensions.fadeIn
import
chat.rocket.android.util.extensions.fadeIn
import
chat.rocket.android.util.extensions.fadeOut
import
chat.rocket.android.util.extensions.fadeOut
...
@@ -71,6 +77,7 @@ import chat.rocket.common.model.RoomType
...
@@ -71,6 +77,7 @@ import chat.rocket.common.model.RoomType
import
chat.rocket.common.model.roomTypeOf
import
chat.rocket.common.model.roomTypeOf
import
chat.rocket.core.internal.realtime.socket.model.State
import
chat.rocket.core.internal.realtime.socket.model.State
import
chat.rocket.core.model.ChatRoom
import
chat.rocket.core.model.ChatRoom
import
com.bumptech.glide.load.resource.gif.GifDrawable
import
dagger.android.support.AndroidSupportInjection
import
dagger.android.support.AndroidSupportInjection
import
io.reactivex.Observable
import
io.reactivex.Observable
import
io.reactivex.disposables.CompositeDisposable
import
io.reactivex.disposables.CompositeDisposable
...
@@ -79,6 +86,8 @@ import kotlinx.android.synthetic.main.fragment_chat_room.*
...
@@ -79,6 +86,8 @@ import kotlinx.android.synthetic.main.fragment_chat_room.*
import
kotlinx.android.synthetic.main.message_attachment_options.*
import
kotlinx.android.synthetic.main.message_attachment_options.*
import
kotlinx.android.synthetic.main.message_composer.*
import
kotlinx.android.synthetic.main.message_composer.*
import
kotlinx.android.synthetic.main.message_list.*
import
kotlinx.android.synthetic.main.message_list.*
import
kotlinx.coroutines.experimental.android.UI
import
kotlinx.coroutines.experimental.launch
import
java.util.concurrent.TimeUnit
import
java.util.concurrent.TimeUnit
import
java.util.concurrent.atomic.AtomicInteger
import
java.util.concurrent.atomic.AtomicInteger
import
javax.inject.Inject
import
javax.inject.Inject
...
@@ -131,7 +140,8 @@ internal const val MENU_ACTION_FAVORITE_MESSAGES = 5
...
@@ -131,7 +140,8 @@ internal const val MENU_ACTION_FAVORITE_MESSAGES = 5
internal
const
val
MENU_ACTION_FILES
=
6
internal
const
val
MENU_ACTION_FILES
=
6
class
ChatRoomFragment
:
Fragment
(),
ChatRoomView
,
EmojiKeyboardListener
,
EmojiReactionListener
,
class
ChatRoomFragment
:
Fragment
(),
ChatRoomView
,
EmojiKeyboardListener
,
EmojiReactionListener
,
ChatRoomAdapter
.
OnActionSelected
{
ChatRoomAdapter
.
OnActionSelected
,
Drawable
.
Callback
{
@Inject
@Inject
lateinit
var
presenter
:
ChatRoomPresenter
lateinit
var
presenter
:
ChatRoomPresenter
@Inject
@Inject
...
@@ -208,10 +218,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
...
@@ -208,10 +218,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
requireNotNull
(
bundle
)
{
"no arguments supplied when the fragment was instantiated"
}
requireNotNull
(
bundle
)
{
"no arguments supplied when the fragment was instantiated"
}
}
}
adapter
=
ChatRoomAdapter
(
adapter
=
ChatRoomAdapter
(
chatRoomId
,
chatRoomType
,
chatRoomName
,
this
,
reactionListener
=
this
)
chatRoomType
,
chatRoomName
,
this
,
reactionListener
=
this
)
}
}
override
fun
onCreateView
(
override
fun
onCreateView
(
...
@@ -395,10 +402,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
...
@@ -395,10 +402,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
}
}
}
override
fun
openDirectMessage
(
chatRoom
:
ChatRoom
,
permalink
:
String
)
{
}
private
val
layoutChangeListener
=
private
val
layoutChangeListener
=
View
.
OnLayoutChangeListener
{
_
,
_
,
_
,
_
,
bottom
,
_
,
_
,
_
,
oldBottom
->
View
.
OnLayoutChangeListener
{
_
,
_
,
_
,
_
,
bottom
,
_
,
_
,
_
,
oldBottom
->
val
y
=
oldBottom
-
bottom
val
y
=
oldBottom
-
bottom
...
@@ -641,8 +644,12 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
...
@@ -641,8 +644,12 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
override
fun
onEmojiAdded
(
emoji
:
Emoji
)
{
override
fun
onEmojiAdded
(
emoji
:
Emoji
)
{
val
cursorPosition
=
text_message
.
selectionStart
val
cursorPosition
=
text_message
.
selectionStart
if
(
cursorPosition
>
-
1
)
{
if
(
cursorPosition
>
-
1
)
{
text_message
.
text
?.
insert
(
cursorPosition
,
EmojiParser
.
parse
(
emoji
.
shortname
))
context
?.
let
{
text_message
.
setSelection
(
cursorPosition
+
emoji
.
unicode
.
length
)
val
offset
=
if
(!
emoji
.
isCustom
())
emoji
.
unicode
.
length
else
emoji
.
shortname
.
length
val
parsed
=
if
(
emoji
.
isCustom
())
emoji
.
shortname
else
EmojiParser
.
parse
(
it
,
emoji
.
shortname
)
text_message
.
text
?.
insert
(
cursorPosition
,
parsed
)
text_message
.
setSelection
(
cursorPosition
+
offset
)
}
}
}
}
}
...
@@ -773,9 +780,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
...
@@ -773,9 +780,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
button_send
.
isVisible
=
false
button_send
.
isVisible
=
false
button_show_attachment_options
.
alpha
=
1f
button_show_attachment_options
.
alpha
=
1f
button_show_attachment_options
.
isVisible
=
true
button_show_attachment_options
.
isVisible
=
true
activity
?.
supportFragmentManager
?.
addOnBackStackChangedListener
{
activity
?.
supportFragmentManager
?.
addOnBackStackChangedListener
{
println
(
"attach"
)
println
(
"attach"
)
}
}
activity
?.
supportFragmentManager
?.
registerFragmentLifecycleCallbacks
(
activity
?.
supportFragmentManager
?.
registerFragmentLifecycleCallbacks
(
object
:
FragmentManager
.
FragmentLifecycleCallbacks
()
{
object
:
FragmentManager
.
FragmentLifecycleCallbacks
()
{
override
fun
onFragmentAttached
(
override
fun
onFragmentAttached
(
...
@@ -791,6 +800,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
...
@@ -791,6 +800,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
},
},
true
true
)
)
subscribeComposeTextMessage
()
subscribeComposeTextMessage
()
emojiKeyboardPopup
=
emojiKeyboardPopup
=
EmojiKeyboardPopup
(
activity
!!
,
activity
!!
.
findViewById
(
R
.
id
.
fragment_container
))
EmojiKeyboardPopup
(
activity
!!
,
activity
!!
.
findViewById
(
R
.
id
.
fragment_container
))
...
@@ -979,6 +989,18 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
...
@@ -979,6 +989,18 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
(
activity
as
ChatRoomActivity
).
showToolbarTitle
(
toolbarTitle
)
(
activity
as
ChatRoomActivity
).
showToolbarTitle
(
toolbarTitle
)
}
}
override
fun
unscheduleDrawable
(
who
:
Drawable
?,
what
:
Runnable
?)
{
text_message
?.
removeCallbacks
(
what
)
}
override
fun
invalidateDrawable
(
who
:
Drawable
?)
{
text_message
?.
invalidate
()
}
override
fun
scheduleDrawable
(
who
:
Drawable
?,
what
:
Runnable
?,
`when`
:
Long
)
{
text_message
?.
postDelayed
(
what
,
`when`
)
}
override
fun
showMessageInfo
(
id
:
String
)
{
override
fun
showMessageInfo
(
id
:
String
)
{
presenter
.
messageInfo
(
id
)
presenter
.
messageInfo
(
id
)
}
}
...
@@ -1039,4 +1061,8 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
...
@@ -1039,4 +1061,8 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
override
fun
openDirectMessage
(
roomName
:
String
,
message
:
String
)
{
override
fun
openDirectMessage
(
roomName
:
String
,
message
:
String
)
{
presenter
.
openDirectMessage
(
roomName
,
message
)
presenter
.
openDirectMessage
(
roomName
,
message
)
}
}
override
fun
sendMessage
(
chatRoomId
:
String
,
text
:
String
)
{
presenter
.
sendMessage
(
chatRoomId
,
text
,
null
)
}
}
}
app/src/main/java/chat/rocket/android/chatroom/uimodel/ActionsAttachmentUiModel.kt
0 → 100644
View file @
4e3936ca
package
chat.rocket.android.chatroom.uimodel
import
chat.rocket.android.R
import
chat.rocket.core.model.Message
import
chat.rocket.core.model.attachment.actions.Action
import
chat.rocket.core.model.attachment.actions.ActionsAttachment
data class
ActionsAttachmentUiModel
(
override
val
attachmentUrl
:
String
,
val
title
:
String
?,
val
actions
:
List
<
Action
>,
val
buttonAlignment
:
String
,
override
val
message
:
Message
,
override
val
rawData
:
ActionsAttachment
,
override
val
messageId
:
String
,
override
var
reactions
:
List
<
ReactionUiModel
>,
override
var
nextDownStreamMessage
:
BaseUiModel
<*>?
=
null
,
override
var
preview
:
Message
?
=
null
,
override
var
isTemporary
:
Boolean
=
false
,
override
var
unread
:
Boolean
?
=
null
,
override
var
menuItemsToHide
:
MutableList
<
Int
>
=
mutableListOf
(),
override
var
currentDayMarkerText
:
String
,
override
var
showDayMarker
:
Boolean
)
:
BaseAttachmentUiModel
<
ActionsAttachment
>
{
override
val
viewType
:
Int
get
()
=
BaseUiModel
.
ViewType
.
ACTIONS_ATTACHMENT
.
viewType
override
val
layoutId
:
Int
get
()
=
R
.
layout
.
item_actions_attachment
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/uimodel/BaseUiModel.kt
View file @
4e3936ca
...
@@ -29,7 +29,8 @@ interface BaseUiModel<out T> {
...
@@ -29,7 +29,8 @@ interface BaseUiModel<out T> {
AUTHOR_ATTACHMENT
(
7
),
AUTHOR_ATTACHMENT
(
7
),
COLOR_ATTACHMENT
(
8
),
COLOR_ATTACHMENT
(
8
),
GENERIC_FILE_ATTACHMENT
(
9
),
GENERIC_FILE_ATTACHMENT
(
9
),
MESSAGE_REPLY
(
10
)
MESSAGE_REPLY
(
10
),
ACTIONS_ATTACHMENT
(
11
)
}
}
}
}
...
...
app/src/main/java/chat/rocket/android/chatroom/uimodel/UiModelMapper.kt
View file @
4e3936ca
...
@@ -46,6 +46,7 @@ import chat.rocket.core.model.attachment.GenericFileAttachment
...
@@ -46,6 +46,7 @@ import chat.rocket.core.model.attachment.GenericFileAttachment
import
chat.rocket.core.model.attachment.ImageAttachment
import
chat.rocket.core.model.attachment.ImageAttachment
import
chat.rocket.core.model.attachment.MessageAttachment
import
chat.rocket.core.model.attachment.MessageAttachment
import
chat.rocket.core.model.attachment.VideoAttachment
import
chat.rocket.core.model.attachment.VideoAttachment
import
chat.rocket.core.model.attachment.actions.ActionsAttachment
import
chat.rocket.core.model.isSystemMessage
import
chat.rocket.core.model.isSystemMessage
import
chat.rocket.core.model.url.Url
import
chat.rocket.core.model.url.Url
import
kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.CommonPool
...
@@ -305,10 +306,26 @@ class UiModelMapper @Inject constructor(
...
@@ -305,10 +306,26 @@ class UiModelMapper @Inject constructor(
is
MessageAttachment
->
mapMessageAttachment
(
message
,
attachment
)
is
MessageAttachment
->
mapMessageAttachment
(
message
,
attachment
)
is
AuthorAttachment
->
mapAuthorAttachment
(
message
,
attachment
)
is
AuthorAttachment
->
mapAuthorAttachment
(
message
,
attachment
)
is
ColorAttachment
->
mapColorAttachment
(
message
,
attachment
)
is
ColorAttachment
->
mapColorAttachment
(
message
,
attachment
)
is
ActionsAttachment
->
mapActionsAttachment
(
message
,
attachment
)
else
->
null
else
->
null
}
}
}
}
private
fun
mapActionsAttachment
(
message
:
Message
,
attachment
:
ActionsAttachment
):
BaseUiModel
<
*
>?
{
return
with
(
attachment
)
{
val
content
=
stripMessageQuotes
(
message
)
val
localDateTime
=
DateTimeHelper
.
getLocalDateTime
(
message
.
timestamp
)
val
dayMarkerText
=
DateTimeHelper
.
getFormattedDateForMessages
(
localDateTime
,
context
)
ActionsAttachmentUiModel
(
attachmentUrl
=
url
,
title
=
title
,
actions
=
actions
,
buttonAlignment
=
buttonAlignment
,
message
=
message
,
rawData
=
attachment
,
messageId
=
message
.
id
,
reactions
=
getReactions
(
message
),
preview
=
message
.
copy
(
message
=
content
.
message
),
unread
=
message
.
unread
,
showDayMarker
=
false
,
currentDayMarkerText
=
dayMarkerText
)
}
}
private
fun
mapColorAttachment
(
message
:
Message
,
attachment
:
ColorAttachment
):
BaseUiModel
<
*
>?
{
private
fun
mapColorAttachment
(
message
:
Message
,
attachment
:
ColorAttachment
):
BaseUiModel
<
*
>?
{
return
with
(
attachment
)
{
return
with
(
attachment
)
{
val
content
=
stripMessageQuotes
(
message
)
val
content
=
stripMessageQuotes
(
message
)
...
@@ -493,7 +510,7 @@ class UiModelMapper @Inject constructor(
...
@@ -493,7 +510,7 @@ class UiModelMapper @Inject constructor(
list
.
add
(
list
.
add
(
ReactionUiModel
(
messageId
=
message
.
id
,
ReactionUiModel
(
messageId
=
message
.
id
,
shortname
=
shortname
,
shortname
=
shortname
,
unicode
=
EmojiParser
.
parse
(
shortname
),
unicode
=
EmojiParser
.
parse
(
context
,
shortname
),
count
=
count
,
count
=
count
,
usernames
=
usernames
)
usernames
=
usernames
)
)
)
...
...
app/src/main/java/chat/rocket/android/helper/MessageParser.kt
View file @
4e3936ca
...
@@ -7,6 +7,7 @@ import android.graphics.Paint
...
@@ -7,6 +7,7 @@ import android.graphics.Paint
import
android.graphics.RectF
import
android.graphics.RectF
import
android.text.Spanned
import
android.text.Spanned
import
android.text.style.ClickableSpan
import
android.text.style.ClickableSpan
import
android.text.style.ImageSpan
import
android.text.style.ReplacementSpan
import
android.text.style.ReplacementSpan
import
android.util.Patterns
import
android.util.Patterns
import
android.view.View
import
android.view.View
...
@@ -25,7 +26,6 @@ import org.commonmark.node.Document
...
@@ -25,7 +26,6 @@ import org.commonmark.node.Document
import
org.commonmark.node.ListItem
import
org.commonmark.node.ListItem
import
org.commonmark.node.Node
import
org.commonmark.node.Node
import
org.commonmark.node.OrderedList
import
org.commonmark.node.OrderedList
import
org.commonmark.node.Paragraph
import
org.commonmark.node.Text
import
org.commonmark.node.Text
import
ru.noties.markwon.Markwon
import
ru.noties.markwon.Markwon
import
ru.noties.markwon.SpannableBuilder
import
ru.noties.markwon.SpannableBuilder
...
@@ -60,11 +60,11 @@ class MessageParser @Inject constructor(
...
@@ -60,11 +60,11 @@ class MessageParser @Inject constructor(
}
}
}
}
val
builder
=
SpannableBuilder
()
val
builder
=
SpannableBuilder
()
val
content
=
EmojiRepository
.
shortnameToUnicode
(
text
,
true
)
val
content
=
EmojiRepository
.
shortnameToUnicode
(
text
)
val
parentNode
=
parser
.
parse
(
toLenientMarkdown
(
content
))
val
parentNode
=
parser
.
parse
(
toLenientMarkdown
(
content
))
parentNode
.
accept
(
MarkdownVisitor
(
configuration
,
builder
))
parentNode
.
accept
(
MarkdownVisitor
(
configuration
,
builder
))
parentNode
.
accept
(
LinkVisitor
(
builder
))
parentNode
.
accept
(
LinkVisitor
(
builder
))
parentNode
.
accept
(
EmojiVisitor
(
configuration
,
builder
))
parentNode
.
accept
(
EmojiVisitor
(
con
text
,
con
figuration
,
builder
))
message
.
mentions
?.
let
{
message
.
mentions
?.
let
{
parentNode
.
accept
(
MentionVisitor
(
context
,
builder
,
mentions
,
selfUsername
))
parentNode
.
accept
(
MentionVisitor
(
context
,
builder
,
mentions
,
selfUsername
))
}
}
...
@@ -126,16 +126,29 @@ class MessageParser @Inject constructor(
...
@@ -126,16 +126,29 @@ class MessageParser @Inject constructor(
}
}
class
EmojiVisitor
(
class
EmojiVisitor
(
private
val
context
:
Context
,
configuration
:
SpannableConfiguration
,
configuration
:
SpannableConfiguration
,
private
val
builder
:
SpannableBuilder
private
val
builder
:
SpannableBuilder
)
:
SpannableMarkdownVisitor
(
configuration
,
builder
)
{
)
:
SpannableMarkdownVisitor
(
configuration
,
builder
)
{
private
val
emojiSize
=
context
.
resources
.
getDimensionPixelSize
(
R
.
dimen
.
radius_mention
)
override
fun
visit
(
document
:
Document
)
{
override
fun
visit
(
document
:
Document
)
{
val
spannable
=
EmojiParser
.
parse
(
builder
.
text
())
val
spannable
=
EmojiParser
.
parse
(
context
,
builder
.
text
())
if
(
spannable
is
Spanned
)
{
if
(
spannable
is
Spanned
)
{
val
spans
=
spannable
.
getSpans
(
0
,
spannable
.
length
,
EmojiTypefaceSpan
::
class
.
java
)
val
emojiOneTypefaceSpans
=
spannable
.
getSpans
(
0
,
spannable
.
length
,
spans
.
forEach
{
EmojiTypefaceSpan
::
class
.
java
)
builder
.
setSpan
(
it
,
spannable
.
getSpanStart
(
it
),
spannable
.
getSpanEnd
(
it
),
0
)
val
emojiImageSpans
=
spannable
.
getSpans
(
0
,
spannable
.
length
,
ImageSpan
::
class
.
java
)
emojiOneTypefaceSpans
.
forEach
{
builder
.
setSpan
(
it
,
spannable
.
getSpanStart
(
it
),
spannable
.
getSpanEnd
(
it
),
Spanned
.
SPAN_EXCLUSIVE_EXCLUSIVE
)
}
emojiImageSpans
.
forEach
{
it
.
drawable
?.
setBounds
(
0
,
0
,
emojiSize
,
emojiSize
)
builder
.
setSpan
(
it
,
spannable
.
getSpanStart
(
it
),
spannable
.
getSpanEnd
(
it
),
Spanned
.
SPAN_EXCLUSIVE_EXCLUSIVE
)
}
}
}
}
}
}
...
...
app/src/main/java/chat/rocket/android/main/presentation/MainPresenter.kt
View file @
4e3936ca
package
chat.rocket.android.main.presentation
package
chat.rocket.android.main.presentation
import
android.content.Context
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.db.DatabaseManagerFactory
import
chat.rocket.android.db.DatabaseManagerFactory
import
chat.rocket.android.emoji.Emoji
import
chat.rocket.android.emoji.EmojiRepository
import
chat.rocket.android.emoji.Fitzpatrick
import
chat.rocket.android.emoji.internal.EmojiCategory
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.main.uimodel.NavHeaderUiModel
import
chat.rocket.android.main.uimodel.NavHeaderUiModel
import
chat.rocket.android.main.uimodel.NavHeaderUiModelMapper
import
chat.rocket.android.main.uimodel.NavHeaderUiModelMapper
...
@@ -30,6 +35,7 @@ import chat.rocket.common.RocketChatException
...
@@ -30,6 +35,7 @@ import chat.rocket.common.RocketChatException
import
chat.rocket.common.model.UserStatus
import
chat.rocket.common.model.UserStatus
import
chat.rocket.common.util.ifNull
import
chat.rocket.common.util.ifNull
import
chat.rocket.core.RocketChatClient
import
chat.rocket.core.RocketChatClient
import
chat.rocket.core.internal.rest.getCustomEmojis
import
chat.rocket.core.internal.rest.logout
import
chat.rocket.core.internal.rest.logout
import
chat.rocket.core.internal.rest.me
import
chat.rocket.core.internal.rest.me
import
chat.rocket.core.internal.rest.unregisterPushToken
import
chat.rocket.core.internal.rest.unregisterPushToken
...
@@ -125,6 +131,38 @@ class MainPresenter @Inject constructor(
...
@@ -125,6 +131,38 @@ class MainPresenter @Inject constructor(
}
}
}
}
/**
* Load all emojis for the current server. Simple emojis are always the same for every server,
* but custom emojis vary according to the its url.
*/
fun
loadEmojis
()
{
launchUI
(
strategy
)
{
EmojiRepository
.
setCurrentServerUrl
(
currentServer
)
val
customEmojiList
=
mutableListOf
<
Emoji
>()
try
{
for
(
customEmoji
in
retryIO
(
"getCustomEmojis()"
)
{
client
.
getCustomEmojis
()
})
{
customEmojiList
.
add
(
Emoji
(
shortname
=
":${customEmoji.name}:"
,
category
=
EmojiCategory
.
CUSTOM
.
name
,
url
=
"$currentServer/emoji-custom/${customEmoji.name}.${customEmoji.extension}"
,
count
=
0
,
fitzpatrick
=
Fitzpatrick
.
Default
.
type
,
keywords
=
customEmoji
.
aliases
,
shortnameAlternates
=
customEmoji
.
aliases
,
siblings
=
mutableListOf
(),
unicode
=
""
,
isDefault
=
true
))
}
EmojiRepository
.
load
(
view
as
Context
,
customEmojis
=
customEmojiList
)
}
catch
(
ex
:
RocketChatException
)
{
Timber
.
e
(
ex
)
EmojiRepository
.
load
(
view
as
Context
)
}
}
}
/**
/**
* Logout from current server.
* Logout from current server.
*/
*/
...
...
app/src/main/java/chat/rocket/android/main/ui/MainActivity.kt
View file @
4e3936ca
...
@@ -76,6 +76,7 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
...
@@ -76,6 +76,7 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
presenter
.
connect
()
presenter
.
connect
()
presenter
.
loadServerAccounts
()
presenter
.
loadServerAccounts
()
presenter
.
loadCurrentInfo
()
presenter
.
loadCurrentInfo
()
presenter
.
loadEmojis
()
setupToolbar
()
setupToolbar
()
setupNavigationView
()
setupNavigationView
()
}
}
...
...
app/src/main/java/chat/rocket/android/util/extensions/Text.kt
View file @
4e3936ca
...
@@ -66,12 +66,13 @@ var TextView.content: CharSequence?
...
@@ -66,12 +66,13 @@ var TextView.content: CharSequence?
Markwon
.
unscheduleDrawables
(
this
)
Markwon
.
unscheduleDrawables
(
this
)
Markwon
.
unscheduleTableRows
(
this
)
Markwon
.
unscheduleTableRows
(
this
)
if
(
value
is
Spanned
)
{
if
(
value
is
Spanned
)
{
val
result
=
EmojiParser
.
parse
(
value
.
toString
())
as
Spannable
val
context
=
this
.
context
val
result
=
EmojiParser
.
parse
(
context
,
value
.
toString
())
as
Spannable
val
end
=
if
(
value
.
length
>
result
.
length
)
result
.
length
else
value
.
length
val
end
=
if
(
value
.
length
>
result
.
length
)
result
.
length
else
value
.
length
TextUtils
.
copySpansFrom
(
value
,
0
,
end
,
Any
::
class
.
java
,
result
,
0
)
TextUtils
.
copySpansFrom
(
value
,
0
,
end
,
Any
::
class
.
java
,
result
,
0
)
text
=
result
text
=
result
}
else
{
}
else
{
val
result
=
EmojiParser
.
parse
(
value
.
toString
())
as
Spannable
val
result
=
EmojiParser
.
parse
(
context
,
value
.
toString
())
as
Spannable
text
=
result
text
=
result
}
}
Markwon
.
scheduleDrawables
(
this
)
Markwon
.
scheduleDrawables
(
this
)
...
...
app/src/main/res/layout/item_action_button.xml
0 → 100644
View file @
4e3936ca
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:fresco=
"http://schemas.android.com/apk/res-auto"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:orientation=
"horizontal"
>
<com.google.android.material.button.MaterialButton
android:id=
"@+id/action_button"
style=
"@style/Widget.MaterialComponents.Button"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginEnd=
"2dp"
android:layout_marginStart=
"2dp"
android:textAppearance=
"@style/TextAppearance.AppCompat.Body2"
android:textSize=
"12sp"
/>
<com.facebook.drawee.view.SimpleDraweeView
android:id=
"@+id/action_image_button"
android:layout_width=
"match_parent"
android:layout_height=
"75dp"
android:layout_marginBottom=
"10dp"
android:layout_marginEnd=
"2dp"
android:layout_marginStart=
"2dp"
android:visibility=
"gone"
fresco:actualImageScaleType=
"fitStart"
fresco:placeholderImage=
"@drawable/image_dummy"
/>
</RelativeLayout>
\ No newline at end of file
app/src/main/res/layout/item_actions_attachment.xml
0 → 100644
View file @
4e3936ca
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:app=
"http://schemas.android.com/apk/res-auto"
xmlns:tools=
"http://schemas.android.com/tools"
android:id=
"@+id/actions_attachment_container"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:background=
"?android:attr/selectableItemBackground"
android:clickable=
"true"
android:focusable=
"true"
android:paddingBottom=
"@dimen/message_item_top_and_bottom_padding"
android:paddingEnd=
"@dimen/screen_edge_left_and_right_padding"
android:paddingStart=
"@dimen/screen_edge_left_and_right_padding"
>
<TextView
android:id=
"@+id/title"
style=
"@style/Message.TextView"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_marginBottom=
"4dp"
android:layout_marginStart=
"56dp"
android:layout_marginTop=
"2dp"
android:textDirection=
"locale"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintStart_toStartOf=
"parent"
tools:text=
"This is a multiline chat message from Bertie that will take more than just one line of text. I have sure that everything is amazing!"
/>
<View
android:id=
"@+id/quote_bar"
android:layout_width=
"4dp"
android:layout_height=
"0dp"
android:background=
"@drawable/quote_vertical_gray_bar"
app:layout_constraintBottom_toTopOf=
"@id/recycler_view_reactions"
app:layout_constraintStart_toStartOf=
"@id/title"
app:layout_constraintTop_toBottomOf=
"@id/title"
/>
<androidx.recyclerview.widget.RecyclerView
android:id=
"@+id/actions_list"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_marginStart=
"8dp"
android:textAppearance=
"@style/TextAppearance.AppCompat.Body2"
android:textColor=
"@color/colorAccent"
android:textDirection=
"locale"
app:layout_constraintEnd_toEndOf=
"@id/title"
app:layout_constraintStart_toEndOf=
"@id/quote_bar"
app:layout_constraintTop_toBottomOf=
"@id/title"
/>
<include
layout=
"@layout/layout_reactions"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
app:layout_constraintStart_toStartOf=
"@id/quote_bar"
app:layout_constraintTop_toBottomOf=
"@id/actions_list"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
app/src/main/res/values/dimens.xml
View file @
4e3936ca
...
@@ -31,6 +31,7 @@
...
@@ -31,6 +31,7 @@
<dimen
name=
"supposed_keyboard_height"
>
252dp
</dimen>
<dimen
name=
"supposed_keyboard_height"
>
252dp
</dimen>
<dimen
name=
"picker_popup_height"
>
250dp
</dimen>
<dimen
name=
"picker_popup_height"
>
250dp
</dimen>
<dimen
name=
"picker_popup_width"
>
300dp
</dimen>
<dimen
name=
"picker_popup_width"
>
300dp
</dimen>
<dimen
name=
"emoji_size"
>
22dp
</dimen>
<!--Toolbar-->
<!--Toolbar-->
<dimen
name=
"toolbar_height"
>
56dp
</dimen>
<dimen
name=
"toolbar_height"
>
56dp
</dimen>
...
...
build.gradle
View file @
4e3936ca
...
@@ -10,7 +10,7 @@ buildscript {
...
@@ -10,7 +10,7 @@ buildscript {
}
}
dependencies
{
dependencies
{
classpath
'com.android.tools.build:gradle:3.
3.0-alpha05
'
classpath
'com.android.tools.build:gradle:3.
2.0-rc02
'
classpath
"org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"
classpath
"org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"
classpath
"org.jetbrains.dokka:dokka-gradle-plugin:${versions.dokka}"
classpath
"org.jetbrains.dokka:dokka-gradle-plugin:${versions.dokka}"
classpath
'com.google.gms:google-services:4.0.2'
classpath
'com.google.gms:google-services:4.0.2'
...
...
dependencies.gradle
View file @
4e3936ca
...
@@ -5,7 +5,7 @@ ext {
...
@@ -5,7 +5,7 @@ ext {
compileSdk
:
28
,
compileSdk
:
28
,
targetSdk
:
28
,
targetSdk
:
28
,
minSdk
:
21
,
minSdk
:
21
,
buildTools
:
'28.0.
1
'
,
buildTools
:
'28.0.
2
'
,
dokka
:
'0.9.16'
,
dokka
:
'0.9.16'
,
// For app
// For app
...
@@ -47,6 +47,7 @@ ext {
...
@@ -47,6 +47,7 @@ ext {
frescoImageViewer
:
'0.5.1'
,
frescoImageViewer
:
'0.5.1'
,
markwon
:
'1.1.0'
,
markwon
:
'1.1.0'
,
aVLoadingIndicatorView:
'2.1.3'
,
aVLoadingIndicatorView:
'2.1.3'
,
glide
:
'4.8.0-SNAPSHOT'
,
// For wearable
// For wearable
wear
:
'2.3.0'
,
wear
:
'2.3.0'
,
...
@@ -106,6 +107,8 @@ ext {
...
@@ -106,6 +107,8 @@ ext {
kotshiCompiler
:
"se.ansman.kotshi:compiler:${versions.kotshi}"
,
kotshiCompiler
:
"se.ansman.kotshi:compiler:${versions.kotshi}"
,
frescoImageViewer
:
"com.github.luciofm:FrescoImageViewer:${versions.frescoImageViewer}"
,
frescoImageViewer
:
"com.github.luciofm:FrescoImageViewer:${versions.frescoImageViewer}"
,
glide
:
"com.github.bumptech.glide:glide:${versions.glide}"
,
glideProcessor
:
"com.github.bumptech.glide:compiler:${versions.glide}"
,
markwon
:
"ru.noties:markwon:${versions.markwon}"
,
markwon
:
"ru.noties:markwon:${versions.markwon}"
,
...
...
emoji/build.gradle
View file @
4e3936ca
apply
plugin:
'com.android.library'
apply
plugin:
'com.android.library'
apply
plugin:
'kotlin-android'
apply
plugin:
'kotlin-android'
apply
plugin:
'kotlin-android-extensions'
apply
plugin:
'kotlin-android-extensions'
apply
plugin:
'kotlin-kapt'
android
{
android
{
compileSdkVersion
versions
.
compileSdk
compileSdkVersion
versions
.
compileSdk
...
@@ -14,6 +15,11 @@ android {
...
@@ -14,6 +15,11 @@ android {
testInstrumentationRunner
"androidx.test.runner.AndroidJUnitRunner"
testInstrumentationRunner
"androidx.test.runner.AndroidJUnitRunner"
javaCompileOptions
{
annotationProcessorOptions
{
arguments
=
[
"room.schemaLocation"
:
"$projectDir/schemas"
.
toString
()]
}
}
}
}
buildTypes
{
buildTypes
{
...
@@ -34,6 +40,10 @@ dependencies {
...
@@ -34,6 +40,10 @@ dependencies {
implementation
libraries
.
constraintlayout
implementation
libraries
.
constraintlayout
implementation
libraries
.
recyclerview
implementation
libraries
.
recyclerview
implementation
libraries
.
material
implementation
libraries
.
material
implementation
libraries
.
glide
kapt
libraries
.
glideProcessor
implementation
libraries
.
room
kapt
libraries
.
roomProcessor
}
}
kotlin
{
kotlin
{
...
...
emoji/proguard-rules.pro
View file @
4e3936ca
...
@@ -19,3 +19,12 @@
...
@@ -19,3 +19,12 @@
#
If
you
keep
the
line
number
information
,
uncomment
this
to
#
If
you
keep
the
line
number
information
,
uncomment
this
to
#
hide
the
original
source
file
name
.
#
hide
the
original
source
file
name
.
#-
renamesourcefileattribute
SourceFile
#-
renamesourcefileattribute
SourceFile
-
keep
public
class
*
implements
com
.
bumptech
.
glide
.
module
.
GlideModule
-
keep
public
class
*
extends
com
.
bumptech
.
glide
.
module
.
AppGlideModule
-
keep
public
enum
com
.
bumptech
.
glide
.
load
.
ImageHeaderParser
$
**
{
**
[]
$
VALUES
;
public
*
;
}
#
for
DexGuard
only
-
keepresourcexmlelements
manifest
/
application
/
meta
-
data
@
value
=
GlideModule
emoji/src/main/java/chat/rocket/android/emoji/ComposerEditText.kt
View file @
4e3936ca
package
chat.rocket.android.emoji
package
chat.rocket.android.emoji
import
android.content.Context
import
android.content.Context
import
androidx.appcompat.widget.AppCompatEditText
import
android.text.Spanned
import
android.text.style.ImageSpan
import
android.util.AttributeSet
import
android.util.AttributeSet
import
android.view.KeyEvent
import
android.view.KeyEvent
import
androidx.appcompat.widget.AppCompatEditText
import
androidx.core.text.getSpans
class
ComposerEditText
:
AppCompatEditText
{
class
ComposerEditText
:
AppCompatEditText
{
var
listener
:
ComposerEditTextListener
?
=
null
var
listener
:
ComposerEditTextListener
?
=
null
constructor
(
context
:
Context
,
attrs
:
AttributeSet
?,
defStyleAttr
:
Int
)
:
constructor
(
context
:
Context
,
attrs
:
AttributeSet
?,
defStyleAttr
:
Int
)
:
...
@@ -20,6 +24,21 @@ class ComposerEditText : AppCompatEditText {
...
@@ -20,6 +24,21 @@ class ComposerEditText : AppCompatEditText {
constructor
(
context
:
Context
)
:
this
(
context
,
null
)
constructor
(
context
:
Context
)
:
this
(
context
,
null
)
override
fun
onSelectionChanged
(
selStart
:
Int
,
selEnd
:
Int
)
{
super
.
onSelectionChanged
(
selStart
,
selEnd
)
text
?.
getSpans
<
ImageSpan
>()
?.
forEach
{
val
s
=
text
?.
getSpanStart
(
it
)
?:
-
1
val
e
=
text
?.
getSpanEnd
(
it
)
?:
-
1
val
flags
=
if
(
selStart
in
s
..
e
)
{
Spanned
.
SPAN_EXCLUSIVE_EXCLUSIVE
or
Spanned
.
SPAN_COMPOSING
}
else
{
Spanned
.
SPAN_EXCLUSIVE_EXCLUSIVE
}
text
?.
setSpan
(
it
,
s
,
e
,
flags
)
}
}
override
fun
dispatchKeyEventPreIme
(
event
:
KeyEvent
):
Boolean
{
override
fun
dispatchKeyEventPreIme
(
event
:
KeyEvent
):
Boolean
{
if
(
event
.
keyCode
==
KeyEvent
.
KEYCODE_BACK
)
{
if
(
event
.
keyCode
==
KeyEvent
.
KEYCODE_BACK
)
{
val
state
=
keyDispatcherState
val
state
=
keyDispatcherState
...
...
emoji/src/main/java/chat/rocket/android/emoji/Emoji.kt
View file @
4e3936ca
package
chat.rocket.android.emoji
package
chat.rocket.android.emoji
import
androidx.room.Entity
import
androidx.room.Ignore
import
androidx.room.PrimaryKey
@Entity
data class
Emoji
(
data class
Emoji
(
val
shortname
:
String
,
@PrimaryKey
val
shortnameAlternates
:
List
<
String
>,
var
shortname
:
String
=
""
,
val
unicode
:
String
,
var
shortnameAlternates
:
List
<
String
>
=
listOf
(),
val
keywords
:
List
<
String
>,
var
unicode
:
String
=
""
,
val
category
:
String
,
@Ignore
val
keywords
:
List
<
String
>
=
listOf
(),
val
count
:
Int
=
0
,
var
category
:
String
=
""
,
val
siblings
:
MutableCollection
<
Emoji
>
=
mutableListOf
(),
var
count
:
Int
=
0
,
val
fitzpatrick
:
Fitzpatrick
=
Fitzpatrick
.
Default
var
siblings
:
MutableList
<
String
>
=
mutableListOf
(),
// Siblings are the same emoji with different skin tones.
var
fitzpatrick
:
String
=
Fitzpatrick
.
Default
.
type
,
var
url
:
String
?
=
null
,
// Filled for custom emojis
var
isDefault
:
Boolean
=
true
// Tell if this is the default emoji if it has siblings (usually a yellow-toned one).
)
)
emoji/src/main/java/chat/rocket/android/emoji/EmojiDao.kt
0 → 100644
View file @
4e3936ca
package
chat.rocket.android.emoji
import
androidx.room.Dao
import
androidx.room.Delete
import
androidx.room.Insert
import
androidx.room.OnConflictStrategy.IGNORE
import
androidx.room.Query
import
androidx.room.Update
@Dao
interface
EmojiDao
{
@Query
(
"SELECT * FROM emoji"
)
fun
loadAllEmojis
():
List
<
Emoji
>
@Query
(
"SELECT * FROM emoji WHERE url IS NULL"
)
fun
loadSimpleEmojis
():
List
<
Emoji
>
@Query
(
"SELECT * FROM emoji WHERE url IS NOT NULL"
)
fun
loadAllCustomEmojis
():
List
<
Emoji
>
@Query
(
"SELECT * FROM emoji WHERE shortname=:shortname"
)
fun
loadEmojiByShortname
(
shortname
:
String
):
List
<
Emoji
>
@Query
(
"SELECT * FROM emoji WHERE UPPER(category)=UPPER(:category)"
)
fun
loadEmojisByCategory
(
category
:
String
):
List
<
Emoji
>
@Query
(
"SELECT * FROM emoji WHERE UPPER(category)=UPPER(:category) AND url LIKE :url"
)
fun
loadEmojisByCategoryAndUrl
(
category
:
String
,
url
:
String
):
List
<
Emoji
>
@Insert
(
onConflict
=
IGNORE
)
fun
insertEmoji
(
emoji
:
Emoji
)
@Insert
(
onConflict
=
IGNORE
)
fun
insertAllEmojis
(
vararg
emojis
:
Emoji
)
@Update
fun
updateEmoji
(
emoji
:
Emoji
)
@Delete
fun
deleteEmoji
(
emoji
:
Emoji
)
@Query
(
"DELETE FROM emoji"
)
fun
deleteAll
()
}
emoji/src/main/java/chat/rocket/android/emoji/EmojiKeyboardPopup.kt
View file @
4e3936ca
...
@@ -22,6 +22,8 @@ import chat.rocket.android.emoji.internal.EmojiCategory
...
@@ -22,6 +22,8 @@ import chat.rocket.android.emoji.internal.EmojiCategory
import
chat.rocket.android.emoji.internal.EmojiPagerAdapter
import
chat.rocket.android.emoji.internal.EmojiPagerAdapter
import
chat.rocket.android.emoji.internal.PREF_EMOJI_SKIN_TONE
import
chat.rocket.android.emoji.internal.PREF_EMOJI_SKIN_TONE
import
com.google.android.material.tabs.TabLayout
import
com.google.android.material.tabs.TabLayout
import
kotlinx.coroutines.experimental.android.UI
import
kotlinx.coroutines.experimental.launch
class
EmojiKeyboardPopup
(
context
:
Context
,
view
:
View
)
:
OverKeyboardPopupWindow
(
context
,
view
)
{
class
EmojiKeyboardPopup
(
context
:
Context
,
view
:
View
)
:
OverKeyboardPopupWindow
(
context
,
view
)
{
...
@@ -49,9 +51,11 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
...
@@ -49,9 +51,11 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
}
}
override
fun
onViewCreated
(
view
:
View
)
{
override
fun
onViewCreated
(
view
:
View
)
{
launch
(
UI
)
{
setupViewPager
()
setupViewPager
()
setupBottomBar
()
setupBottomBar
()
}
}
}
private
fun
setupBottomBar
()
{
private
fun
setupBottomBar
()
{
searchView
.
setOnClickListener
{
searchView
.
setOnClickListener
{
...
@@ -81,42 +85,42 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
...
@@ -81,42 +85,42 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
.
create
()
.
create
()
view
.
findViewById
<
TextView
>(
R
.
id
.
default_tone_text
).
also
{
view
.
findViewById
<
TextView
>(
R
.
id
.
default_tone_text
).
also
{
it
.
text
=
EmojiParser
.
parse
(
it
.
text
)
it
.
text
=
EmojiParser
.
parse
(
context
,
it
.
text
)
}.
setOnClickListener
{
}.
setOnClickListener
{
dialog
.
dismiss
()
dialog
.
dismiss
()
changeSkinTone
(
Fitzpatrick
.
Default
)
changeSkinTone
(
Fitzpatrick
.
Default
)
}
}
view
.
findViewById
<
TextView
>(
R
.
id
.
light_tone_text
).
also
{
view
.
findViewById
<
TextView
>(
R
.
id
.
light_tone_text
).
also
{
it
.
text
=
EmojiParser
.
parse
(
it
.
text
)
it
.
text
=
EmojiParser
.
parse
(
context
,
it
.
text
)
}.
setOnClickListener
{
}.
setOnClickListener
{
dialog
.
dismiss
()
dialog
.
dismiss
()
changeSkinTone
(
Fitzpatrick
.
LightTone
)
changeSkinTone
(
Fitzpatrick
.
LightTone
)
}
}
view
.
findViewById
<
TextView
>(
R
.
id
.
medium_light_text
).
also
{
view
.
findViewById
<
TextView
>(
R
.
id
.
medium_light_text
).
also
{
it
.
text
=
EmojiParser
.
parse
(
it
.
text
)
it
.
text
=
EmojiParser
.
parse
(
context
,
it
.
text
)
}.
setOnClickListener
{
}.
setOnClickListener
{
dialog
.
dismiss
()
dialog
.
dismiss
()
changeSkinTone
(
Fitzpatrick
.
MediumLightTone
)
changeSkinTone
(
Fitzpatrick
.
MediumLightTone
)
}
}
view
.
findViewById
<
TextView
>(
R
.
id
.
medium_tone_text
).
also
{
view
.
findViewById
<
TextView
>(
R
.
id
.
medium_tone_text
).
also
{
it
.
text
=
EmojiParser
.
parse
(
it
.
text
)
it
.
text
=
EmojiParser
.
parse
(
context
,
it
.
text
)
}.
setOnClickListener
{
}.
setOnClickListener
{
dialog
.
dismiss
()
dialog
.
dismiss
()
changeSkinTone
(
Fitzpatrick
.
MediumTone
)
changeSkinTone
(
Fitzpatrick
.
MediumTone
)
}
}
view
.
findViewById
<
TextView
>(
R
.
id
.
medium_dark_tone_text
).
also
{
view
.
findViewById
<
TextView
>(
R
.
id
.
medium_dark_tone_text
).
also
{
it
.
text
=
EmojiParser
.
parse
(
it
.
text
)
it
.
text
=
EmojiParser
.
parse
(
context
,
it
.
text
)
}.
setOnClickListener
{
}.
setOnClickListener
{
dialog
.
dismiss
()
dialog
.
dismiss
()
changeSkinTone
(
Fitzpatrick
.
MediumDarkTone
)
changeSkinTone
(
Fitzpatrick
.
MediumDarkTone
)
}
}
view
.
findViewById
<
TextView
>(
R
.
id
.
dark_tone_text
).
also
{
view
.
findViewById
<
TextView
>(
R
.
id
.
dark_tone_text
).
also
{
it
.
text
=
EmojiParser
.
parse
(
it
.
text
)
it
.
text
=
EmojiParser
.
parse
(
context
,
it
.
text
)
}.
setOnClickListener
{
}.
setOnClickListener
{
dialog
.
dismiss
()
dialog
.
dismiss
()
changeSkinTone
(
Fitzpatrick
.
DarkTone
)
changeSkinTone
(
Fitzpatrick
.
DarkTone
)
...
@@ -148,7 +152,7 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
...
@@ -148,7 +152,7 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
}
}
}
}
private
fun
setupViewPager
()
{
private
suspend
fun
setupViewPager
()
{
context
.
let
{
context
.
let
{
val
callback
=
when
(
it
)
{
val
callback
=
when
(
it
)
{
is
EmojiKeyboardListener
->
it
is
EmojiKeyboardListener
->
it
...
@@ -167,6 +171,7 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
...
@@ -167,6 +171,7 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
callback
.
onEmojiAdded
(
emoji
)
callback
.
onEmojiAdded
(
emoji
)
}
}
})
})
viewPager
.
offscreenPageLimit
=
EmojiCategory
.
values
().
size
viewPager
.
offscreenPageLimit
=
EmojiCategory
.
values
().
size
viewPager
.
adapter
=
adapter
viewPager
.
adapter
=
adapter
...
@@ -183,6 +188,7 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
...
@@ -183,6 +188,7 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
}
else
{
}
else
{
EmojiCategory
.
RECENTS
.
ordinal
EmojiCategory
.
RECENTS
.
ordinal
}
}
viewPager
.
currentItem
=
currentTab
viewPager
.
currentItem
=
currentTab
}
}
}
}
...
...
emoji/src/main/java/chat/rocket/android/emoji/EmojiParser.kt
View file @
4e3936ca
package
chat.rocket.android.emoji
package
chat.rocket.android.emoji
import
android.content.Context
import
android.graphics.Bitmap
import
android.graphics.Typeface
import
android.text.Spannable
import
android.text.Spannable
import
android.text.SpannableString
import
android.text.SpannableString
import
android.text.Spanned
import
android.text.Spanned
import
android.text.style.ImageSpan
import
android.util.Log
import
chat.rocket.android.emoji.internal.GlideApp
import
com.bumptech.glide.load.engine.DiskCacheStrategy
import
com.bumptech.glide.load.resource.gif.GifDrawable
import
kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.Deferred
import
kotlinx.coroutines.experimental.async
class
EmojiParser
{
class
EmojiParser
{
companion
object
{
companion
object
{
private
val
regex
=
":[\\w]+:"
.
toRegex
()
/**
/**
* Parses a text string containing unicode characters and/or shortnames to a rendered
* Parses a text string containing unicode characters and/or shortnames to a rendered
* Spannable.
* Spannable.
...
@@ -15,10 +29,18 @@ class EmojiParser {
...
@@ -15,10 +29,18 @@ class EmojiParser {
* @param factory Optional. A [Spannable.Factory] instance to reuse when creating [Spannable].
* @param factory Optional. A [Spannable.Factory] instance to reuse when creating [Spannable].
* @return A rendered Spannable containing any supported emoji.
* @return A rendered Spannable containing any supported emoji.
*/
*/
fun
parse
(
text
:
CharSequence
,
factory
:
Spannable
.
Factory
?
=
null
):
CharSequence
{
fun
parse
(
context
:
Context
,
text
:
CharSequence
,
factory
:
Spannable
.
Factory
?
=
null
):
CharSequence
{
val
unicodedText
=
EmojiRepository
.
shortnameToUnicode
(
text
,
true
)
val
unicodedText
=
EmojiRepository
.
shortnameToUnicode
(
text
)
val
spannable
=
factory
?.
newSpannable
(
unicodedText
)
?:
SpannableString
.
valueOf
(
unicodedText
)
val
spannable
=
factory
?.
newSpannable
(
unicodedText
)
val
typeface
=
EmojiRepository
.
cachedTypeface
?:
SpannableString
.
valueOf
(
unicodedText
)
val
typeface
=
try
{
EmojiRepository
.
cachedTypeface
}
catch
(
ex
:
UninitializedPropertyAccessException
)
{
// swallow this exception and create typeface now
Typeface
.
createFromAsset
(
context
.
assets
,
"fonts/emojione-android.ttf"
)
}
// Look for groups of emojis, set a EmojiTypefaceSpan with the emojione font.
// Look for groups of emojis, set a EmojiTypefaceSpan with the emojione font.
val
length
=
spannable
.
length
val
length
=
spannable
.
length
var
inEmoji
=
false
var
inEmoji
=
false
...
@@ -32,6 +54,7 @@ class EmojiParser {
...
@@ -32,6 +54,7 @@ class EmojiParser {
offset
+=
count
offset
+=
count
continue
continue
}
}
if
(
codepoint
>=
0
x200
)
{
if
(
codepoint
>=
0
x200
)
{
if
(!
inEmoji
)
{
if
(!
inEmoji
)
{
emojiStart
=
offset
emojiStart
=
offset
...
@@ -44,13 +67,60 @@ class EmojiParser {
...
@@ -44,13 +67,60 @@ class EmojiParser {
}
}
inEmoji
=
false
inEmoji
=
false
}
}
offset
+=
count
offset
+=
count
if
(
offset
>=
length
&&
inEmoji
)
{
if
(
offset
>=
length
&&
inEmoji
)
{
spannable
.
setSpan
(
EmojiTypefaceSpan
(
"sans-serif"
,
typeface
),
spannable
.
setSpan
(
EmojiTypefaceSpan
(
"sans-serif"
,
typeface
),
emojiStart
,
offset
,
Spanned
.
SPAN_EXCLUSIVE_EXCLUSIVE
)
emojiStart
,
offset
,
Spanned
.
SPAN_EXCLUSIVE_EXCLUSIVE
)
}
}
}
}
return
spannable
val
customEmojis
=
EmojiRepository
.
getCustomEmojis
()
val
px
=
context
.
resources
.
getDimensionPixelSize
(
R
.
dimen
.
custom_emoji_small
)
return
spannable
.
also
{
regex
.
findAll
(
spannable
).
iterator
().
forEach
{
match
->
customEmojis
.
find
{
it
.
shortname
.
toLowerCase
()
==
match
.
value
.
toLowerCase
()
}
?.
let
{
it
.
url
?.
let
{
url
->
try
{
val
glideRequest
=
if
(
url
.
endsWith
(
"gif"
,
true
))
{
GlideApp
.
with
(
context
).
asGif
()
}
else
{
GlideApp
.
with
(
context
).
asBitmap
()
}
val
futureTarget
=
glideRequest
.
diskCacheStrategy
(
DiskCacheStrategy
.
ALL
)
.
load
(
url
)
.
submit
(
px
,
px
)
val
range
=
match
.
range
futureTarget
.
get
()
?.
let
{
image
->
if
(
image
is
Bitmap
)
{
spannable
.
setSpan
(
ImageSpan
(
context
,
image
),
range
.
start
,
range
.
endInclusive
+
1
,
Spanned
.
SPAN_EXCLUSIVE_EXCLUSIVE
)
}
else
if
(
image
is
GifDrawable
)
{
image
.
setBounds
(
0
,
0
,
image
.
intrinsicWidth
,
image
.
intrinsicHeight
)
spannable
.
setSpan
(
ImageSpan
(
image
),
range
.
start
,
range
.
endInclusive
+
1
,
Spanned
.
SPAN_EXCLUSIVE_EXCLUSIVE
)
}
}
}
catch
(
ex
:
Throwable
)
{
Log
.
e
(
"EmojiParser"
,
""
,
ex
)
}
}
}
}
}
}
fun
parseAsync
(
context
:
Context
,
text
:
CharSequence
,
factory
:
Spannable
.
Factory
?
=
null
):
Deferred
<
CharSequence
>
{
return
async
(
CommonPool
)
{
parse
(
context
,
text
,
factory
)
}
}
}
}
}
}
}
emoji/src/main/java/chat/rocket/android/emoji/EmojiPickerPopup.kt
View file @
4e3936ca
...
@@ -14,6 +14,8 @@ import chat.rocket.android.emoji.internal.EmojiCategory
...
@@ -14,6 +14,8 @@ import chat.rocket.android.emoji.internal.EmojiCategory
import
chat.rocket.android.emoji.internal.EmojiPagerAdapter
import
chat.rocket.android.emoji.internal.EmojiPagerAdapter
import
chat.rocket.android.emoji.internal.PREF_EMOJI_SKIN_TONE
import
chat.rocket.android.emoji.internal.PREF_EMOJI_SKIN_TONE
import
kotlinx.android.synthetic.main.emoji_picker.*
import
kotlinx.android.synthetic.main.emoji_picker.*
import
kotlinx.coroutines.experimental.android.UI
import
kotlinx.coroutines.experimental.launch
class
EmojiPickerPopup
(
context
:
Context
)
:
Dialog
(
context
)
{
class
EmojiPickerPopup
(
context
:
Context
)
:
Dialog
(
context
)
{
...
@@ -27,9 +29,11 @@ class EmojiPickerPopup(context: Context) : Dialog(context) {
...
@@ -27,9 +29,11 @@ class EmojiPickerPopup(context: Context) : Dialog(context) {
setContentView
(
R
.
layout
.
emoji_picker
)
setContentView
(
R
.
layout
.
emoji_picker
)
tabs
.
setupWithViewPager
(
pager_categories
)
tabs
.
setupWithViewPager
(
pager_categories
)
launch
(
UI
)
{
setupViewPager
()
setupViewPager
()
setSize
()
setSize
()
}
}
}
private
fun
setSize
()
{
private
fun
setSize
()
{
val
lp
=
WindowManager
.
LayoutParams
()
val
lp
=
WindowManager
.
LayoutParams
()
...
@@ -39,7 +43,7 @@ class EmojiPickerPopup(context: Context) : Dialog(context) {
...
@@ -39,7 +43,7 @@ class EmojiPickerPopup(context: Context) : Dialog(context) {
window
.
setLayout
(
dialogWidth
,
dialogHeight
)
window
.
setLayout
(
dialogWidth
,
dialogHeight
)
}
}
private
fun
setupViewPager
()
{
private
suspend
fun
setupViewPager
()
{
adapter
=
EmojiPagerAdapter
(
object
:
EmojiKeyboardListener
{
adapter
=
EmojiPagerAdapter
(
object
:
EmojiKeyboardListener
{
override
fun
onEmojiAdded
(
emoji
:
Emoji
)
{
override
fun
onEmojiAdded
(
emoji
:
Emoji
)
{
EmojiRepository
.
addToRecents
(
emoji
)
EmojiRepository
.
addToRecents
(
emoji
)
...
...
emoji/src/main/java/chat/rocket/android/emoji/EmojiRepository.kt
View file @
4e3936ca
This diff is collapsed.
Click to expand it.
emoji/src/main/java/chat/rocket/android/emoji/internal/EmojiCategory.kt
View file @
4e3936ca
...
@@ -7,12 +7,17 @@ import chat.rocket.android.emoji.EmojiRepository
...
@@ -7,12 +7,17 @@ import chat.rocket.android.emoji.EmojiRepository
import
chat.rocket.android.emoji.EmojiTypefaceSpan
import
chat.rocket.android.emoji.EmojiTypefaceSpan
import
chat.rocket.android.emoji.R
import
chat.rocket.android.emoji.R
internal
enum
class
EmojiCategory
{
enum
class
EmojiCategory
{
RECENTS
{
RECENTS
{
override
fun
resourceIcon
()
=
R
.
drawable
.
ic_emoji_recents
override
fun
resourceIcon
()
=
R
.
drawable
.
ic_emoji_recents
override
fun
textIcon
()
=
getTextIconFor
(
"\uD83D\uDD58"
)
override
fun
textIcon
()
=
getTextIconFor
(
"\uD83D\uDD58"
)
},
},
CUSTOM
{
override
fun
resourceIcon
()
=
R
.
drawable
.
ic_emoji_custom
override
fun
textIcon
()
=
getTextIconFor
(
"\uD83D\uDD58"
)
},
PEOPLE
()
{
PEOPLE
()
{
override
fun
resourceIcon
()
=
R
.
drawable
.
ic_emoji_people
override
fun
resourceIcon
()
=
R
.
drawable
.
ic_emoji_people
...
...
emoji/src/main/java/chat/rocket/android/emoji/internal/EmojiGlideModule.kt
0 → 100644
View file @
4e3936ca
package
chat.rocket.android.emoji.internal
import
android.content.Context
import
com.bumptech.glide.GlideBuilder
import
com.bumptech.glide.annotation.GlideModule
import
com.bumptech.glide.load.engine.cache.ExternalPreferredCacheDiskCacheFactory
import
com.bumptech.glide.module.AppGlideModule
@GlideModule
class
EmojiGlideModule
:
AppGlideModule
()
{
override
fun
applyOptions
(
context
:
Context
,
builder
:
GlideBuilder
)
{
builder
.
setDiskCache
(
ExternalPreferredCacheDiskCacheFactory
(
context
))
}
}
emoji/src/main/java/chat/rocket/android/emoji/internal/EmojiPagerAdapter.kt
View file @
4e3936ca
...
@@ -14,7 +14,9 @@ import chat.rocket.android.emoji.EmojiParser
...
@@ -14,7 +14,9 @@ import chat.rocket.android.emoji.EmojiParser
import
chat.rocket.android.emoji.EmojiRepository
import
chat.rocket.android.emoji.EmojiRepository
import
chat.rocket.android.emoji.Fitzpatrick
import
chat.rocket.android.emoji.Fitzpatrick
import
chat.rocket.android.emoji.R
import
chat.rocket.android.emoji.R
import
com.bumptech.glide.load.engine.DiskCacheStrategy
import
kotlinx.android.synthetic.main.emoji_category_layout.view.*
import
kotlinx.android.synthetic.main.emoji_category_layout.view.*
import
kotlinx.android.synthetic.main.emoji_image_row_item.view.*
import
kotlinx.android.synthetic.main.emoji_row_item.view.*
import
kotlinx.android.synthetic.main.emoji_row_item.view.*
import
kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.android.UI
import
kotlinx.coroutines.experimental.android.UI
...
@@ -43,22 +45,33 @@ internal class EmojiPagerAdapter(private val listener: EmojiKeyboardListener) :
...
@@ -43,22 +45,33 @@ internal class EmojiPagerAdapter(private val listener: EmojiKeyboardListener) :
container
.
addView
(
view
)
container
.
addView
(
view
)
launch
(
UI
)
{
launch
(
UI
)
{
val
currentServerUrl
=
EmojiRepository
.
getCurrentServerUrl
()
val
emojis
=
if
(
category
!=
EmojiCategory
.
RECENTS
)
{
val
emojis
=
if
(
category
!=
EmojiCategory
.
RECENTS
)
{
if
(
category
==
EmojiCategory
.
CUSTOM
)
{
currentServerUrl
?.
let
{
url
->
EmojiRepository
.
getEmojiSequenceByCategoryAndUrl
(
category
,
url
)
}
?:
emptySequence
()
}
else
{
EmojiRepository
.
getEmojiSequenceByCategory
(
category
)
EmojiRepository
.
getEmojiSequenceByCategory
(
category
)
}
}
else
{
}
else
{
sequenceOf
(*
EmojiRepository
.
getRecents
().
toTypedArray
())
sequenceOf
(*
EmojiRepository
.
getRecents
().
toTypedArray
())
}
}
val
recentEmojiSize
=
EmojiRepository
.
getRecents
().
size
val
recentEmojiSize
=
EmojiRepository
.
getRecents
().
size
text_no_recent_emoji
.
isVisible
=
category
==
EmojiCategory
.
RECENTS
&&
recentEmojiSize
==
0
text_no_recent_emoji
.
isVisible
=
category
==
EmojiCategory
.
RECENTS
&&
recentEmojiSize
==
0
if
(
adapters
[
category
]
==
null
)
{
if
(
adapters
[
category
]
==
null
)
{
val
adapter
=
EmojiAdapter
(
listener
=
listener
)
val
adapter
=
EmojiAdapter
(
listener
=
listener
)
emoji_recycler_view
.
adapter
=
adapter
emoji_recycler_view
.
adapter
=
adapter
adapters
[
category
]
=
adapter
adapters
[
category
]
=
adapter
adapter
.
addEmojisFromSequence
(
emojis
)
adapter
.
addEmojisFromSequence
(
emojis
)
}
}
adapters
[
category
]
!!
.
setFitzpatrick
(
fitzpatrick
)
adapters
[
category
]
!!
.
setFitzpatrick
(
fitzpatrick
)
}
}
}
}
return
view
return
view
}
}
...
@@ -88,20 +101,24 @@ internal class EmojiPagerAdapter(private val listener: EmojiKeyboardListener) :
...
@@ -88,20 +101,24 @@ internal class EmojiPagerAdapter(private val listener: EmojiKeyboardListener) :
private
val
listener
:
EmojiKeyboardListener
private
val
listener
:
EmojiKeyboardListener
)
:
RecyclerView
.
Adapter
<
EmojiRowViewHolder
>()
{
)
:
RecyclerView
.
Adapter
<
EmojiRowViewHolder
>()
{
private
val
CUSTOM
=
1
private
val
NORMAL
=
2
private
val
allEmojis
=
mutableListOf
<
Emoji
>()
private
val
emojis
=
mutableListOf
<
Emoji
>()
private
val
emojis
=
mutableListOf
<
Emoji
>()
fun
addEmojis
(
emojis
:
List
<
Emoji
>)
{
override
fun
getItemViewType
(
position
:
Int
):
Int
{
this
.
emojis
.
clear
()
return
if
(
emojis
[
position
].
isCustom
())
CUSTOM
else
NORMAL
this
.
emojis
.
addAll
(
emojis
)
notifyDataSetChanged
()
}
}
suspend
fun
addEmojisFromSequence
(
emojiSequence
:
Sequence
<
Emoji
>)
{
suspend
fun
addEmojisFromSequence
(
emojiSequence
:
Sequence
<
Emoji
>)
{
withContext
(
CommonPool
)
{
withContext
(
CommonPool
)
{
emojiSequence
.
forEachIndexed
{
index
,
emoji
->
emojiSequence
.
forEachIndexed
{
index
,
emoji
->
withContext
(
UI
)
{
withContext
(
UI
)
{
allEmojis
.
add
(
emoji
)
if
(
emoji
.
isDefault
)
{
emojis
.
add
(
emoji
)
emojis
.
add
(
emoji
)
notifyItemInserted
(
index
)
notifyItemInserted
(
emojis
.
size
-
1
)
}
}
}
}
}
}
}
...
@@ -115,12 +132,26 @@ internal class EmojiPagerAdapter(private val listener: EmojiKeyboardListener) :
...
@@ -115,12 +132,26 @@ internal class EmojiPagerAdapter(private val listener: EmojiKeyboardListener) :
override
fun
onBindViewHolder
(
holder
:
EmojiRowViewHolder
,
position
:
Int
)
{
override
fun
onBindViewHolder
(
holder
:
EmojiRowViewHolder
,
position
:
Int
)
{
val
emoji
=
emojis
[
position
]
val
emoji
=
emojis
[
position
]
holder
.
bind
(
holder
.
bind
(
emoji
.
siblings
.
find
{
it
.
fitzpatrick
==
fitzpatrick
}
?:
emoji
if
(
fitzpatrick
!=
Fitzpatrick
.
Default
)
{
emoji
.
siblings
.
find
{
it
.
endsWith
(
"${fitzpatrick.type}:"
)
}
?.
let
{
shortname
->
allEmojis
.
firstOrNull
{
it
.
shortname
==
shortname
}
}
?:
emoji
}
else
{
emoji
}
)
)
}
}
override
fun
onCreateViewHolder
(
parent
:
ViewGroup
,
viewType
:
Int
):
EmojiRowViewHolder
{
override
fun
onCreateViewHolder
(
parent
:
ViewGroup
,
viewType
:
Int
):
EmojiRowViewHolder
{
val
view
=
LayoutInflater
.
from
(
parent
.
context
).
inflate
(
R
.
layout
.
emoji_row_item
,
parent
,
false
)
val
view
=
if
(
viewType
==
CUSTOM
)
{
LayoutInflater
.
from
(
parent
.
context
).
inflate
(
R
.
layout
.
emoji_image_row_item
,
parent
,
false
)
}
else
{
LayoutInflater
.
from
(
parent
.
context
).
inflate
(
R
.
layout
.
emoji_row_item
,
parent
,
false
)
}
return
EmojiRowViewHolder
(
view
,
listener
)
return
EmojiRowViewHolder
(
view
,
listener
)
}
}
...
@@ -134,16 +165,26 @@ internal class EmojiPagerAdapter(private val listener: EmojiKeyboardListener) :
...
@@ -134,16 +165,26 @@ internal class EmojiPagerAdapter(private val listener: EmojiKeyboardListener) :
fun
bind
(
emoji
:
Emoji
)
{
fun
bind
(
emoji
:
Emoji
)
{
with
(
itemView
)
{
with
(
itemView
)
{
if
(
emoji
.
unicode
.
isNotEmpty
())
{
// Handle simple emoji.
val
parsedUnicode
=
unicodeCache
[
emoji
.
unicode
]
val
parsedUnicode
=
unicodeCache
[
emoji
.
unicode
]
emoji_view
.
setSpannableFactory
(
spannableFactory
)
emoji_view
.
setSpannableFactory
(
spannableFactory
)
emoji_view
.
text
=
if
(
parsedUnicode
==
null
)
{
emoji_view
.
text
=
if
(
parsedUnicode
==
null
)
{
EmojiParser
.
parse
(
emoji
.
unicode
,
spannableFactory
).
let
{
EmojiParser
.
parse
(
itemView
.
context
,
emoji
.
unicode
,
spannableFactory
).
let
{
unicodeCache
[
emoji
.
unicode
]
=
it
unicodeCache
[
emoji
.
unicode
]
=
it
it
it
}
}
}
else
{
}
else
{
parsedUnicode
parsedUnicode
}
}
}
else
{
// Handle custom emoji.
GlideApp
.
with
(
context
)
.
load
(
emoji
.
url
)
.
diskCacheStrategy
(
DiskCacheStrategy
.
ALL
)
.
into
(
emoji_image_view
)
}
itemView
.
setOnClickListener
{
itemView
.
setOnClickListener
{
listener
.
onEmojiAdded
(
emoji
)
listener
.
onEmojiAdded
(
emoji
)
}
}
...
...
emoji/src/main/java/chat/rocket/android/emoji/internal/Extensions.kt
0 → 100644
View file @
4e3936ca
package
chat.rocket.android.emoji.internal
import
chat.rocket.android.emoji.Emoji
fun
Emoji
.
isCustom
():
Boolean
=
this
.
url
!=
null
emoji/src/main/java/chat/rocket/android/emoji/internal/db/EmojiDatabase.kt
0 → 100644
View file @
4e3936ca
package
chat.rocket.android.emoji.internal.db
import
android.content.Context
import
androidx.room.Database
import
androidx.room.Room
import
androidx.room.RoomDatabase
import
androidx.room.TypeConverters
import
chat.rocket.android.emoji.Emoji
import
chat.rocket.android.emoji.EmojiDao
@Database
(
entities
=
[
Emoji
::
class
],
version
=
1
)
@TypeConverters
(
StringListConverter
::
class
)
abstract
class
EmojiDatabase
:
RoomDatabase
()
{
abstract
fun
emojiDao
():
EmojiDao
companion
object
:
SingletonHolder
<
EmojiDatabase
,
Context
>({
Room
.
databaseBuilder
(
it
.
applicationContext
,
EmojiDatabase
::
class
.
java
,
"emoji.db"
)
.
fallbackToDestructiveMigration
()
.
build
()
})
}
open
class
SingletonHolder
<
out
T
,
in
A
>(
creator
:
(
A
)
->
T
)
{
private
var
creator
:
((
A
)
->
T
)?
=
creator
@kotlin
.
jvm
.
Volatile
private
var
instance
:
T
?
=
null
fun
getInstance
(
arg
:
A
):
T
{
val
i
=
instance
if
(
i
!=
null
)
{
return
i
}
return
synchronized
(
this
)
{
val
i2
=
instance
if
(
i2
!=
null
)
{
i2
}
else
{
val
created
=
creator
!!
(
arg
)
instance
=
created
creator
=
null
created
}
}
}
}
emoji/src/main/java/chat/rocket/android/emoji/internal/db/StringListConverter.kt
0 → 100644
View file @
4e3936ca
package
chat.rocket.android.emoji.internal.db
import
androidx.room.TypeConverter
class
StringListConverter
{
@TypeConverter
fun
fromStringList
(
list
:
List
<
String
>?):
String
{
return
list
?.
joinToString
(
separator
=
","
)
?:
""
}
@TypeConverter
fun
fromString
(
value
:
String
?):
List
<
String
>
{
return
value
?.
split
(
","
)
?:
emptyList
()
}
}
emoji/src/main/res/drawable-hdpi/ic_emoji_custom.png
0 → 100644
View file @
4e3936ca
1.61 KB
emoji/src/main/res/drawable-mdpi/ic_emoji_custom.png
0 → 100644
View file @
4e3936ca
1.09 KB
emoji/src/main/res/drawable-xhdpi/ic_emoji_custom.png
0 → 100644
View file @
4e3936ca
2.42 KB
emoji/src/main/res/drawable-xxhdpi/ic_emoji_custom.png
0 → 100644
View file @
4e3936ca
3.23 KB
emoji/src/main/res/drawable-xxxhdpi/ic_emoji_custom.png
0 → 100644
View file @
4e3936ca
6.84 KB
emoji/src/main/res/layout/emoji_image_row_item.xml
0 → 100644
View file @
4e3936ca
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:tools=
"http://schemas.android.com/tools"
android:layout_width=
"48dp"
android:layout_height=
"48dp"
android:layout_gravity=
"center"
>
<ImageView
android:id=
"@+id/emoji_image_view"
android:layout_width=
"32dp"
android:layout_height=
"32dp"
android:layout_gravity=
"center"
tools:src=
"@tools:sample/avatars"
/>
</FrameLayout>
emoji/src/main/res/layout/emoji_row_item.xml
View file @
4e3936ca
...
@@ -6,6 +6,7 @@
...
@@ -6,6 +6,7 @@
android:layout_width=
"48dp"
android:layout_width=
"48dp"
android:layout_height=
"48dp"
android:layout_height=
"48dp"
android:foreground=
"?selectableItemBackground"
android:foreground=
"?selectableItemBackground"
android:gravity=
"center"
android:textColor=
"#000000"
android:textColor=
"#000000"
android:textSize=
"26sp"
android:textSize=
"26sp"
tools:text=
"😀"
/>
tools:text=
"😀"
/>
emoji/src/main/res/values/dimens.xml
View file @
4e3936ca
...
@@ -5,5 +5,6 @@
...
@@ -5,5 +5,6 @@
<dimen
name=
"supposed_keyboard_height"
>
252dp
</dimen>
<dimen
name=
"supposed_keyboard_height"
>
252dp
</dimen>
<dimen
name=
"picker_popup_height"
>
250dp
</dimen>
<dimen
name=
"picker_popup_height"
>
250dp
</dimen>
<dimen
name=
"picker_popup_width"
>
300dp
</dimen>
<dimen
name=
"picker_popup_width"
>
300dp
</dimen>
<dimen
name=
"custom_emoji_large"
>
32dp
</dimen>
<dimen
name=
"custom_emoji_small"
>
22dp
</dimen>
</resources>
</resources>
gradle/wrapper/gradle-wrapper.properties
View file @
4e3936ca
#
Wed Aug 01 22:00:00 ED
T 2018
#
Mon Aug 06 11:30:07 BR
T 2018
distributionBase
=
GRADLE_USER_HOME
distributionBase
=
GRADLE_USER_HOME
distributionPath
=
wrapper/dists
distributionPath
=
wrapper/dists
zipStoreBase
=
GRADLE_USER_HOME
zipStoreBase
=
GRADLE_USER_HOME
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment