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
30b52d33
Commit
30b52d33
authored
Aug 04, 2018
by
Leonardo Aramaki
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Save Emoji data offline on sqlite using Room
parent
2668032b
Changes
11
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
218 additions
and
59 deletions
+218
-59
MainPresenter.kt
...va/chat/rocket/android/main/presentation/MainPresenter.kt
+3
-2
build.gradle
emoji/build.gradle
+2
-0
Emoji.kt
emoji/src/main/java/chat/rocket/android/emoji/Emoji.kt
+16
-9
EmojiDao.kt
emoji/src/main/java/chat/rocket/android/emoji/EmojiDao.kt
+42
-0
EmojiKeyboardPopup.kt
...main/java/chat/rocket/android/emoji/EmojiKeyboardPopup.kt
+9
-3
EmojiParser.kt
emoji/src/main/java/chat/rocket/android/emoji/EmojiParser.kt
+0
-5
EmojiPickerPopup.kt
...c/main/java/chat/rocket/android/emoji/EmojiPickerPopup.kt
+7
-3
EmojiRepository.kt
...rc/main/java/chat/rocket/android/emoji/EmojiRepository.kt
+62
-36
EmojiPagerAdapter.kt
...a/chat/rocket/android/emoji/internal/EmojiPagerAdapter.kt
+11
-1
EmojiDatabase.kt
...va/chat/rocket/android/emoji/internal/db/EmojiDatabase.kt
+48
-0
StringListConverter.kt
...t/rocket/android/emoji/internal/db/StringListConverter.kt
+18
-0
No files found.
app/src/main/java/chat/rocket/android/main/presentation/MainPresenter.kt
View file @
30b52d33
...
...
@@ -137,11 +137,12 @@ class MainPresenter @Inject constructor(
category
=
EmojiCategory
.
CUSTOM
.
name
,
url
=
"$currentServer/emoji-custom/${customEmoji.name}.${customEmoji.extension}"
,
count
=
0
,
fitzpatrick
=
Fitzpatrick
.
Default
,
fitzpatrick
=
Fitzpatrick
.
Default
.
type
,
keywords
=
customEmoji
.
aliases
,
shortnameAlternates
=
customEmoji
.
aliases
,
siblings
=
mutableListOf
(),
unicode
=
""
unicode
=
""
,
default
=
true
))
}
...
...
emoji/build.gradle
View file @
30b52d33
...
...
@@ -37,6 +37,8 @@ dependencies {
implementation
libraries
.
material
implementation
libraries
.
glide
kapt
libraries
.
glideProcessor
implementation
libraries
.
room
kapt
libraries
.
roomProcessor
}
kotlin
{
...
...
emoji/src/main/java/chat/rocket/android/emoji/Emoji.kt
View file @
30b52d33
package
chat.rocket.android.emoji
import
androidx.room.Entity
import
androidx.room.Ignore
import
androidx.room.PrimaryKey
@Entity
data class
Emoji
(
val
shortname
:
String
,
val
shortnameAlternates
:
List
<
String
>,
val
unicode
:
String
,
val
keywords
:
List
<
String
>,
val
category
:
String
,
val
count
:
Int
=
0
,
val
siblings
:
MutableCollection
<
Emoji
>
=
mutableListOf
(),
val
fitzpatrick
:
Fitzpatrick
=
Fitzpatrick
.
Default
,
val
url
:
String
?
=
null
// Filled for custom emojis
@PrimaryKey
var
shortname
:
String
=
""
,
var
shortnameAlternates
:
List
<
String
>
=
listOf
(),
var
unicode
:
String
=
""
,
@Ignore
val
keywords
:
List
<
String
>
=
listOf
(),
var
category
:
String
=
""
,
var
count
:
Int
=
0
,
var
siblings
:
List
<
String
>
=
listOf
(),
var
fitzpatrick
:
String
=
Fitzpatrick
.
Default
.
type
,
var
url
:
String
?
=
null
,
// Filled for custom emojis
var
default
:
Boolean
=
true
)
emoji/src/main/java/chat/rocket/android/emoji/EmojiDao.kt
0 → 100644
View file @
30b52d33
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
):
Emoji
?
@Query
(
"SELECT * FROM emoji WHERE UPPER(category)=UPPER(:category)"
)
fun
loadEmojisByCategory
(
category
:
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 @
30b52d33
...
...
@@ -22,6 +22,8 @@ import chat.rocket.android.emoji.internal.EmojiCategory
import
chat.rocket.android.emoji.internal.EmojiPagerAdapter
import
chat.rocket.android.emoji.internal.PREF_EMOJI_SKIN_TONE
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
)
{
...
...
@@ -49,9 +51,11 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
}
override
fun
onViewCreated
(
view
:
View
)
{
launch
(
UI
)
{
setupViewPager
()
setupBottomBar
()
}
}
private
fun
setupBottomBar
()
{
searchView
.
setOnClickListener
{
...
...
@@ -148,7 +152,7 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
}
}
private
fun
setupViewPager
()
{
private
suspend
fun
setupViewPager
()
{
context
.
let
{
val
callback
=
when
(
it
)
{
is
EmojiKeyboardListener
->
it
...
...
@@ -167,6 +171,7 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
callback
.
onEmojiAdded
(
emoji
)
}
})
viewPager
.
offscreenPageLimit
=
EmojiCategory
.
values
().
size
viewPager
.
adapter
=
adapter
...
...
@@ -183,6 +188,7 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
}
else
{
EmojiCategory
.
RECENTS
.
ordinal
}
viewPager
.
currentItem
=
currentTab
}
}
...
...
emoji/src/main/java/chat/rocket/android/emoji/EmojiParser.kt
View file @
30b52d33
...
...
@@ -2,19 +2,14 @@ package chat.rocket.android.emoji
import
android.content.Context
import
android.graphics.Bitmap
import
android.graphics.drawable.BitmapDrawable
import
android.text.Spannable
import
android.text.SpannableString
import
android.text.Spanned
import
android.text.style.ImageSpan
import
android.util.Log
import
chat.rocket.android.emoji.internal.GlideApp
import
com.bumptech.glide.Glide
import
com.bumptech.glide.load.engine.DiskCacheStrategy
import
com.bumptech.glide.load.resource.gif.GifDrawable
import
com.bumptech.glide.request.FutureTarget
import
com.bumptech.glide.request.RequestFutureTarget
import
com.bumptech.glide.request.RequestOptions
import
kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.Deferred
import
kotlinx.coroutines.experimental.async
...
...
emoji/src/main/java/chat/rocket/android/emoji/EmojiPickerPopup.kt
View file @
30b52d33
...
...
@@ -14,6 +14,8 @@ import chat.rocket.android.emoji.internal.EmojiCategory
import
chat.rocket.android.emoji.internal.EmojiPagerAdapter
import
chat.rocket.android.emoji.internal.PREF_EMOJI_SKIN_TONE
import
kotlinx.android.synthetic.main.emoji_picker.*
import
kotlinx.coroutines.experimental.android.UI
import
kotlinx.coroutines.experimental.launch
class
EmojiPickerPopup
(
context
:
Context
)
:
Dialog
(
context
)
{
...
...
@@ -27,9 +29,11 @@ class EmojiPickerPopup(context: Context) : Dialog(context) {
setContentView
(
R
.
layout
.
emoji_picker
)
tabs
.
setupWithViewPager
(
pager_categories
)
launch
(
UI
)
{
setupViewPager
()
setSize
()
}
}
private
fun
setSize
()
{
val
lp
=
WindowManager
.
LayoutParams
()
...
...
@@ -39,7 +43,7 @@ class EmojiPickerPopup(context: Context) : Dialog(context) {
window
.
setLayout
(
dialogWidth
,
dialogHeight
)
}
private
fun
setupViewPager
()
{
private
suspend
fun
setupViewPager
()
{
adapter
=
EmojiPagerAdapter
(
object
:
EmojiKeyboardListener
{
override
fun
onEmojiAdded
(
emoji
:
Emoji
)
{
EmojiRepository
.
addToRecents
(
emoji
)
...
...
emoji/src/main/java/chat/rocket/android/emoji/EmojiRepository.kt
View file @
30b52d33
...
...
@@ -5,9 +5,11 @@ import android.content.SharedPreferences
import
android.graphics.Typeface
import
chat.rocket.android.emoji.internal.EmojiCategory
import
chat.rocket.android.emoji.internal.PREF_EMOJI_RECENTS
import
chat.rocket.android.emoji.internal.db.EmojiDatabase
import
com.bumptech.glide.Glide
import
kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.launch
import
kotlinx.coroutines.experimental.withContext
import
org.json.JSONArray
import
org.json.JSONObject
import
java.io.BufferedReader
...
...
@@ -24,18 +26,20 @@ object EmojiRepository {
private
val
FITZPATRICK_REGEX
=
"(.*)_(tone[0-9]):"
.
toRegex
(
RegexOption
.
IGNORE_CASE
)
private
val
shortNameToUnicode
=
HashMap
<
String
,
String
>()
private
val
SHORTNAME_PATTERN
=
Pattern
.
compile
(
":([-+\\w]+):"
)
private
val
ALL_EMOJIS
=
mutableListOf
<
Emoji
>()
private
var
customEmojis
:
List
<
Emoji
>
=
emptyList
()
private
var
customEmojis
=
listOf
<
Emoji
>()
private
lateinit
var
preferences
:
SharedPreferences
internal
lateinit
var
cachedTypeface
:
Typeface
private
lateinit
var
db
:
EmojiDatabase
fun
load
(
context
:
Context
,
customEmojis
:
List
<
Emoji
>
=
emptyList
(),
path
:
String
=
"emoji.json"
)
{
launch
(
CommonPool
)
{
cachedTypeface
=
Typeface
.
createFromAsset
(
context
.
assets
,
"fonts/emojione-android.ttf"
)
this
@EmojiRepository
.
customEmojis
=
customEmojis
val
allEmojis
=
mutableListOf
<
Emoji
>()
db
=
EmojiDatabase
.
getInstance
(
context
)
cachedTypeface
=
Typeface
.
createFromAsset
(
context
.
assets
,
"fonts/emojione-android.ttf"
)
preferences
=
context
.
getSharedPreferences
(
"emoji"
,
Context
.
MODE_PRIVATE
)
ALL_EMOJIS
.
clear
()
val
stream
=
context
.
assets
.
open
(
path
)
// Load emojis from emojione ttf file temporarily here. We still need to work on them.
val
emojis
=
loadEmojis
(
stream
).
also
{
it
.
addAll
(
customEmojis
)
}.
toList
()
...
...
@@ -43,9 +47,11 @@ object EmojiRepository {
for
(
emoji
in
emojis
)
{
val
unicodeIntList
=
mutableListOf
<
Int
>()
// If empty it's a custom emoji.
emoji
.
category
=
emoji
.
category
.
toUpperCase
()
// If unicode is empty it's a custom emoji, just add it.
if
(
emoji
.
unicode
.
isEmpty
())
{
ALL_EMOJIS
.
add
(
emoji
)
allEmojis
.
add
(
emoji
)
continue
}
...
...
@@ -59,31 +65,38 @@ object EmojiRepository {
unicodeIntList
.
add
(
value
)
}
}
val
unicodeIntArray
=
unicodeIntList
.
toIntArray
()
val
unicode
=
String
(
unicodeIntArray
,
0
,
unicodeIntArray
.
size
)
val
emojiWithUnicode
=
emoji
.
copy
(
unicode
=
unicode
)
if
(
hasFitzpatrick
(
emoji
.
shortname
))
{
val
matchResult
=
FITZPATRICK_REGEX
.
find
(
emoji
.
shortname
)
val
prefix
=
matchResult
!!
.
groupValues
[
1
]
+
":"
val
fitzpatrick
=
Fitzpatrick
.
valueOf
(
matchResult
.
groupValues
[
2
])
val
defaultEmoji
=
ALL_EMOJIS
.
firstOrNull
{
it
.
shortname
==
prefix
}
val
emojiWithFitzpatrick
=
emojiWithUnicode
.
copy
(
fitzpatrick
=
fitzpatrick
)
val
defaultEmoji
=
allEmojis
.
firstOrNull
{
it
.
shortname
==
prefix
}
val
emojiWithFitzpatrick
=
emojiWithUnicode
.
copy
(
fitzpatrick
=
fitzpatrick
.
type
)
if
(
defaultEmoji
!=
null
)
{
defaultEmoji
.
siblings
.
add
(
emojiWithFitzpatrick
)
emojiWithFitzpatrick
.
default
=
false
defaultEmoji
.
siblings
.
toMutableList
().
add
(
emoji
.
shortname
)
}
else
{
// This emoji doesn't have a default tone, ie. :man_in_business_suit_levitating_tone1:
// In this case, the default emoji becomes the first toned one.
ALL_EMOJIS
.
add
(
emojiWithFitzpatrick
)
allEmojis
.
add
(
emojiWithFitzpatrick
)
}
}
else
{
ALL_EMOJIS
.
add
(
emojiWithUnicode
)
allEmojis
.
add
(
emojiWithUnicode
)
}
shortNameToUnicode
.
apply
{
put
(
emoji
.
shortname
,
unicode
)
emoji
.
shortnameAlternates
.
forEach
{
alternate
->
put
(
alternate
,
unicode
)
}
}
}
saveEmojisToDatabase
(
allEmojis
.
toList
())
val
density
=
context
.
resources
.
displayMetrics
.
density
val
px
=
(
32
*
density
).
toInt
()
...
...
@@ -96,6 +109,12 @@ object EmojiRepository {
}
}
private
suspend
fun
saveEmojisToDatabase
(
emojis
:
List
<
Emoji
>)
{
withContext
(
CommonPool
)
{
db
.
emojiDao
().
insertAllEmojis
(*
emojis
.
toTypedArray
())
}
}
private
fun
hasFitzpatrick
(
shortname
:
String
):
Boolean
{
return
FITZPATRICK_REGEX
matches
shortname
}
...
...
@@ -105,21 +124,15 @@ object EmojiRepository {
*
* @return All emojis for all categories.
*/
internal
fun
getAll
()
=
ALL_EMOJIS
internal
suspend
fun
getAll
():
List
<
Emoji
>
=
withContext
(
CommonPool
)
{
return
@withContext
db
.
emojiDao
().
loadAllEmojis
()
}
/**
* Get all emojis for a given category.
*
* @param category Emoji category such as: PEOPLE, NATURE, ETC
*
* @return All emoji from specified category
*/
internal
fun
getEmojisByCategory
(
category
:
EmojiCategory
):
List
<
Emoji
>
{
return
ALL_EMOJIS
.
filter
{
it
.
category
.
toLowerCase
()
==
category
.
name
.
toLowerCase
()
}
internal
suspend
fun
getEmojiSequenceByCategory
(
category
:
EmojiCategory
):
Sequence
<
Emoji
>
{
val
list
=
withContext
(
CommonPool
)
{
db
.
emojiDao
().
loadEmojisByCategory
(
category
.
name
.
toLowerCase
())
}
internal
fun
getEmojiSequenceByCategory
(
category
:
EmojiCategory
):
Sequence
<
Emoji
>
{
val
list
=
ALL_EMOJIS
.
filter
{
it
.
category
.
toLowerCase
()
==
category
.
name
.
toLowerCase
()
}
return
buildSequence
{
list
.
forEach
{
yield
(
it
)
...
...
@@ -134,7 +147,9 @@ object EmojiRepository {
*
* @return Emoji given by shortname or null
*/
internal
fun
getEmojiByShortname
(
shortname
:
String
)
=
ALL_EMOJIS
.
firstOrNull
{
it
.
shortname
==
shortname
}
private
suspend
fun
getEmojiByShortname
(
shortname
:
String
):
Emoji
?
=
withContext
(
CommonPool
)
{
return
@withContext
db
.
emojiDao
().
loadEmojiByShortname
(
shortname
)
}
/**
* Add an emoji to the Recents category.
...
...
@@ -151,6 +166,14 @@ object EmojiRepository {
preferences
.
edit
().
putString
(
PREF_EMOJI_RECENTS
,
recentsJson
.
toString
()).
apply
()
}
internal
suspend
fun
getCustomEmojisAsync
():
List
<
Emoji
>
{
return
withContext
(
CommonPool
)
{
db
.
emojiDao
().
loadAllCustomEmojis
().
also
{
this
.
customEmojis
=
it
}
}
}
internal
fun
getCustomEmojis
():
List
<
Emoji
>
=
customEmojis
/**
...
...
@@ -158,19 +181,22 @@ object EmojiRepository {
*
* @return All recent emojis ordered by usage.
*/
internal
fun
getRecents
():
List
<
Emoji
>
{
internal
suspend
fun
getRecents
():
List
<
Emoji
>
{
val
list
=
mutableListOf
<
Emoji
>()
val
recentsJson
=
JSONObject
(
preferences
.
getString
(
PREF_EMOJI_RECENTS
,
"{}"
))
for
(
shortname
in
recentsJson
.
keys
())
{
val
emoji
=
getEmojiByShortname
(
shortname
)
emoji
?.
let
{
val
useCount
=
recentsJson
.
getInt
(
it
.
shortname
)
list
.
add
(
it
.
copy
(
count
=
useCount
))
}
}
list
.
sortWith
(
Comparator
{
o1
,
o2
->
o2
.
count
-
o1
.
count
})
// for (shortname in recentsJson.keys()) {
// val emoji = getEmojiByShortname(shortname)
// emoji?.let {
// val useCount = recentsJson.getInt(it.shortname)
// list.add(it.copy(count = useCount))
// }
// }
//
// list.sortWith(Comparator { o1, o2 ->
// o2.count - o1.count
// })
return
list
}
...
...
emoji/src/main/java/chat/rocket/android/emoji/internal/EmojiPagerAdapter.kt
View file @
30b52d33
...
...
@@ -53,17 +53,21 @@ internal class EmojiPagerAdapter(private val listener: EmojiKeyboardListener) :
}
else
{
sequenceOf
(*
EmojiRepository
.
getRecents
().
toTypedArray
())
}
val
recentEmojiSize
=
EmojiRepository
.
getRecents
().
size
text_no_recent_emoji
.
isVisible
=
category
==
EmojiCategory
.
RECENTS
&&
recentEmojiSize
==
0
if
(
adapters
[
category
]
==
null
)
{
val
adapter
=
EmojiAdapter
(
listener
=
listener
)
emoji_recycler_view
.
adapter
=
adapter
adapters
[
category
]
=
adapter
adapter
.
addEmojisFromSequence
(
emojis
)
}
adapters
[
category
]
!!
.
setFitzpatrick
(
fitzpatrick
)
}
}
return
view
}
...
...
@@ -126,7 +130,13 @@ internal class EmojiPagerAdapter(private val listener: EmojiKeyboardListener) :
override
fun
onBindViewHolder
(
holder
:
EmojiRowViewHolder
,
position
:
Int
)
{
val
emoji
=
emojis
[
position
]
holder
.
bind
(
emoji
.
siblings
.
find
{
it
.
fitzpatrick
==
fitzpatrick
}
?:
emoji
emoji
.
siblings
.
find
{
it
.
endsWith
(
fitzpatrick
.
type
)
}
?.
let
{
shortname
->
emojis
.
firstOrNull
{
it
.
shortname
==
shortname
}
}
?:
emoji
)
}
...
...
emoji/src/main/java/chat/rocket/android/emoji/internal/db/EmojiDatabase.kt
0 → 100644
View file @
30b52d33
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 @
30b52d33
package
chat.rocket.android.emoji.internal.db
import
androidx.room.TypeConverter
internal
object
StringListConverter
{
@TypeConverter
@JvmStatic
fun
toString
(
list
:
List
<
String
>?):
String
?
{
return
if
(
list
==
null
)
null
else
list
.
joinToString
(
separator
=
","
)
}
@TypeConverter
@JvmStatic
fun
toStringList
(
value
:
String
?):
List
<
String
>?
{
return
value
?.
split
(
","
)
}
}
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