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
190d0dc5
Commit
190d0dc5
authored
Jul 01, 2018
by
divyanshu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
resolved conflicts
parent
74031054
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
288 additions
and
179 deletions
+288
-179
build.gradle
app/build.gradle
+25
-16
ChatRoomFragment.kt
.../java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
+244
-105
build.gradle
draw/build.gradle
+1
-1
ExampleInstrumentedTest.java
...ava/chat/rocket/android/draw/ExampleInstrumentedTest.java
+0
-26
DrawingActivity.kt
...src/main/java/chat/rocket/android/draw/DrawingActivity.kt
+6
-5
CustomDrawView.kt
...in/java/chat/rocket/android/draw/widget/CustomDrawView.kt
+6
-4
activity_drawing.xml
draw/src/main/res/layout/activity_drawing.xml
+5
-4
ExampleUnitTest.java
...c/test/java/chat/rocket/android/draw/ExampleUnitTest.java
+0
-17
settings.gradle
settings.gradle
+1
-1
No files found.
app/build.gradle
View file @
190d0dc5
...
...
@@ -3,7 +3,6 @@ apply plugin: 'io.fabric'
apply
plugin:
'kotlin-android'
apply
plugin:
'kotlin-android-extensions'
apply
plugin:
'kotlin-kapt'
apply
plugin:
'realm-android'
android
{
compileSdkVersion
versions
.
compileSdk
...
...
@@ -11,11 +10,11 @@ android {
defaultConfig
{
applicationId
"chat.rocket.android"
minSdkVersion
21
minSdkVersion
versions
.
minSdk
targetSdkVersion
versions
.
targetSdk
versionCode
20
22
versionName
"2.
3
.0"
testInstrumentationRunner
"android
.support
.test.runner.AndroidJUnitRunner"
versionCode
20
30
versionName
"2.
4
.0"
testInstrumentationRunner
"android
x
.test.runner.AndroidJUnitRunner"
multiDexEnabled
true
}
...
...
@@ -26,12 +25,19 @@ android {
keyAlias
System
.
getenv
(
"KEY_ALIAS"
)
keyPassword
System
.
getenv
(
"KEY_PASSWORD"
)
}
debug
{
storeFile
project
.
rootProject
.
file
(
'debug.keystore'
).
getCanonicalFile
()
storePassword
"android"
keyAlias
"androiddebugkey"
keyPassword
"android"
}
}
buildTypes
{
release
{
buildConfigField
"String"
,
"REQUIRED_SERVER_VERSION"
,
'"0.62.0"'
buildConfigField
"String"
,
"RECOMMENDED_SERVER_VERSION"
,
'"0.6
3.0
"'
buildConfigField
"String"
,
"RECOMMENDED_SERVER_VERSION"
,
'"0.6
4.2
"'
signingConfig
signingConfigs
.
release
minifyEnabled
false
proguardFiles
getDefaultProguardFile
(
'proguard-android.txt'
),
'proguard-rules.pro'
...
...
@@ -39,13 +45,15 @@ android {
debug
{
buildConfigField
"String"
,
"REQUIRED_SERVER_VERSION"
,
'"0.62.0"'
buildConfigField
"String"
,
"RECOMMENDED_SERVER_VERSION"
,
'"0.63.0"'
buildConfigField
"String"
,
"RECOMMENDED_SERVER_VERSION"
,
'"0.64.2"'
signingConfig
signingConfigs
.
debug
applicationIdSuffix
".dev"
}
}
packagingOptions
{
exclude
'META-INF/core.kotlin_module'
exclude
'META-INF/main.kotlin_module'
}
}
...
...
@@ -53,6 +61,8 @@ dependencies {
implementation
fileTree
(
include:
[
'*.jar'
],
dir:
'libs'
)
implementation
project
(
':player'
)
implementation
project
(
':emoji'
)
implementation
project
(
':draw'
)
implementation
libraries
.
kotlin
implementation
libraries
.
coroutines
...
...
@@ -60,11 +70,11 @@ dependencies {
implementation
libraries
.
appCompat
implementation
libraries
.
recyclerview
implementation
libraries
.
design
implementation
libraries
.
constraint
L
ayout
implementation
libraries
.
card
V
iew
implementation
libraries
.
material
implementation
libraries
.
constraint
l
ayout
implementation
libraries
.
card
v
iew
implementation
libraries
.
flexbox
implementation
libraries
.
customTabs
implementation
libraries
.
browser
implementation
libraries
.
androidKtx
...
...
@@ -73,12 +83,11 @@ dependencies {
kapt
libraries
.
daggerProcessor
kapt
libraries
.
daggerAndroidApt
implementation
libraries
.
playServicesG
cm
implementation
libraries
.
f
cm
implementation
libraries
.
playServicesAuth
implementation
libraries
.
room
kapt
libraries
.
roomProcessor
implementation
libraries
.
roomRxjava
implementation
libraries
.
lifecycleExtensions
kapt
libraries
.
lifecycleCompiler
...
...
@@ -106,11 +115,11 @@ dependencies {
implementation
libraries
.
markwon
implementation
libraries
.
sheetMenu
implementation
libraries
.
aVLoadingIndicatorView
implementation
(
'com.crashlytics.sdk.android:crashlytics:2.6.8@aar'
)
{
implementation
"com.github.luciofm:livedata-ktx:b1e8bbc25a"
implementation
(
'com.crashlytics.sdk.android:crashlytics:2.9.2@aar'
)
{
transitive
=
true
}
...
...
app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
View file @
190d0dc5
package
chat.rocket.android.chatroom.ui
import
android.Manifest
import
android.app.Activity
import
android.content.ClipData
import
android.content.ClipboardManager
import
android.content.Context
import
android.content.Intent
import
android.graphics.Bitmap
import
android.graphics.BitmapFactory
import
android.net.Uri
import
android.os.Bundle
import
android.os.Environment
import
android.os.Handler
import
android.support.annotation.DrawableRes
import
android.support.v4.app.Fragment
import
android.support.v7.widget.DefaultItemAnimator
import
android.support.v7.widget.LinearLayoutManager
import
android.support.v7.widget.RecyclerView
import
android.text.SpannableStringBuilder
import
android.view.*
import
android.view.KeyEvent
import
android.view.LayoutInflater
import
android.view.Menu
import
android.view.MenuInflater
import
android.view.MenuItem
import
android.view.View
import
android.view.ViewGroup
import
androidx.annotation.DrawableRes
import
androidx.core.text.bold
import
androidx.core.view.isVisible
import
androidx.fragment.app.Fragment
import
androidx.recyclerview.widget.DefaultItemAnimator
import
androidx.recyclerview.widget.LinearLayoutManager
import
androidx.recyclerview.widget.RecyclerView
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.adapter.*
import
chat.rocket.android.chatroom.adapter.ChatRoomAdapter
import
chat.rocket.android.chatroom.adapter.CommandSuggestionsAdapter
import
chat.rocket.android.chatroom.adapter.PEOPLE
import
chat.rocket.android.chatroom.adapter.PeopleSuggestionsAdapter
import
chat.rocket.android.chatroom.adapter.RoomSuggestionsAdapter
import
chat.rocket.android.chatroom.presentation.ChatRoomPresenter
import
chat.rocket.android.chatroom.presentation.ChatRoomView
import
chat.rocket.android.chatroom.viewmodel.BaseViewModel
import
chat.rocket.android.chatroom.viewmodel.MessageViewModel
import
chat.rocket.android.chatroom.viewmodel.suggestion.ChatRoomSuggestionViewModel
import
chat.rocket.android.chatroom.viewmodel.suggestion.CommandSuggestionViewModel
import
chat.rocket.android.chatroom.viewmodel.suggestion.PeopleSuggestionViewModel
import
chat.rocket.android.chatroom.uimodel.BaseUiModel
import
chat.rocket.android.chatroom.uimodel.MessageUiModel
import
chat.rocket.android.chatroom.uimodel.suggestion.ChatRoomSuggestionUiModel
import
chat.rocket.android.chatroom.uimodel.suggestion.CommandSuggestionUiModel
import
chat.rocket.android.chatroom.uimodel.suggestion.PeopleSuggestionUiModel
import
chat.rocket.android.draw.DrawingActivity
import
chat.rocket.android.emoji.ComposerEditText
import
chat.rocket.android.emoji.Emoji
import
chat.rocket.android.emoji.EmojiKeyboardListener
import
chat.rocket.android.emoji.EmojiKeyboardPopup
import
chat.rocket.android.emoji.EmojiParser
import
chat.rocket.android.emoji.EmojiPickerPopup
import
chat.rocket.android.emoji.EmojiReactionListener
import
chat.rocket.android.helper.AndroidPermissionsHelper
import
chat.rocket.android.helper.EndlessRecyclerViewScrollListener
import
chat.rocket.android.helper.KeyboardHelper
import
chat.rocket.android.helper.MessageParser
import
chat.rocket.android.util.extensions.*
import
chat.rocket.android.widget.emoji.*
import
chat.rocket.android.util.extensions.asObservable
import
chat.rocket.android.util.extensions.circularRevealOrUnreveal
import
chat.rocket.android.util.extensions.fadeIn
import
chat.rocket.android.util.extensions.fadeOut
import
chat.rocket.android.util.extensions.hideKeyboard
import
chat.rocket.android.util.extensions.inflate
import
chat.rocket.android.util.extensions.rotateBy
import
chat.rocket.android.util.extensions.showToast
import
chat.rocket.android.util.extensions.textContent
import
chat.rocket.android.util.extensions.ui
import
chat.rocket.common.model.RoomType
import
chat.rocket.common.model.roomTypeOf
import
chat.rocket.core.internal.realtime.socket.model.State
import
chat.rocket.core.model.ChatRoom
import
dagger.android.support.AndroidSupportInjection
...
...
@@ -41,6 +74,9 @@ import kotlinx.android.synthetic.main.fragment_chat_room.*
import
kotlinx.android.synthetic.main.message_attachment_options.*
import
kotlinx.android.synthetic.main.message_composer.*
import
kotlinx.android.synthetic.main.message_list.*
import
java.io.File
import
java.io.FileOutputStream
import
java.util.*
import
java.util.concurrent.TimeUnit
import
java.util.concurrent.atomic.AtomicInteger
import
javax.inject.Inject
...
...
@@ -49,10 +85,11 @@ fun newInstance(
chatRoomId
:
String
,
chatRoomName
:
String
,
chatRoomType
:
String
,
is
ChatRoom
ReadOnly
:
Boolean
,
isReadOnly
:
Boolean
,
chatRoomLastSeen
:
Long
,
isSubscribed
:
Boolean
=
true
,
isChatRoomCreator
:
Boolean
=
false
,
isCreator
:
Boolean
=
false
,
isFavorite
:
Boolean
=
false
,
chatRoomMessage
:
String
?
=
null
):
Fragment
{
return
ChatRoomFragment
().
apply
{
...
...
@@ -60,10 +97,11 @@ fun newInstance(
putString
(
BUNDLE_CHAT_ROOM_ID
,
chatRoomId
)
putString
(
BUNDLE_CHAT_ROOM_NAME
,
chatRoomName
)
putString
(
BUNDLE_CHAT_ROOM_TYPE
,
chatRoomType
)
putBoolean
(
BUNDLE_IS_CHAT_ROOM_READ_ONLY
,
is
ChatRoom
ReadOnly
)
putBoolean
(
BUNDLE_IS_CHAT_ROOM_READ_ONLY
,
isReadOnly
)
putLong
(
BUNDLE_CHAT_ROOM_LAST_SEEN
,
chatRoomLastSeen
)
putBoolean
(
BUNDLE_CHAT_ROOM_IS_SUBSCRIBED
,
isSubscribed
)
putBoolean
(
BUNDLE_CHAT_ROOM_IS_CREATOR
,
isChatRoomCreator
)
putBoolean
(
BUNDLE_CHAT_ROOM_IS_CREATOR
,
isCreator
)
putBoolean
(
BUNDLE_CHAT_ROOM_IS_FAVORITE
,
isFavorite
)
putString
(
BUNDLE_CHAT_ROOM_MESSAGE
,
chatRoomMessage
)
}
}
...
...
@@ -74,11 +112,20 @@ private const val BUNDLE_CHAT_ROOM_NAME = "chat_room_name"
private
const
val
BUNDLE_CHAT_ROOM_TYPE
=
"chat_room_type"
private
const
val
BUNDLE_IS_CHAT_ROOM_READ_ONLY
=
"is_chat_room_read_only"
private
const
val
REQUEST_CODE_FOR_PERFORM_SAF
=
42
private
const
val
REQUEST_CODE_FOR_DRAW
=
101
private
const
val
BUNDLE_CHAT_ROOM_LAST_SEEN
=
"chat_room_last_seen"
private
const
val
BUNDLE_CHAT_ROOM_IS_SUBSCRIBED
=
"chat_room_is_subscribed"
private
const
val
BUNDLE_CHAT_ROOM_IS_CREATOR
=
"chat_room_is_creator"
private
const
val
BUNDLE_CHAT_ROOM_IS_FAVORITE
=
"chat_room_is_favorite"
private
const
val
BUNDLE_CHAT_ROOM_MESSAGE
=
"chat_room_message"
private
const
val
MENU_ACTION_FAVORITE_UNFAVORITE_CHAT
=
1
private
const
val
MENU_ACTION_MEMBER
=
2
private
const
val
MENU_ACTION_MENTIONS
=
3
private
const
val
MENU_ACTION_PINNED_MESSAGES
=
4
private
const
val
MENU_ACTION_FAVORITE_MESSAGES
=
5
private
const
val
MENU_ACTION_FILES
=
6
class
ChatRoomFragment
:
Fragment
(),
ChatRoomView
,
EmojiKeyboardListener
,
EmojiReactionListener
{
@Inject
...
...
@@ -91,8 +138,9 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
private
lateinit
var
chatRoomType
:
String
private
var
chatRoomMessage
:
String
?
=
null
private
var
isSubscribed
:
Boolean
=
true
private
var
isChatRoomReadOnly
:
Boolean
=
false
private
var
isChatRoomCreator
:
Boolean
=
false
private
var
isReadOnly
:
Boolean
=
false
private
var
isCreator
:
Boolean
=
false
private
var
isFavorite
:
Boolean
=
false
private
var
isBroadcastChannel
:
Boolean
=
false
private
lateinit
var
emojiKeyboardPopup
:
EmojiKeyboardPopup
private
var
chatRoomLastSeen
:
Long
=
-
1
...
...
@@ -131,10 +179,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
chatRoomId
=
bundle
.
getString
(
BUNDLE_CHAT_ROOM_ID
)
chatRoomName
=
bundle
.
getString
(
BUNDLE_CHAT_ROOM_NAME
)
chatRoomType
=
bundle
.
getString
(
BUNDLE_CHAT_ROOM_TYPE
)
is
ChatRoom
ReadOnly
=
bundle
.
getBoolean
(
BUNDLE_IS_CHAT_ROOM_READ_ONLY
)
isReadOnly
=
bundle
.
getBoolean
(
BUNDLE_IS_CHAT_ROOM_READ_ONLY
)
isSubscribed
=
bundle
.
getBoolean
(
BUNDLE_CHAT_ROOM_IS_SUBSCRIBED
)
chatRoomLastSeen
=
bundle
.
getLong
(
BUNDLE_CHAT_ROOM_LAST_SEEN
)
isChatRoomCreator
=
bundle
.
getBoolean
(
BUNDLE_CHAT_ROOM_IS_CREATOR
)
isCreator
=
bundle
.
getBoolean
(
BUNDLE_CHAT_ROOM_IS_CREATOR
)
isFavorite
=
bundle
.
getBoolean
(
BUNDLE_CHAT_ROOM_IS_FAVORITE
)
chatRoomMessage
=
bundle
.
getString
(
BUNDLE_CHAT_ROOM_MESSAGE
)
}
else
{
requireNotNull
(
bundle
)
{
"no arguments supplied when the fragment was instantiated"
}
...
...
@@ -187,64 +236,141 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
override
fun
onActivityResult
(
requestCode
:
Int
,
resultCode
:
Int
,
resultData
:
Intent
?)
{
if
(
requestCode
==
REQUEST_CODE_FOR_PERFORM_SAF
&&
resultCode
==
Activity
.
RESULT_OK
)
{
if
(
resultData
!=
null
)
{
uploadFile
(
resultData
.
data
)
if
(
resultData
!=
null
&&
resultCode
==
Activity
.
RESULT_OK
)
{
when
(
requestCode
){
REQUEST_CODE_FOR_PERFORM_SAF
->
{
uploadFile
(
resultData
.
data
)
}
REQUEST_CODE_FOR_DRAW
->
{
val
result
=
resultData
.
getByteArrayExtra
(
"bitmap"
)
val
bitmap
=
BitmapFactory
.
decodeByteArray
(
result
,
0
,
result
.
size
)
val
uri
=
saveImage
(
bitmap
)
uploadFile
(
uri
)
}
}
}
}
override
fun
onCreateOptionsMenu
(
menu
:
Menu
,
inflater
:
MenuInflater
)
{
super
.
onCreateOptionsMenu
(
menu
,
inflater
)
inflater
.
inflate
(
R
.
menu
.
chatroom_actions
,
menu
)
menu
.
findItem
(
R
.
id
.
action_members_list
)
?.
isVisible
=
!
isBroadcastChannel
private
fun
saveImage
(
bitmap
:
Bitmap
):
Uri
{
val
imageDir
=
"${Environment.DIRECTORY_PICTURES}/Rocket.Chat Images/"
val
path
=
Environment
.
getExternalStoragePublicDirectory
(
imageDir
)
val
file
=
File
(
path
,
UUID
.
randomUUID
().
toString
()+
".png"
)
path
.
mkdirs
()
file
.
createNewFile
()
val
outputStream
=
FileOutputStream
(
file
)
bitmap
.
compress
(
Bitmap
.
CompressFormat
.
PNG
,
100
,
outputStream
)
outputStream
.
flush
()
outputStream
.
close
()
return
Uri
.
fromFile
(
file
)
}
override
fun
onPrepareOptionsMenu
(
menu
:
Menu
)
{
menu
.
clear
()
if
(
isFavorite
)
{
menu
.
add
(
Menu
.
NONE
,
MENU_ACTION_FAVORITE_UNFAVORITE_CHAT
,
Menu
.
NONE
,
R
.
string
.
title_unfavorite_chat
)
.
setIcon
(
R
.
drawable
.
ic_star_yellow_24dp
)
.
setShowAsAction
(
MenuItem
.
SHOW_AS_ACTION_IF_ROOM
)
}
else
{
menu
.
add
(
Menu
.
NONE
,
MENU_ACTION_FAVORITE_UNFAVORITE_CHAT
,
Menu
.
NONE
,
R
.
string
.
title_favorite_chat
)
.
setIcon
(
R
.
drawable
.
ic_star_border_white_24dp
)
.
setShowAsAction
(
MenuItem
.
SHOW_AS_ACTION_IF_ROOM
)
}
menu
.
add
(
Menu
.
NONE
,
MENU_ACTION_MEMBER
,
Menu
.
NONE
,
R
.
string
.
title_members_list
)
menu
.
add
(
Menu
.
NONE
,
MENU_ACTION_MENTIONS
,
Menu
.
NONE
,
R
.
string
.
msg_mentions
)
menu
.
add
(
Menu
.
NONE
,
MENU_ACTION_PINNED_MESSAGES
,
Menu
.
NONE
,
R
.
string
.
title_pinned_messages
)
menu
.
add
(
Menu
.
NONE
,
MENU_ACTION_FAVORITE_MESSAGES
,
Menu
.
NONE
,
R
.
string
.
title_favorite_messages
)
menu
.
add
(
Menu
.
NONE
,
MENU_ACTION_FILES
,
Menu
.
NONE
,
R
.
string
.
title_files
)
super
.
onPrepareOptionsMenu
(
menu
)
}
override
fun
onOptionsItemSelected
(
item
:
MenuItem
):
Boolean
{
when
(
item
.
itemId
)
{
R
.
id
.
action_members_list
->
{
presenter
.
toMembersList
(
chatRoomId
)
}
R
.
id
.
action_pinned_messages
->
{
presenter
.
toPinnedMessageList
(
chatRoomId
)
}
R
.
id
.
action_favorite_messages
->
{
presenter
.
toFavoriteMessageList
(
chatRoomId
)
}
R
.
id
.
action_files
->
{
presenter
.
toFileList
(
chatRoomId
)
MENU_ACTION_FAVORITE_UNFAVORITE_CHAT
->
{
presenter
.
toggleFavoriteChatRoom
(
chatRoomId
,
isFavorite
)
}
MENU_ACTION_MEMBER
->
presenter
.
toMembersList
(
chatRoomId
)
MENU_ACTION_MENTIONS
->
presenter
.
toMentions
(
chatRoomId
)
MENU_ACTION_PINNED_MESSAGES
->
presenter
.
toPinnedMessageList
(
chatRoomId
)
MENU_ACTION_FAVORITE_MESSAGES
->
presenter
.
toFavoriteMessageList
(
chatRoomId
)
MENU_ACTION_FILES
->
presenter
.
toFileList
(
chatRoomId
)
}
return
true
}
override
fun
showMessages
(
dataSet
:
List
<
BaseViewModel
<*
>>)
{
override
fun
showFavoriteIcon
(
isFavorite
:
Boolean
)
{
this
.
isFavorite
=
isFavorite
activity
?.
invalidateOptionsMenu
()
}
override
fun
showMessages
(
dataSet
:
List
<
BaseUiModel
<*
>>)
{
ui
{
// track the message sent immediately after the current message
var
prevMessage
ViewModel
:
MessageView
Model
?
=
null
var
prevMessage
UiModel
:
MessageUi
Model
?
=
null
// Loop over received messages to determine first unread
for
(
i
in
dataSet
.
indices
)
{
val
msgModel
=
dataSet
[
i
]
if
(
msgModel
is
Message
View
Model
)
{
if
(
msgModel
is
Message
Ui
Model
)
{
val
msg
=
msgModel
.
rawData
if
(
msg
.
timestamp
<
chatRoomLastSeen
)
{
// This message was sent before the last seen of the room. Hence, it was seen.
// if there is a message after (below) this, mark it firstUnread.
if
(
prevMessage
View
Model
!=
null
)
{
prevMessage
View
Model
.
isFirstUnread
=
true
if
(
prevMessage
Ui
Model
!=
null
)
{
prevMessage
Ui
Model
.
isFirstUnread
=
true
}
break
}
prevMessage
View
Model
=
msgModel
prevMessage
Ui
Model
=
msgModel
}
}
if
(
recycler_view
.
adapter
==
null
)
{
adapter
=
ChatRoomAdapter
(
chatRoomType
,
chatRoomName
,
presenter
,
reactionListener
=
this
@ChatRoomFragment
chatRoomType
,
chatRoomName
,
presenter
,
reactionListener
=
this
@ChatRoomFragment
,
context
=
context
)
recycler_view
.
adapter
=
adapter
if
(
dataSet
.
size
>=
30
)
{
...
...
@@ -261,7 +387,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
verticalScrollOffset
.
set
(
0
)
}
presenter
.
loadActiveMembers
(
chatRoomId
,
chatRoomType
,
filterSelfOut
=
true
)
toggleNoChatView
(
adapter
.
itemCount
)
empty_chat_view
.
isVisible
=
adapter
.
itemCount
==
0
}
}
...
...
@@ -272,27 +398,17 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
)
{
// TODO: We should rely solely on the user being able to post, but we cannot guarantee
// that the "(channels|groups).roles" endpoint is supported by the server in use.
setupMessageComposer
(
userCanPost
)
isBroadcastChannel
=
channelIsBroadcast
if
(
isBroadcastChannel
&&
!
userCanMod
)
activity
?.
invalidateOptionsMenu
()
ui
{
setupMessageComposer
(
userCanPost
)
isBroadcastChannel
=
channelIsBroadcast
if
(
isBroadcastChannel
&&
!
userCanMod
)
activity
?.
invalidateOptionsMenu
()
}
}
override
fun
openDirectMessage
(
chatRoom
:
ChatRoom
,
permalink
:
String
)
{
}
private
fun
toggleNoChatView
(
size
:
Int
)
{
if
(
size
==
0
)
{
image_chat_icon
.
setVisible
(
true
)
text_chat_title
.
setVisible
(
true
)
text_chat_description
.
setVisible
(
true
)
}
else
{
image_chat_icon
.
setVisible
(
false
)
text_chat_title
.
setVisible
(
false
)
text_chat_description
.
setVisible
(
false
)
}
}
private
val
layoutChangeListener
=
View
.
OnLayoutChangeListener
{
_
,
_
,
_
,
_
,
bottom
,
_
,
_
,
_
,
oldBottom
->
val
y
=
oldBottom
-
bottom
...
...
@@ -361,7 +477,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
}
override
fun
showTypingStatus
(
usernameList
:
Array
List
<
String
>)
{
override
fun
showTypingStatus
(
usernameList
:
List
<
String
>)
{
ui
{
when
(
usernameList
.
size
)
{
1
->
{
...
...
@@ -401,12 +517,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
showMessage
(
getString
(
R
.
string
.
msg_invalid_file
))
}
override
fun
showNewMessage
(
message
:
List
<
Base
View
Model
<*
>>)
{
override
fun
showNewMessage
(
message
:
List
<
Base
Ui
Model
<*
>>)
{
ui
{
adapter
.
prependData
(
message
)
recycler_view
.
scrollToPosition
(
0
)
verticalScrollOffset
.
set
(
0
)
toggleNoChatView
(
adapter
.
itemCount
)
empty_chat_view
.
isVisible
=
adapter
.
itemCount
==
0
}
}
...
...
@@ -434,7 +549,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
}
override
fun
dispatchUpdateMessage
(
index
:
Int
,
message
:
List
<
Base
View
Model
<*
>>)
{
override
fun
dispatchUpdateMessage
(
index
:
Int
,
message
:
List
<
Base
Ui
Model
<*
>>)
{
ui
{
adapter
.
updateItem
(
message
.
last
())
if
(
message
.
size
>
1
)
{
...
...
@@ -464,11 +579,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
override
fun
showLoading
()
{
ui
{
view_loading
.
setVisible
(
true
)
}
ui
{
view_loading
.
isVisible
=
true
}
}
override
fun
hideLoading
()
{
ui
{
view_loading
.
setVisible
(
false
)
}
ui
{
view_loading
.
isVisible
=
false
}
}
override
fun
showMessage
(
message
:
String
)
{
...
...
@@ -485,19 +600,19 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
override
fun
showGenericErrorMessage
()
=
showMessage
(
getString
(
R
.
string
.
msg_generic_error
))
override
fun
populatePeopleSuggestions
(
members
:
List
<
PeopleSuggestion
View
Model
>)
{
override
fun
populatePeopleSuggestions
(
members
:
List
<
PeopleSuggestion
Ui
Model
>)
{
ui
{
suggestions_view
.
addItems
(
"@"
,
members
)
}
}
override
fun
populateRoomSuggestions
(
chatRooms
:
List
<
ChatRoomSuggestion
View
Model
>)
{
override
fun
populateRoomSuggestions
(
chatRooms
:
List
<
ChatRoomSuggestion
Ui
Model
>)
{
ui
{
suggestions_view
.
addItems
(
"#"
,
chatRooms
)
}
}
override
fun
populateCommandSuggestions
(
commands
:
List
<
CommandSuggestion
View
Model
>)
{
override
fun
populateCommandSuggestions
(
commands
:
List
<
CommandSuggestion
Ui
Model
>)
{
ui
{
suggestions_view
.
addItems
(
"/"
,
commands
)
}
...
...
@@ -507,6 +622,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
ui
{
val
clipboard
=
it
.
getSystemService
(
Context
.
CLIPBOARD_SERVICE
)
as
ClipboardManager
clipboard
.
primaryClip
=
ClipData
.
newPlainText
(
""
,
message
)
showToast
(
R
.
string
.
msg_message_copied
)
}
}
...
...
@@ -524,7 +640,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
override
fun
onEmojiAdded
(
emoji
:
Emoji
)
{
val
cursorPosition
=
text_message
.
selectionStart
if
(
cursorPosition
>
-
1
)
{
text_message
.
text
.
insert
(
cursorPosition
,
EmojiParser
.
parse
(
emoji
.
shortname
))
text_message
.
text
?
.
insert
(
cursorPosition
,
EmojiParser
.
parse
(
emoji
.
shortname
))
text_message
.
setSelection
(
cursorPosition
+
emoji
.
unicode
.
length
)
}
}
...
...
@@ -532,7 +648,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
override
fun
onNonEmojiKeyPressed
(
keyCode
:
Int
)
{
when
(
keyCode
)
{
KeyEvent
.
KEYCODE_BACK
->
with
(
text_message
)
{
if
(
selectionStart
>
0
)
text
.
delete
(
selectionStart
-
1
,
selectionStart
)
if
(
selectionStart
>
0
)
text
?
.
delete
(
selectionStart
-
1
,
selectionStart
)
}
else
->
throw
IllegalArgumentException
(
"pressed key not expected"
)
}
...
...
@@ -549,7 +665,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
override
fun
showReactionsPopup
(
messageId
:
String
)
{
ui
{
val
emojiPickerPopup
=
EmojiPickerPopup
(
it
)
emojiPickerPopup
.
listener
=
object
:
Emoji
ListenerAdapter
()
{
emojiPickerPopup
.
listener
=
object
:
Emoji
KeyboardListener
{
override
fun
onEmojiAdded
(
emoji
:
Emoji
)
{
onReactionAdded
(
messageId
,
emoji
)
}
...
...
@@ -593,23 +709,23 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
handler
.
postDelayed
(
dismissStatus
,
2000
)
}
is
State
.
Disconnected
->
connection_status_text
.
text
=
getString
(
R
.
string
.
status_disconnected
)
getString
(
R
.
string
.
status_disconnected
)
is
State
.
Connecting
->
connection_status_text
.
text
=
getString
(
R
.
string
.
status_connecting
)
getString
(
R
.
string
.
status_connecting
)
is
State
.
Authenticating
->
connection_status_text
.
text
=
getString
(
R
.
string
.
status_authenticating
)
getString
(
R
.
string
.
status_authenticating
)
is
State
.
Disconnecting
->
connection_status_text
.
text
=
getString
(
R
.
string
.
status_disconnecting
)
getString
(
R
.
string
.
status_disconnecting
)
is
State
.
Waiting
->
connection_status_text
.
text
=
getString
(
R
.
string
.
status_waiting
,
state
.
seconds
)
getString
(
R
.
string
.
status_waiting
,
state
.
seconds
)
}
}
}
override
fun
onJoined
(
userCanPost
:
Boolean
)
{
ui
{
input_container
.
setVisible
(
true
)
button_join_chat
.
setVisible
(
false
)
input_container
.
isVisible
=
true
button_join_chat
.
isVisible
=
false
isSubscribed
=
true
setupMessageComposer
(
userCanPost
)
}
...
...
@@ -621,13 +737,13 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
private
fun
setupRecyclerView
()
{
// Initialize the endlessRecyclerViewScrollListener so we don't NPE at onDestroyView
val
linearLayoutManager
=
LinearLayoutManager
(
context
,
LinearLayoutManager
.
VERTICAL
,
true
)
val
linearLayoutManager
=
LinearLayoutManager
(
context
,
RecyclerView
.
VERTICAL
,
true
)
linearLayoutManager
.
stackFromEnd
=
true
recycler_view
.
layoutManager
=
linearLayoutManager
recycler_view
.
itemAnimator
=
DefaultItemAnimator
()
endlessRecyclerViewScrollListener
=
object
:
EndlessRecyclerViewScrollListener
(
recycler_view
.
layoutManager
as
LinearLayoutManager
)
{
override
fun
onLoadMore
(
page
:
Int
,
totalItemsCount
:
Int
,
recyclerView
:
RecyclerView
?
)
{
override
fun
onLoadMore
(
page
:
Int
,
totalItemsCount
:
Int
,
recyclerView
:
RecyclerView
)
{
presenter
.
loadMessages
(
chatRoomId
,
chatRoomType
,
page
*
30L
)
}
}
...
...
@@ -643,22 +759,21 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
private
fun
setupMessageComposer
(
canPost
:
Boolean
)
{
if
(
is
ChatRoom
ReadOnly
&&
!
canPost
)
{
text_room_is_read_only
.
setVisible
(
true
)
input_container
.
setVisible
(
false
)
}
else
if
(!
isSubscribed
)
{
input_container
.
setVisible
(
false
)
button_join_chat
.
setVisible
(
true
)
if
(
isReadOnly
&&
!
canPost
)
{
text_room_is_read_only
.
isVisible
=
true
input_container
.
isVisible
=
false
}
else
if
(!
isSubscribed
&&
roomTypeOf
(
chatRoomType
)
!
is
RoomType
.
DirectMessage
)
{
input_container
.
isVisible
=
false
button_join_chat
.
isVisible
=
true
button_join_chat
.
setOnClickListener
{
presenter
.
joinChat
(
chatRoomId
)
}
}
else
{
button_send
.
alpha
=
0f
button_send
.
setVisible
(
false
)
button_send
.
isVisible
=
false
button_show_attachment_options
.
alpha
=
1f
button_show_attachment_options
.
setVisible
(
true
)
button_show_attachment_options
.
isVisible
=
true
subscribeComposeTextMessage
()
emojiKeyboardPopup
=
EmojiKeyboardPopup
(
activity
!!
,
activity
!!
.
findViewById
(
R
.
id
.
fragment_container
))
EmojiKeyboardPopup
(
activity
!!
,
activity
!!
.
findViewById
(
R
.
id
.
fragment_container
))
emojiKeyboardPopup
.
listener
=
this
text_message
.
listener
=
object
:
ComposerEditText
.
ComposerEditTextListener
{
override
fun
onKeyboardOpened
()
{
...
...
@@ -708,6 +823,30 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
button_add_reaction
.
setOnClickListener
{
view
->
openEmojiKeyboardPopup
()
}
button_drawing
.
setOnClickListener
{
if
(!
canWriteToExternalStorage
())
{
checkWritingPermission
()
}
else
{
val
intent
=
Intent
(
activity
,
DrawingActivity
::
class
.
java
)
startActivityForResult
(
intent
,
REQUEST_CODE_FOR_DRAW
)
}
handler
.
postDelayed
({
hideAttachmentOptions
()
},
400
)
}
}
}
private
fun
canWriteToExternalStorage
():
Boolean
{
return
context
?.
let
{
AndroidPermissionsHelper
.
checkPermission
(
it
,
Manifest
.
permission
.
WRITE_EXTERNAL_STORAGE
)
}
!!
}
private
fun
checkWritingPermission
()
{
activity
?.
let
{
AndroidPermissionsHelper
.
requestPermission
(
it
,
Manifest
.
permission
.
WRITE_EXTERNAL_STORAGE
,
AndroidPermissionsHelper
.
WRITE_EXTERNAL_STORAGE_CODE
)
}
}
...
...
@@ -756,10 +895,10 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
private
fun
setupActionSnackbar
()
{
actionSnackbar
=
ActionSnackbar
.
make
(
message_list_container
,
parser
=
parser
)
actionSnackbar
.
cancelView
.
setOnClickListener
(
{
actionSnackbar
.
cancelView
.
setOnClickListener
{
clearMessageComposition
()
KeyboardHelper
.
showSoftKeyboard
(
text_message
)
}
)
}
}
private
fun
subscribeComposeTextMessage
()
{
...
...
@@ -787,14 +926,14 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
private
fun
setupComposeButtons
(
charSequence
:
CharSequence
)
{
if
(
charSequence
.
isNotEmpty
()
&&
playComposeMessageButtonsAnimation
)
{
button_show_attachment_options
.
fadeOut
(
1F
,
0F
,
120
)
button_send
.
fadeIn
(
0F
,
1F
,
120
)
button_show_attachment_options
.
isVisible
=
false
button_send
.
isVisible
=
true
playComposeMessageButtonsAnimation
=
false
}
if
(
charSequence
.
isEmpty
())
{
button_send
.
fadeOut
(
1F
,
0F
,
120
)
button_show_attachment_options
.
fadeIn
(
0F
,
1F
,
120
)
button_send
.
isVisible
=
false
button_show_attachment_options
.
isVisible
=
true
playComposeMessageButtonsAnimation
=
true
}
}
...
...
@@ -808,7 +947,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
private
fun
showAttachmentOptions
()
{
view_dim
.
setVisible
(
true
)
view_dim
.
isVisible
=
true
// Play anim.
button_show_attachment_options
.
rotateBy
(
45F
)
...
...
@@ -820,10 +959,10 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
button_show_attachment_options
.
rotateBy
(-
45F
)
layout_message_attachment_options
.
circularRevealOrUnreveal
(
centerX
,
centerY
,
max
,
0F
)
view_dim
.
setVisible
(
false
)
view_dim
.
isVisible
=
false
}
private
fun
setupToolbar
(
toolbarTitle
:
String
)
{
(
activity
as
ChatRoomActivity
).
showToolbarTitle
(
toolbarTitle
)
}
}
\ No newline at end of file
}
draw/build.gradle
View file @
190d0dc5
...
...
@@ -25,8 +25,8 @@ dependencies {
implementation
fileTree
(
dir:
'libs'
,
include:
[
'*.jar'
])
implementation
libraries
.
appCompat
implementation
libraries
.
constraintLayout
implementation
libraries
.
kotlin
implementation
libraries
.
constraintlayout
implementation
libraries
.
androidKtx
testImplementation
'junit:junit:4.12'
...
...
draw/src/androidTest/java/chat/rocket/android/draw/ExampleInstrumentedTest.java
deleted
100644 → 0
View file @
74031054
package
chat
.
rocket
.
android
.
draw
;
import
android.content.Context
;
import
android.support.test.InstrumentationRegistry
;
import
android.support.test.runner.AndroidJUnit4
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
static
org
.
junit
.
Assert
.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith
(
AndroidJUnit4
.
class
)
public
class
ExampleInstrumentedTest
{
@Test
public
void
useAppContext
()
{
// Context of the app under test.
Context
appContext
=
InstrumentationRegistry
.
getTargetContext
();
assertEquals
(
"chat.rocket.android.draw.test"
,
appContext
.
getPackageName
());
}
}
draw/src/main/java/chat/rocket/android/draw/DrawingActivity.kt
View file @
190d0dc5
package
chat.rocket.android.draw
import
android.app.Activity
import
android.content.Intent
import
android.content.res.Resources
import
android.
support.v7.app.AppCompatActivity
import
android.
graphics.Bitmap
import
android.os.Bundle
import
android.support.v4.content.res.ResourcesCompat
import
android.view.View
import
android.widget.SeekBar
import
androidx.appcompat.app.AppCompatActivity
import
androidx.core.content.res.ResourcesCompat
import
androidx.core.view.isVisible
import
kotlinx.android.synthetic.main.activity_drawing.*
import
kotlinx.android.synthetic.main.color_palette_view.*
import
android.content.Intent
import
android.graphics.Bitmap
import
android.app.Activity
import
java.io.ByteArrayOutputStream
class
DrawingActivity
:
AppCompatActivity
()
{
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
...
...
draw/src/main/java/chat/rocket/android/draw/widget/CustomDrawView.kt
View file @
190d0dc5
package
chat.rocket.android.draw.widget
import
android.content.Context
import
android.graphics.*
import
android.graphics.Bitmap
import
android.graphics.Canvas
import
android.graphics.Color
import
android.graphics.Paint
import
android.util.AttributeSet
import
android.view.MotionEvent
import
android.view.View
import
java.util.*
import
android.support.v4.graphics.ColorUtils
import
android.support.annotation.ColorInt
import
androidx.annotation.ColorInt
import
androidx.core.graphics.ColorUtils
class
CustomDrawView
(
context
:
Context
,
attrs
:
AttributeSet
)
:
View
(
context
,
attrs
)
{
var
mPaths
=
LinkedHashMap
<
MyPath
,
PaintOptions
>()
...
...
draw/src/main/res/layout/activity_drawing.xml
View file @
190d0dc5
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
<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:layout_width=
"match_parent"
...
...
@@ -36,7 +37,7 @@
android:background=
"@color/color_white"
android:foreground=
"?selectableItemBackgroundBorderless"
/>
<android
.support.constrain
t.ConstraintLayout
<android
x.constraintlayout.widge
t.ConstraintLayout
android:id=
"@+id/draw_tools"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
...
...
@@ -155,6 +156,6 @@
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintTop_toBottomOf=
"@id/image_draw_eraser"
/>
</android
.support.constrain
t.ConstraintLayout>
</android
x.constraintlayout.widge
t.ConstraintLayout>
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
draw/src/test/java/chat/rocket/android/draw/ExampleUnitTest.java
deleted
100644 → 0
View file @
74031054
package
chat
.
rocket
.
android
.
draw
;
import
org.junit.Test
;
import
static
org
.
junit
.
Assert
.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public
class
ExampleUnitTest
{
@Test
public
void
addition_isCorrect
()
{
assertEquals
(
4
,
2
+
2
);
}
}
\ No newline at end of file
settings.gradle
View file @
190d0dc5
include
':app'
,
':player'
,
':wear'
\ No newline at end of file
include
':app'
,
':player'
,
':emoji'
,
':draw'
//, ':wear'
\ No newline at end of file
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