Commit 6c14cdd1 authored by Tiago Cunha's avatar Tiago Cunha

Better handling of attachments

parent d13702d9
...@@ -30,10 +30,16 @@ public class Avatar { ...@@ -30,10 +30,16 @@ public class Avatar {
}; };
private final String hostname; private final String hostname;
private final String username; private final String username;
private final String avatar;
public Avatar(String hostname, String username) { public Avatar(String hostname, String username) {
this(hostname, username, null);
}
public Avatar(String hostname, String username, String avatar) {
this.hostname = hostname; this.hostname = hostname;
this.username = username; this.username = username;
this.avatar = avatar;
} }
private static int getColorForUser(String username) { private static int getColorForUser(String username) {
...@@ -76,12 +82,16 @@ public class Avatar { ...@@ -76,12 +82,16 @@ public class Avatar {
private String getImageUrl() { private String getImageUrl() {
//from Rocket.Chat:packages/rocketchat-ui/lib/avatar.coffee //from Rocket.Chat:packages/rocketchat-ui/lib/avatar.coffee
//REMARK! this is often SVG image! (see: Rocket.Chat:server/startup/avatar.coffee) //REMARK! this is often SVG image! (see: Rocket.Chat:server/startup/avatar.coffee)
if (TextUtils.isEmpty(avatar)) {
try { try {
return "https://" + hostname + "/avatar/" + URLEncoder.encode(username, "UTF-8") + ".jpg"; return "https://" + hostname + "/avatar/" + URLEncoder.encode(username, "UTF-8") + ".jpg";
} catch (UnsupportedEncodingException exception) { } catch (UnsupportedEncodingException exception) {
RCLog.e(exception, "failed to get URL for user: %s", username); RCLog.e(exception, "failed to get URL for user: %s", username);
return null; return null;
} }
} else {
return avatar;
}
} }
/** /**
...@@ -100,6 +110,10 @@ public class Avatar { ...@@ -100,6 +110,10 @@ public class Avatar {
} }
private Drawable getTextDrawable(Context context) { private Drawable getTextDrawable(Context context) {
if (username == null) {
return null;
}
int round = (int) (4 * context.getResources().getDisplayMetrics().density); int round = (int) (4 * context.getResources().getDisplayMetrics().density);
return TextDrawable.builder() return TextDrawable.builder()
...@@ -114,16 +128,16 @@ public class Avatar { ...@@ -114,16 +128,16 @@ public class Avatar {
// Picasso can be triggered only on Main Thread. // Picasso can be triggered only on Main Thread.
if (Looper.myLooper() != Looper.getMainLooper()) { if (Looper.myLooper() != Looper.getMainLooper()) {
new Handler(Looper.getMainLooper()).post(() -> { new Handler(Looper.getMainLooper()).post(() ->
getBitmap(context, size).continueWith(_task -> { getBitmap(context, size)
.continueWith(_task -> {
if (_task.isFaulted()) { if (_task.isFaulted()) {
task.setError(_task.getError()); task.setError(_task.getError());
} else { } else {
task.setResult(_task.getResult()); task.setResult(_task.getResult());
} }
return null; return null;
}); }));
});
return task.getTask(); return task.getTask();
} }
......
...@@ -38,6 +38,8 @@ public class Message extends RealmObject { ...@@ -38,6 +38,8 @@ public class Message extends RealmObject {
private String msg; private String msg;
private User u; private User u;
private boolean groupable; private boolean groupable;
private String alias;
private String avatar;
private String attachments; //JSONArray. private String attachments; //JSONArray.
private String urls; //JSONArray. private String urls; //JSONArray.
...@@ -133,6 +135,22 @@ public class Message extends RealmObject { ...@@ -133,6 +135,22 @@ public class Message extends RealmObject {
this.urls = urls; this.urls = urls;
} }
public String getAlias() {
return alias;
}
public void setAlias(String alias) {
this.alias = alias;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
@Override @Override
public String toString() { public String toString() {
return "Message{" + return "Message{" +
...@@ -144,6 +162,8 @@ public class Message extends RealmObject { ...@@ -144,6 +162,8 @@ public class Message extends RealmObject {
", msg='" + msg + '\'' + ", msg='" + msg + '\'' +
", u=" + u + ", u=" + u +
", groupable=" + groupable + ", groupable=" + groupable +
", alias='" + alias + '\'' +
", avatar='" + avatar + '\'' +
", attachments='" + attachments + '\'' + ", attachments='" + attachments + '\'' +
", urls='" + urls + '\'' + ", urls='" + urls + '\'' +
'}'; '}';
...@@ -184,6 +204,12 @@ public class Message extends RealmObject { ...@@ -184,6 +204,12 @@ public class Message extends RealmObject {
if (u != null ? !u.equals(message.u) : message.u != null) { if (u != null ? !u.equals(message.u) : message.u != null) {
return false; return false;
} }
if (alias != null ? !alias.equals(message.alias) : message.alias != null) {
return false;
}
if (avatar != null ? !avatar.equals(message.avatar) : message.avatar != null) {
return false;
}
if (attachments != null ? !attachments.equals(message.attachments) if (attachments != null ? !attachments.equals(message.attachments)
: message.attachments != null) { : message.attachments != null) {
return false; return false;
...@@ -202,6 +228,8 @@ public class Message extends RealmObject { ...@@ -202,6 +228,8 @@ public class Message extends RealmObject {
result = 31 * result + (msg != null ? msg.hashCode() : 0); result = 31 * result + (msg != null ? msg.hashCode() : 0);
result = 31 * result + (u != null ? u.hashCode() : 0); result = 31 * result + (u != null ? u.hashCode() : 0);
result = 31 * result + (groupable ? 1 : 0); result = 31 * result + (groupable ? 1 : 0);
result = 31 * result + (alias != null ? alias.hashCode() : 0);
result = 31 * result + (avatar != null ? avatar.hashCode() : 0);
result = 31 * result + (attachments != null ? attachments.hashCode() : 0); result = 31 * result + (attachments != null ? attachments.hashCode() : 0);
result = 31 * result + (urls != null ? urls.hashCode() : 0); result = 31 * result + (urls != null ? urls.hashCode() : 0);
return result; return result;
......
...@@ -35,7 +35,7 @@ public class MessageRenderer extends AbstractRenderer<Message> { ...@@ -35,7 +35,7 @@ public class MessageRenderer extends AbstractRenderer<Message> {
imageView.setImageResource(R.drawable.ic_error_outline_black_24dp); imageView.setImageResource(R.drawable.ic_error_outline_black_24dp);
break; break;
default: default:
userRenderer.avatarInto(imageView, hostname); userRenderer.avatarInto(imageView, hostname, object.getAvatar());
break; break;
} }
return this; return this;
...@@ -45,7 +45,7 @@ public class MessageRenderer extends AbstractRenderer<Message> { ...@@ -45,7 +45,7 @@ public class MessageRenderer extends AbstractRenderer<Message> {
* show Username in textView. * show Username in textView.
*/ */
public MessageRenderer usernameInto(TextView textView) { public MessageRenderer usernameInto(TextView textView) {
userRenderer.usernameInto(textView); userRenderer.usernameInto(textView, object.getAlias());
return this; return this;
} }
......
package chat.rocket.android.renderer; package chat.rocket.android.renderer;
import android.content.Context; import android.content.Context;
import android.graphics.Color;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.ForegroundColorSpan;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
...@@ -22,12 +26,19 @@ public class UserRenderer extends AbstractRenderer<User> { ...@@ -22,12 +26,19 @@ public class UserRenderer extends AbstractRenderer<User> {
* show Avatar image. * show Avatar image.
*/ */
public UserRenderer avatarInto(ImageView imageView, String hostname) { public UserRenderer avatarInto(ImageView imageView, String hostname) {
return avatarInto(imageView, hostname, null);
}
/**
* show Avatar image - overriding the user default.
*/
public UserRenderer avatarInto(ImageView imageView, String hostname, String avatar) {
if (!shouldHandle(imageView)) { if (!shouldHandle(imageView)) {
return this; return this;
} }
if (!TextUtils.isEmpty(object.getUsername())) { if (!TextUtils.isEmpty(object.getUsername()) || !TextUtils.isEmpty(avatar)) {
new Avatar(hostname, object.getUsername()).into(imageView); new Avatar(hostname, object.getUsername(), avatar).into(imageView);
} }
return this; return this;
} }
...@@ -36,11 +47,34 @@ public class UserRenderer extends AbstractRenderer<User> { ...@@ -36,11 +47,34 @@ public class UserRenderer extends AbstractRenderer<User> {
* show Username in textView. * show Username in textView.
*/ */
public UserRenderer usernameInto(TextView textView) { public UserRenderer usernameInto(TextView textView) {
return usernameInto(textView, null);
}
/**
* show Username in textView - adding the alias first.
*/
public UserRenderer usernameInto(TextView textView, String alias) {
if (!shouldHandle(textView)) { if (!shouldHandle(textView)) {
return this; return this;
} }
textView.setText(object.getUsername()); final SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
final ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.BLACK);
if (TextUtils.isEmpty(alias)) {
spannableStringBuilder.append(object.getUsername());
spannableStringBuilder.setSpan(foregroundColorSpan, 0, object.getUsername().length(),
Spannable.SPAN_INCLUSIVE_INCLUSIVE);
} else {
spannableStringBuilder.append(alias);
spannableStringBuilder.append(" @");
spannableStringBuilder.append(object.getUsername());
spannableStringBuilder
.setSpan(foregroundColorSpan, 0, alias.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
}
textView.setText(spannableStringBuilder);
return this; return this;
} }
......
package chat.rocket.android.widget.message;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.emojione.Emojione;
import chat.rocket.android.widget.R;
import chat.rocket.android.widget.helper.InlineHightlighter;
import chat.rocket.android.widget.helper.Linkify;
import chat.rocket.android.widget.helper.MarkDown;
public class MessageAttachmentFieldLayout extends LinearLayout {
private TextView titleView;
private TextView valueView;
public MessageAttachmentFieldLayout(Context context) {
super(context);
initialize(context, null);
}
public MessageAttachmentFieldLayout(Context context, AttributeSet attrs) {
super(context, attrs);
initialize(context, attrs);
}
public MessageAttachmentFieldLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialize(context, attrs);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public MessageAttachmentFieldLayout(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initialize(context, attrs);
}
private void initialize(Context context, AttributeSet attrs) {
setOrientation(VERTICAL);
LayoutInflater.from(context)
.inflate(R.layout.message_inline_attachment_field, this, true);
titleView = (TextView) findViewById(R.id.field_title);
valueView = (TextView) findViewById(R.id.field_value);
}
public void setTitle(String title) {
titleView.setText(title);
}
public void setValue(String value) {
valueView.setText(Emojione.shortnameToUnicode(value, false));
MarkDown.apply(valueView);
Linkify.markup(valueView);
InlineHightlighter.highlight(valueView);
}
}
...@@ -3,13 +3,16 @@ package chat.rocket.android.widget.message; ...@@ -3,13 +3,16 @@ package chat.rocket.android.widget.message;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.Color;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.support.graphics.drawable.VectorDrawableCompat; import android.support.graphics.drawable.VectorDrawableCompat;
import android.support.v4.widget.TextViewCompat;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
...@@ -21,7 +24,6 @@ import org.json.JSONObject; ...@@ -21,7 +24,6 @@ import org.json.JSONObject;
import java.io.IOException; import java.io.IOException;
import chat.rocket.android.widget.R; import chat.rocket.android.widget.R;
import chat.rocket.android.widget.helper.ImageFormat;
import okhttp3.Interceptor; import okhttp3.Interceptor;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
import okhttp3.Request; import okhttp3.Request;
...@@ -81,11 +83,16 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout { ...@@ -81,11 +83,16 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout {
public Response intercept(Chain chain) throws IOException { public Response intercept(Chain chain) throws IOException {
// uid/token is required to download attachment files. // uid/token is required to download attachment files.
// see: RocketChat:lib/fileUpload.coffee // see: RocketChat:lib/fileUpload.coffee
if (chain.request().url().host().equals(hostname)) {
Request newRequest = chain.request().newBuilder() Request newRequest = chain.request().newBuilder()
.header("Cookie", "rc_uid=" + userId + ";rc_token=" + token) .header("Cookie", "rc_uid=" + userId + ";rc_token=" + token)
.build(); .build();
return chain.proceed(newRequest); return chain.proceed(newRequest);
} }
return chain.proceed(chain.request());
}
}; };
OkHttpClient okHttpClient = new OkHttpClient.Builder() OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(interceptor) .addInterceptor(interceptor)
...@@ -114,33 +121,79 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout { ...@@ -114,33 +121,79 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout {
} }
private void appendAttachmentView(JSONObject attachmentObj) throws JSONException { private void appendAttachmentView(JSONObject attachmentObj) throws JSONException {
if (attachmentObj.isNull("image_url")) { if (attachmentObj == null) {
return; return;
} }
String imageURL = attachmentObj.getString("image_url"); View attachmentView = inflater.inflate(R.layout.message_inline_attachment, this, false);
String imageType = attachmentObj.getString("image_type");
colorizeAttachmentBar(attachmentObj, attachmentView);
showAuthorAttachment(attachmentObj, attachmentView);
showTitleAttachment(attachmentObj, attachmentView);
showReferenceAttachment(attachmentObj, attachmentView);
showImageAttachment(attachmentObj, attachmentView);
// audio
// video
showFieldsAttachment(attachmentObj, attachmentView);
addView(attachmentView);
}
private void colorizeAttachmentBar(JSONObject attachmentObj, View attachmentView)
throws JSONException {
final View attachmentStrip = attachmentView.findViewById(R.id.attachment_strip);
if (TextUtils.isEmpty(imageURL) final String colorString = attachmentObj.optString("color");
|| !imageType.startsWith("image/") if (TextUtils.isEmpty(colorString)) {
|| !ImageFormat.SUPPORTED_LIST.contains(imageType)) { attachmentStrip.setBackgroundResource(R.color.inline_attachment_quote_line);
return; return;
} }
View attachmentView = inflater.inflate(R.layout.message_inline_attachment, this, false); try {
attachmentStrip.setBackgroundColor(Color.parseColor(colorString));
} catch (Exception e) {
attachmentStrip.setBackgroundResource(R.color.inline_attachment_quote_line);
}
}
new Picasso.Builder(getContext()) private void showAuthorAttachment(JSONObject attachmentObj, View attachmentView)
.downloader(getDownloader()) throws JSONException {
.build() final View authorBox = attachmentView.findViewById(R.id.author_box);
.load(absolutize(imageURL)) if (attachmentObj.isNull("author_name") || attachmentObj.isNull("author_link")
.placeholder(VectorDrawableCompat.create(getResources(), R.drawable.image_dummy, null)) || attachmentObj.isNull("author_icon")) {
.error(VectorDrawableCompat.create(getResources(), R.drawable.image_error, null)) authorBox.setVisibility(GONE);
.into((ImageView) attachmentView.findViewById(R.id.image)); return;
}
authorBox.setVisibility(VISIBLE);
loadImage(attachmentObj.getString("author_icon"),
(ImageView) attachmentView.findViewById(R.id.author_icon));
final TextView authorName = (TextView) attachmentView.findViewById(R.id.author_name);
authorName.setText(attachmentObj.getString("author_name"));
final String link = absolutize(attachmentObj.getString("author_link"));
authorName.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(link));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
view.getContext().startActivity(intent);
}
});
// timestamp and link - need to format time
}
private void showTitleAttachment(JSONObject attachmentObj, View attachmentView)
throws JSONException {
TextView titleView = (TextView) attachmentView.findViewById(R.id.title); TextView titleView = (TextView) attachmentView.findViewById(R.id.title);
if (attachmentObj.isNull("title")) { if (attachmentObj.isNull("title")) {
titleView.setVisibility(View.GONE); titleView.setVisibility(View.GONE);
} else { return;
}
titleView.setVisibility(View.VISIBLE); titleView.setVisibility(View.VISIBLE);
titleView.setText(attachmentObj.getString("title")); titleView.setText(attachmentObj.getString("title"));
...@@ -157,13 +210,89 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout { ...@@ -157,13 +210,89 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout {
view.getContext().startActivity(intent); view.getContext().startActivity(intent);
} }
}); });
TextViewCompat.setTextAppearance(titleView,
R.style.TextAppearance_RocketChat_MessageAttachment_Title_Link);
} }
} }
addView(attachmentView); private void showReferenceAttachment(JSONObject attachmentObj, View attachmentView)
throws JSONException {
final View refBox = attachmentView.findViewById(R.id.ref_box);
if (attachmentObj.isNull("thumb_url") && attachmentObj.isNull("text")) {
refBox.setVisibility(GONE);
return;
}
refBox.setVisibility(VISIBLE);
final ImageView thumbImage = (ImageView) refBox.findViewById(R.id.thumb);
final String thumbUrl = attachmentObj.optString("thumb_url");
if (TextUtils.isEmpty(thumbUrl)) {
thumbImage.setVisibility(GONE);
} else {
thumbImage.setVisibility(VISIBLE);
loadImage(thumbUrl, thumbImage);
}
final TextView refText = (TextView) refBox.findViewById(R.id.text);
final String refString = attachmentObj.optString("text");
if (TextUtils.isEmpty(refString)) {
refText.setVisibility(GONE);
} else {
refText.setVisibility(VISIBLE);
refText.setText(refString);
}
}
private void showImageAttachment(JSONObject attachmentObj, View attachmentView)
throws JSONException {
final ImageView attachedImage = (ImageView) attachmentView.findViewById(R.id.image);
if (attachmentObj.isNull("image_url")) {
attachedImage.setVisibility(GONE);
return;
}
attachedImage.setVisibility(VISIBLE);
loadImage(attachmentObj.getString("image_url"), attachedImage);
}
private void showFieldsAttachment(JSONObject attachmentObj, View attachmentView)
throws JSONException {
if (attachmentObj.isNull("fields")) {
return;
}
final ViewGroup attachmentContent =
(ViewGroup) attachmentView.findViewById(R.id.attachment_content);
final JSONArray fields = attachmentObj.getJSONArray("fields");
for (int i = 0, size = fields.length(); i < size; i++) {
final JSONObject fieldObject = fields.getJSONObject(i);
if (fieldObject.isNull("title") || fieldObject.isNull("value")) {
return;
}
MessageAttachmentFieldLayout fieldLayout = new MessageAttachmentFieldLayout(getContext());
fieldLayout.setTitle(fieldObject.getString("title"));
fieldLayout.setValue(fieldObject.getString("value"));
attachmentContent.addView(fieldLayout);
}
} }
private String absolutize(String url) { private String absolutize(String url) {
return url.startsWith("/") ? "https://" + hostname + url : url; return url.startsWith("/") ? "https://" + hostname + url : url;
} }
private void loadImage(String url, ImageView imageView) {
new Picasso.Builder(getContext())
.downloader(getDownloader())
.build()
.load(absolutize(url))
.placeholder(VectorDrawableCompat.create(getResources(), R.drawable.image_dummy, null))
.error(VectorDrawableCompat.create(getResources(), R.drawable.image_error, null))
.into(imageView);
}
} }
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="horizontal"
android:layout_margin="4dp" android:paddingTop="4dp"
android:padding="4dp"> android:paddingBottom="4dp">
<View <View
android:id="@+id/attachment_strip"
android:layout_width="3dp" android:layout_width="3dp"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginRight="5dp" android:layout_marginRight="5dp"
android:background="@color/inline_attachment_quote_line" /> android:background="@color/inline_attachment_quote_line" />
<LinearLayout <LinearLayout
android:id="@+id/attachment_content"
android:layout_width="0px" android:layout_width="0px"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:orientation="vertical"> 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">
<ImageView
android:id="@+id/author_icon"
android:layout_width="16dp"
android:layout_height="16dp"
tools:src="@drawable/circle_black" />
<android.support.v4.widget.Space
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.support.v4.widget.Space
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" />
</LinearLayout>
<TextView <TextView
android:id="@+id/title" android:id="@+id/title"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="2dp" android:layout_marginBottom="8dp"
android:layout_marginBottom="2dp"
android:textAppearance="@style/TextAppearance.RocketChat.MessageAttachment.Title" android:textAppearance="@style/TextAppearance.RocketChat.MessageAttachment.Title"
android:background="?attr/selectableItemBackground" /> android:background="?attr/selectableItemBackground"
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">
<ImageView
android:id="@+id/thumb"
android:layout_width="32dp"
android:layout_height="32dp"
tools:src="@drawable/circle_black" />
<android.support.v4.widget.Space
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" />
</LinearLayout>
<ImageView <ImageView
android:id="@+id/image" android:id="@+id/image"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:maxHeight="200dp" android:maxHeight="200dp"
android:layout_marginTop="4dp" android:layout_marginBottom="8dp"
android:layout_marginRight="8dp"
android:adjustViewBounds="true" android:adjustViewBounds="true"
android:scaleType="fitStart" /> android:scaleType="fitStart" />
<!-- audio -->
<!-- video -->
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/field_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textStyle="bold"
android:textColor="@android:color/black"
tools:text="Test" />
<TextView
android:id="@+id/field_value"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="Test" />
</LinearLayout>
\ No newline at end of file
...@@ -17,6 +17,9 @@ ...@@ -17,6 +17,9 @@
<style name="TextAppearance.RocketChat.MessageAttachment.Title" parent="TextAppearance.AppCompat.Title"> <style name="TextAppearance.RocketChat.MessageAttachment.Title" parent="TextAppearance.AppCompat.Title">
<item name="android:textSize">14sp</item> <item name="android:textSize">14sp</item>
</style>
<style name="TextAppearance.RocketChat.MessageAttachment.Title.Link" parent="TextAppearance.RocketChat.MessageAttachment.Title">
<item name="android:textColor">?android:attr/textColorLink</item> <item name="android:textColor">?android:attr/textColorLink</item>
</style> </style>
......
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