Commit 190d0dc5 authored by divyanshu's avatar divyanshu

resolved conflicts

parent 74031054
......@@ -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 2022
versionName "2.3.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
versionCode 2030
versionName "2.4.0"
testInstrumentationRunner "androidx.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.63.0"'
buildConfigField "String", "RECOMMENDED_SERVER_VERSION", '"0.64.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.constraintLayout
implementation libraries.cardView
implementation libraries.material
implementation libraries.constraintlayout
implementation libraries.cardview
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.playServicesGcm
implementation libraries.fcm
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
}
......
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,
isChatRoomReadOnly: 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, isChatRoomReadOnly)
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)
isChatRoomReadOnly = 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 prevMessageViewModel: MessageViewModel? = null
var prevMessageUiModel: MessageUiModel? = null
// Loop over received messages to determine first unread
for (i in dataSet.indices) {
val msgModel = dataSet[i]
if (msgModel is MessageViewModel) {
if (msgModel is MessageUiModel) {
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 (prevMessageViewModel != null) {
prevMessageViewModel.isFirstUnread = true
if (prevMessageUiModel != null) {
prevMessageUiModel.isFirstUnread = true
}
break
}
prevMessageViewModel = msgModel
prevMessageUiModel = 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: ArrayList<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<BaseViewModel<*>>) {
override fun showNewMessage(message: List<BaseUiModel<*>>) {
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<BaseViewModel<*>>) {
override fun dispatchUpdateMessage(index: Int, message: List<BaseUiModel<*>>) {
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<PeopleSuggestionViewModel>) {
override fun populatePeopleSuggestions(members: List<PeopleSuggestionUiModel>) {
ui {
suggestions_view.addItems("@", members)
}
}
override fun populateRoomSuggestions(chatRooms: List<ChatRoomSuggestionViewModel>) {
override fun populateRoomSuggestions(chatRooms: List<ChatRoomSuggestionUiModel>) {
ui {
suggestions_view.addItems("#", chatRooms)
}
}
override fun populateCommandSuggestions(commands: List<CommandSuggestionViewModel>) {
override fun populateCommandSuggestions(commands: List<CommandSuggestionUiModel>) {
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 : EmojiListenerAdapter() {
emojiPickerPopup.listener = object : EmojiKeyboardListener {
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 (isChatRoomReadOnly && !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
}
......@@ -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'
......
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());
}
}
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?) {
......
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>()
......
<?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.constraint.ConstraintLayout
<androidx.constraintlayout.widget.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.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
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
include ':app', ':player', ':wear'
\ No newline at end of file
include ':app', ':player', ':emoji', ':draw' //, ':wear'
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment