Commit 2e5f7c8b authored by Filipe de Lima Brito's avatar Filipe de Lima Brito

Add Upload File feature

parent 05d9453c
...@@ -16,9 +16,9 @@ import chat.rocket.android.authentication.login.presentation.LoginView ...@@ -16,9 +16,9 @@ import chat.rocket.android.authentication.login.presentation.LoginView
import chat.rocket.android.helper.AnimationHelper import chat.rocket.android.helper.AnimationHelper
import chat.rocket.android.helper.KeyboardHelper import chat.rocket.android.helper.KeyboardHelper
import chat.rocket.android.helper.TextHelper import chat.rocket.android.helper.TextHelper
import chat.rocket.android.util.inflate import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.setVisible import chat.rocket.android.util.extensions.setVisible
import chat.rocket.android.util.textContent import chat.rocket.android.util.extensions.textContent
import dagger.android.support.AndroidSupportInjection import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_authentication_log_in.* import kotlinx.android.synthetic.main.fragment_authentication_log_in.*
import javax.inject.Inject import javax.inject.Inject
......
...@@ -11,7 +11,7 @@ import chat.rocket.android.R ...@@ -11,7 +11,7 @@ import chat.rocket.android.R
import chat.rocket.android.authentication.server.presentation.ServerPresenter import chat.rocket.android.authentication.server.presentation.ServerPresenter
import chat.rocket.android.authentication.server.presentation.ServerView import chat.rocket.android.authentication.server.presentation.ServerView
import chat.rocket.android.helper.KeyboardHelper import chat.rocket.android.helper.KeyboardHelper
import chat.rocket.android.util.* import chat.rocket.android.util.extensions.*
import dagger.android.support.AndroidSupportInjection import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_authentication_server.* import kotlinx.android.synthetic.main.fragment_authentication_server.*
import javax.inject.Inject import javax.inject.Inject
......
...@@ -14,8 +14,8 @@ import chat.rocket.android.authentication.signup.presentation.SignupView ...@@ -14,8 +14,8 @@ import chat.rocket.android.authentication.signup.presentation.SignupView
import chat.rocket.android.helper.AnimationHelper import chat.rocket.android.helper.AnimationHelper
import chat.rocket.android.helper.KeyboardHelper import chat.rocket.android.helper.KeyboardHelper
import chat.rocket.android.helper.TextHelper import chat.rocket.android.helper.TextHelper
import chat.rocket.android.util.setVisible import chat.rocket.android.util.extensions.setVisible
import chat.rocket.android.util.textContent import chat.rocket.android.util.extensions.textContent
import dagger.android.support.AndroidSupportInjection import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_authentication_sign_up.* import kotlinx.android.synthetic.main.fragment_authentication_sign_up.*
import javax.inject.Inject import javax.inject.Inject
......
...@@ -14,8 +14,8 @@ import chat.rocket.android.R ...@@ -14,8 +14,8 @@ import chat.rocket.android.R
import chat.rocket.android.authentication.twofactor.presentation.TwoFAPresenter import chat.rocket.android.authentication.twofactor.presentation.TwoFAPresenter
import chat.rocket.android.authentication.twofactor.presentation.TwoFAView import chat.rocket.android.authentication.twofactor.presentation.TwoFAView
import chat.rocket.android.helper.AnimationHelper import chat.rocket.android.helper.AnimationHelper
import chat.rocket.android.util.setVisible import chat.rocket.android.util.extensions.setVisible
import chat.rocket.android.util.textContent import chat.rocket.android.util.extensions.textContent
import dagger.android.support.AndroidSupportInjection import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_authentication_two_fa.* import kotlinx.android.synthetic.main.fragment_authentication_two_fa.*
import javax.inject.Inject import javax.inject.Inject
......
...@@ -6,6 +6,7 @@ import chat.rocket.android.server.domain.GetCurrentServerInteractor ...@@ -6,6 +6,7 @@ import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.launchUI import chat.rocket.android.util.launchUI
import chat.rocket.common.RocketChatException
import chat.rocket.common.model.roomTypeOf import chat.rocket.common.model.roomTypeOf
import chat.rocket.common.util.ifNull import chat.rocket.common.util.ifNull
import chat.rocket.core.internal.realtime.State import chat.rocket.core.internal.realtime.State
...@@ -16,6 +17,7 @@ import chat.rocket.core.internal.rest.messages ...@@ -16,6 +17,7 @@ import chat.rocket.core.internal.rest.messages
import chat.rocket.core.internal.rest.sendMessage import chat.rocket.core.internal.rest.sendMessage
import chat.rocket.core.model.Message import chat.rocket.core.model.Message
import chat.rocket.core.model.Value import chat.rocket.core.model.Value
import chat.rocket.core.model.attachment.Attachment
import kotlinx.coroutines.experimental.CommonPool import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.channels.Channel import kotlinx.coroutines.experimental.channels.Channel
import kotlinx.coroutines.experimental.launch import kotlinx.coroutines.experimental.launch
...@@ -80,14 +82,27 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView, ...@@ -80,14 +82,27 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
ex.message?.let { ex.message?.let {
view.showMessage(it) view.showMessage(it)
}.ifNull { }.ifNull {
view.showGenericErrorMessage() view.showGenericErrorMessage()
} }
view.enableMessageInput() view.enableMessageInput()
} }
} }
} }
fun sendFile(chatRoomId: String, fileName: String) {
launchUI(strategy) {
view.showLoading()
try {
// client.sendMessage(chatRoomId)
} catch (ex: RocketChatException) {
} finally {
view.hideLoading()
}
}
}
fun subscribeMessages(roomId: String) { fun subscribeMessages(roomId: String) {
client.addStateChannel(stateChannel) client.addStateChannel(stateChannel)
launch(CommonPool + strategy.jobs) { launch(CommonPool + strategy.jobs) {
......
package chat.rocket.android.chatroom.presentation package chat.rocket.android.chatroom.presentation
import android.net.Uri
import chat.rocket.android.chatroom.viewmodel.MessageViewModel import chat.rocket.android.chatroom.viewmodel.MessageViewModel
import chat.rocket.android.core.behaviours.LoadingView import chat.rocket.android.core.behaviours.LoadingView
import chat.rocket.android.core.behaviours.MessageView import chat.rocket.android.core.behaviours.MessageView
...@@ -20,6 +21,13 @@ interface ChatRoomView : LoadingView, MessageView { ...@@ -20,6 +21,13 @@ interface ChatRoomView : LoadingView, MessageView {
*/ */
fun sendMessage(text: String) fun sendMessage(text: String)
/**
* Send a file to a chat room.
*
* @param uri The file URI to send.
*/
fun sendFile(uri: Uri)
/** /**
* Shows a (recent) message sent to a chat room. * Shows a (recent) message sent to a chat room.
* *
......
...@@ -7,7 +7,7 @@ import android.support.v4.app.Fragment ...@@ -7,7 +7,7 @@ import android.support.v4.app.Fragment
import android.support.v7.app.AppCompatActivity import android.support.v7.app.AppCompatActivity
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.util.addFragment import chat.rocket.android.util.addFragment
import chat.rocket.android.util.textContent import chat.rocket.android.util.extensions.textContent
import dagger.android.AndroidInjection import dagger.android.AndroidInjection
import dagger.android.AndroidInjector import dagger.android.AndroidInjector
import dagger.android.DispatchingAndroidInjector import dagger.android.DispatchingAndroidInjector
......
...@@ -8,8 +8,8 @@ import chat.rocket.android.R ...@@ -8,8 +8,8 @@ import chat.rocket.android.R
import chat.rocket.android.chatroom.viewmodel.AttachmentType import chat.rocket.android.chatroom.viewmodel.AttachmentType
import chat.rocket.android.chatroom.viewmodel.MessageViewModel import chat.rocket.android.chatroom.viewmodel.MessageViewModel
import chat.rocket.android.player.PlayerActivity import chat.rocket.android.player.PlayerActivity
import chat.rocket.android.util.inflate import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.setVisible import chat.rocket.android.util.extensions.setVisible
import com.facebook.drawee.view.SimpleDraweeView import com.facebook.drawee.view.SimpleDraweeView
import com.stfalcon.frescoimageviewer.ImageViewer import com.stfalcon.frescoimageviewer.ImageViewer
import kotlinx.android.synthetic.main.avatar.view.* import kotlinx.android.synthetic.main.avatar.view.*
......
package chat.rocket.android.chatroom.ui package chat.rocket.android.chatroom.ui
import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.os.Handler
import android.support.v4.app.Fragment import android.support.v4.app.Fragment
import android.support.v7.widget.DefaultItemAnimator import android.support.v7.widget.DefaultItemAnimator
import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.LinearLayoutManager
...@@ -14,11 +18,10 @@ import chat.rocket.android.chatroom.presentation.ChatRoomPresenter ...@@ -14,11 +18,10 @@ import chat.rocket.android.chatroom.presentation.ChatRoomPresenter
import chat.rocket.android.chatroom.presentation.ChatRoomView import chat.rocket.android.chatroom.presentation.ChatRoomView
import chat.rocket.android.chatroom.viewmodel.MessageViewModel import chat.rocket.android.chatroom.viewmodel.MessageViewModel
import chat.rocket.android.helper.EndlessRecyclerViewScrollListener import chat.rocket.android.helper.EndlessRecyclerViewScrollListener
import chat.rocket.android.util.inflate import chat.rocket.android.util.extensions.*
import chat.rocket.android.util.setVisible
import chat.rocket.android.util.textContent
import dagger.android.support.AndroidSupportInjection import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_chat_room.* 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_composer.*
import javax.inject.Inject import javax.inject.Inject
...@@ -37,6 +40,7 @@ private const val BUNDLE_CHAT_ROOM_ID = "chat_room_id" ...@@ -37,6 +40,7 @@ private const val BUNDLE_CHAT_ROOM_ID = "chat_room_id"
private const val BUNDLE_CHAT_ROOM_NAME = "chat_room_name" private const val BUNDLE_CHAT_ROOM_NAME = "chat_room_name"
private const val BUNDLE_CHAT_ROOM_TYPE = "chat_room_type" 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 BUNDLE_IS_CHAT_ROOM_READ_ONLY = "is_chat_room_read_only"
private const val REQUEST_CODE_FOR_PERFORM_SAF = 42
class ChatRoomFragment : Fragment(), ChatRoomView { class ChatRoomFragment : Fragment(), ChatRoomView {
@Inject lateinit var presenter: ChatRoomPresenter @Inject lateinit var presenter: ChatRoomPresenter
...@@ -45,6 +49,12 @@ class ChatRoomFragment : Fragment(), ChatRoomView { ...@@ -45,6 +49,12 @@ class ChatRoomFragment : Fragment(), ChatRoomView {
private lateinit var chatRoomType: String private lateinit var chatRoomType: String
private var isChatRoomReadOnly: Boolean = false private var isChatRoomReadOnly: Boolean = false
private lateinit var adapter: ChatRoomAdapter private lateinit var adapter: ChatRoomAdapter
// For reveal and unreveal anim.
private val hypotenuse by lazy { Math.hypot(relative_layout.width.toDouble(), relative_layout.height.toDouble()).toFloat() }
private val max by lazy { Math.max(layout_message_attachment_options.width.toDouble(), layout_message_attachment_options.height.toDouble()).toFloat() }
private val centerX by lazy { recycler_view.right }
private val centerY by lazy { recycler_view.bottom }
private lateinit var handler: Handler
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
...@@ -66,6 +76,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView { ...@@ -66,6 +76,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
presenter.loadMessages(chatRoomId, chatRoomType) presenter.loadMessages(chatRoomId, chatRoomType)
handler = Handler()
setupComposer() setupComposer()
} }
...@@ -74,6 +85,14 @@ class ChatRoomFragment : Fragment(), ChatRoomView { ...@@ -74,6 +85,14 @@ class ChatRoomFragment : Fragment(), ChatRoomView {
super.onDestroyView() super.onDestroyView()
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
if (requestCode == REQUEST_CODE_FOR_PERFORM_SAF && resultCode == Activity.RESULT_OK) {
if (resultData != null) {
sendFile(resultData.data)
}
}
}
override fun showMessages(dataSet: List<MessageViewModel>) { override fun showMessages(dataSet: List<MessageViewModel>) {
activity?.apply { activity?.apply {
if (recycler_view.adapter == null) { if (recycler_view.adapter == null) {
...@@ -101,6 +120,16 @@ class ChatRoomFragment : Fragment(), ChatRoomView { ...@@ -101,6 +120,16 @@ class ChatRoomFragment : Fragment(), ChatRoomView {
} }
} }
override fun sendFile(uri: Uri) {
var fileName: String? = null
activity?.apply {
fileName = uri.getFileName(this)
}
if (fileName != null) {
presenter.sendFile(chatRoomId, fileName.toString())
}
}
override fun showNewMessage(message: MessageViewModel) { override fun showNewMessage(message: MessageViewModel) {
text_message.textContent = "" text_message.textContent = ""
adapter.addItem(message) adapter.addItem(message)
...@@ -108,12 +137,12 @@ class ChatRoomFragment : Fragment(), ChatRoomView { ...@@ -108,12 +137,12 @@ class ChatRoomFragment : Fragment(), ChatRoomView {
} }
override fun disableMessageInput() { override fun disableMessageInput() {
text_send.isEnabled = false button_send.isEnabled = false
text_message.isEnabled = false text_message.isEnabled = false
} }
override fun enableMessageInput(clear: Boolean) { override fun enableMessageInput(clear: Boolean) {
text_send.isEnabled = true button_send.isEnabled = true
text_message.isEnabled = true text_message.isEnabled = true
if (clear) text_message.textContent = "" if (clear) text_message.textContent = ""
} }
...@@ -133,9 +162,68 @@ class ChatRoomFragment : Fragment(), ChatRoomView { ...@@ -133,9 +162,68 @@ class ChatRoomFragment : Fragment(), ChatRoomView {
private fun setupComposer() { private fun setupComposer() {
if (isChatRoomReadOnly) { if (isChatRoomReadOnly) {
text_room_is_read_only.setVisible(true) text_room_is_read_only.setVisible(true)
top_container.setVisible(false) input_container.setVisible(false)
} else { } else {
text_send.setOnClickListener { sendMessage(text_message.textContent) } var playAnimation = true
text_message.asObservable(0)
.subscribe({ t ->
if (t.isNotEmpty() && playAnimation) {
button_show_attachment_options.fadeInOrOut(1F, 0F, 120)
button_send.fadeInOrOut(0F, 1F, 120)
playAnimation = false
}
if (t.isEmpty()) {
button_send.fadeInOrOut(1F, 0F, 120)
button_show_attachment_options.fadeInOrOut(0F, 1F, 120)
playAnimation = true
}
})
button_send.setOnClickListener { sendMessage(text_message.textContent) }
button_show_attachment_options.setOnClickListener {
if (layout_message_attachment_options.isShown) {
hideAttachmentOptions()
} else {
showAttachmentOptions()
}
}
view_dim.setOnClickListener { hideAttachmentOptions() }
button_files.setOnClickListener {
handler.postDelayed({
performSAF()
}, 300)
handler.postDelayed({
hideAttachmentOptions()
}, 600)
}
} }
} }
private fun showAttachmentOptions() {
view_dim.setVisible(true)
// Play anim.
button_show_attachment_options.rotateBy(45F)
layout_message_attachment_options.circularRevealOrUnreveal(centerX, centerY, 0F, hypotenuse)
}
private fun hideAttachmentOptions() {
// Play anim.
button_show_attachment_options.rotateBy(-45F)
layout_message_attachment_options.circularRevealOrUnreveal(centerX, centerY, max, 0F)
view_dim.setVisible(false)
}
private fun performSAF() {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "*/*"
startActivityForResult(intent, REQUEST_CODE_FOR_PERFORM_SAF)
}
} }
\ No newline at end of file
...@@ -10,9 +10,9 @@ import android.widget.ImageView ...@@ -10,9 +10,9 @@ import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.helper.UrlHelper import chat.rocket.android.helper.UrlHelper
import chat.rocket.android.util.inflate import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.setVisible import chat.rocket.android.util.extensions.setVisible
import chat.rocket.android.util.textContent import chat.rocket.android.util.extensions.textContent
import chat.rocket.common.model.RoomType import chat.rocket.common.model.RoomType
import chat.rocket.core.model.ChatRoom import chat.rocket.core.model.ChatRoom
import com.facebook.drawee.view.SimpleDraweeView import com.facebook.drawee.view.SimpleDraweeView
......
...@@ -14,8 +14,8 @@ import chat.rocket.android.R ...@@ -14,8 +14,8 @@ import chat.rocket.android.R
import chat.rocket.android.authentication.ui.AuthenticationActivity import chat.rocket.android.authentication.ui.AuthenticationActivity
import chat.rocket.android.chatrooms.presentation.ChatRoomsPresenter import chat.rocket.android.chatrooms.presentation.ChatRoomsPresenter
import chat.rocket.android.chatrooms.presentation.ChatRoomsView import chat.rocket.android.chatrooms.presentation.ChatRoomsView
import chat.rocket.android.util.inflate import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.setVisible import chat.rocket.android.util.extensions.setVisible
import chat.rocket.android.widget.DividerItemDecoration import chat.rocket.android.widget.DividerItemDecoration
import chat.rocket.core.model.ChatRoom import chat.rocket.core.model.ChatRoom
import dagger.android.support.AndroidSupportInjection import dagger.android.support.AndroidSupportInjection
......
...@@ -5,7 +5,7 @@ import android.text.Spanned ...@@ -5,7 +5,7 @@ import android.text.Spanned
import android.text.method.LinkMovementMethod import android.text.method.LinkMovementMethod
import android.text.style.ClickableSpan import android.text.style.ClickableSpan
import android.widget.TextView import android.widget.TextView
import chat.rocket.android.util.ifEmpty import chat.rocket.android.util.extensions.ifEmpty
object TextHelper { object TextHelper {
......
...@@ -11,10 +11,10 @@ import chat.rocket.android.R ...@@ -11,10 +11,10 @@ import chat.rocket.android.R
import chat.rocket.android.main.ui.MainActivity import chat.rocket.android.main.ui.MainActivity
import chat.rocket.android.profile.presentation.ProfilePresenter import chat.rocket.android.profile.presentation.ProfilePresenter
import chat.rocket.android.profile.presentation.ProfileView import chat.rocket.android.profile.presentation.ProfileView
import chat.rocket.android.util.getObservable import chat.rocket.android.util.extensions.asObservable
import chat.rocket.android.util.inflate import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.setVisible import chat.rocket.android.util.extensions.setVisible
import chat.rocket.android.util.textContent import chat.rocket.android.util.extensions.textContent
import dagger.android.support.AndroidSupportInjection import dagger.android.support.AndroidSupportInjection
import io.reactivex.rxkotlin.Observables import io.reactivex.rxkotlin.Observables
import kotlinx.android.synthetic.main.app_bar.* import kotlinx.android.synthetic.main.app_bar.*
...@@ -126,7 +126,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { ...@@ -126,7 +126,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
} }
private fun listenToChanges() { private fun listenToChanges() {
Observables.combineLatest(text_name.getObservable(), text_username.getObservable(), text_email.getObservable()).subscribe({ t -> Observables.combineLatest(text_name.asObservable(), text_username.asObservable(), text_email.asObservable()).subscribe({ t ->
if (t.first.toString() != currentName || t.second.toString() != currentUsername || t.third.toString() != currentEmail) { if (t.first.toString() != currentName || t.second.toString() != currentUsername || t.third.toString() != currentEmail) {
startActionMode() startActionMode()
} else { } else {
......
package chat.rocket.android.util.extensions
import android.view.View
import android.view.ViewAnimationUtils
import android.view.animation.AccelerateInterpolator
import android.view.animation.DecelerateInterpolator
fun View.rotateBy(value: Float, duration: Long = 200) {
animate()
.rotationBy(value)
.setDuration(duration)
.start()
}
fun View.fadeInOrOut(startValue: Float, finishValue: Float, duration: Long = 200) {
animate()
.alpha(startValue)
.setDuration(duration)
.setInterpolator(DecelerateInterpolator())
.withEndAction({
animate()
.alpha(finishValue)
.setDuration(duration)
.setInterpolator(AccelerateInterpolator()).start()
}).start()
if (startValue > finishValue) {
setVisible(false)
} else {
setVisible(true)
}
}
fun View.circularRevealOrUnreveal(centerX: Int, centerY: Int, startRadius: Float, endRadius: Float, duration: Long = 600) {
val anim = ViewAnimationUtils.createCircularReveal(this, centerX, centerY, startRadius, endRadius)
anim.duration = duration
if (startRadius < endRadius) {
setVisible(true)
} else {
setVisible(false)
}
anim.start()
}
\ No newline at end of file
package chat.rocket.android.util.extensions
import android.widget.EditText
import com.jakewharton.rxbinding2.widget.RxTextView
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import java.util.concurrent.TimeUnit
fun EditText.asObservable(debounceTimeout: Long = 100): Observable<CharSequence> {
return RxTextView.textChanges(this)
.debounce(debounceTimeout, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(AndroidSchedulers.mainThread())
}
\ No newline at end of file
package chat.rocket.android.util.extensions
import android.app.Activity
import android.net.Uri
import android.widget.TextView
import android.provider.OpenableColumns
fun String.ifEmpty(value: String): String {
if (isEmpty()) {
return value
}
return this
}
var TextView.textContent: String
get() = text.toString()
set(value) {
text = value
}
var TextView.hintContent: String
get() = hint.toString()
set(value) {
hint = value
}
fun Uri.getFileName(activity: Activity): String? {
val cursor = activity.contentResolver.query(this, null, null, null, null, null)
var fileName: String? = null
cursor.use { cursor ->
if (cursor != null && cursor.moveToFirst()) {
fileName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME))
}
}
return fileName
}
fun Uri.getFileSize(activity: Activity): String? {
val cursor = activity.contentResolver.query(this, null, null, null, null, null)
var fileSize: String? = null
cursor.use { cursor ->
val sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE)
if (cursor != null && cursor.moveToFirst()) {
if (!cursor.isNull(sizeIndex)) {
fileSize = cursor.getString(sizeIndex)
}
}
}
return fileSize
}
\ No newline at end of file
package chat.rocket.android.util package chat.rocket.android.util.extensions
import android.support.annotation.LayoutRes import android.support.annotation.LayoutRes
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.EditText
import android.widget.TextView
import com.jakewharton.rxbinding2.widget.RxTextView
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import java.util.concurrent.TimeUnit
fun String.ifEmpty(value: String): String {
if (isEmpty()) {
return value
}
return this
}
fun View.setVisible(visible: Boolean) { fun View.setVisible(visible: Boolean) {
visibility = if (visible) { visibility = if (visible) {
...@@ -28,23 +15,4 @@ fun View.setVisible(visible: Boolean) { ...@@ -28,23 +15,4 @@ fun View.setVisible(visible: Boolean) {
fun ViewGroup.inflate(@LayoutRes resource: Int): View { fun ViewGroup.inflate(@LayoutRes resource: Int): View {
return LayoutInflater.from(context).inflate(resource, this, false) return LayoutInflater.from(context).inflate(resource, this, false)
}
var TextView.textContent: String
get() = text.toString()
set(value) {
text = value
}
var TextView.hintContent: String
get() = hint.toString()
set(value) {
hint = value
}
fun EditText.getObservable(): Observable<CharSequence> {
return RxTextView.textChanges(this)
.debounce(100, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(AndroidSchedulers.mainThread())
} }
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF2F343D"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</vector>
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="17.0"
android:viewportWidth="18.0">
<path
android:fillColor="#FF1D74F5"
android:fillType="nonZero"
android:pathData="M4.221,11.799L10.444,5.576C10.97,5.05 11.833,5.067 12.383,5.617C12.928,6.163 12.946,7.034 12.423,7.557L6.195,13.785C5.226,14.754 3.613,14.717 2.599,13.704C1.582,12.687 1.546,11.08 2.52,10.106L9.295,3.331C10.713,1.913 13.07,1.966 14.552,3.448C16.035,4.931 16.087,7.287 14.668,8.706L7.898,15.476L8.747,16.324L15.516,9.555C17.383,7.688 17.316,4.588 15.364,2.636C13.414,0.686 10.313,0.616 8.446,2.483L1.671,9.258C0.248,10.681 0.302,13.03 1.788,14.515C3.27,15.997 5.626,16.051 7.044,14.633L13.272,8.405C14.242,7.435 14.209,5.82 13.195,4.805C12.175,3.786 10.569,3.754 9.595,4.728L3.373,10.95L4.221,11.799Z" />
</vector>
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="20.0"
android:viewportWidth="20.0">
<path
android:fillColor="#FF2F343D"
android:fillType="evenOdd"
android:pathData="M12.4,7.6m-1.2,0a1.2,1.2 0,1 1,2.4 0a1.2,1.2 0,1 1,-2.4 0" />
<path
android:fillColor="#FF2F343D"
android:fillType="evenOdd"
android:pathData="M7.6,7.6m-1.2,0a1.2,1.2 0,1 1,2.4 0a1.2,1.2 0,1 1,-2.4 0" />
<path
android:pathData="M10,10m-8.4,0a8.4,8.4 0,1 1,16.8 0a8.4,8.4 0,1 1,-16.8 0"
android:strokeColor="#FF2F343D"
android:strokeWidth="1.5" />
<path
android:pathData="M6.606,12.794L6.606,12.794C8.48,14.669 11.52,14.669 13.394,12.794"
android:strokeColor="#FF2F343D"
android:strokeWidth="1.5" />
</vector>
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="20.0"
android:viewportWidth="22.0">
<path
android:fillColor="#FF1D74F5"
android:fillType="nonZero"
android:pathData="M0.869,1.32C0.731,0.987 0.79,0.565 1.045,0.276C1.281,0.01 1.634,-0.079 1.967,0.076L20.645,9.134C20.939,9.29 21.136,9.645 21.136,10C21.155,10.377 20.939,10.71 20.645,10.866L1.967,19.924C1.634,20.079 1.281,19.99 1.045,19.724C0.79,19.435 0.712,19.036 0.869,18.68L4.263,10L0.869,1.32ZM18.193,10L3.262,2.741L5.832,9.29L9.953,9.334C10.404,9.312 10.777,9.734 10.777,10.266C10.796,10.777 10.423,11.199 9.953,11.199L5.636,11.199L3.262,17.259L18.193,10Z" />
</vector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid
android:color="@color/colorLightTheme" />
<corners
android:radius="6dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid
android:color="@color/colorBackgroundContentFileAttachment" />
<corners
android:radius="6dp" />
<stroke
android:width="2dp"
android:color="@color/colorDrawableTintGrey" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid
android:color="@color/colorBackgroundFileAttachment" />
<corners
android:radius="6dp" />
</shape>
\ No newline at end of file
...@@ -2,10 +2,21 @@ ...@@ -2,10 +2,21 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/relative_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical">
<com.wang.avi.AVLoadingIndicatorView
android:id="@+id/view_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:visibility="gone"
app:indicatorColor="@color/black"
app:indicatorName="BallPulseIndicator"
tools:visibility="visible" />
<android.support.v7.widget.RecyclerView <android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view" android:id="@+id/recycler_view"
android:layout_width="match_parent" android:layout_width="match_parent"
...@@ -13,21 +24,29 @@ ...@@ -13,21 +24,29 @@
android:layout_above="@+id/layout_message_composer" android:layout_above="@+id/layout_message_composer"
android:scrollbars="vertical" /> android:scrollbars="vertical" />
<View
android:id="@+id/view_dim"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/layout_message_composer"
android:background="@color/colorDim"
android:visibility="gone" />
<include
android:id="@+id/layout_message_attachment_options"
layout="@layout/message_attachment_options"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_above="@+id/layout_message_composer"
android:visibility="gone"
tools:visibility="visible" />
<include <include
android:id="@+id/layout_message_composer" android:id="@+id/layout_message_composer"
layout="@layout/message_composer" layout="@layout/message_composer"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentBottom="true" /> android:layout_alignParentBottom="true" />
<com.wang.avi.AVLoadingIndicatorView
android:id="@+id/view_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:visibility="gone"
app:indicatorColor="@color/black"
app:indicatorName="BallPulseIndicator"
tools:visibility="visible" />
</RelativeLayout> </RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:fresco="http://schemas.android.com/apk/res-auto" xmlns:fresco="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/attachment_container" android:id="@+id/attachment_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:orientation="vertical">
<TextView
android:id="@+id/text_file_attachment"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@drawable/style_message_file_upload_content_bg"
android:drawablePadding="10dp"
android:drawableStart="@drawable/ic_files_24dp"
android:ellipsize="end"
android:gravity="center"
android:maxLength="20"
android:maxLines="1"
android:padding="5dp"
android:visibility="gone"
tools:text="brazilian_anthem.mp4"
tools:visibility="visible" />
<com.facebook.drawee.view.SimpleDraweeView <com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/image_attachment" android:id="@+id/image_attachment"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="150dp" android:layout_height="150dp"
android:visibility="gone"
fresco:actualImageScaleType="fitStart" fresco:actualImageScaleType="fitStart"
fresco:placeholderImage="@drawable/image_dummy" fresco:placeholderImage="@drawable/image_dummy"
tools:visibility="visible" tools:visibility="visible" />
android:visibility="gone"/>
<FrameLayout <FrameLayout
android:id="@+id/audio_video_attachment" android:id="@+id/audio_video_attachment"
...@@ -23,17 +39,18 @@ ...@@ -23,17 +39,18 @@
android:background="@color/black" android:background="@color/black"
android:visibility="gone" android:visibility="gone"
tools:visibility="gone"> tools:visibility="gone">
<ImageView <ImageView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:src="@drawable/exo_controls_play"/> android:src="@drawable/exo_controls_play" />
</FrameLayout> </FrameLayout>
<TextView <TextView
android:id="@+id/file_name" android:id="@+id/file_name"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
tools:text="Filename.png"/> tools:text="Filename.png" />
</LinearLayout> </LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/style_attachment_options"
android:orientation="vertical">
<Button
android:id="@+id/button_files"
style="?android:attr/borderlessButtonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="20dp"
android:drawableStart="@drawable/ic_files_24dp"
android:gravity="start|center"
android:text="@string/action_files" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<View <View
...@@ -22,36 +22,51 @@ ...@@ -22,36 +22,51 @@
app:layout_constraintTop_toBottomOf="@+id/divider" /> app:layout_constraintTop_toBottomOf="@+id/divider" />
<LinearLayout <LinearLayout
android:id="@+id/top_container" android:id="@+id/input_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/screen_edge_left_and_right_margins" android:layout_marginEnd="10dp"
android:layout_marginStart="@dimen/screen_edge_left_and_right_margins" android:layout_marginStart="10dp"
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
android:orientation="horizontal" android:orientation="horizontal"
android:paddingBottom="10dp" android:paddingBottom="10dp"
app:layout_constraintTop_toBottomOf="@+id/divider"> app:layout_constraintTop_toBottomOf="@+id/divider">
<ImageButton
android:id="@+id/button_add_reaction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/msg_content_description_show_attachment_options"
android:src="@drawable/ic_reaction_24dp" />
<EditText <EditText
android:id="@+id/text_message" android:id="@+id/text_message"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="8dp" android:layout_marginEnd="16dp"
android:layout_weight="1" android:layout_weight="1"
android:background="@android:color/transparent" android:background="@android:color/transparent"
android:hint="@string/msg_message" android:hint="@string/msg_message"
android:maxLines="4" /> android:maxLines="4" />
<TextView <ImageButton
android:id="@+id/text_send" android:id="@+id/button_show_attachment_options"
style="@style/TextAppearance.AppCompat.Medium" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/msg_content_description_show_attachment_options"
android:src="@drawable/ic_add_24dp" />
<ImageButton
android:id="@+id/button_send"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackgroundBorderless" android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true" android:contentDescription="@string/msg_content_description_send_message"
android:focusable="true" android:src="@drawable/ic_send_24dp"
android:text="@string/action_send" android:visibility="gone" />
android:textColor="@color/colorAccent" />
</LinearLayout> </LinearLayout>
</android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout>
\ No newline at end of file
...@@ -11,12 +11,12 @@ ...@@ -11,12 +11,12 @@
<!-- Actions --> <!-- Actions -->
<string name="action_connect">Conectar</string> <string name="action_connect">Conectar</string>
<string name="action_send">Enviar</string>
<string name="action_terms_of_service">Termos de Serviço</string> <string name="action_terms_of_service">Termos de Serviço</string>
<string name="action_privacy_policy">Política de Privacidade</string> <string name="action_privacy_policy">Política de Privacidade</string>
<string name="action_search">Pesquisar</string> <string name="action_search">Pesquisar</string>
<string name="action_update">Atualizar</string> <string name="action_update">Atualizar</string>
<string name="action_logout">Sair</string> <string name="action_logout">Sair</string>
<string name="action_files">Arquivos</string>
<!-- Regular information messages --> <!-- Regular information messages -->
<string name="msg_no_internet_connection">Sem conexão à internet</string> <string name="msg_no_internet_connection">Sem conexão à internet</string>
...@@ -44,6 +44,8 @@ ...@@ -44,6 +44,8 @@
<string name="msg_content_description_log_in_using_meteor">Fazer login através do Meteor</string> <string name="msg_content_description_log_in_using_meteor">Fazer login através do Meteor</string>
<string name="msg_content_description_log_in_using_twitter">Fazer login através do Twitter</string> <string name="msg_content_description_log_in_using_twitter">Fazer login através do Twitter</string>
<string name="msg_content_description_log_in_using_gitlab">Fazer login através do Gitlab</string> <string name="msg_content_description_log_in_using_gitlab">Fazer login através do Gitlab</string>
<string name="msg_content_description_send_message">Enviar mensagem</string>
<string name="msg_content_description_show_attachment_options">Mostrar opções de anexo</string>
<string name="msg_you">Você</string> <string name="msg_you">Você</string>
<string name="msg_unknown">Desconhecido</string> <string name="msg_unknown">Desconhecido</string>
......
...@@ -15,7 +15,14 @@ ...@@ -15,7 +15,14 @@
<color name="colorDividerMessageComposer">#D8D8D8</color> <color name="colorDividerMessageComposer">#D8D8D8</color>
<color name="colorLightTheme">#FBFBFB</color>
<color name="colorDim">#99000000</color>
<color name="colorBackgroundFileAttachment">#E2FFC8</color>
<color name="colorBackgroundContentFileAttachment">#FFD8F5C0</color>
<color name="white">#FFFFFFFF</color> <color name="white">#FFFFFFFF</color>
<color name="black">#FF000000</color> <color name="black">#FF000000</color>
</resources> </resources>
\ No newline at end of file
...@@ -12,12 +12,12 @@ ...@@ -12,12 +12,12 @@
<!-- Actions --> <!-- Actions -->
<string name="action_connect">Connect</string> <string name="action_connect">Connect</string>
<string name="action_send">Send</string>
<string name="action_terms_of_service">Terms of Service</string> <string name="action_terms_of_service">Terms of Service</string>
<string name="action_privacy_policy">Privacy Policy</string> <string name="action_privacy_policy">Privacy Policy</string>
<string name="action_search">Search</string> <string name="action_search">Search</string>
<string name="action_update">Update</string> <string name="action_update">Update</string>
<string name="action_logout">Log Out</string> <string name="action_logout">Log Out</string>
<string name="action_files">Files</string>
<!-- Regular information messages --> <!-- Regular information messages -->
<string name="msg_no_internet_connection">No internet connection</string> <string name="msg_no_internet_connection">No internet connection</string>
...@@ -46,6 +46,8 @@ ...@@ -46,6 +46,8 @@
<string name="msg_content_description_log_in_using_meteor">Login using Meteor</string> <string name="msg_content_description_log_in_using_meteor">Login using Meteor</string>
<string name="msg_content_description_log_in_using_twitter">Login using Twitter</string> <string name="msg_content_description_log_in_using_twitter">Login using Twitter</string>
<string name="msg_content_description_log_in_using_gitlab">Login using Gitlab</string> <string name="msg_content_description_log_in_using_gitlab">Login using Gitlab</string>
<string name="msg_content_description_send_message">Send message</string>
<string name="msg_content_description_show_attachment_options">Show attachment options</string>
<string name="msg_you">You</string> <string name="msg_you">You</string>
<string name="msg_unknown">Unknown</string> <string name="msg_unknown">Unknown</string>
......
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