Commit fe3ac9e8 authored by Rafael Kellermann Streit's avatar Rafael Kellermann Streit Committed by GitHub

Merge branch 'develop' into feature/message-actions

parents b125b252 12247fd5
......@@ -9,7 +9,6 @@ import kotlinx.android.synthetic.main.activity_room.*
class RoomActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_room)
......@@ -35,8 +34,7 @@ class RoomActivity : AppCompatActivity() {
}
private fun addFragment(fragment: Fragment, tag: String) {
supportFragmentManager
.beginTransaction()
supportFragmentManager.beginTransaction()
.add(R.id.fragment_container, fragment, tag)
.commit()
}
......
......@@ -96,6 +96,7 @@ object RestApiHelper {
val parsedHttpUrl = HttpUrl.parse(getEndpointUrlForFileList(roomType, hostname))
?.newBuilder()
?.addQueryParameter("roomId", roomId)
?.addQueryParameter("sort", "{\"uploadedAt\":-1}")
?.addQueryParameter("offset", offset)
?.build()
......
......@@ -316,9 +316,9 @@ public class RoomFragment extends AbstractChatRoomFragment implements
case R.id.action_favorite_messages:
showRoomListFragment(R.id.action_favorite_messages);
break;
// case R.id.action_file_list:
// showRoomListFragment(R.id.action_file_list);
// break;
case R.id.action_file_list:
showRoomListFragment(R.id.action_file_list);
break;
case R.id.action_member_list:
showRoomListFragment(R.id.action_member_list);
break;
......
package chat.rocket.android.fragment.chatroom.list
import chat.rocket.core.models.Attachment
import chat.rocket.core.models.Message
import chat.rocket.core.models.User
......@@ -32,7 +33,7 @@ interface RoomListContract {
* @param dataSet The file data set to show.
* @param total The total number of files.
*/
fun showFileList(dataSet: ArrayList<String>, total: String)
fun showFileList(dataSet: ArrayList<Attachment>, total: String)
/**
* Shows a list of members of a room.
......
......@@ -9,8 +9,10 @@ import android.view.View
import android.view.ViewGroup
import chat.rocket.android.R
import chat.rocket.android.helper.EndlessRecyclerViewScrollListener
import chat.rocket.android.layouthelper.chatroom.list.RoomFileListAdapter
import chat.rocket.android.layouthelper.chatroom.list.RoomMemberListAdapter
import chat.rocket.android.layouthelper.chatroom.list.RoomMessagesAdapter
import chat.rocket.core.models.Attachment
import chat.rocket.core.models.Message
import chat.rocket.core.models.User
import kotlinx.android.synthetic.main.fragment_room_list.*
......@@ -84,6 +86,14 @@ class RoomListFragment : Fragment(), RoomListContract.View {
userId,
offset)
}
R.id.action_file_list -> {
presenter.requestFileList(roomId,
roomType,
hostname,
token,
userId,
offset)
}
R.id.action_favorite_messages -> {
presenter.requestFavoriteMessages(roomId,
roomType,
......@@ -139,8 +149,23 @@ class RoomListFragment : Fragment(), RoomListContract.View {
}
}
// TODO (after REST api fixes)
override fun showFileList(dataSet: ArrayList<String>, total: String) {}
override fun showFileList(dataSet: ArrayList<Attachment>, total: String) {
activity.title = getString(R.string.fragment_room_list_file_list_title, total)
if (recyclerView.adapter == null) {
recyclerView.adapter = RoomFileListAdapter(dataSet)
val linearLayoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
recyclerView.layoutManager = linearLayoutManager
if (dataSet.size >= 50) {
recyclerView.addOnScrollListener(object : EndlessRecyclerViewScrollListener(linearLayoutManager) {
override fun onLoadMore(page: Int, totalItemsCount: Int, recyclerView: RecyclerView?) {
loadNextDataFromApi(page)
}
})
}
} else {
(recyclerView.adapter as RoomFileListAdapter).addDataSet(dataSet)
}
}
override fun showMemberList(dataSet: ArrayList<User>, total: String) {
activity.title = getString(R.string.fragment_room_list_member_list_title, total)
......
......@@ -2,11 +2,13 @@ package chat.rocket.android.fragment.chatroom.list
import android.content.Context
import android.os.Handler
import android.util.Log
import chat.rocket.android.R
import chat.rocket.android.api.rest.RestApiHelper
import chat.rocket.android.helper.OkHttpHelper
import chat.rocket.android.helper.UrlHelper
import chat.rocket.core.SyncState
import chat.rocket.core.models.Attachment
import chat.rocket.core.models.AttachmentTitle
import chat.rocket.core.models.Message
import chat.rocket.core.models.User
import okhttp3.Call
......@@ -98,13 +100,43 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) :
})
}
// TODO (after the REST api fixes)
override fun requestFileList(roomId: String,
roomType: String,
hostname: String,
token: String,
userId: String,
offset: Int) {}
offset: Int) {
view.showWaitingView(true)
OkHttpHelper.getClient()
.newCall(RestApiHelper.getRequestForFileList(roomId,
roomType,
hostname,
token,
userId,
offset.toString()))
.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
if (!call.isCanceled) {
val message = e.message
if (message != null) {
showErrorMessage(message)
}
}
}
@Throws(IOException::class)
override fun onResponse(call: Call, response: Response) {
if (response.isSuccessful) {
val result = response.body()?.string()
if (result != null) {
handleFilesJson(result, hostname)
}
} else {
showErrorMessage(response.message())
}
}
})
}
override fun requestMemberList(roomId: String,
roomType: String,
......@@ -159,27 +191,13 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) :
val messageJsonObject = messagesJSONArray.getJSONObject(it)
val userJsonObject = messageJsonObject.getJSONObject("u")
val timestampString = messageJsonObject.optString("ts")
val timestamp = if (timestampString.isBlank()) {
0
} else {
Timestamp.valueOf(timestampString.replace("T", " ").replace("Z", "")).time
}
val editedAtString = messageJsonObject.optString("_updatedAt")
val editedAt = if (editedAtString.isBlank()) {
0
} else {
Timestamp.valueOf(editedAtString.replace("T", " ").replace("Z", "")).time
}
Message.builder()
.setId(messageJsonObject.optString("_id"))
.setRoomId(messageJsonObject.optString("rid"))
.setMessage(messageJsonObject.optString("msg"))
.setUser(getUserFromJsonObject(userJsonObject))
.setTimestamp(timestamp)
.setEditedAt(editedAt)
.setTimestamp(getLongTimestamp(messageJsonObject.optString("ts")))
.setEditedAt(getLongTimestamp(messageJsonObject.optString("_updatedAt")))
.setGroupable(messageJsonObject.optBoolean("groupable"))
.setSyncState(SyncState.SYNCED)
.build()
......@@ -202,6 +220,52 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) :
}
}
private fun handleFilesJson(json: String, hostname: String) {
try {
val jsonObject = JSONObject(json)
val filesJsonArray = jsonObject.getJSONArray("files")
val total = filesJsonArray.length()
val dataSet = ArrayList<Attachment>(total)
(0 until total).mapTo(dataSet) {
val fileJsonObject = filesJsonArray.getJSONObject(it)
val fileLink = UrlHelper.getAttachmentLink(hostname, fileJsonObject.optString("_id"), fileJsonObject.optString("name"))
val attachmentTitle = AttachmentTitle.builder()
.setTitle(fileJsonObject.optString("name"))
.setLink(fileLink)
.setDownloadLink(fileLink)
.build()
val attachment = Attachment.builder()
val type = fileJsonObject.optString("type")
when {
type.startsWith("image") -> attachment.setImageUrl(fileLink)
type.startsWith("audio") -> attachment.setAudioUrl(fileLink)
type.startsWith("video") -> attachment.setVideoUrl(fileLink)
}
attachment.setCollapsed(false)
.setAttachmentTitle(attachmentTitle)
.setTimestamp(getSafeTimestamp(fileJsonObject.optString("uploadedAt")))
.build()
}
if (dataSet.isEmpty() && !hasItem) {
showEmptyViewMessage(context.getString(R.string.fragment_room_list_no_file_list_to_show))
} else {
if (dataSet.isNotEmpty()) {
hasItem = true
showFileList(dataSet, jsonObject.optString("total"))
}
}
} catch (exception: JSONException) {
showInvalidRequest()
}
}
private fun handleMembersJson(json: String) {
try {
val jsonObject = JSONObject(json)
......@@ -221,7 +285,7 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) :
showMemberList(dataSet, jsonObject.optString("total"))
}
}
}catch (exception: JSONException) {
} catch (exception: JSONException) {
showInvalidRequest()
}
}
......@@ -236,6 +300,17 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) :
.build()
}
private fun getLongTimestamp(timestamp: String): Long {
return if (timestamp.isNotBlank()) {
Timestamp.valueOf(getSafeTimestamp(timestamp)).time
} else {
0
}
}
private fun getSafeTimestamp(timestamp: String): String =
timestamp.replace("T", " ").replace("Z", "")
private fun showPinnedMessageList(dataSet: ArrayList<Message>, total: String) {
mainHandler.post {
view.showWaitingView(false)
......@@ -250,6 +325,13 @@ class RoomListPresenter(val context: Context, val view: RoomListContract.View) :
}
}
private fun showFileList(dataSet: ArrayList<Attachment>, total: String) {
mainHandler.post {
view.showWaitingView(false)
view.showFileList(dataSet, total)
}
}
private fun showMemberList(dataSet: ArrayList<User>, total: String) {
mainHandler.post {
view.showWaitingView(false)
......
......@@ -8,7 +8,8 @@ object UrlHelper {
* @param uri The URI.
* @return The URI whit no scheme (HTTP or HTTPS)
*/
fun removeUriScheme(uri: String) = uri.replace("http://", "").replace("https://", "")
fun removeUriScheme(uri: String) =
uri.replace("http://", "").replace("https://", "")
/**
* Returns the hostname with the security protocol (scheme) HTTPS.
......@@ -17,7 +18,7 @@ object UrlHelper {
* @return The hostname with the security protocol (scheme) HTTPS.
*/
fun getSafeHostname(hostname: String): String =
"https://" + hostname.replace("http://", "").replace("https://", "")
"https://" + removeUriScheme(hostname)
/**
* Returns an URL with no spaces and inverted slashes.
......@@ -25,17 +26,17 @@ object UrlHelper {
* @param url The URL.
* @return The URL with no spaces and inverted slashes.
*/
fun getUrl(url: String) =
fun getSafeUrl(url: String) =
url.replace(" ", "%20").replace("\\", "")
/**
* Returns an URL for a file.
* Returns an attachment link.
*
* @param path The path to the file.
* @param userId The user ID.
* @param token The token.
* @return The URL for a file
* @param hostname The hostname.
* @param fileId The file ID.
* @param fileName The file name.
* @return The attachment link.
*/
fun getUrlForFile(path: String, userId: String, token: String): String =
"https://" + removeUriScheme(getUrl(path)) + "?rc_uid=$userId" + "&rc_token=$token"
fun getAttachmentLink(hostname: String, fileId: String, fileName: String): String =
getSafeUrl(getSafeHostname(hostname) + "/file-upload/" + fileId + "/" + fileName)
}
\ No newline at end of file
......@@ -4,14 +4,19 @@ import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import chat.rocket.android.R
import chat.rocket.android.widget.message.RocketChatMessageLayout
import chat.rocket.android.helper.DateTime
import chat.rocket.android.widget.message.RocketChatMessageAttachmentsLayout
import chat.rocket.core.models.Attachment
import kotlinx.android.synthetic.main.day.view.*
import kotlinx.android.synthetic.main.item_room_file.view.*
import java.sql.Timestamp
/**
* Created by Filipe de Lima Brito (filipedelimabrito@gmail.com) on 9/22/17.
*/
class RoomFileListAdapter(private var dataSet: List<String>) : RecyclerView.Adapter<RoomFileListAdapter.ViewHolder>() {
class RoomFileListAdapter(private var dataSet: List<Attachment>) : RecyclerView.Adapter<RoomFileListAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_room_file, parent, false)
......@@ -19,17 +24,22 @@ class RoomFileListAdapter(private var dataSet: List<String>) : RecyclerView.Adap
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.fileNameLink.setText(dataSet[position])
val attachment = dataSet[position]
holder.newDay.text = DateTime.fromEpocMs(Timestamp.valueOf(attachment.timestamp).time, DateTime.Format.DATE)
holder.attachment.appendAttachmentView(attachment, true, false)
}
override fun getItemCount(): Int = dataSet.size
fun setDataSet(dataSet: List<String>) {
this.dataSet = dataSet
notifyDataSetChanged()
fun addDataSet(dataSet: List<Attachment>) {
val previousDataSetSize = this.dataSet.size
this.dataSet += dataSet
notifyItemRangeInserted(previousDataSetSize, dataSet.size)
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val fileNameLink : RocketChatMessageLayout = itemView.fileLink
val newDay: TextView = itemView.day
val attachment: RocketChatMessageAttachmentsLayout = itemView.attachment
}
}
\ No newline at end of file
......@@ -3,20 +3,20 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/margin_16">
android:paddingRight="@dimen/margin_16"
android:paddingStart="@dimen/margin_16"
android:paddingLeft="@dimen/margin_16"
android:paddingEnd="@dimen/margin_16"
android:paddingBottom="@dimen/margin_16">
<chat.rocket.android.widget.message.RocketChatMessageLayout
android:id="@+id/fileLink"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_16"
android:layout_marginStart="@dimen/margin_16" />
<include
android:id="@+id/dayLayout"
layout="@layout/day" />
<View
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1"
android:background="@color/colorDivider"
android:layout_marginTop="@dimen/margin_8"
app:layout_constraintTop_toBottomOf="@+id/fileLink" />
<chat.rocket.android.widget.message.RocketChatMessageAttachmentsLayout
android:id="@+id/attachment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_16"
app:layout_constraintTop_toBottomOf="@+id/dayLayout" />
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
......@@ -10,9 +10,9 @@
android:title="@string/menu_favorite_messages"
app:showAsAction="never" />
<!--<item android:id="@+id/action_file_list"-->
<!--android:title="@string/menu_file_list"-->
<!--app:showAsAction="never" />-->
<item android:id="@+id/action_file_list"
android:title="@string/menu_file_list"
app:showAsAction="never" />
<item android:id="@+id/action_member_list"
android:title="@string/menu_member_list"
......
......@@ -21,20 +21,17 @@ class UrlHelperTest {
@Test
fun getUrlTest() {
assertEquals("https://demo.rocket.chat/GENERAL/file.txt", UrlHelper.getUrl("https://demo.rocket.chat/GENERAL/file.txt"))
assertEquals("http://demo.rocket.chat/GENERAL/file.txt", UrlHelper.getUrl("http://demo.rocket.chat/GENERAL/file.txt"))
assertEquals("demo.rocket.chat/GENERAL/file.txt", UrlHelper.getUrl("demo.rocket.chat/GENERAL/file.txt"))
assertEquals("demo.rocket.chat/GENERAL/a%20sample%20file.txt", UrlHelper.getUrl("demo.rocket.chat/GENERAL/a sample file.txt"))
assertEquals("demo.rocket.chat/GENERAL/file.txt", UrlHelper.getUrl("demo.rocket.chat\\/GENERAL\\/file.txt"))
assertEquals("https://demo.rocket.chat/GENERAL/file.txt", UrlHelper.getSafeUrl("https://demo.rocket.chat/GENERAL/file.txt"))
assertEquals("http://demo.rocket.chat/GENERAL/file.txt", UrlHelper.getSafeUrl("http://demo.rocket.chat/GENERAL/file.txt"))
assertEquals("demo.rocket.chat/GENERAL/file.txt", UrlHelper.getSafeUrl("demo.rocket.chat/GENERAL/file.txt"))
assertEquals("demo.rocket.chat/GENERAL/a%20sample%20file.txt", UrlHelper.getSafeUrl("demo.rocket.chat/GENERAL/a sample file.txt"))
assertEquals("demo.rocket.chat/GENERAL/file.txt", UrlHelper.getSafeUrl("demo.rocket.chat\\/GENERAL\\/file.txt"))
}
@Test
fun getUrlForFileTest() {
assertEquals("https://demo.rocket.chat/GENERAL/file.txt?rc_uid=userId&rc_token=token", UrlHelper.getUrlForFile("https://demo.rocket.chat/GENERAL/file.txt","userId", "token"))
assertEquals("https://demo.rocket.chat/GENERAL/file.txt?rc_uid=userId&rc_token=token", UrlHelper.getUrlForFile("http://demo.rocket.chat/GENERAL/file.txt","userId", "token"))
assertEquals("https://demo.rocket.chat/GENERAL/file.txt?rc_uid=userId&rc_token=token", UrlHelper.getUrlForFile("demo.rocket.chat/GENERAL/file.txt","userId", "token"))
assertEquals("https://demo.rocket.chat/GENERAL/a%20sample%20file.txt?rc_uid=userId&rc_token=token", UrlHelper.getUrlForFile("demo.rocket.chat/GENERAL/a sample file.txt","userId", "token"))
assertEquals("https://demo.rocket.chat/GENERAL/file.txt?rc_uid=userId&rc_token=token", UrlHelper.getUrlForFile("demo.rocket.chat\\/GENERAL\\/file.txt","userId", "token"))
fun getAttachmentLinkTest() {
assertEquals("https://demo.rocket.chat/file-upload/aFileId/aFileName.txt", UrlHelper.getAttachmentLink("https://demo.rocket.chat", "aFileId", "aFileName.txt"))
assertEquals("https://demo.rocket.chat/file-upload/aFileId/aFileName.txt", UrlHelper.getAttachmentLink("http://demo.rocket.chat", "aFileId", "aFileName.txt"))
assertEquals("https://demo.rocket.chat/file-upload/aFileId/aFileName.txt", UrlHelper.getAttachmentLink("demo.rocket.chat", "aFileId", "aFileName.txt"))
}
}
\ No newline at end of file
......@@ -6,7 +6,9 @@ import android.support.graphics.drawable.VectorDrawableCompat
import chat.rocket.android.widget.R
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.drawee.drawable.ProgressBarDrawable
import com.facebook.drawee.drawable.ScalingUtils
import com.facebook.drawee.generic.GenericDraweeHierarchy
import com.facebook.drawee.generic.RoundingParams
import com.facebook.drawee.view.SimpleDraweeView
object FrescoHelper {
......@@ -31,6 +33,8 @@ object FrescoHelper {
val hierarchy: GenericDraweeHierarchy = draweeView.hierarchy
hierarchy.setPlaceholderImage(VectorDrawableCompat.create(draweeView.resources, R.drawable.image_dummy, null))
hierarchy.setFailureImage(VectorDrawableCompat.create(draweeView.resources, R.drawable.image_error, null))
hierarchy.roundingParams = RoundingParams().setCornersRadii(5F, 5F, 5F, 5F)
hierarchy.actualImageScaleType = ScalingUtils.ScaleType.FIT_CENTER
hierarchy.setProgressBarImage(ProgressBarDrawable())
val controller = Fresco.newDraweeControllerBuilder()
......
......@@ -71,21 +71,21 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout {
return;
}
this.attachments = attachments;
removeAllViews();
for (int i = 0, size = attachments.size(); i < size; i++) {
appendAttachmentView(attachments.get(i), autoloadImages);
appendAttachmentView(attachments.get(i), autoloadImages, true);
}
}
private void appendAttachmentView(Attachment attachment, boolean autoloadImages) {
public void appendAttachmentView(Attachment attachment, boolean autoloadImages, boolean showAttachmentStrip) {
if (attachment == null) {
return;
}
removeAllViews();
View attachmentView = inflater.inflate(R.layout.message_inline_attachment, this, false);
colorizeAttachmentBar(attachment, attachmentView);
colorizeAttachmentBar(attachment, attachmentView, showAttachmentStrip);
showAuthorAttachment(attachment, attachmentView);
showTitleAttachment(attachment, attachmentView);
showReferenceAttachment(attachment, attachmentView);
......@@ -97,19 +97,23 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout {
addView(attachmentView);
}
private void colorizeAttachmentBar(Attachment attachment, View attachmentView) {
private void colorizeAttachmentBar(Attachment attachment, View attachmentView, boolean showAttachmentStrip) {
final View attachmentStrip = attachmentView.findViewById(R.id.attachment_strip);
final String colorString = attachment.getColor();
if (TextUtils.isEmpty(colorString)) {
attachmentStrip.setBackgroundResource(R.color.inline_attachment_quote_line);
return;
}
if (showAttachmentStrip) {
final String colorString = attachment.getColor();
if (TextUtils.isEmpty(colorString)) {
attachmentStrip.setBackgroundResource(R.color.inline_attachment_quote_line);
return;
}
try {
attachmentStrip.setBackgroundColor(Color.parseColor(colorString));
} catch (Exception e) {
attachmentStrip.setBackgroundResource(R.color.inline_attachment_quote_line);
try {
attachmentStrip.setBackgroundColor(Color.parseColor(colorString));
} catch (Exception e) {
attachmentStrip.setBackgroundResource(R.color.inline_attachment_quote_line);
}
} else {
attachmentStrip.setVisibility(GONE);
}
}
......@@ -204,8 +208,7 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout {
}
}
private void showImageAttachment(Attachment attachment, View attachmentView,
boolean autoloadImages) {
private void showImageAttachment(Attachment attachment, View attachmentView, boolean autoloadImages) {
final View imageContainer = attachmentView.findViewById(R.id.image_container);
if (attachment.getImageUrl() == null) {
imageContainer.setVisibility(GONE);
......
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke
android:color="@color/inline_attachment_box_outline"
android:width="1dp"/>
<solid android:color="@color/inline_attachment_box_background"/>
<corners android:radius="2dp"/>
android:width="1dp"
android:color="@color/inline_attachment_box_outline" />
<solid
android:color="@color/inline_attachment_box_background" />
<corners
android:radius="2dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:fresco="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="4dp"
android:paddingBottom="4dp">
xmlns:fresco="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:orientation="horizontal"
android:paddingBottom="4dp"
android:paddingTop="4dp">
<View
android:id="@+id/attachment_strip"
android:layout_width="3dp"
android:layout_height="match_parent"
android:layout_marginRight="5dp"
android:background="@color/inline_attachment_quote_line" />
android:id="@+id/attachment_strip"
android:layout_width="3dp"
android:layout_height="match_parent"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:background="@color/inline_attachment_quote_line" />
<LinearLayout
android:id="@+id/attachment_content"
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
android:id="@+id/attachment_content"
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<LinearLayout
android:id="@+id/author_box"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:layout_marginBottom="8dp">
android:id="@+id/author_box"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/author_icon"
android:layout_width="16dp"
android:layout_height="16dp"
tools:src="@drawable/circle_black"
fresco:actualImageScaleType="fitCenter" />
android:id="@+id/author_icon"
android:layout_width="16dp"
android:layout_height="16dp"
fresco:actualImageScaleType="fitCenter"
tools:src="@drawable/circle_black" />
<android.support.v4.widget.Space
android:layout_width="8dp"
android:layout_height="8dp" />
android:layout_width="8dp"
android:layout_height="8dp" />
<TextView
android:id="@+id/author_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.RocketChat.MessageAttachment.Title.Link"
tools:text="Bradley Hilton" />
android:id="@+id/author_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.RocketChat.MessageAttachment.Title.Link"
tools:text="Bradley Hilton" />
<android.support.v4.widget.Space
android:layout_width="8dp"
android:layout_height="8dp" />
android:layout_width="8dp"
android:layout_height="8dp" />
<TextView
android:id="@+id/timestamp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="14:53" />
android:id="@+id/timestamp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="14:53" />
</LinearLayout>
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:textAppearance="@style/TextAppearance.RocketChat.MessageAttachment.Title"
android:background="?attr/selectableItemBackground"
tools:text="Attachment Example" />
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="?attr/selectableItemBackground"
android:textAppearance="@style/TextAppearance.RocketChat.MessageAttachment.Title"
tools:text="Attachment Example" />
<LinearLayout
android:id="@+id/ref_box"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:layout_marginBottom="8dp">
android:id="@+id/ref_box"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/thumb"
android:layout_width="32dp"
android:layout_height="32dp"
tools:src="@drawable/circle_black"
fresco:actualImageScaleType="fitCenter" />
android:id="@+id/thumb"
android:layout_width="32dp"
android:layout_height="32dp"
fresco:actualImageScaleType="fitCenter"
tools:src="@drawable/circle_black" />
<android.support.v4.widget.Space
android:layout_width="8dp"
android:layout_height="8dp" />
android:layout_width="8dp"
android:layout_height="8dp" />
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Bradley Hilton" />
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Bradley Hilton" />
</LinearLayout>
<FrameLayout
android:id="@+id/image_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:id="@+id/image_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="8dp"
android:padding="5dp"
android:background="@drawable/inline_attachment_background">
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="150dp"
android:layout_marginBottom="8dp"
fresco:actualImageScaleType="fitStart" />
android:id="@+id/image"
android:layout_width="200dp"
android:layout_height="200dp"/>
<TextView
android:id="@+id/image_load"
android:layout_width="match_parent"
android:layout_height="150dp"
android:gravity="center_horizontal|bottom"
android:paddingBottom="16dp"
android:text="@string/click_to_load" />
android:id="@+id/image_load"
android:layout_width="200dp"
android:layout_height="200dp"
android:gravity="center_horizontal|bottom"
android:paddingBottom="16dp"
android:text="@string/click_to_load" />
</FrameLayout>
<!-- audio -->
<!-- video -->
</LinearLayout>
</LinearLayout>
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