Unverified Commit 2ed0f6d7 authored by Filipe de Lima Brito's avatar Filipe de Lima Brito Committed by GitHub

Merge pull request #1304 from RocketChat/new/file-list

[NEW] File list
parents bbfeb193 a4e4bad7
...@@ -12,7 +12,18 @@ object DateTimeHelper { ...@@ -12,7 +12,18 @@ object DateTimeHelper {
private val lastWeek = today.minusWeeks(1) private val lastWeek = today.minusWeeks(1)
/** /**
* Returns a date from a [LocalDateTime] or the textual representation if the [LocalDateTime] has a max period of a week from the current date. * Returns a [LocalDateTime] from a [Long].
*
* @param long The [Long]
* @return The [LocalDateTime] from a [Long].
*/
fun getLocalDateTime(long: Long): LocalDateTime {
return LocalDateTime.ofInstant(Instant.ofEpochMilli(long), ZoneId.systemDefault())
}
/**
* Returns a date from a [LocalDateTime] or the textual representation if the [LocalDateTime]
* has a max period of a week from the current date.
* *
* @param localDateTime The [LocalDateTime]. * @param localDateTime The [LocalDateTime].
* @param context The context. * @param context The context.
...@@ -45,13 +56,18 @@ object DateTimeHelper { ...@@ -45,13 +56,18 @@ object DateTimeHelper {
} }
/** /**
* Returns a [LocalDateTime] from a [Long]. * Returns a date time from a [LocalDateTime].
* *
* @param long The [Long] * @param localDateTime The [LocalDateTime].
* @return The [LocalDateTime] from a [Long]. * @return The time from a [LocalDateTime].
*/ */
fun getLocalDateTime(long: Long): LocalDateTime { fun getDateTime(localDateTime: LocalDateTime): String {
return LocalDateTime.ofInstant(Instant.ofEpochMilli(long), ZoneId.systemDefault()) return formatLocalDateTime(localDateTime)
}
private fun formatLocalDateTime(localDateTime: LocalDateTime): String {
val formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT)
return localDateTime.format(formatter).toString()
} }
private fun formatLocalDate(localDate: LocalDate): String { private fun formatLocalDate(localDate: LocalDate): String {
......
...@@ -5,21 +5,7 @@ import android.view.MenuItem ...@@ -5,21 +5,7 @@ import android.view.MenuItem
import android.view.ViewGroup import android.view.ViewGroup
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.chatroom.presentation.ChatRoomPresenter import chat.rocket.android.chatroom.presentation.ChatRoomPresenter
import chat.rocket.android.chatroom.ui.chatRoomIntent import chat.rocket.android.chatroom.viewmodel.*
import chat.rocket.android.chatroom.viewmodel.AudioAttachmentViewModel
import chat.rocket.android.chatroom.viewmodel.AuthorAttachmentViewModel
import chat.rocket.android.chatroom.viewmodel.BaseFileAttachmentViewModel
import chat.rocket.android.chatroom.viewmodel.BaseViewModel
import chat.rocket.android.chatroom.viewmodel.ColorAttachmentViewModel
import chat.rocket.android.chatroom.viewmodel.GenericFileAttachmentViewModel
import chat.rocket.android.chatroom.viewmodel.ImageAttachmentViewModel
import chat.rocket.android.chatroom.viewmodel.MessageAttachmentViewModel
import chat.rocket.android.chatroom.viewmodel.MessageReplyViewModel
import chat.rocket.android.chatroom.viewmodel.MessageViewModel
import chat.rocket.android.chatroom.viewmodel.UrlPreviewViewModel
import chat.rocket.android.chatroom.viewmodel.VideoAttachmentViewModel
import chat.rocket.android.chatroom.viewmodel.toViewType
import chat.rocket.android.main.presentation.MainNavigator
import chat.rocket.android.util.extensions.inflate import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.widget.emoji.EmojiReactionListener import chat.rocket.android.widget.emoji.EmojiReactionListener
import chat.rocket.core.model.Message import chat.rocket.core.model.Message
...@@ -28,13 +14,12 @@ import timber.log.Timber ...@@ -28,13 +14,12 @@ import timber.log.Timber
import java.security.InvalidParameterException import java.security.InvalidParameterException
class ChatRoomAdapter( class ChatRoomAdapter(
private val roomType: String, private val roomType: String? = null,
private val roomName: String, private val roomName: String? = null,
private val presenter: ChatRoomPresenter?, private val presenter: ChatRoomPresenter? = null,
private val enableActions: Boolean = true, private val enableActions: Boolean = true,
private val reactionListener: EmojiReactionListener? = null private val reactionListener: EmojiReactionListener? = null
) : RecyclerView.Adapter<BaseViewHolder<*>>() { ) : RecyclerView.Adapter<BaseViewHolder<*>>() {
private val dataSet = ArrayList<BaseViewModel<*>>() private val dataSet = ArrayList<BaseViewModel<*>>()
init { init {
...@@ -178,7 +163,7 @@ class ChatRoomAdapter( ...@@ -178,7 +163,7 @@ class ChatRoomAdapter(
} }
fun updateItem(message: BaseViewModel<*>) { fun updateItem(message: BaseViewModel<*>) {
var index = dataSet.indexOfLast { it.messageId == message.messageId } val index = dataSet.indexOfLast { it.messageId == message.messageId }
val indexOfNext = dataSet.indexOfFirst { it.messageId == message.messageId } val indexOfNext = dataSet.indexOfFirst { it.messageId == message.messageId }
Timber.d("index: $index") Timber.d("index: $index")
if (index > -1) { if (index > -1) {
...@@ -219,11 +204,15 @@ class ChatRoomAdapter( ...@@ -219,11 +204,15 @@ class ChatRoomAdapter(
message.apply { message.apply {
when (item.itemId) { when (item.itemId) {
R.id.action_message_reply -> { R.id.action_message_reply -> {
if (roomName != null && roomType != null) {
presenter?.citeMessage(roomName, roomType, id, true) presenter?.citeMessage(roomName, roomType, id, true)
} }
}
R.id.action_message_quote -> { R.id.action_message_quote -> {
if (roomName != null && roomType != null) {
presenter?.citeMessage(roomName, roomType, id, false) presenter?.citeMessage(roomName, roomType, id, false)
} }
}
R.id.action_message_copy -> { R.id.action_message_copy -> {
presenter?.copyMessage(id) presenter?.copyMessage(id)
} }
......
...@@ -3,6 +3,7 @@ package chat.rocket.android.chatroom.adapter ...@@ -3,6 +3,7 @@ package chat.rocket.android.chatroom.adapter
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.view.View import android.view.View
import androidx.core.net.toUri
import chat.rocket.android.chatroom.viewmodel.GenericFileAttachmentViewModel import chat.rocket.android.chatroom.viewmodel.GenericFileAttachmentViewModel
import chat.rocket.android.util.extensions.content import chat.rocket.android.util.extensions.content
import chat.rocket.android.widget.emoji.EmojiReactionListener import chat.rocket.android.widget.emoji.EmojiReactionListener
...@@ -25,7 +26,7 @@ class GenericFileAttachmentViewHolder(itemView: View, ...@@ -25,7 +26,7 @@ class GenericFileAttachmentViewHolder(itemView: View,
text_file_name.content = data.attachmentTitle text_file_name.content = data.attachmentTitle
text_file_name.setOnClickListener { text_file_name.setOnClickListener {
it.context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(data.attachmentUrl))) it.context.startActivity(Intent(Intent.ACTION_VIEW, data.attachmentUrl.toUri()))
} }
} }
} }
......
package chat.rocket.android.chatroom.adapter package chat.rocket.android.chatroom.adapter
import android.Manifest
import android.app.Activity
import android.graphics.Color
import android.graphics.Typeface
import android.media.MediaScannerConnection
import android.net.Uri
import android.os.Environment
import android.support.design.widget.AppBarLayout
import android.support.v7.widget.Toolbar
import android.text.TextUtils
import android.util.TypedValue
import android.view.ContextThemeWrapper
import android.view.Gravity
import android.view.View import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.core.view.setPadding
import chat.rocket.android.R
import chat.rocket.android.chatroom.viewmodel.ImageAttachmentViewModel import chat.rocket.android.chatroom.viewmodel.ImageAttachmentViewModel
import chat.rocket.android.helper.AndroidPermissionsHelper import chat.rocket.android.helper.ImageHelper
import chat.rocket.android.widget.emoji.EmojiReactionListener import chat.rocket.android.widget.emoji.EmojiReactionListener
import com.facebook.binaryresource.FileBinaryResource
import com.facebook.cache.common.CacheKey
import com.facebook.drawee.backends.pipeline.Fresco import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.imageformat.ImageFormatChecker
import com.facebook.imagepipeline.cache.DefaultCacheKeyFactory
import com.facebook.imagepipeline.core.ImagePipelineFactory
import com.facebook.imagepipeline.request.ImageRequest
import com.facebook.imagepipeline.request.ImageRequestBuilder
import com.stfalcon.frescoimageviewer.ImageViewer
import kotlinx.android.synthetic.main.message_attachment.view.* import kotlinx.android.synthetic.main.message_attachment.view.*
import timber.log.Timber
import java.io.File
class ImageAttachmentViewHolder( class ImageAttachmentViewHolder(
itemView: View, itemView: View,
listener: ActionsListener, listener: ActionsListener,
reactionListener: EmojiReactionListener? = null reactionListener: EmojiReactionListener? = null
) : BaseViewHolder<ImageAttachmentViewModel>(itemView, listener, reactionListener) { ) : BaseViewHolder<ImageAttachmentViewModel>(itemView, listener, reactionListener) {
private var cacheKey: CacheKey? = null
init { init {
with(itemView) { with(itemView) {
...@@ -59,138 +28,13 @@ class ImageAttachmentViewHolder( ...@@ -59,138 +28,13 @@ class ImageAttachmentViewHolder(
}.build() }.build()
image_attachment.controller = controller image_attachment.controller = controller
file_name.text = data.attachmentTitle file_name.text = data.attachmentTitle
image_attachment.setOnClickListener { view -> image_attachment.setOnClickListener {
// TODO - implement a proper image viewer with a proper Transition ImageHelper.openImage(
// TODO - We should definitely write our own ImageViewer it.context,
var imageViewer: ImageViewer? = null data.attachmentUrl,
val request = data.attachmentTitle.toString()
ImageRequestBuilder.newBuilderWithSource(Uri.parse(data.attachmentUrl))
.setLowestPermittedRequestLevel(ImageRequest.RequestLevel.DISK_CACHE)
.build()
cacheKey = DefaultCacheKeyFactory.getInstance()
.getEncodedCacheKey(request, null)
val pad = context.resources
.getDimensionPixelSize(R.dimen.viewer_toolbar_padding)
val lparams = AppBarLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
val toolbar = Toolbar(context).also {
it.inflateMenu(R.menu.image_actions)
it.overflowIcon?.setTint(Color.WHITE)
it.setOnMenuItemClickListener {
return@setOnMenuItemClickListener when (it.itemId) {
R.id.action_save_image -> saveImage()
else -> super.onMenuItemClick(it)
}
}
val titleSize = context.resources
.getDimensionPixelSize(R.dimen.viewer_toolbar_title)
val titleTextView = TextView(context).also {
it.text = data.attachmentTitle
it.setTextColor(Color.WHITE)
it.setTextSize(TypedValue.COMPLEX_UNIT_PX, titleSize.toFloat())
it.ellipsize = TextUtils.TruncateAt.END
it.setSingleLine()
it.typeface = Typeface.DEFAULT_BOLD
it.setPadding(pad)
}
val backArrowView = ImageView(context).also {
it.setImageResource(R.drawable.ic_arrow_back_white_24dp)
it.setOnClickListener { imageViewer?.onDismiss() }
it.setPadding(0, pad, pad, pad)
}
val layoutParams = AppBarLayout.LayoutParams(
AppBarLayout.LayoutParams.WRAP_CONTENT,
AppBarLayout.LayoutParams.WRAP_CONTENT
)
it.addView(backArrowView, layoutParams)
it.addView(titleTextView, layoutParams)
}
val appBarLayout = AppBarLayout(context).also {
it.layoutParams = lparams
it.setBackgroundColor(Color.BLACK)
it.addView(
toolbar, AppBarLayout.LayoutParams(
AppBarLayout.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
) )
} }
val builder = ImageViewer.createPipelineDraweeControllerBuilder()
.setImageRequest(request)
.setAutoPlayAnimations(true)
imageViewer = ImageViewer.Builder(view.context, listOf(data.attachmentUrl))
.setOverlayView(appBarLayout)
.setStartPosition(0)
.hideStatusBar(false)
.setCustomDraweeControllerBuilder(builder)
.show()
}
}
}
private fun saveImage(): Boolean {
if (!canWriteToExternalStorage()) {
checkWritingPermission()
return false
}
if (ImagePipelineFactory.getInstance().mainFileCache.hasKey(cacheKey)) {
val context = itemView.context
val resource = ImagePipelineFactory.getInstance().mainFileCache.getResource(cacheKey)
val cachedFile = (resource as FileBinaryResource).file
val imageFormat = ImageFormatChecker.getImageFormat(resource.openStream())
val imageDir = "${Environment.DIRECTORY_PICTURES}/Rocket.Chat Images/"
val imagePath = Environment.getExternalStoragePublicDirectory(imageDir)
val imageFile =
File(imagePath, "${cachedFile.nameWithoutExtension}.${imageFormat.fileExtension}")
imagePath.mkdirs()
imageFile.createNewFile()
try {
cachedFile.copyTo(imageFile, true)
MediaScannerConnection.scanFile(
context,
arrayOf(imageFile.absolutePath),
null
) { path, uri ->
Timber.i("Scanned $path:")
Timber.i("-> uri=$uri")
}
} catch (ex: Exception) {
Timber.e(ex)
val message = context.getString(R.string.msg_image_saved_failed)
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
} finally {
val message = context.getString(R.string.msg_image_saved_successfully)
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}
}
return true
}
private fun canWriteToExternalStorage(): Boolean {
return AndroidPermissionsHelper.checkPermission(
itemView.context,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
}
private fun checkWritingPermission() {
val context = itemView.context
if (context is ContextThemeWrapper && context.baseContext is Activity) {
val activity = context.baseContext as Activity
AndroidPermissionsHelper.requestPermission(
activity,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
AndroidPermissionsHelper.WRITE_EXTERNAL_STORAGE_CODE
)
} }
} }
} }
\ No newline at end of file
...@@ -3,27 +3,32 @@ package chat.rocket.android.chatroom.presentation ...@@ -3,27 +3,32 @@ package chat.rocket.android.chatroom.presentation
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.chatroom.ui.ChatRoomActivity import chat.rocket.android.chatroom.ui.ChatRoomActivity
import chat.rocket.android.chatroom.ui.chatRoomIntent import chat.rocket.android.chatroom.ui.chatRoomIntent
import chat.rocket.android.members.ui.newInstance
import chat.rocket.android.server.ui.changeServerIntent import chat.rocket.android.server.ui.changeServerIntent
import chat.rocket.android.util.extensions.addFragmentBackStack import chat.rocket.android.util.extensions.addFragmentBackStack
class ChatRoomNavigator(internal val activity: ChatRoomActivity) { class ChatRoomNavigator(internal val activity: ChatRoomActivity) {
fun toMembersList(chatRoomId: String, chatRoomType: String) { fun toMembersList(chatRoomId: String) {
activity.addFragmentBackStack("MembersFragment", R.id.fragment_container) { activity.addFragmentBackStack("MembersFragment", R.id.fragment_container) {
newInstance(chatRoomId, chatRoomType) chat.rocket.android.members.ui.newInstance(chatRoomId)
} }
} }
fun toPinnedMessageList(chatRoomId: String, chatRoomType: String) { fun toPinnedMessageList(chatRoomId: String) {
activity.addFragmentBackStack("PinnedMessages", R.id.fragment_container) { activity.addFragmentBackStack("PinnedMessages", R.id.fragment_container) {
chat.rocket.android.pinnedmessages.ui.newInstance(chatRoomId, chatRoomType) chat.rocket.android.pinnedmessages.ui.newInstance(chatRoomId)
} }
} }
fun toFavoriteMessageList(chatRoomId: String, chatRoomType: String) { fun toFavoriteMessageList(chatRoomId: String) {
activity.addFragmentBackStack("FavoriteMessages", R.id.fragment_container) { activity.addFragmentBackStack("FavoriteMessages", R.id.fragment_container) {
chat.rocket.android.favoritemessages.ui.newInstance(chatRoomId, chatRoomType) chat.rocket.android.favoritemessages.ui.newInstance(chatRoomId)
}
}
fun toFileList(chatRoomId: String) {
activity.addFragmentBackStack("Files", R.id.fragment_container) {
chat.rocket.android.files.ui.newInstance(chatRoomId)
} }
} }
......
...@@ -638,14 +638,17 @@ class ChatRoomPresenter @Inject constructor( ...@@ -638,14 +638,17 @@ class ChatRoomPresenter @Inject constructor(
} }
} }
fun toMembersList(chatRoomId: String, chatRoomType: String) = fun toMembersList(chatRoomId: String) =
navigator.toMembersList(chatRoomId, chatRoomType) navigator.toMembersList(chatRoomId)
fun toPinnedMessageList(chatRoomId: String, chatRoomType: String) = fun toPinnedMessageList(chatRoomId: String) =
navigator.toPinnedMessageList(chatRoomId, chatRoomType) navigator.toPinnedMessageList(chatRoomId)
fun toFavoriteMessageList(chatRoomId: String, chatRoomType: String) = fun toFavoriteMessageList(chatRoomId: String) =
navigator.toFavoriteMessageList(chatRoomId, chatRoomType) navigator.toFavoriteMessageList(chatRoomId)
fun toFileList(chatRoomId: String) =
navigator.toFileList(chatRoomId)
fun loadChatRooms() { fun loadChatRooms() {
launchUI(strategy) { launchUI(strategy) {
......
...@@ -154,7 +154,7 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector { ...@@ -154,7 +154,7 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector {
drawable?.let { drawable?.let {
val wrappedDrawable = DrawableHelper.wrapDrawable(it) val wrappedDrawable = DrawableHelper.wrapDrawable(it)
val mutableDrawable = wrappedDrawable.mutate() val mutableDrawable = wrappedDrawable.mutate()
DrawableHelper.tintDrawable(mutableDrawable, this, R.color.white) DrawableHelper.tintDrawable(mutableDrawable, this, R.color.colorWhite)
DrawableHelper.compoundDrawable(text_room_name, mutableDrawable) DrawableHelper.compoundDrawable(text_room_name, mutableDrawable)
} }
} else { } else {
......
...@@ -230,13 +230,16 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -230,13 +230,16 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
R.id.action_members_list -> { R.id.action_members_list -> {
presenter.toMembersList(chatRoomId, chatRoomType) presenter.toMembersList(chatRoomId)
} }
R.id.action_pinned_messages -> { R.id.action_pinned_messages -> {
presenter.toPinnedMessageList(chatRoomId, chatRoomType) presenter.toPinnedMessageList(chatRoomId)
} }
R.id.action_favorite_messages -> { R.id.action_favorite_messages -> {
presenter.toFavoriteMessageList(chatRoomId, chatRoomType) presenter.toFavoriteMessageList(chatRoomId)
}
R.id.action_files -> {
presenter.toFileList(chatRoomId)
} }
} }
return true return true
......
...@@ -26,7 +26,7 @@ class ActionListAdapter( ...@@ -26,7 +26,7 @@ class ActionListAdapter(
holder.itemView.setOnClickListener { holder.itemView.setOnClickListener {
callback?.onMenuItemClick(item) callback?.onMenuItemClick(item)
} }
val deleteTextColor = holder.itemView.context.resources.getColor(R.color.red) val deleteTextColor = holder.itemView.context.resources.getColor(R.color.colorRed)
val color = if (item.itemId == R.id.action_message_delete) { val color = if (item.itemId == R.id.action_message_delete) {
deleteTextColor deleteTextColor
} else { } else {
......
...@@ -11,13 +11,14 @@ import chat.rocket.android.authentication.ui.AuthenticationActivity ...@@ -11,13 +11,14 @@ import chat.rocket.android.authentication.ui.AuthenticationActivity
import chat.rocket.android.chatroom.di.ChatRoomFragmentProvider import chat.rocket.android.chatroom.di.ChatRoomFragmentProvider
import chat.rocket.android.chatroom.di.ChatRoomModule import chat.rocket.android.chatroom.di.ChatRoomModule
import chat.rocket.android.chatroom.di.FavoriteMessagesFragmentProvider import chat.rocket.android.chatroom.di.FavoriteMessagesFragmentProvider
import chat.rocket.android.chatroom.di.PinnedMessagesFragmentProvider
import chat.rocket.android.chatroom.ui.ChatRoomActivity import chat.rocket.android.chatroom.ui.ChatRoomActivity
import chat.rocket.android.chatrooms.di.ChatRoomsFragmentProvider import chat.rocket.android.chatrooms.di.ChatRoomsFragmentProvider
import chat.rocket.android.dagger.scope.PerActivity import chat.rocket.android.dagger.scope.PerActivity
import chat.rocket.android.files.di.FilesFragmentProvider
import chat.rocket.android.main.di.MainModule import chat.rocket.android.main.di.MainModule
import chat.rocket.android.main.ui.MainActivity import chat.rocket.android.main.ui.MainActivity
import chat.rocket.android.members.di.MembersFragmentProvider import chat.rocket.android.members.di.MembersFragmentProvider
import chat.rocket.android.pinnedmessages.di.PinnedMessagesFragmentProvider
import chat.rocket.android.profile.di.ProfileFragmentProvider import chat.rocket.android.profile.di.ProfileFragmentProvider
import chat.rocket.android.server.di.ChangeServerModule import chat.rocket.android.server.di.ChangeServerModule
import chat.rocket.android.server.ui.ChangeServerActivity import chat.rocket.android.server.ui.ChangeServerActivity
...@@ -30,21 +31,25 @@ import dagger.android.ContributesAndroidInjector ...@@ -30,21 +31,25 @@ import dagger.android.ContributesAndroidInjector
abstract class ActivityBuilder { abstract class ActivityBuilder {
@PerActivity @PerActivity
@ContributesAndroidInjector(modules = [AuthenticationModule::class, @ContributesAndroidInjector(
modules = [AuthenticationModule::class,
ServerFragmentProvider::class, ServerFragmentProvider::class,
LoginFragmentProvider::class, LoginFragmentProvider::class,
RegisterUsernameFragmentProvider::class, RegisterUsernameFragmentProvider::class,
ResetPasswordFragmentProvider::class, ResetPasswordFragmentProvider::class,
SignupFragmentProvider::class, SignupFragmentProvider::class,
TwoFAFragmentProvider::class TwoFAFragmentProvider::class
]) ]
)
abstract fun bindAuthenticationActivity(): AuthenticationActivity abstract fun bindAuthenticationActivity(): AuthenticationActivity
@PerActivity @PerActivity
@ContributesAndroidInjector(modules = [MainModule::class, @ContributesAndroidInjector(
modules = [MainModule::class,
ChatRoomsFragmentProvider::class, ChatRoomsFragmentProvider::class,
ProfileFragmentProvider::class ProfileFragmentProvider::class
]) ]
)
abstract fun bindMainActivity(): MainActivity abstract fun bindMainActivity(): MainActivity
@PerActivity @PerActivity
...@@ -54,7 +59,8 @@ abstract class ActivityBuilder { ...@@ -54,7 +59,8 @@ abstract class ActivityBuilder {
ChatRoomFragmentProvider::class, ChatRoomFragmentProvider::class,
MembersFragmentProvider::class, MembersFragmentProvider::class,
PinnedMessagesFragmentProvider::class, PinnedMessagesFragmentProvider::class,
FavoriteMessagesFragmentProvider::class FavoriteMessagesFragmentProvider::class,
FilesFragmentProvider::class
] ]
) )
abstract fun bindChatRoomActivity(): ChatRoomActivity abstract fun bindChatRoomActivity(): ChatRoomActivity
......
...@@ -15,12 +15,13 @@ import javax.inject.Inject ...@@ -15,12 +15,13 @@ import javax.inject.Inject
class FavoriteMessagesPresenter @Inject constructor( class FavoriteMessagesPresenter @Inject constructor(
private val view: FavoriteMessagesView, private val view: FavoriteMessagesView,
private val strategy: CancelStrategy, private val strategy: CancelStrategy,
private val serverInteractor: GetCurrentServerInteractor,
private val roomsInteractor: ChatRoomsInteractor, private val roomsInteractor: ChatRoomsInteractor,
private val mapper: ViewModelMapper, private val mapper: ViewModelMapper,
factory: RocketChatClientFactory val serverInteractor: GetCurrentServerInteractor,
val factory: RocketChatClientFactory
) { ) {
private val client = factory.create(serverInteractor.get()!!) private val serverUrl = serverInteractor.get()!!
private val client = factory.create(serverUrl)
private var offset: Int = 0 private var offset: Int = 0
/** /**
...@@ -31,21 +32,19 @@ class FavoriteMessagesPresenter @Inject constructor( ...@@ -31,21 +32,19 @@ class FavoriteMessagesPresenter @Inject constructor(
fun loadFavoriteMessages(roomId: String) { fun loadFavoriteMessages(roomId: String) {
launchUI(strategy) { launchUI(strategy) {
try { try {
val serverUrl = serverInteractor.get()!!
val chatRoom = roomsInteractor.getById(serverUrl, roomId)
chatRoom?.let { room ->
view.showLoading() view.showLoading()
val favoriteMessages = roomsInteractor.getById(serverUrl, roomId)?.let {
client.getFavoriteMessages(roomId, room.type, offset) val favoriteMessages = client.getFavoriteMessages(roomId, it.type, offset)
offset = favoriteMessages.offset.toInt()
val messageList = mapper.map(favoriteMessages.result) val messageList = mapper.map(favoriteMessages.result)
view.showFavoriteMessages(messageList) view.showFavoriteMessages(messageList)
view.hideLoading() offset += 1 * 30
}.ifNull { }.ifNull {
Timber.e("Couldn't find a room with id: $roomId at current server.") Timber.e("Couldn't find a room with id: $roomId at current server.")
} }
} catch (e: RocketChatException) { } catch (exception: RocketChatException) {
Timber.e(e) Timber.e(exception)
} finally {
view.hideLoading()
} }
} }
} }
......
...@@ -23,21 +23,18 @@ import dagger.android.support.AndroidSupportInjection ...@@ -23,21 +23,18 @@ import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_favorite_messages.* import kotlinx.android.synthetic.main.fragment_favorite_messages.*
import javax.inject.Inject import javax.inject.Inject
fun newInstance(chatRoomId: String, chatRoomType: String): Fragment { fun newInstance(chatRoomId: String): Fragment {
return FavoriteMessagesFragment().apply { return FavoriteMessagesFragment().apply {
arguments = Bundle(1).apply { arguments = Bundle(1).apply {
putString(INTENT_CHAT_ROOM_ID, chatRoomId) putString(INTENT_CHAT_ROOM_ID, chatRoomId)
putString(INTENT_CHAT_ROOM_TYPE, chatRoomType)
} }
} }
} }
private const val INTENT_CHAT_ROOM_ID = "chat_room_id" private const val INTENT_CHAT_ROOM_ID = "chat_room_id"
private const val INTENT_CHAT_ROOM_TYPE = "chat_room_type"
class FavoriteMessagesFragment : Fragment(), FavoriteMessagesView { class FavoriteMessagesFragment : Fragment(), FavoriteMessagesView {
private lateinit var chatRoomId: String private lateinit var chatRoomId: String
private lateinit var chatRoomType: String
private lateinit var adapter: ChatRoomAdapter private lateinit var adapter: ChatRoomAdapter
@Inject @Inject
lateinit var presenter: FavoriteMessagesPresenter lateinit var presenter: FavoriteMessagesPresenter
...@@ -49,7 +46,6 @@ class FavoriteMessagesFragment : Fragment(), FavoriteMessagesView { ...@@ -49,7 +46,6 @@ class FavoriteMessagesFragment : Fragment(), FavoriteMessagesView {
val bundle = arguments val bundle = arguments
if (bundle != null) { if (bundle != null) {
chatRoomId = bundle.getString(INTENT_CHAT_ROOM_ID) chatRoomId = bundle.getString(INTENT_CHAT_ROOM_ID)
chatRoomType = bundle.getString(INTENT_CHAT_ROOM_TYPE)
} else { } else {
requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" } requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" }
} }
...@@ -70,7 +66,7 @@ class FavoriteMessagesFragment : Fragment(), FavoriteMessagesView { ...@@ -70,7 +66,7 @@ class FavoriteMessagesFragment : Fragment(), FavoriteMessagesView {
override fun showFavoriteMessages(favoriteMessages: List<BaseViewModel<*>>) { override fun showFavoriteMessages(favoriteMessages: List<BaseViewModel<*>>) {
ui { ui {
if (recycler_view.adapter == null) { if (recycler_view.adapter == null) {
adapter = ChatRoomAdapter(chatRoomType, "", null, false) adapter = ChatRoomAdapter(enableActions = false)
recycler_view.adapter = adapter recycler_view.adapter = adapter
val linearLayoutManager = val linearLayoutManager =
LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
......
package chat.rocket.android.files.adapter
import android.support.v7.widget.RecyclerView
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import chat.rocket.android.R
import chat.rocket.android.files.viewmodel.FileViewModel
import chat.rocket.android.util.extensions.inflate
import kotlinx.android.synthetic.main.item_generic_attachment.view.*
class FilesAdapter(private val listener: (FileViewModel) -> Unit) :
RecyclerView.Adapter<FilesAdapter.ViewHolder>() {
private var dataSet: List<FileViewModel> = ArrayList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FilesAdapter.ViewHolder =
ViewHolder(parent.inflate(R.layout.item_generic_attachment))
override fun onBindViewHolder(holder: FilesAdapter.ViewHolder, position: Int) =
holder.bind(dataSet[position], listener)
override fun getItemCount(): Int = dataSet.size
fun prependData(dataSet: List<FileViewModel>) {
this.dataSet = dataSet
notifyItemRangeInserted(0, dataSet.size)
}
fun appendData(dataSet: List<FileViewModel>) {
val previousDataSetSize = this.dataSet.size
this.dataSet += dataSet
notifyItemRangeInserted(previousDataSetSize, dataSet.size)
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(fileViewModel: FileViewModel, listener: (FileViewModel) -> Unit) {
with(itemView) {
when {
fileViewModel.isImage -> {
image_file_thumbnail.setImageURI(fileViewModel.url)
image_file_media_thumbnail.isVisible = false
image_file_thumbnail.isVisible = true
}
fileViewModel.isMedia -> {
image_file_media_thumbnail.setImageDrawable(
context.resources.getDrawable(
R.drawable.ic_play_arrow_black_24dp, null
)
)
image_file_thumbnail.isVisible = false
image_file_media_thumbnail.isVisible = true
}
else -> {
image_file_media_thumbnail.setImageDrawable(
context.resources.getDrawable(
R.drawable.ic_insert_drive_file_black_24dp, null
)
)
image_file_thumbnail.isVisible = false
image_file_media_thumbnail.isVisible = true
}
}
text_file_name.text = fileViewModel.name
text_uploader.text = fileViewModel.uploader
text_upload_date.text = fileViewModel.uploadDate
setOnClickListener { listener(fileViewModel) }
}
}
}
}
\ No newline at end of file
package chat.rocket.android.files.di
import android.arch.lifecycle.LifecycleOwner
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.dagger.scope.PerFragment
import chat.rocket.android.files.presentation.FilesView
import chat.rocket.android.files.ui.FilesFragment
import dagger.Module
import dagger.Provides
import kotlinx.coroutines.experimental.Job
@Module
@PerFragment
class FilesFragmentModule {
@Provides
fun provideLifecycleOwner(frag: FilesFragment): LifecycleOwner {
return frag
}
@Provides
fun provideCancelStrategy(owner: LifecycleOwner, jobs: Job): CancelStrategy {
return CancelStrategy(owner, jobs)
}
@Provides
fun provideFilesView(frag: FilesFragment): FilesView {
return frag
}
}
\ No newline at end of file
package chat.rocket.android.files.di
import chat.rocket.android.files.ui.FilesFragment
import dagger.Module
import dagger.android.ContributesAndroidInjector
@Module
abstract class FilesFragmentProvider {
@ContributesAndroidInjector(modules = [FilesFragmentModule::class])
abstract fun provideFilesFragment(): FilesFragment
}
\ No newline at end of file
package chat.rocket.android.files.presentation
import androidx.core.net.toUri
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.files.viewmodel.FileViewModel
import chat.rocket.android.files.viewmodel.FileViewModelMapper
import chat.rocket.android.server.domain.ChatRoomsInteractor
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.extensions.launchUI
import chat.rocket.common.RocketChatException
import chat.rocket.common.util.ifNull
import chat.rocket.core.internal.rest.getFiles
import timber.log.Timber
import javax.inject.Inject
class FilesPresenter @Inject constructor(
private val view: FilesView,
private val strategy: CancelStrategy,
private val roomsInteractor: ChatRoomsInteractor,
private val mapper: FileViewModelMapper,
val serverInteractor: GetCurrentServerInteractor,
val factory: RocketChatClientFactory
) {
private val serverUrl = serverInteractor.get()!!
private val client = factory.create(serverUrl)
private var offset: Int = 0
/**
* Load all files for the given room id.
*
* @param roomId The id of the room to get files from.
*/
fun loadFiles(roomId: String) {
launchUI(strategy) {
try {
view.showLoading()
roomsInteractor.getById(serverUrl, roomId)?.let {
val files = client.getFiles(roomId, it.type, offset)
val filesViewModel = mapper.mapToViewModelList(files.result)
view.showFiles(filesViewModel, files.total)
offset += 1 * 30
}.ifNull {
Timber.e("Couldn't find a room with id: $roomId at current server.")
}
} catch (exception: RocketChatException) {
exception.message?.let {
view.showMessage(it)
}.ifNull {
view.showGenericErrorMessage()
}
Timber.e(exception)
} finally {
view.hideLoading()
}
}
}
fun openFile(fileViewModel: FileViewModel) {
when {
fileViewModel.isImage -> fileViewModel.url?.let {
view.openImage(it, fileViewModel.name ?: "")
}
fileViewModel.isMedia -> fileViewModel.url?.let {
view.playMedia(it)
}
else -> fileViewModel.url?.let {
view.openDocument(it.toUri())
}
}
}
}
\ No newline at end of file
package chat.rocket.android.files.presentation
import android.net.Uri
import chat.rocket.android.core.behaviours.LoadingView
import chat.rocket.android.core.behaviours.MessageView
import chat.rocket.android.files.viewmodel.FileViewModel
interface FilesView : MessageView, LoadingView {
/**
* Show list of files for the current room.
*
* @param dataSet The data set to show.
* @param total The total number of files.
*/
fun showFiles(dataSet: List<FileViewModel>, total: Long)
/**
* Plays a media file (audio/video).
*
* @param url The file url to play its media.
*/
fun playMedia(url: String)
/**
* Opens an image file
*
* @param url The file url to open its image.
* @param name The file name.
*/
fun openImage(url: String, name: String)
/**
* Opens a document file (.pdf, .txt and so on).
*
* @param uri The file uri to open its document.
*/
fun openDocument(uri: Uri)
}
\ No newline at end of file
package chat.rocket.android.files.ui
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import chat.rocket.android.R
import chat.rocket.android.chatroom.ui.ChatRoomActivity
import chat.rocket.android.files.adapter.FilesAdapter
import chat.rocket.android.files.presentation.FilesPresenter
import chat.rocket.android.files.presentation.FilesView
import chat.rocket.android.files.viewmodel.FileViewModel
import chat.rocket.android.helper.EndlessRecyclerViewScrollListener
import chat.rocket.android.helper.ImageHelper
import chat.rocket.android.player.PlayerActivity
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.ui
import chat.rocket.android.widget.DividerItemDecoration
import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_files.*
import javax.inject.Inject
fun newInstance(chatRoomId: String): Fragment {
return FilesFragment().apply {
arguments = Bundle(1).apply {
putString(BUNDLE_CHAT_ROOM_ID, chatRoomId)
}
}
}
private const val BUNDLE_CHAT_ROOM_ID = "chat_room_id"
class FilesFragment : Fragment(), FilesView {
@Inject
lateinit var presenter: FilesPresenter
private val adapter: FilesAdapter =
FilesAdapter { fileViewModel -> presenter.openFile(fileViewModel) }
private val linearLayoutManager =
LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
private lateinit var chatRoomId: String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this)
val bundle = arguments
if (bundle != null) {
chatRoomId = bundle.getString(BUNDLE_CHAT_ROOM_ID)
} else {
requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" }
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? = container?.inflate(R.layout.fragment_files)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupRecyclerView()
presenter.loadFiles(chatRoomId)
}
override fun showFiles(dataSet: List<FileViewModel>, total: Long) {
setupToolbar(total)
if (adapter.itemCount == 0) {
adapter.prependData(dataSet)
if (dataSet.size >= 30) {
recycler_view.addOnScrollListener(object :
EndlessRecyclerViewScrollListener(linearLayoutManager) {
override fun onLoadMore(
page: Int,
totalItemsCount: Int,
recyclerView: RecyclerView?
) {
presenter.loadFiles(chatRoomId)
}
})
}
} else {
adapter.appendData(dataSet)
}
}
override fun playMedia(url: String) {
ui {
activity?.let {
PlayerActivity.play(it, url)
}
}
}
override fun openImage(url: String, name: String) {
ui {
activity?.let {
ImageHelper.openImage(it, url, name)
}
}
}
override fun openDocument(uri: Uri) {
ui {
startActivity(Intent(Intent.ACTION_VIEW, uri))
}
}
override fun showMessage(resId: Int) {
ui {
showToast(resId)
}
}
override fun showMessage(message: String) {
ui {
showToast(message)
}
}
override fun showGenericErrorMessage() {
showMessage(getString(R.string.msg_generic_error))
}
override fun showLoading() {
ui { view_loading.isVisible = true }
}
override fun hideLoading() {
ui { view_loading.isVisible = false }
}
private fun setupRecyclerView() {
ui {
recycler_view.layoutManager = linearLayoutManager
recycler_view.addItemDecoration(DividerItemDecoration(it))
recycler_view.adapter = adapter
}
}
private fun setupToolbar(totalFiles: Long) {
(activity as ChatRoomActivity?)?.setupToolbarTitle(
getString(R.string.title_files_total, totalFiles)
)
}
}
\ No newline at end of file
package chat.rocket.android.files.viewmodel
import DateTimeHelper
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.util.extensions.fileUrl
import chat.rocket.core.model.Value
import chat.rocket.core.model.attachment.GenericAttachment
class FileViewModel(
private val genericAttachment: GenericAttachment,
private val settings: Map<String, Value<Any>>,
private val tokenRepository: TokenRepository,
private val baseUrl: String
) {
val name: String?
val uploader: String?
val uploadDate: String?
val url: String?
val isMedia: Boolean
val isImage: Boolean
init {
name = getFileName()
uploader = getUserDisplayName()
uploadDate = getFileUploadDate()
url = getFileUrl()
isMedia = isFileMedia()
isImage = isFileImage()
}
private fun getFileName(): String? {
return genericAttachment.name
}
private fun getUserDisplayName(): String {
val username = "@${genericAttachment.user?.username}"
val realName = genericAttachment.user?.name
val uploaderName = if (settings.useRealName()) realName else username
return uploaderName ?: username
}
private fun getFileUploadDate(): String {
return DateTimeHelper.getDateTime(
DateTimeHelper.getLocalDateTime(genericAttachment.uploadedAt)
)
}
private fun getFileUrl(): String? {
val token = tokenRepository.get(baseUrl)
if (token != null) {
genericAttachment.path?.let {
return baseUrl.fileUrl(it, token)
}
}
return ""
}
private fun isFileMedia(): Boolean {
genericAttachment.type?.let {
return it.contains("audio") || it.contains("video")
}
return false
}
private fun isFileImage(): Boolean {
genericAttachment.type?.let {
return it.contains("image")
}
return false
}
}
\ No newline at end of file
package chat.rocket.android.files.viewmodel
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.baseUrl
import chat.rocket.core.model.Value
import chat.rocket.core.model.attachment.GenericAttachment
import javax.inject.Inject
class FileViewModelMapper @Inject constructor(
serverInteractor: GetCurrentServerInteractor,
getSettingsInteractor: GetSettingsInteractor,
private val tokenRepository: TokenRepository
) {
private var settings: Map<String, Value<Any>> =
getSettingsInteractor.get(serverInteractor.get()!!)
private val baseUrl = settings.baseUrl()
fun mapToViewModelList(fileList: List<GenericAttachment>): List<FileViewModel> {
return fileList.map { FileViewModel(it, settings, tokenRepository, baseUrl) }
}
}
\ No newline at end of file
package chat.rocket.android.helper
import android.Manifest
import android.app.Activity
import android.content.Context
import android.graphics.Color
import android.graphics.Typeface
import android.media.MediaScannerConnection
import android.os.Environment
import android.support.design.widget.AppBarLayout
import android.support.v7.widget.Toolbar
import android.text.TextUtils
import android.util.TypedValue
import android.view.ContextThemeWrapper
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.core.net.toUri
import androidx.core.view.setPadding
import chat.rocket.android.R
import com.facebook.binaryresource.FileBinaryResource
import com.facebook.cache.common.CacheKey
import com.facebook.imageformat.ImageFormatChecker
import com.facebook.imagepipeline.cache.DefaultCacheKeyFactory
import com.facebook.imagepipeline.core.ImagePipelineFactory
import com.facebook.imagepipeline.request.ImageRequest
import com.facebook.imagepipeline.request.ImageRequestBuilder
import com.stfalcon.frescoimageviewer.ImageViewer
import timber.log.Timber
import java.io.File
object ImageHelper {
private var cacheKey: CacheKey? = null
// TODO - implement a proper image viewer with a proper Transition
// TODO - We should definitely write our own ImageViewer
fun openImage(context: Context, imageUrl: String, imageName: String) {
var imageViewer: ImageViewer? = null
val request =
ImageRequestBuilder.newBuilderWithSource(imageUrl.toUri())
.setLowestPermittedRequestLevel(ImageRequest.RequestLevel.DISK_CACHE)
.build()
cacheKey = DefaultCacheKeyFactory.getInstance()
.getEncodedCacheKey(request, null)
val pad = context.resources
.getDimensionPixelSize(R.dimen.viewer_toolbar_padding)
val lparams = AppBarLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
val toolbar = Toolbar(context).also {
it.inflateMenu(R.menu.image_actions)
it.overflowIcon?.setTint(Color.WHITE)
it.setOnMenuItemClickListener {
return@setOnMenuItemClickListener when (it.itemId) {
R.id.action_save_image -> saveImage(context)
else -> true
}
}
val titleSize = context.resources
.getDimensionPixelSize(R.dimen.viewer_toolbar_title)
val titleTextView = TextView(context).also {
it.text = imageName
it.setTextColor(Color.WHITE)
it.setTextSize(TypedValue.COMPLEX_UNIT_PX, titleSize.toFloat())
it.ellipsize = TextUtils.TruncateAt.END
it.setSingleLine()
it.typeface = Typeface.DEFAULT_BOLD
it.setPadding(pad)
}
val backArrowView = ImageView(context).also {
it.setImageResource(R.drawable.ic_arrow_back_white_24dp)
it.setOnClickListener { imageViewer?.onDismiss() }
it.setPadding(0, pad, pad, pad)
}
val layoutParams = AppBarLayout.LayoutParams(
AppBarLayout.LayoutParams.WRAP_CONTENT,
AppBarLayout.LayoutParams.WRAP_CONTENT
)
it.addView(backArrowView, layoutParams)
it.addView(titleTextView, layoutParams)
}
val appBarLayout = AppBarLayout(context).also {
it.layoutParams = lparams
it.setBackgroundColor(Color.BLACK)
it.addView(
toolbar, AppBarLayout.LayoutParams(
AppBarLayout.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
)
}
val builder = ImageViewer.createPipelineDraweeControllerBuilder()
.setImageRequest(request)
.setAutoPlayAnimations(true)
imageViewer = ImageViewer.Builder(context, listOf(imageUrl))
.setOverlayView(appBarLayout)
.setStartPosition(0)
.hideStatusBar(false)
.setCustomDraweeControllerBuilder(builder)
.show()
}
private fun saveImage(context: Context): Boolean {
if (!canWriteToExternalStorage(context)) {
checkWritingPermission(context)
return false
}
if (ImagePipelineFactory.getInstance().mainFileCache.hasKey(cacheKey)) {
val resource = ImagePipelineFactory.getInstance().mainFileCache.getResource(cacheKey)
val cachedFile = (resource as FileBinaryResource).file
val imageFormat = ImageFormatChecker.getImageFormat(resource.openStream())
val imageDir = "${Environment.DIRECTORY_PICTURES}/Rocket.Chat Images/"
val imagePath = Environment.getExternalStoragePublicDirectory(imageDir)
val imageFile =
File(imagePath, "${cachedFile.nameWithoutExtension}.${imageFormat.fileExtension}")
imagePath.mkdirs()
imageFile.createNewFile()
try {
cachedFile.copyTo(imageFile, true)
MediaScannerConnection.scanFile(
context,
arrayOf(imageFile.absolutePath),
null
) { path, uri ->
Timber.i("Scanned $path:")
Timber.i("-> uri=$uri")
}
} catch (ex: Exception) {
Timber.e(ex)
val message = context.getString(R.string.msg_image_saved_failed)
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
} finally {
val message = context.getString(R.string.msg_image_saved_successfully)
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}
}
return true
}
private fun canWriteToExternalStorage(context: Context): Boolean {
return AndroidPermissionsHelper.checkPermission(
context,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
}
private fun checkWritingPermission(context: Context) {
if (context is ContextThemeWrapper && context.baseContext is Activity) {
val activity = context.baseContext as Activity
AndroidPermissionsHelper.requestPermission(
activity,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
AndroidPermissionsHelper.WRITE_EXTERNAL_STORAGE_CODE
)
}
}
}
\ No newline at end of file
...@@ -93,7 +93,7 @@ class MessageParser @Inject constructor( ...@@ -93,7 +93,7 @@ class MessageParser @Inject constructor(
private val othersTextColor = ResourcesCompat.getColor(context.resources, R.color.colorAccent, context.theme) private val othersTextColor = ResourcesCompat.getColor(context.resources, R.color.colorAccent, context.theme)
private val othersBackgroundColor = ResourcesCompat.getColor(context.resources, android.R.color.transparent, context.theme) private val othersBackgroundColor = ResourcesCompat.getColor(context.resources, android.R.color.transparent, context.theme)
private val myselfTextColor = ResourcesCompat.getColor(context.resources, R.color.white, context.theme) private val myselfTextColor = ResourcesCompat.getColor(context.resources, R.color.colorWhite, context.theme)
private val myselfBackgroundColor = ResourcesCompat.getColor(context.resources, R.color.colorAccent, context.theme) private val myselfBackgroundColor = ResourcesCompat.getColor(context.resources, R.color.colorAccent, context.theme)
private val mentionPadding = context.resources.getDimensionPixelSize(R.dimen.padding_mention).toFloat() private val mentionPadding = context.resources.getDimensionPixelSize(R.dimen.padding_mention).toFloat()
private val mentionRadius = context.resources.getDimensionPixelSize(R.dimen.radius_mention).toFloat() private val mentionRadius = context.resources.getDimensionPixelSize(R.dimen.radius_mention).toFloat()
......
...@@ -3,39 +3,44 @@ package chat.rocket.android.members.presentation ...@@ -3,39 +3,44 @@ package chat.rocket.android.members.presentation
import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.members.viewmodel.MemberViewModel import chat.rocket.android.members.viewmodel.MemberViewModel
import chat.rocket.android.members.viewmodel.MemberViewModelMapper import chat.rocket.android.members.viewmodel.MemberViewModelMapper
import chat.rocket.android.server.domain.ChatRoomsInteractor
import chat.rocket.android.server.domain.GetCurrentServerInteractor import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.extensions.launchUI import chat.rocket.android.util.extensions.launchUI
import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
import chat.rocket.common.model.roomTypeOf
import chat.rocket.common.util.ifNull import chat.rocket.common.util.ifNull
import chat.rocket.core.RocketChatClient import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.getMembers import chat.rocket.core.internal.rest.getMembers
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
class MembersPresenter @Inject constructor( class MembersPresenter @Inject constructor(
private val view: MembersView, private val view: MembersView,
private val navigator: MembersNavigator, private val navigator: MembersNavigator,
private val strategy: CancelStrategy, private val strategy: CancelStrategy,
serverInteractor: GetCurrentServerInteractor, private val roomsInteractor: ChatRoomsInteractor,
factory: RocketChatClientFactory, private val mapper: MemberViewModelMapper,
private val mapper: MemberViewModelMapper val serverInteractor: GetCurrentServerInteractor,
val factory: RocketChatClientFactory
) { ) {
private val client: RocketChatClient = factory.create(serverInteractor.get()!!) private val serverUrl = serverInteractor.get()!!
private val client: RocketChatClient = factory.create(serverUrl)
private var offset: Long = 0
fun loadChatRoomsMembers(chatRoomId: String, chatRoomType: String, offset: Long = 0) { fun loadChatRoomsMembers(roomId: String) {
launchUI(strategy) { launchUI(strategy) {
try { try {
view.showLoading() view.showLoading()
roomsInteractor.getById(serverUrl, roomId)?.let {
val members = retryIO("getMembers($chatRoomId, $chatRoomType, $offset)") { val members = client.getMembers(it.id, it.type, offset, 60)
client.getMembers(chatRoomId, roomTypeOf(chatRoomType), offset, 60)
}
val memberViewModels = mapper.mapToViewModelList(members.result) val memberViewModels = mapper.mapToViewModelList(members.result)
view.showMembers(memberViewModels, members.total) view.showMembers(memberViewModels, members.total)
} catch (ex: RocketChatException) { offset += 1 * 60L
ex.message?.let { }.ifNull {
Timber.e("Couldn't find a room with id: $roomId at current server")
}
} catch (exception: RocketChatException) {
exception.message?.let {
view.showMessage(it) view.showMessage(it)
}.ifNull { }.ifNull {
view.showGenericErrorMessage() view.showGenericErrorMessage()
......
...@@ -2,7 +2,6 @@ package chat.rocket.android.members.ui ...@@ -2,7 +2,6 @@ package chat.rocket.android.members.ui
import android.os.Bundle import android.os.Bundle
import android.support.v4.app.Fragment import android.support.v4.app.Fragment
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater import android.view.LayoutInflater
...@@ -24,17 +23,15 @@ import dagger.android.support.AndroidSupportInjection ...@@ -24,17 +23,15 @@ import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_members.* import kotlinx.android.synthetic.main.fragment_members.*
import javax.inject.Inject import javax.inject.Inject
fun newInstance(chatRoomId: String, chatRoomType: String): Fragment { fun newInstance(chatRoomId: String): Fragment {
return MembersFragment().apply { return MembersFragment().apply {
arguments = Bundle(1).apply { arguments = Bundle(1).apply {
putString(BUNDLE_CHAT_ROOM_ID, chatRoomId) putString(BUNDLE_CHAT_ROOM_ID, chatRoomId)
putString(BUNDLE_CHAT_ROOM_TYPE, chatRoomType)
} }
} }
} }
private const val BUNDLE_CHAT_ROOM_ID = "chat_room_id" private const val BUNDLE_CHAT_ROOM_ID = "chat_room_id"
private const val BUNDLE_CHAT_ROOM_TYPE = "chat_room_type"
class MembersFragment : Fragment(), MembersView { class MembersFragment : Fragment(), MembersView {
@Inject @Inject
...@@ -43,9 +40,7 @@ class MembersFragment : Fragment(), MembersView { ...@@ -43,9 +40,7 @@ class MembersFragment : Fragment(), MembersView {
MembersAdapter { memberViewModel -> presenter.toMemberDetails(memberViewModel) } MembersAdapter { memberViewModel -> presenter.toMemberDetails(memberViewModel) }
private val linearLayoutManager = private val linearLayoutManager =
LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
private lateinit var chatRoomId: String private lateinit var chatRoomId: String
private lateinit var chatRoomType: String
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
...@@ -54,7 +49,6 @@ class MembersFragment : Fragment(), MembersView { ...@@ -54,7 +49,6 @@ class MembersFragment : Fragment(), MembersView {
val bundle = arguments val bundle = arguments
if (bundle != null) { if (bundle != null) {
chatRoomId = bundle.getString(BUNDLE_CHAT_ROOM_ID) chatRoomId = bundle.getString(BUNDLE_CHAT_ROOM_ID)
chatRoomType = bundle.getString(BUNDLE_CHAT_ROOM_TYPE)
} else { } else {
requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" } requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" }
} }
...@@ -68,9 +62,8 @@ class MembersFragment : Fragment(), MembersView { ...@@ -68,9 +62,8 @@ class MembersFragment : Fragment(), MembersView {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
setupRecyclerView() setupRecyclerView()
presenter.loadChatRoomsMembers(chatRoomId, chatRoomType) presenter.loadChatRoomsMembers(chatRoomId)
} }
override fun showMembers(dataSet: List<MemberViewModel>, total: Long) { override fun showMembers(dataSet: List<MemberViewModel>, total: Long) {
...@@ -86,7 +79,7 @@ class MembersFragment : Fragment(), MembersView { ...@@ -86,7 +79,7 @@ class MembersFragment : Fragment(), MembersView {
totalItemsCount: Int, totalItemsCount: Int,
recyclerView: RecyclerView? recyclerView: RecyclerView?
) { ) {
presenter.loadChatRoomsMembers(chatRoomId, chatRoomType, page * 60L) presenter.loadChatRoomsMembers(chatRoomId)
} }
}) })
} }
......
package chat.rocket.android.chatroom.di package chat.rocket.android.pinnedmessages.di
import chat.rocket.android.chatroom.di.PinnedMessagesFragmentModule
import chat.rocket.android.pinnedmessages.ui.PinnedMessagesFragment import chat.rocket.android.pinnedmessages.ui.PinnedMessagesFragment
import dagger.Module import dagger.Module
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector
......
...@@ -16,13 +16,14 @@ import javax.inject.Inject ...@@ -16,13 +16,14 @@ import javax.inject.Inject
class PinnedMessagesPresenter @Inject constructor( class PinnedMessagesPresenter @Inject constructor(
private val view: PinnedMessagesView, private val view: PinnedMessagesView,
private val strategy: CancelStrategy, private val strategy: CancelStrategy,
private val serverInteractor: GetCurrentServerInteractor,
private val roomsInteractor: ChatRoomsInteractor, private val roomsInteractor: ChatRoomsInteractor,
private val mapper: ViewModelMapper, private val mapper: ViewModelMapper,
factory: RocketChatClientFactory val serverInteractor: GetCurrentServerInteractor,
val factory: RocketChatClientFactory
) { ) {
private val client = factory.create(serverInteractor.get()!!) private val serverUrl = serverInteractor.get()!!
private var pinnedMessagesListOffset: Int = 0 private val client = factory.create(serverUrl)
private var offset: Int = 0
/** /**
* Load all pinned messages for the given room id. * Load all pinned messages for the given room id.
...@@ -32,21 +33,20 @@ class PinnedMessagesPresenter @Inject constructor( ...@@ -32,21 +33,20 @@ class PinnedMessagesPresenter @Inject constructor(
fun loadPinnedMessages(roomId: String) { fun loadPinnedMessages(roomId: String) {
launchUI(strategy) { launchUI(strategy) {
try { try {
val serverUrl = serverInteractor.get()!!
val chatRoom = roomsInteractor.getById(serverUrl, roomId)
chatRoom?.let { room ->
view.showLoading() view.showLoading()
val pinnedMessages = roomsInteractor.getById(serverUrl, roomId)?.let {
client.getPinnedMessages(roomId, room.type, pinnedMessagesListOffset) val pinnedMessages = client.getPinnedMessages(roomId, it.type, offset)
pinnedMessagesListOffset = pinnedMessages.offset.toInt() val messageList =
val messageList = mapper.map(pinnedMessages.result.filterNot { it.isSystemMessage() }) mapper.map(pinnedMessages.result.filterNot { it.isSystemMessage() })
view.showPinnedMessages(messageList) view.showPinnedMessages(messageList)
view.hideLoading() offset += 1 * 30
}.ifNull { }.ifNull {
Timber.e("Couldn't find a room with id: $roomId at current server.") Timber.e("Couldn't find a room with id: $roomId at current server.")
} }
} catch (e: RocketChatException) { } catch (exception: RocketChatException) {
Timber.e(e) Timber.e(exception)
} finally {
view.hideLoading()
} }
} }
} }
......
...@@ -23,22 +23,19 @@ import dagger.android.support.AndroidSupportInjection ...@@ -23,22 +23,19 @@ import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_pinned_messages.* import kotlinx.android.synthetic.main.fragment_pinned_messages.*
import javax.inject.Inject import javax.inject.Inject
fun newInstance(chatRoomId: String, chatRoomType: String): Fragment { fun newInstance(chatRoomId: String): Fragment {
return PinnedMessagesFragment().apply { return PinnedMessagesFragment().apply {
arguments = Bundle(1).apply { arguments = Bundle(1).apply {
putString(BUNDLE_CHAT_ROOM_ID, chatRoomId) putString(BUNDLE_CHAT_ROOM_ID, chatRoomId)
putString(BUNDLE_CHAT_ROOM_TYPE, chatRoomType)
} }
} }
} }
private const val BUNDLE_CHAT_ROOM_ID = "chat_room_id" private const val BUNDLE_CHAT_ROOM_ID = "chat_room_id"
private const val BUNDLE_CHAT_ROOM_TYPE = "chat_room_type"
class PinnedMessagesFragment : Fragment(), PinnedMessagesView { class PinnedMessagesFragment : Fragment(), PinnedMessagesView {
private lateinit var chatRoomId: String private lateinit var chatRoomId: String
private lateinit var chatRoomType: String
private lateinit var adapter: ChatRoomAdapter private lateinit var adapter: ChatRoomAdapter
@Inject @Inject
lateinit var presenter: PinnedMessagesPresenter lateinit var presenter: PinnedMessagesPresenter
...@@ -50,7 +47,6 @@ class PinnedMessagesFragment : Fragment(), PinnedMessagesView { ...@@ -50,7 +47,6 @@ class PinnedMessagesFragment : Fragment(), PinnedMessagesView {
val bundle = arguments val bundle = arguments
if (bundle != null) { if (bundle != null) {
chatRoomId = bundle.getString(BUNDLE_CHAT_ROOM_ID) chatRoomId = bundle.getString(BUNDLE_CHAT_ROOM_ID)
chatRoomType = bundle.getString(BUNDLE_CHAT_ROOM_TYPE)
} else { } else {
requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" } requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" }
} }
...@@ -66,14 +62,13 @@ class PinnedMessagesFragment : Fragment(), PinnedMessagesView { ...@@ -66,14 +62,13 @@ class PinnedMessagesFragment : Fragment(), PinnedMessagesView {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
setupToolbar() setupToolbar()
presenter.loadPinnedMessages(chatRoomId) presenter.loadPinnedMessages(chatRoomId)
} }
override fun showPinnedMessages(pinnedMessages: List<BaseViewModel<*>>) { override fun showPinnedMessages(pinnedMessages: List<BaseViewModel<*>>) {
ui { ui {
if (recycler_view_pinned.adapter == null) { if (recycler_view_pinned.adapter == null) {
adapter = ChatRoomAdapter(chatRoomType, "", null, false) adapter = ChatRoomAdapter(enableActions = false)
recycler_view_pinned.adapter = adapter recycler_view_pinned.adapter = adapter
val linearLayoutManager = val linearLayoutManager =
LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
......
...@@ -103,5 +103,5 @@ fun PublicSettings.uploadMaxFileSize(): Int { ...@@ -103,5 +103,5 @@ fun PublicSettings.uploadMaxFileSize(): Int {
return this[UPLOAD_MAX_FILE_SIZE]?.value?.let { it as Int } ?: Int.MAX_VALUE return this[UPLOAD_MAX_FILE_SIZE]?.value?.let { it as Int } ?: Int.MAX_VALUE
} }
fun PublicSettings.baseUrl(): String? = this[SITE_URL]?.value as String? fun PublicSettings.baseUrl(): String = this[SITE_URL]?.value as String
fun PublicSettings.siteName(): String? = this[SITE_NAME]?.value as String? fun PublicSettings.siteName(): String? = this[SITE_NAME]?.value as String?
\ No newline at end of file
...@@ -2,6 +2,7 @@ package chat.rocket.android.util.extensions ...@@ -2,6 +2,7 @@ package chat.rocket.android.util.extensions
import android.graphics.Color import android.graphics.Color
import android.util.Patterns import android.util.Patterns
import chat.rocket.common.model.Token
import timber.log.Timber import timber.log.Timber
fun String.removeTrailingSlash(): String { fun String.removeTrailingSlash(): String {
...@@ -17,7 +18,11 @@ fun String.sanitize(): String { ...@@ -17,7 +18,11 @@ fun String.sanitize(): String {
return tmp.removeTrailingSlash() return tmp.removeTrailingSlash()
} }
fun String.avatarUrl(avatar: String, isGroupOrChannel: Boolean = false, format: String = "jpeg"): String { fun String.avatarUrl(
avatar: String,
isGroupOrChannel: Boolean = false,
format: String = "jpeg"
): String {
return if (isGroupOrChannel) { return if (isGroupOrChannel) {
"${removeTrailingSlash()}/avatar/%23${avatar.removeTrailingSlash()}?format=$format" "${removeTrailingSlash()}/avatar/%23${avatar.removeTrailingSlash()}?format=$format"
} else { } else {
...@@ -25,6 +30,14 @@ fun String.avatarUrl(avatar: String, isGroupOrChannel: Boolean = false, format: ...@@ -25,6 +30,14 @@ fun String.avatarUrl(avatar: String, isGroupOrChannel: Boolean = false, format:
} }
} }
fun String.fileUrl(path: String, token: Token): String {
return (this + path + "?rc_uid=${token.userId}" + "&rc_token=${token.authToken}").safeUrl()
}
fun String.safeUrl(): String {
return this.replace(" ", "%20").replace("\\", "")
}
fun String.serverLogoUrl(favicon: String) = "${removeTrailingSlash()}/$favicon" fun String.serverLogoUrl(favicon: String) = "${removeTrailingSlash()}/$favicon"
fun String.casUrl(serverUrl: String, token: String) = fun String.casUrl(serverUrl: String, token: String) =
......
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FFFFFF"
android:pathData="M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z" />
</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="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M6,2c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2L18,22c1.1,0 2,-0.9 2,-2L20,8l-6,-6L6,2zM13,9L13,3.5L18.5,9L13,9z" />
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M8,5v14l11,-7z" />
</vector>
\ No newline at end of file
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginTop="@dimen/nav_header_height" android:layout_marginTop="@dimen/nav_header_height"
android:alpha="0" android:alpha="0"
android:background="@color/white" android:background="@color/colorWhite"
android:elevation="20dp" android:elevation="20dp"
android:visibility="gone" /> android:visibility="gone" />
</FrameLayout> </FrameLayout>
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerInParent="true" android:layout_centerInParent="true"
app:indicatorColor="@color/black" app:indicatorColor="@color/colorBlack"
app:indicatorName="BallPulseIndicator" /> app:indicatorName="BallPulseIndicator" />
</RelativeLayout> </RelativeLayout>
\ No newline at end of file
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
android:drawablePadding="@dimen/text_view_drawable_padding" android:drawablePadding="@dimen/text_view_drawable_padding"
android:ellipsize="end" android:ellipsize="end"
android:maxLines="1" android:maxLines="1"
android:textColor="@color/white" android:textColor="@color/colorWhite"
android:textSize="18sp" android:textSize="18sp"
android:textStyle="bold" android:textStyle="bold"
tools:text="Developers" /> tools:text="Developers" />
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
android:layout_alignParentStart="true" android:layout_alignParentStart="true"
android:ellipsize="end" android:ellipsize="end"
android:maxLines="1" android:maxLines="1"
android:textColor="@color/white" android:textColor="@color/colorWhite"
android:textSize="18sp" android:textSize="18sp"
android:textStyle="bold" android:textStyle="bold"
tools:text="@string/title_password" /> tools:text="@string/title_password" />
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
android:id="@+id/emoji_keyboard_container" android:id="@+id/emoji_keyboard_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:background="@color/white"> android:background="@color/colorWhite">
<View <View
android:id="@+id/divider" android:id="@+id/divider"
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
android:id="@+id/picker_container" android:id="@+id/picker_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@color/white" android:background="@color/colorWhite"
android:orientation="vertical"> android:orientation="vertical">
<android.support.design.widget.TabLayout <android.support.design.widget.TabLayout
...@@ -22,6 +22,6 @@ ...@@ -22,6 +22,6 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginEnd="8dp" android:layout_marginEnd="8dp"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
android:background="@color/white" /> android:background="@color/colorWhite" />
</LinearLayout> </LinearLayout>
\ No newline at end of file
...@@ -214,7 +214,7 @@ ...@@ -214,7 +214,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:src="@drawable/ic_expand_more_black_24dp" android:src="@drawable/ic_expand_more_black_24dp"
android:theme="@style/Theme.AppCompat" android:theme="@style/Theme.AppCompat"
android:tint="@color/white" android:tint="@color/colorWhite"
android:visibility="gone" android:visibility="gone"
app:backgroundTint="@color/colorAccent" app:backgroundTint="@color/colorAccent"
app:elevation="@dimen/fab_elevation" app:elevation="@dimen/fab_elevation"
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:visibility="gone" android:visibility="gone"
app:indicatorColor="@color/black" app:indicatorColor="@color/colorBlack"
app:indicatorName="BallPulseIndicator" app:indicatorName="BallPulseIndicator"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
...@@ -136,7 +136,7 @@ ...@@ -136,7 +136,7 @@
android:elevation="4dp" android:elevation="4dp"
android:gravity="center" android:gravity="center"
android:textAppearance="@style/TextAppearance.AppCompat.Body2" android:textAppearance="@style/TextAppearance.AppCompat.Body2"
android:textColor="@color/white" android:textColor="@color/colorWhite"
android:visibility="gone" android:visibility="gone"
tools:alpha="1" tools:alpha="1"
tools:text="connected" tools:text="connected"
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerInParent="true" android:layout_centerInParent="true"
android:visibility="gone" android:visibility="gone"
app:indicatorColor="@color/black" app:indicatorColor="@color/colorBlack"
app:indicatorName="BallPulseIndicator" /> app:indicatorName="BallPulseIndicator" />
<TextView <TextView
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
android:elevation="4dp" android:elevation="4dp"
android:gravity="center" android:gravity="center"
android:textAppearance="@style/TextAppearance.AppCompat.Body2" android:textAppearance="@style/TextAppearance.AppCompat.Body2"
android:textColor="@color/white" android:textColor="@color/colorWhite"
android:visibility="gone" android:visibility="gone"
tools:alpha="1" tools:alpha="1"
tools:text="connected" tools:text="connected"
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerInParent="true" android:layout_centerInParent="true"
android:visibility="gone" android:visibility="gone"
app:indicatorColor="@color/black" app:indicatorColor="@color/colorBlack"
app:indicatorName="BallPulseIndicator" app:indicatorName="BallPulseIndicator"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
......
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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"
android:layout_height="match_parent"
tools:context=".files.ui.FilesFragment">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
<com.wang.avi.AVLoadingIndicatorView
android:id="@+id/view_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:indicatorColor="@color/colorBlack"
app:indicatorName="BallPulseIndicator"
app:layout_constraintBottom_toBottomOf="@+id/recycler_view"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/image_file"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/ic_insert_drive_file_black_24dp"
android:tint="@color/icon_grey"
app:layout_constraintBottom_toTopOf="@+id/text_no_file"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<TextView
android:id="@+id/text_no_file"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="@string/msg_no_files"
android:textColor="@color/colorSecondaryText"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@+id/text_all_files_appear_here"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/image_file" />
<TextView
android:id="@+id/text_all_files_appear_here"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/msg_all_files_appear_here"
android:textColor="@color/colorSecondaryTextLight"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_no_file" />
<android.support.constraint.Group
android:id="@+id/group_no_file"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:constraint_referenced_ids="image_file,text_no_file,text_all_files_appear_here"
tools:visibility="visible" />
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
style="@style/TextAppearance.AppCompat.Title" style="@style/TextAppearance.AppCompat.Title"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textColor="@color/white" android:textColor="@color/colorWhite"
tools:text="Ronald Perkins" /> tools:text="Ronald Perkins" />
<TextView <TextView
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="5dp" android:layout_marginTop="5dp"
android:textColor="@color/white" android:textColor="@color/colorWhite"
tools:text="\@ronaldPerkins" /> tools:text="\@ronaldPerkins" />
</LinearLayout> </LinearLayout>
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerInParent="true" android:layout_centerInParent="true"
android:layout_gravity="center" android:layout_gravity="center"
app:indicatorColor="@color/black" app:indicatorColor="@color/colorBlack"
app:indicatorName="BallPulseIndicator" /> app:indicatorName="BallPulseIndicator" />
</android.support.design.widget.CoordinatorLayout> </android.support.design.widget.CoordinatorLayout>
\ No newline at end of file
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
tools:visibility="visible" tools:visibility="visible"
android:visibility="gone" android:visibility="gone"
app:indicatorColor="@color/black" app:indicatorColor="@color/colorBlack"
app:indicatorName="BallPulseIndicator" app:indicatorName="BallPulseIndicator"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
android:layout_marginBottom="8dp" android:layout_marginBottom="8dp"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:visibility="gone" android:visibility="gone"
app:indicatorColor="@color/black" app:indicatorColor="@color/colorBlack"
app:indicatorName="BallPulseIndicator" app:indicatorName="BallPulseIndicator"
app:layout_constraintBottom_toBottomOf="@+id/recycler_view_pinned" app:layout_constraintBottom_toBottomOf="@+id/recycler_view_pinned"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
......
...@@ -69,7 +69,7 @@ ...@@ -69,7 +69,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerInParent="true" android:layout_centerInParent="true"
app:indicatorColor="@color/black" app:indicatorColor="@color/colorBlack"
app:indicatorName="BallPulseIndicator" /> app:indicatorName="BallPulseIndicator" />
</RelativeLayout> </RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:paddingBottom="@dimen/member_item_top_and_bottom_padding"
android:paddingEnd="@dimen/screen_edge_left_and_right_padding"
android:paddingStart="@dimen/screen_edge_left_and_right_padding"
android:paddingTop="@dimen/member_item_top_and_bottom_padding">
<LinearLayout
android:id="@+id/image_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/image_file_thumbnail"
android:layout_width="80dp"
android:layout_height="70dp"
android:visibility="gone"
app:roundedCornerRadius="3dp" />
<ImageView
android:id="@+id/image_file_media_thumbnail"
android:layout_width="80dp"
android:layout_height="70dp"
android:visibility="gone" />
</LinearLayout>
<TextView
android:id="@+id/text_file_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@color/colorPrimaryText"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/image_container"
app:layout_constraintTop_toTopOf="@+id/image_container"
tools:text="File.mp3" />
<TextView
android:id="@+id/text_uploader"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@color/colorSecondaryText"
app:layout_constraintBottom_toTopOf="@+id/text_upload_date"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/image_container"
tools:text="\@filipe.brito" />
<TextView
android:id="@+id/text_upload_date"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:textColor="@color/colorSecondaryTextLight"
app:layout_constraintBottom_toBottomOf="@+id/image_container"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/image_container"
tools:text="Ma 22, 2018 6:42 PM" />
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
...@@ -30,13 +30,13 @@ ...@@ -30,13 +30,13 @@
android:layout_gravity="center" android:layout_gravity="center"
android:layout_marginEnd="4dp" android:layout_marginEnd="4dp"
android:layout_weight="1" android:layout_weight="1"
android:background="@color/red" /> android:background="@color/colorRed" />
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/msg_unread_messages" android:text="@string/msg_unread_messages"
android:textColor="@color/red" /> android:textColor="@color/colorRed" />
<View <View
android:layout_width="0dp" android:layout_width="0dp"
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
android:layout_gravity="center" android:layout_gravity="center"
android:layout_marginStart="4dp" android:layout_marginStart="4dp"
android:layout_weight="1" android:layout_weight="1"
android:background="@color/red" /> android:background="@color/colorRed" />
</LinearLayout> </LinearLayout>
<include <include
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
android:ellipsize="end" android:ellipsize="end"
android:maxLines="2" android:maxLines="2"
android:textColor="@color/white" android:textColor="@color/colorWhite"
android:textSize="14sp" android:textSize="14sp"
android:typeface="normal" android:typeface="normal"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
android:id="@+id/audio_video_attachment" android:id="@+id/audio_video_attachment"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="150dp" android:layout_height="150dp"
android:background="@color/black" android:background="@color/colorBlack"
android:visibility="gone" android:visibility="gone"
tools:visibility="visible"> tools:visibility="visible">
......
...@@ -21,10 +21,10 @@ ...@@ -21,10 +21,10 @@
android:id="@+id/text_room_is_read_only" android:id="@+id/text_room_is_read_only"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="45dp" android:layout_height="45dp"
android:background="@color/white" android:background="@color/colorWhite"
android:gravity="center" android:gravity="center"
android:text="@string/msg_this_room_is_read_only" android:text="@string/msg_this_room_is_read_only"
android:textColor="@color/black" android:textColor="@color/colorBlack"
android:visibility="gone" android:visibility="gone"
app:layout_constraintTop_toBottomOf="@+id/divider" /> app:layout_constraintTop_toBottomOf="@+id/divider" />
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
android:id="@+id/button_join_chat" android:id="@+id/button_join_chat"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="45dp" android:layout_height="45dp"
android:background="@color/white" android:background="@color/colorWhite"
android:text="@string/action_join_chat" android:text="@string/action_join_chat"
android:textColor="@color/colorAccent" android:textColor="@color/colorAccent"
android:visibility="gone" android:visibility="gone"
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
android:theme="@style/Theme.AppCompat" android:theme="@style/Theme.AppCompat"
android:tint="@color/gray_material" android:tint="@color/gray_material"
android:visibility="invisible" android:visibility="invisible"
app:backgroundTint="@color/white" app:backgroundTint="@color/colorWhite"
app:fabSize="mini" app:fabSize="mini"
app:layout_anchor="@id/recycler_view" app:layout_anchor="@id/recycler_view"
app:layout_anchorGravity="bottom|end" /> app:layout_anchorGravity="bottom|end" />
......
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="10dp" android:layout_marginEnd="10dp"
android:layout_marginStart="10dp" android:layout_marginStart="10dp"
android:textColor="@color/white" android:textColor="@color/colorWhite"
app:layout_constraintBottom_toBottomOf="@+id/image_user_status" app:layout_constraintBottom_toBottomOf="@+id/image_user_status"
app:layout_constraintEnd_toStartOf="@+id/image_account_expand" app:layout_constraintEnd_toStartOf="@+id/image_account_expand"
app:layout_constraintStart_toEndOf="@+id/image_user_status" app:layout_constraintStart_toEndOf="@+id/image_user_status"
...@@ -69,7 +69,7 @@ ...@@ -69,7 +69,7 @@
android:ellipsize="end" android:ellipsize="end"
android:maxLines="1" android:maxLines="1"
android:textAppearance="@style/TextAppearance.AppCompat.Small" android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textColor="@color/white" android:textColor="@color/colorWhite"
app:layout_constraintEnd_toStartOf="@+id/image_account_expand" app:layout_constraintEnd_toStartOf="@+id/image_account_expand"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_user_name" app:layout_constraintTop_toBottomOf="@+id/text_user_name"
...@@ -80,7 +80,7 @@ ...@@ -80,7 +80,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:src="@drawable/ic_expand_more_24dp" android:src="@drawable/ic_expand_more_24dp"
android:tint="@color/white" android:tint="@color/colorWhite"
app:layout_constraintBottom_toBottomOf="@+id/text_server_url" app:layout_constraintBottom_toBottomOf="@+id/text_server_url"
app:layout_constraintEnd_toEndOf="parent" /> app:layout_constraintEnd_toEndOf="parent" />
</android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout>
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
android:ellipsize="end" android:ellipsize="end"
android:maxLines="1" android:maxLines="1"
android:textColor="@color/black" android:textColor="@color/colorBlack"
android:textSize="14sp" android:textSize="14sp"
tools:text="/leave" /> tools:text="/leave" />
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="5dp" android:layout_marginStart="5dp"
android:maxLines="1" android:maxLines="1"
android:textColor="@color/black" android:textColor="@color/colorBlack"
android:textSize="16sp" android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/image_status" app:layout_constraintStart_toEndOf="@+id/image_status"
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:maxLines="1" android:maxLines="1"
android:textColor="@color/black" android:textColor="@color/colorBlack"
android:textSize="16sp" android:textSize="16sp"
tools:text="@tools:sample/full_names" /> tools:text="@tools:sample/full_names" />
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
android:layout_height="18dp" android:layout_height="18dp"
android:background="@drawable/style_total_unread_messages" android:background="@drawable/style_total_unread_messages"
android:gravity="center" android:gravity="center"
android:textColor="@color/white" android:textColor="@color/colorWhite"
android:textSize="10sp" android:textSize="10sp"
android:visibility="gone" android:visibility="gone"
tools:text="99+" tools:text="99+"
......
...@@ -16,4 +16,9 @@ ...@@ -16,4 +16,9 @@
android:id="@+id/action_favorite_messages" android:id="@+id/action_favorite_messages"
android:title="@string/title_favorite_messages" android:title="@string/title_favorite_messages"
app:showAsAction="never" /> app:showAsAction="never" />
<item
android:id="@+id/action_files"
android:title="@string/msg_files"
app:showAsAction="never" />
</menu> </menu>
\ No newline at end of file
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
<item <item
android:id="@+id/action_save_image" android:id="@+id/action_save_image"
android:title="Save to Gallery" android:icon="@drawable/ic_file_download_white_24dp"
app:showAsAction="never" /> android:title="@string/action_save_to_gallery"
app:showAsAction="always" />
</menu> </menu>
\ No newline at end of file
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
<string name="title_about">Acerca de</string> <string name="title_about">Acerca de</string>
<!-- Actions --> <!-- Actions -->
<string name="action_connect">Conectar</string>"' <string name="action_connect">Conectar</string>
<string name="action_use_this_username">Usa este nombre de usuario</string> <string name="action_use_this_username">Usa este nombre de usuario</string>
<string name="action_login_or_sign_up">Toca en este botón para iniciar sesión o crear una cuenta</string> <string name="action_login_or_sign_up">Toca en este botón para iniciar sesión o crear una cuenta</string>
<string name="action_terms_of_service">Términos de Servicio</string> <string name="action_terms_of_service">Términos de Servicio</string>
...@@ -34,6 +34,9 @@ ...@@ -34,6 +34,9 @@
<string name="action_away">Ausente</string> <string name="action_away">Ausente</string>
<string name="action_busy">Ocupado</string> <string name="action_busy">Ocupado</string>
<string name="action_invisible">Invisible</string> <string name="action_invisible">Invisible</string>
// TODO: Add proper translation.
<string name="action_save_to_gallery">Save to gallery</string>
<!-- Settings List --> <!-- Settings List -->
<string-array name="settings_actions"> <string-array name="settings_actions">
...@@ -161,7 +164,7 @@ ...@@ -161,7 +164,7 @@
<string name="permission_starring_not_allowed">Starring is not allowed</string> <string name="permission_starring_not_allowed">Starring is not allowed</string>
<!-- Members List --> <!-- Members List -->
<string name="title_members_list">Lista de miembros</string> <string name="title_members_list">Miembros</string>
<!-- Pinned Messages --> <!-- Pinned Messages -->
<string name="title_pinned_messages">Mensajes fijados</string> <string name="title_pinned_messages">Mensajes fijados</string>
...@@ -174,6 +177,13 @@ ...@@ -174,6 +177,13 @@
<string name="no_favorite_messages">No favorite messages</string> <string name="no_favorite_messages">No favorite messages</string>
<string name="no_favorite_description">All the favorite messages\nappear here</string> <string name="no_favorite_description">All the favorite messages\nappear here</string>
<!-- Files -->
<!-- TODO Add proper translation-->
<string name="msg_files">Files</string>
<string name="title_files_total">Files (%d)</string>
<string name="msg_no_files">No files</string>
<string name="msg_all_files_appear_here">All the files appear here</string>
<!-- Upload Messages --> <!-- Upload Messages -->
<string name="max_file_size_exceeded">Tamaño del archivo (%1$d bytes) excedió el tamaño máximo de carga de %2$d bytes</string> <string name="max_file_size_exceeded">Tamaño del archivo (%1$d bytes) excedió el tamaño máximo de carga de %2$d bytes</string>
......
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
<string name="action_away">Loin</string> <string name="action_away">Loin</string>
<string name="action_busy">Occupé</string> <string name="action_busy">Occupé</string>
<string name="action_invisible">Invisible</string> <string name="action_invisible">Invisible</string>
// TODO: Add proper translation.
<string name="action_save_to_gallery">Save to gallery</string>
<!-- Settings List --> <!-- Settings List -->
<string-array name="settings_actions"> <string-array name="settings_actions">
...@@ -162,7 +164,7 @@ ...@@ -162,7 +164,7 @@
<string name="permission_starring_not_allowed">Starring is not allowed</string> <string name="permission_starring_not_allowed">Starring is not allowed</string>
<!-- Members List --> <!-- Members List -->
<string name="title_members_list">Liste des membres</string> <string name="title_members_list">Membres</string>
<!-- Pinned Messages --> <!-- Pinned Messages -->
<string name="title_pinned_messages">Messages épinglés</string> <string name="title_pinned_messages">Messages épinglés</string>
...@@ -175,6 +177,13 @@ ...@@ -175,6 +177,13 @@
<string name="no_favorite_messages">No favorite messages</string> <string name="no_favorite_messages">No favorite messages</string>
<string name="no_favorite_description">All the favorite messages\nappear here</string> <string name="no_favorite_description">All the favorite messages\nappear here</string>
<!-- Files -->
<!-- TODO Add proper translation-->
<string name="msg_files">Files</string>
<string name="title_files_total">Files (%d)</string>
<string name="msg_no_files">No files</string>
<string name="msg_all_files_appear_here">All the files appear here</string>
<!-- Upload Messages --> <!-- Upload Messages -->
<string name="max_file_size_exceeded">Taille du fichier (%1$d bytes) dépassé la taille de téléchargement maximale de %2$d bytes</string> <string name="max_file_size_exceeded">Taille du fichier (%1$d bytes) dépassé la taille de téléchargement maximale de %2$d bytes</string>
......
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
<string name="action_away">दूर</string> <string name="action_away">दूर</string>
<string name="action_busy">व्यस्त</string> <string name="action_busy">व्यस्त</string>
<string name="action_invisible">अदृश्य</string> <string name="action_invisible">अदृश्य</string>
// TODO: Add proper translation.
<string name="action_save_to_gallery">Save to gallery</string>
<!-- Settings List --> <!-- Settings List -->
<string-array name="settings_actions"> <string-array name="settings_actions">
...@@ -163,7 +165,7 @@ ...@@ -163,7 +165,7 @@
<string name="permission_starring_not_allowed">Starring is not allowed</string> <string name="permission_starring_not_allowed">Starring is not allowed</string>
<!-- Members List --> <!-- Members List -->
<string name="title_members_list">सदस्यों की सूची</string> <string name="title_members_list">सदस्य</string>
<!-- Pinned Messages --> <!-- Pinned Messages -->
<string name="title_pinned_messages">पिन किए गए संदेश</string> <string name="title_pinned_messages">पिन किए गए संदेश</string>
...@@ -176,6 +178,13 @@ ...@@ -176,6 +178,13 @@
<string name="no_favorite_messages">No favorite messages</string> <string name="no_favorite_messages">No favorite messages</string>
<string name="no_favorite_description">All the favorite messages\nappear here</string> <string name="no_favorite_description">All the favorite messages\nappear here</string>
<!-- Files -->
<!-- TODO Add proper translation-->
<string name="msg_files">Files</string>
<string name="title_files_total">Files (%d)</string>
<string name="msg_no_files">No files</string>
<string name="msg_all_files_appear_here">All the files appear here</string>
<!-- Upload Messages --> <!-- Upload Messages -->
<string name="max_file_size_exceeded">फ़ाइल का आकार %1$d बाइट्स ने %2$d बाइट्स के अधिकतम अपलोड आकार को पार कर लिया है</string> <string name="max_file_size_exceeded">फ़ाइल का आकार %1$d बाइट्स ने %2$d बाइट्स के अधिकतम अपलोड आकार को पार कर लिया है</string>
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
<string name="action_away">Ausente</string> <string name="action_away">Ausente</string>
<string name="action_busy">Ocupado</string> <string name="action_busy">Ocupado</string>
<string name="action_invisible">Invisível</string> <string name="action_invisible">Invisível</string>
<string name="action_save_to_gallery">Salvar na galeria</string>
<!-- Settings List --> <!-- Settings List -->
<string-array name="settings_actions"> <string-array name="settings_actions">
...@@ -151,7 +152,7 @@ ...@@ -151,7 +152,7 @@
<string name="permission_starring_not_allowed">Favoritar não permitido</string> <string name="permission_starring_not_allowed">Favoritar não permitido</string>
<!-- Members List --> <!-- Members List -->
<string name="title_members_list">Lista de Membros</string> <string name="title_members_list">Membros</string>
<!-- Pinned Messages --> <!-- Pinned Messages -->
<string name="title_pinned_messages">Mensagens Pinadas</string> <string name="title_pinned_messages">Mensagens Pinadas</string>
...@@ -159,11 +160,16 @@ ...@@ -159,11 +160,16 @@
<string name="no_pinned_description">Todas as mensagens pinadas\naparecerão aqui</string> <string name="no_pinned_description">Todas as mensagens pinadas\naparecerão aqui</string>
<!-- Favorite Messages --> <!-- Favorite Messages -->
<!-- TODO Add proper translation-->
<string name="title_favorite_messages">Messagens Favoritas</string> <string name="title_favorite_messages">Messagens Favoritas</string>
<string name="no_favorite_messages">Nenhuma messagem favorita</string> <string name="no_favorite_messages">Nenhuma messagem favorita</string>
<string name="no_favorite_description">Todas as mensagens favoritas\naparecerão aqui</string> <string name="no_favorite_description">Todas as mensagens favoritas\naparecerão aqui</string>
<!-- Files -->
<string name="msg_files">Arquivos</string>
<string name="title_files_total">Arquivos (%d)</string>
<string name="msg_no_files">Nenhum arquivo</string>
<string name="msg_all_files_appear_here">Todos os arquivos aparecerão aqui</string>
<!-- Upload Messages --> <!-- Upload Messages -->
<string name="max_file_size_exceeded">Tamanho de arquivo (%1$d bytes) excedeu tamanho máximo de upload (%2$d bytes)</string> <string name="max_file_size_exceeded">Tamanho de arquivo (%1$d bytes) excedeu tamanho máximo de upload (%2$d bytes)</string>
......
...@@ -3,13 +3,13 @@ ...@@ -3,13 +3,13 @@
<!-- Main colors --> <!-- Main colors -->
<color name="colorPrimary">#FF303030</color> <!-- Material Grey 850 --> <color name="colorPrimary">#FF303030</color> <!-- Material Grey 850 -->
<color name="colorPrimaryDark">#ff212121</color> <!-- Material Grey 900 --> <color name="colorPrimaryDark">#FF212121</color> <!-- Material Grey 900 -->
<color name="colorAccent">#FF1976D2</color> <!-- Material Blue 700 --> <color name="colorAccent">#FF1976D2</color> <!-- Material Blue 700 -->
<!-- Text colors --> <!-- Text colors -->
<color name="colorPrimaryText">#DE000000</color> <color name="colorPrimaryText">#DE000000</color>
<color name="colorSecondaryText">#787878</color> <color name="colorSecondaryText">#FF787878</color>
<color name="colorSecondaryTextLight">#c1c1c1</color> <color name="colorSecondaryTextLight">#FFC1C1C1</color>
<!-- User status colors --> <!-- User status colors -->
<color name="colorUserStatusOnline">#2FE1A8</color> <color name="colorUserStatusOnline">#2FE1A8</color>
...@@ -17,7 +17,16 @@ ...@@ -17,7 +17,16 @@
<color name="colorUserStatusAway">#FDD236</color> <color name="colorUserStatusAway">#FDD236</color>
<color name="colorUserStatusOffline">#d9d9d9</color> <color name="colorUserStatusOffline">#d9d9d9</color>
<color name="ic_launcher_background">#FFFFFF</color> <!-- Normal colors -->
<color name="colorWhite">#FFFFFFFF</color>
<color name="colorBlack">#FF000000</color>
<color name="colorRed">#FFFF0000</color>
<color name="darkGray">#FFa0a0a0</color>
<color name="actionMenuColor">#FF727272</color>
<color name="whitesmoke">#FFf1f1f1</color>
<color name="ic_launcher_background">@color/colorWhite</color>
<color name="colorDrawableTintGrey">#9FA2A8</color> <color name="colorDrawableTintGrey">#9FA2A8</color>
...@@ -29,13 +38,6 @@ ...@@ -29,13 +38,6 @@
<color name="colorBackgroundMemberContainer">#4D000000</color> <color name="colorBackgroundMemberContainer">#4D000000</color>
<color name="white">#FFFFFFFF</color>
<color name="black">#FF000000</color>
<color name="red">#FFFF0000</color>
<color name="darkGray">#FFa0a0a0</color>
<color name="actionMenuColor">#FF727272</color>
<color name="whitesmoke">#FFf1f1f1</color>
<color name="translucent_white">#70F1F1F1</color> <color name="translucent_white">#70F1F1F1</color>
<color name="colorEmojiIcon">#FF767676</color> <color name="colorEmojiIcon">#FF767676</color>
...@@ -43,7 +45,7 @@ ...@@ -43,7 +45,7 @@
<color name="quoteBar">#A0A0A0</color> <color name="quoteBar">#A0A0A0</color>
<!-- Suggestions --> <!-- Suggestions -->
<color name="suggestion_background_color">@android:color/white</color> <color name="suggestion_background_color">@color/colorWhite</color>
<color name="icon_grey">#AFADAF</color> <color name="icon_grey">#AFADAF</color>
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
<string name="action_away">Away</string> <string name="action_away">Away</string>
<string name="action_busy">Busy</string> <string name="action_busy">Busy</string>
<string name="action_invisible">Invisible</string> <string name="action_invisible">Invisible</string>
<string name="action_save_to_gallery">Save to gallery</string>
<!-- Settings List --> <!-- Settings List -->
<string-array name="settings_actions"> <string-array name="settings_actions">
...@@ -150,7 +151,7 @@ ...@@ -150,7 +151,7 @@
<string name="permission_starring_not_allowed">Starring is not allowed</string> <string name="permission_starring_not_allowed">Starring is not allowed</string>
<!-- Members List --> <!-- Members List -->
<string name="title_members_list">Members List</string> <string name="title_members_list">Members</string>
<!-- Pinned Messages --> <!-- Pinned Messages -->
<string name="title_pinned_messages">Pinned Messages</string> <string name="title_pinned_messages">Pinned Messages</string>
...@@ -162,6 +163,12 @@ ...@@ -162,6 +163,12 @@
<string name="no_favorite_messages">No favorite messages</string> <string name="no_favorite_messages">No favorite messages</string>
<string name="no_favorite_description">All the favorite messages\nappear here</string> <string name="no_favorite_description">All the favorite messages\nappear here</string>
<!-- Files -->
<string name="msg_files">Files</string>
<string name="title_files_total">Files (%d)</string>
<string name="msg_no_files">No files</string>
<string name="msg_all_files_appear_here">All the files appear here</string>
<!-- Upload Messages --> <!-- Upload Messages -->
<string name="max_file_size_exceeded">File size %1$d bytes exceeded max upload size of %2$d bytes</string> <string name="max_file_size_exceeded">File size %1$d bytes exceeded max upload size of %2$d bytes</string>
......
...@@ -24,7 +24,7 @@ ext { ...@@ -24,7 +24,7 @@ ext {
timber : '4.7.0', timber : '4.7.0',
threeTenABP : '1.0.5', threeTenABP : '1.0.5',
rxBinding : '2.0.0', rxBinding : '2.0.0',
fresco : '1.8.1', fresco : '1.9.0',
kotshi : '1.0.2', kotshi : '1.0.2',
frescoImageViewer : '0.5.1', frescoImageViewer : '0.5.1',
markwon : '1.0.3', markwon : '1.0.3',
......
...@@ -5,7 +5,6 @@ import android.content.Intent ...@@ -5,7 +5,6 @@ import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.support.v7.app.AppCompatActivity import android.support.v7.app.AppCompatActivity
import android.util.Log
import android.view.View import android.view.View
import com.google.android.exoplayer2.DefaultLoadControl import com.google.android.exoplayer2.DefaultLoadControl
import com.google.android.exoplayer2.DefaultRenderersFactory import com.google.android.exoplayer2.DefaultRenderersFactory
...@@ -72,7 +71,6 @@ class PlayerActivity : AppCompatActivity() { ...@@ -72,7 +71,6 @@ class PlayerActivity : AppCompatActivity() {
} }
val uri = Uri.parse(videoUrl) val uri = Uri.parse(videoUrl)
val mediaSource = buildMediaSource(uri) val mediaSource = buildMediaSource(uri)
Log.d("PlayerActivity", "Player with: " + videoUrl)
player.prepare(mediaSource, true, false) player.prepare(mediaSource, true, false)
} }
...@@ -94,7 +92,7 @@ class PlayerActivity : AppCompatActivity() { ...@@ -94,7 +92,7 @@ class PlayerActivity : AppCompatActivity() {
} }
companion object { companion object {
const private val URL_KEY = "URL_KEY" private const val URL_KEY = "URL_KEY"
fun play(context: Context, url: String) { fun play(context: Context, url: String) {
context.startActivity(Intent(context, PlayerActivity::class.java).apply { context.startActivity(Intent(context, PlayerActivity::class.java).apply {
putExtra(URL_KEY, url) putExtra(URL_KEY, url)
......
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