Skip to content
This repository was archived by the owner on Jun 7, 2020. It is now read-only.

Commit 391a936

Browse files
authored
Merge pull request #1948 from RocketChat/new/draft-message
[IMPROVEMENT] Draft messages
2 parents a07ec35 + a3830e7 commit 391a936

12 files changed

Lines changed: 114 additions & 128 deletions

File tree

app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomPresenter.kt

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -123,21 +123,25 @@ class ChatRoomPresenter @Inject constructor(
123123
private var lastState = manager.state
124124
private var typingStatusList = arrayListOf<String>()
125125
private val roomChangesChannel = Channel<Room>(Channel.CONFLATED)
126+
private lateinit var draftKey: String
126127

127128
fun setupChatRoom(
128129
roomId: String,
129130
roomName: String,
130131
roomType: String,
131132
chatRoomMessage: String? = null
132133
) {
134+
draftKey = "${currentServer}_${LocalRepository.DRAFT_KEY}$roomId"
135+
chatRoomId = roomId
136+
chatRoomType = roomType
133137
launch(CommonPool + strategy.jobs) {
134138
try {
135-
chatRoomId = roomId
136-
chatRoomType = roomType
137139
chatRoles = if (roomTypeOf(roomType) !is RoomType.DirectMessage) {
138140
client.chatRoomRoles(roomType = roomTypeOf(roomType), roomName = roomName)
139-
} else emptyList()
140-
} catch (ex: RocketChatException) {
141+
} else {
142+
emptyList()
143+
}
144+
} catch (ex: Exception) {
141145
Timber.e(ex)
142146
chatRoles = emptyList()
143147
} finally {
@@ -183,7 +187,6 @@ class ChatRoomPresenter @Inject constructor(
183187
}
184188
}
185189
}
186-
187190
}
188191
}
189192

@@ -369,6 +372,7 @@ class ChatRoomPresenter @Inject constructor(
369372
client.updateMessage(chatRoomId, messageId, text)
370373
}
371374

375+
clearUnfinishedMessage()
372376
view.enableSendMessageButton()
373377
} catch (ex: Exception) {
374378
Timber.d(ex, "Error sending message...")
@@ -914,7 +918,7 @@ class ChatRoomPresenter @Inject constructor(
914918
navigator.toChatDetails(chatRoomId, chatRoomType, isSubscribed, isMenuDisabled)
915919
}
916920

917-
fun loadChatRooms() {
921+
fun loadChatRoomsSuggestions() {
918922
launchUI(strategy) {
919923
try {
920924
val chatRooms = getChatRoomsAsync()
@@ -1286,31 +1290,26 @@ class ChatRoomPresenter @Inject constructor(
12861290
}
12871291

12881292
/**
1289-
* Save unfinished message, when user left chat room without sending a message. It also clears
1290-
* saved message from local repository when unfinishedMessage is blank.
1293+
* Save unfinished message, when user left chat room without sending a message.
12911294
*
1292-
* @param chatRoomId Chat room Id.
12931295
* @param unfinishedMessage The unfinished message to save.
12941296
*/
1295-
fun saveUnfinishedMessage(chatRoomId: String, unfinishedMessage: String) {
1296-
val key = "${currentServer}_${LocalRepository.UNFINISHED_MSG_KEY}$chatRoomId"
1297+
fun saveUnfinishedMessage(unfinishedMessage: String) {
12971298
if (unfinishedMessage.isNotBlank()) {
1298-
localRepository.save(key, unfinishedMessage)
1299-
} else {
1300-
localRepository.clear(key)
1299+
localRepository.save(draftKey, unfinishedMessage)
13011300
}
13021301
}
13031302

1303+
fun clearUnfinishedMessage() {
1304+
localRepository.clear(draftKey)
1305+
}
13041306
/**
13051307
* Get unfinished message from local repository, when user left chat room without
13061308
* sending a message and now the user is back.
13071309
*
1308-
* @param chatRoomId Chat room Id.
1309-
*
1310-
* @return Returns the unfinished message.
1310+
* @return Returns the unfinished message, null otherwise.
13111311
*/
1312-
fun getUnfinishedMessage(chatRoomId: String): String {
1313-
val key = "${currentServer}_${LocalRepository.UNFINISHED_MSG_KEY}$chatRoomId"
1314-
return localRepository.get(key) ?: ""
1312+
fun getUnfinishedMessage(): String? {
1313+
return localRepository.get(draftKey)
13151314
}
13161315
}

app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt

Lines changed: 85 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ import chat.rocket.android.util.extensions.fadeOut
7474
import chat.rocket.android.util.extensions.getBitmpap
7575
import chat.rocket.android.util.extensions.hideKeyboard
7676
import chat.rocket.android.util.extensions.inflate
77+
import chat.rocket.android.util.extensions.isNotNullNorEmpty
7778
import chat.rocket.android.util.extensions.rotateBy
7879
import chat.rocket.android.util.extensions.showToast
7980
import chat.rocket.android.util.extensions.textContent
@@ -175,6 +176,8 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
175176

176177
internal var isSearchTermQueried = false
177178

179+
private val dismissStatus = { text_connection_status.fadeOut() }
180+
178181
// For reveal and unreveal anim.
179182
private val hypotenuse by lazy {
180183
Math.hypot(
@@ -203,6 +206,65 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
203206
internal val textFile by lazy { dialogView.findViewById<TextView>(R.id.text_file_name) }
204207
private var takenPhotoUri: Uri? = null
205208

209+
private val layoutChangeListener =
210+
View.OnLayoutChangeListener { _, _, _, _, bottom, _, _, _, oldBottom ->
211+
val y = oldBottom - bottom
212+
if (Math.abs(y) > 0 && isAdded) {
213+
// if y is positive the keyboard is up else it's down
214+
recycler_view.post {
215+
if (y > 0 || Math.abs(verticalScrollOffset.get()) >= Math.abs(y)) {
216+
ui { recycler_view.scrollBy(0, y) }
217+
} else {
218+
ui { recycler_view.scrollBy(0, verticalScrollOffset.get()) }
219+
}
220+
}
221+
}
222+
}
223+
224+
private lateinit var endlessRecyclerViewScrollListener: EndlessRecyclerViewScrollListener
225+
226+
private val onScrollListener = object : RecyclerView.OnScrollListener() {
227+
var state = AtomicInteger(RecyclerView.SCROLL_STATE_IDLE)
228+
229+
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
230+
state.compareAndSet(RecyclerView.SCROLL_STATE_IDLE, newState)
231+
when (newState) {
232+
RecyclerView.SCROLL_STATE_IDLE -> {
233+
if (!state.compareAndSet(RecyclerView.SCROLL_STATE_SETTLING, newState)) {
234+
state.compareAndSet(RecyclerView.SCROLL_STATE_DRAGGING, newState)
235+
}
236+
}
237+
RecyclerView.SCROLL_STATE_DRAGGING -> {
238+
state.compareAndSet(RecyclerView.SCROLL_STATE_IDLE, newState)
239+
}
240+
RecyclerView.SCROLL_STATE_SETTLING -> {
241+
state.compareAndSet(RecyclerView.SCROLL_STATE_DRAGGING, newState)
242+
}
243+
}
244+
}
245+
246+
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
247+
if (state.get() != RecyclerView.SCROLL_STATE_IDLE) {
248+
verticalScrollOffset.getAndAdd(dy)
249+
}
250+
}
251+
}
252+
253+
private val fabScrollListener = object : RecyclerView.OnScrollListener() {
254+
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
255+
if (!recyclerView.canScrollVertically(1)) {
256+
text_count.isVisible = false
257+
button_fab.hide()
258+
newMessageCount = 0
259+
} else {
260+
if (dy < 0 && !button_fab.isVisible) {
261+
button_fab.show()
262+
if (newMessageCount != 0) text_count.isVisible = true
263+
}
264+
}
265+
}
266+
}
267+
206268
override fun onCreate(savedInstanceState: Bundle?) {
207269
super.onCreate(savedInstanceState)
208270
AndroidSupportInjection.inject(this)
@@ -230,24 +292,23 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
230292
inflater: LayoutInflater,
231293
container: ViewGroup?,
232294
savedInstanceState: Bundle?
233-
): View? {
234-
return container?.inflate(R.layout.fragment_chat_room)
235-
}
295+
): View? = container?.inflate(R.layout.fragment_chat_room)
236296

237297
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
238298
super.onViewCreated(view, savedInstanceState)
239299
setupToolbar(chatRoomName)
240300

241301
presenter.setupChatRoom(chatRoomId, chatRoomName, chatRoomType, chatRoomMessage)
242-
presenter.loadChatRooms()
302+
presenter.loadChatRoomsSuggestions()
243303
setupRecyclerView()
244304
setupFab()
245305
setupSuggestionsView()
246306
setupActionSnackbar()
247-
(activity as ChatRoomActivity).let {
248-
it.showToolbarTitle(chatRoomName)
249-
it.showToolbarChatRoomIcon(chatRoomType)
307+
with(activity as ChatRoomActivity) {
308+
showToolbarTitle(chatRoomName)
309+
showToolbarChatRoomIcon(chatRoomType)
250310
}
311+
getUnfinishedMessage()
251312

252313
analyticsManager.logScreenView(ScreenViewEvent.ChatRoom)
253314
}
@@ -262,15 +323,13 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
262323
recycler_view.removeOnScrollListener(onScrollListener)
263324
recycler_view.removeOnLayoutChangeListener(layoutChangeListener)
264325

265-
presenter.disconnect()
266-
presenter.saveUnfinishedMessage(chatRoomId, text_message.text.toString())
326+
presenter.saveUnfinishedMessage(text_message.text.toString())
267327
handler.removeCallbacksAndMessages(null)
268328
unsubscribeComposeTextMessage()
329+
presenter.disconnect()
269330

270331
// Hides the keyboard (if it's opened) before going to any view.
271-
activity?.apply {
272-
hideKeyboard()
273-
}
332+
activity?.apply { hideKeyboard() }
274333
super.onDestroyView()
275334
}
276335

@@ -280,15 +339,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
280339
activity?.invalidateOptionsMenu()
281340
}
282341

283-
fun dismissEmojiKeyboard() {
284-
// Check if the keyboard was ever initialized.
285-
// It may be the case when you are looking a not joined room
286-
if (::emojiKeyboardPopup.isInitialized) {
287-
emojiKeyboardPopup.dismiss()
288-
setReactionButtonIcon(R.drawable.ic_reaction_24dp)
289-
}
290-
}
291-
292342
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
293343
if (resultCode == Activity.RESULT_OK) {
294344
when (requestCode) {
@@ -411,64 +461,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
411461
}
412462
}
413463

414-
private val layoutChangeListener =
415-
View.OnLayoutChangeListener { _, _, _, _, bottom, _, _, _, oldBottom ->
416-
val y = oldBottom - bottom
417-
if (Math.abs(y) > 0 && isAdded) {
418-
// if y is positive the keyboard is up else it's down
419-
recycler_view.post {
420-
if (y > 0 || Math.abs(verticalScrollOffset.get()) >= Math.abs(y)) {
421-
ui { recycler_view.scrollBy(0, y) }
422-
} else {
423-
ui { recycler_view.scrollBy(0, verticalScrollOffset.get()) }
424-
}
425-
}
426-
}
427-
}
428-
429-
private lateinit var endlessRecyclerViewScrollListener: EndlessRecyclerViewScrollListener
430-
431-
private val onScrollListener = object : RecyclerView.OnScrollListener() {
432-
var state = AtomicInteger(RecyclerView.SCROLL_STATE_IDLE)
433-
434-
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
435-
state.compareAndSet(RecyclerView.SCROLL_STATE_IDLE, newState)
436-
when (newState) {
437-
RecyclerView.SCROLL_STATE_IDLE -> {
438-
if (!state.compareAndSet(RecyclerView.SCROLL_STATE_SETTLING, newState)) {
439-
state.compareAndSet(RecyclerView.SCROLL_STATE_DRAGGING, newState)
440-
}
441-
}
442-
RecyclerView.SCROLL_STATE_DRAGGING -> {
443-
state.compareAndSet(RecyclerView.SCROLL_STATE_IDLE, newState)
444-
}
445-
RecyclerView.SCROLL_STATE_SETTLING -> {
446-
state.compareAndSet(RecyclerView.SCROLL_STATE_DRAGGING, newState)
447-
}
448-
}
449-
}
450-
451-
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
452-
if (state.get() != RecyclerView.SCROLL_STATE_IDLE) {
453-
verticalScrollOffset.getAndAdd(dy)
454-
}
455-
}
456-
}
457-
458-
private val fabScrollListener = object : RecyclerView.OnScrollListener() {
459-
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
460-
if (!recyclerView.canScrollVertically(1)) {
461-
text_count.isVisible = false
462-
button_fab.hide()
463-
newMessageCount = 0
464-
} else {
465-
if (dy < 0 && !button_fab.isVisible) {
466-
button_fab.show()
467-
if (newMessageCount != 0) text_count.isVisible = true
468-
}
469-
}
470-
}
471-
}
472464

473465
override fun sendMessage(text: String) {
474466
ui {
@@ -503,9 +495,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
503495
}
504496

505497
override fun hideTypingStatusView() {
506-
ui {
507-
text_typing_status.isVisible = false
508-
}
498+
ui { text_typing_status.isVisible = false }
509499
}
510500

511501
override fun showInvalidFileMessage() {
@@ -532,9 +522,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
532522
}
533523

534524
override fun disableSendMessageButton() {
535-
ui {
536-
button_send.isEnabled = false
537-
}
525+
ui { button_send.isEnabled = false }
538526
}
539527

540528
override fun enableSendMessageButton() {
@@ -790,10 +778,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
790778
}
791779
}
792780

793-
private val dismissStatus = {
794-
text_connection_status.fadeOut()
795-
}
796-
797781
private fun setupRecyclerView() {
798782
// Initialize the endlessRecyclerViewScrollListener so we don't NPE at onDestroyView
799783
val linearLayoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, true)
@@ -951,15 +935,9 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
951935
}
952936

953937
private fun getUnfinishedMessage() {
954-
val unfinishedMessage = presenter.getUnfinishedMessage(chatRoomId)
955-
if (unfinishedMessage.isNotBlank()) {
938+
val unfinishedMessage = presenter.getUnfinishedMessage()
939+
if (unfinishedMessage.isNotNullNorEmpty()) {
956940
text_message.setText(unfinishedMessage)
957-
val orientation = resources.configuration.orientation
958-
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
959-
KeyboardHelper.showSoftKeyboard(text_message)
960-
} else {
961-
//TODO show keyboard in full screen mode when landscape orientation
962-
}
963941
}
964942
}
965943

@@ -977,7 +955,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
977955
}
978956
.addSuggestionProviderAction("#") { query ->
979957
if (query.isNotEmpty()) {
980-
presenter.loadChatRooms()
958+
presenter.loadChatRoomsSuggestions()
981959
}
982960
}
983961
.addSuggestionProviderAction("/") {
@@ -1170,4 +1148,13 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
11701148
presenter.reportMessage(messageId = id,
11711149
description = "This message was reported by a user from the Android app")
11721150
}
1151+
1152+
fun dismissEmojiKeyboard() {
1153+
// Check if the keyboard was ever initialized.
1154+
// It may be the case when you are looking a not joined room
1155+
if (::emojiKeyboardPopup.isInitialized) {
1156+
emojiKeyboardPopup.dismiss()
1157+
setReactionButtonIcon(R.drawable.ic_reaction_24dp)
1158+
}
1159+
}
11731160
}

app/src/main/java/chat/rocket/android/infrastructure/LocalRepository.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ interface LocalRepository {
2727
const val SETTINGS_KEY = "settings_"
2828
const val PERMISSIONS_KEY = "permissions_"
2929
const val USER_KEY = "user_"
30-
const val UNFINISHED_MSG_KEY = "unfinished_msg_"
30+
const val DRAFT_KEY = "draft"
3131
const val CURRENT_USERNAME_KEY = "username_"
3232
const val LAST_CHATROOMS_REFRESH = "_chatrooms_refresh"
3333
}

0 commit comments

Comments
 (0)