Commit 52407887 authored by Leonardo Aramaki's avatar Leonardo Aramaki

Merge branch 'develop' into fix/filtering_get_messages_flood

parents 260cb6c0 8ac51b53
......@@ -31,6 +31,7 @@ buildscript {
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig {
applicationId "chat.rocket.android"
minSdkVersion 16
......@@ -38,10 +39,10 @@ android {
versionCode 28
versionName "1.0.16"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
multiDexEnabled true
}
signingConfigs {
release {
storeFile project.rootProject.file('Rocket.jks').getCanonicalFile()
......@@ -50,6 +51,7 @@ android {
keyPassword System.getenv("KEY_PASSWORD")
}
}
buildTypes {
release {
minifyEnabled false
......@@ -57,27 +59,31 @@ android {
signingConfig signingConfigs.release
}
}
packagingOptions {
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/rxjava.properties'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
lintOptions {
//avoiding okio error: https://github.com/square/okhttp/issues/896
lintConfig file("lint.xml")
}
}
play {
jsonFile = file('rocket-chat.json')
track = "${track}"
}
ext {
playLibVersion = '10.2.6'
playLibVersion = '11.0.4'
stethoVersion = '1.4.2'
rxbindingVersion = '2.0.0'
rxlifecycleVersion = '2.1.0'
......
package chat.rocket.android.helper
import java.net.URLEncoder
class RocketChatUserAvatar(val hostname: String, val username: String) {
val imageUri: String
/** REMARK
* This is often a SVG image (see Rocket.Chat:server/startup/avatar.js).
*/
get() {
return "https://" +
hostname.replace("http://", "").replace("https://", "") +
"/avatar/" +
URLEncoder.encode(username, "UTF-8")
}
}
\ No newline at end of file
......@@ -5,9 +5,9 @@ import android.widget.ImageView
import android.widget.TextView
import chat.rocket.android.R
import chat.rocket.android.helper.DateTime
import chat.rocket.android.helper.RocketChatUserAvatar
import chat.rocket.android.widget.AbsoluteUrl
import chat.rocket.android.widget.RocketChatAvatar
import chat.rocket.android.widget.helper.UserAvatarHelper
import chat.rocket.android.widget.message.RocketChatMessageAttachmentsLayout
import chat.rocket.android.widget.message.RocketChatMessageLayout
import chat.rocket.android.widget.message.RocketChatMessageUrlsLayout
......@@ -20,22 +20,21 @@ class MessageRenderer(val message: Message, val autoLoadImage: Boolean) {
* Show user's avatar image in RocketChatAvatar widget.
*/
fun showAvatar(rocketChatAvatarWidget: RocketChatAvatar, hostname: String, userNotFoundAvatarImageView: ImageView) {
if (message.avatar != null) {
// Load user's avatar image from Oauth provider URI.
rocketChatAvatarWidget.loadImage(message.avatar)
} else {
val username: String? = message.user?.username
if (username != null) {
// Load user's avatar image from Rocket.Chat URI.
rocketChatAvatarWidget.loadImage(RocketChatUserAvatar(hostname, username).imageUri)
userNotFoundAvatarImageView.visibility = View.GONE
rocketChatAvatarWidget.visibility = View.VISIBLE
val placeholderDrawable = UserAvatarHelper.getTextDrawable(username, rocketChatAvatarWidget.context)
if (message.avatar != null) {
// Load user's avatar image from Oauth provider URI.
rocketChatAvatarWidget.loadImage(message.avatar, placeholderDrawable)
} else {
rocketChatAvatarWidget.loadImage(UserAvatarHelper.getUri(hostname, username), placeholderDrawable)
}
} else {
rocketChatAvatarWidget.visibility = View.GONE
userNotFoundAvatarImageView.visibility = View.VISIBLE
}
}
}
/**
* Show username in textView.
......
......@@ -4,8 +4,8 @@ import android.view.View
import android.widget.ImageView
import android.widget.TextView
import chat.rocket.android.R
import chat.rocket.android.helper.RocketChatUserAvatar
import chat.rocket.android.widget.RocketChatAvatar
import chat.rocket.android.widget.helper.UserAvatarHelper
import chat.rocket.core.models.User
class UserRenderer(val user: User) {
......@@ -16,7 +16,7 @@ class UserRenderer(val user: User) {
fun showAvatar(rocketChatAvatarWidget: RocketChatAvatar, hostname: String) {
val username: String? = user.username
if (username != null) {
rocketChatAvatarWidget.loadImage(RocketChatUserAvatar(hostname, username).imageUri)
rocketChatAvatarWidget.loadImage(UserAvatarHelper.getUri(hostname, username), UserAvatarHelper.getTextDrawable(username, rocketChatAvatarWidget.context))
} else {
rocketChatAvatarWidget.visibility = View.GONE
}
......
......@@ -22,7 +22,7 @@ ext {
buildToolsVersion = "26.0.0"
supportLibraryVersion = "25.4.0"
constraintLayoutVersion = "1.0.2"
kotlinVersion = "1.1.3"
kotlinVersion = "1.1.3-2"
}
task clean(type: Delete) {
......
......@@ -24,12 +24,18 @@ android {
vectorDrawables.useSupportLibrary = true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets {
test.java.srcDirs += 'src/test/kotlin'
androidTest.java.srcDirs += 'src/androidTest/kotlin'
}
}
ext {
......@@ -49,6 +55,8 @@ dependencies {
compile "com.android.support.constraint:constraint-layout:$rootProject.ext.constraintLayoutVersion"
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$rootProject.ext.kotlinVersion"
testCompile "org.jetbrains.kotlin:kotlin-test:$rootProject.ext.kotlinVersion"
testCompile "org.jetbrains.kotlin:kotlin-test-junit:$rootProject.ext.kotlinVersion"
compile 'org.nibor.autolink:autolink:0.6.0'
......
......@@ -2,6 +2,7 @@ package chat.rocket.android.widget;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.LayoutInflater;
......@@ -11,38 +12,35 @@ import com.facebook.drawee.view.SimpleDraweeView;
public class RocketChatAvatar extends FrameLayout {
private SimpleDraweeView draweeView;
private SimpleDraweeView simpleDraweeViewAvatar;
public RocketChatAvatar(Context context) {
super(context);
initialize(context, null);
initialize(context);
}
public RocketChatAvatar(Context context, AttributeSet attrs) {
super(context, attrs);
initialize(context, attrs);
initialize(context);
}
public RocketChatAvatar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialize(context, attrs);
initialize(context);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public RocketChatAvatar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initialize(context, attrs);
initialize(context);
}
private void initialize(Context context, AttributeSet attrs) {
LayoutInflater
.from(context)
.inflate(R.layout.message_avatar, this, true);
draweeView = findViewById(R.id.drawee_avatar);
private void initialize(Context context) {
LayoutInflater.from(context).inflate(R.layout.message_avatar, this, true);
simpleDraweeViewAvatar = findViewById(R.id.drawee_avatar);
}
public void loadImage(String imageUri) {
FrescoHelper
.loadImage(draweeView, imageUri);
public void loadImage(String imageUri, Drawable placeholderDrawable) {
FrescoHelper.INSTANCE.loadImage(simpleDraweeViewAvatar, imageUri, placeholderDrawable);
}
}
\ No newline at end of file
......@@ -3,7 +3,6 @@ package chat.rocket.android.widget;
import android.content.Context;
import com.facebook.common.logging.FLog;
import com.facebook.drawee.backends.pipeline.DraweeConfig;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.imagepipeline.backends.okhttp3.OkHttpImagePipelineConfigFactory;
import com.facebook.imagepipeline.core.ImagePipelineConfig;
......@@ -13,7 +12,6 @@ import com.facebook.imagepipeline.listener.RequestLoggingListener;
import java.util.HashSet;
import java.util.Set;
import chat.rocket.android.widget.fresco.CustomImageFormatConfigurator;
import okhttp3.OkHttpClient;
public class RocketChatWidgets {
......@@ -26,15 +24,11 @@ public class RocketChatWidgets {
ImagePipelineConfig imagePipelineConfig = OkHttpImagePipelineConfigFactory
.newBuilder(context, okHttpClient)
.setRequestListeners(listeners)
.setImageDecoderConfig(CustomImageFormatConfigurator.createImageDecoderConfig())
.setDownsampleEnabled(true)
.experiment().setBitmapPrepareToDraw(true)
.experiment().setPartialImageCachingEnabled(true)
.build();
DraweeConfig.Builder draweeConfigBuilder = DraweeConfig.newBuilder();
CustomImageFormatConfigurator.addCustomDrawableFactories(draweeConfigBuilder);
Fresco.initialize(context, imagePipelineConfig, draweeConfigBuilder.build());
Fresco.initialize(context, imagePipelineConfig);
}
}
\ No newline at end of file
package chat.rocket.android.widget.fresco;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.support.annotation.ColorInt;
import android.support.v4.graphics.ColorUtils;
import com.facebook.common.internal.ByteStreams;
import com.facebook.imagepipeline.drawable.DrawableFactory;
import com.facebook.imageformat.ImageFormat;
import com.facebook.imageformat.ImageFormatCheckerUtils;
import com.facebook.imagepipeline.common.ImageDecodeOptions;
import com.facebook.imagepipeline.decoder.ImageDecoder;
import com.facebook.imagepipeline.image.CloseableImage;
import com.facebook.imagepipeline.image.EncodedImage;
import com.facebook.imagepipeline.image.QualityInfo;
import java.io.IOException;
import javax.annotation.Nullable;
/**
* Simple decoder that can decode color images that have the following format:
*
* <color>#FF5722</color>
*
* See: https://github.com/facebook/fresco/blob/master/samples/showcase/src/main/java/com/facebook/fresco/samples/showcase/imageformat/color/ColorImage.java
*/
class ColorImage {
/**
* XML color tag that our colors must start with.
*/
public static final String COLOR_TAG = "<color>";
/**
* Custom {@link ImageFormat} for color images.
*/
public static final ImageFormat IMAGE_FORMAT_COLOR =
new ImageFormat("IMAGE_FORMAT_COLOR", "color");
/**
* Create a new image format checker for {@link #IMAGE_FORMAT_COLOR}.
* @return the image format checker
*/
public static ImageFormat.FormatChecker createFormatChecker() {
return new ColorFormatChecker();
}
/**
* Create a new decoder that can decode {@link #IMAGE_FORMAT_COLOR} images.
* @return the decoder
*/
public static ImageDecoder createDecoder() {
return new ColorDecoder();
}
public static ColorDrawableFactory createDrawableFactory() {
return new ColorDrawableFactory();
}
/**
* Custom color format checker that verifies that the header of the file
* corresponds to our {@link #COLOR_TAG}.
*/
public static class ColorFormatChecker implements ImageFormat.FormatChecker {
public static final byte[] HEADER = ImageFormatCheckerUtils.asciiBytes(COLOR_TAG);
@Override
public int getHeaderSize() {
return HEADER.length;
}
@Nullable
@Override
public ImageFormat determineFormat(byte[] headerBytes, int headerSize) {
if (headerSize < getHeaderSize()) {
return null;
}
if (ImageFormatCheckerUtils.startsWithPattern(headerBytes, HEADER)) {
return IMAGE_FORMAT_COLOR;
}
return null;
}
}
/**
* Custom closeable color image that holds a single color int value.
*/
public static class CloseableColorImage extends CloseableImage {
@ColorInt
private final int mColor;
private boolean mClosed = false;
public CloseableColorImage(int color) {
mColor = color;
}
@ColorInt
public int getColor() {
return mColor;
}
@Override
public int getSizeInBytes() {
return 0;
}
@Override
public void close() {
mClosed = true;
}
@Override
public boolean isClosed() {
return mClosed;
}
@Override
public int getWidth() {
return 0;
}
@Override
public int getHeight() {
return 0;
}
}
/**
* Decodes a color XML tag: <color>#rrggbb</color>
*/
public static class ColorDecoder implements ImageDecoder {
@Override
public CloseableImage decode(
EncodedImage encodedImage,
int length,
QualityInfo qualityInfo,
ImageDecodeOptions options) {
try {
// Read the file as a string
String text = new String(ByteStreams.toByteArray(encodedImage.getInputStream()));
// Check if the string matches "<color>#"
if (!text.startsWith(COLOR_TAG + "#")) {
return null;
}
// Parse the int value between # and <
int startIndex = COLOR_TAG.length() + 1;
int endIndex = text.lastIndexOf('<');
int color = Integer.parseInt(text.substring(startIndex, endIndex), 16);
// Add the alpha component so that we actually see the color
color = ColorUtils.setAlphaComponent(color, 255);
// Return the CloseableImage
return new CloseableColorImage(color);
} catch (IOException e) {
e.printStackTrace();
}
// Return nothing if an error occurred
return null;
}
}
/**
* Color drawable factory that is able to render a {@link CloseableColorImage} by creating
* a new {@link ColorDrawable} for the given color.
*/
public static class ColorDrawableFactory implements DrawableFactory {
@Override
public boolean supportsImageType(CloseableImage image) {
// We can only handle CloseableColorImages
return image instanceof CloseableColorImage;
}
@Nullable
@Override
public Drawable createDrawable(CloseableImage image) {
// Just return a simple ColorDrawable with the given color value
return new ColorDrawable(((CloseableColorImage)image).getColor());
}
}
}
package chat.rocket.android.widget.fresco;
import android.support.annotation.Nullable;
import com.facebook.drawee.backends.pipeline.DraweeConfig;
import com.facebook.imagepipeline.decoder.ImageDecoderConfig;
/**
* Helper class to add custom decoders and drawable factories.
* See: https://github.com/facebook/fresco/blob/master/samples/showcase/src/main/java/com/facebook/fresco/samples/showcase/CustomImageFormatConfigurator.java
*/
public class CustomImageFormatConfigurator {
@Nullable
public static ImageDecoderConfig createImageDecoderConfig() {
ImageDecoderConfig.Builder config = ImageDecoderConfig.newBuilder();
config.addDecodingCapability(SvgDecoder.SVG_FORMAT, new SvgDecoder.SvgFormatChecker(), new SvgDecoder.Decoder());
return config.build();
}
public static void addCustomDrawableFactories(DraweeConfig.Builder draweeConfigBuilder) {
draweeConfigBuilder.addCustomDrawableFactory(ColorImage.createDrawableFactory());
draweeConfigBuilder.addCustomDrawableFactory(new SvgDecoder.SvgDrawableFactory());
}
}
\ No newline at end of file
package chat.rocket.android.widget.fresco;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.PictureDrawable;
import com.caverock.androidsvg.SVG;
import com.caverock.androidsvg.SVGParseException;
import com.facebook.imagepipeline.drawable.DrawableFactory;
import com.facebook.imageformat.ImageFormat;
import com.facebook.imageformat.ImageFormatCheckerUtils;
import com.facebook.imagepipeline.common.ImageDecodeOptions;
import com.facebook.imagepipeline.decoder.ImageDecoder;
import com.facebook.imagepipeline.image.CloseableImage;
import com.facebook.imagepipeline.image.EncodedImage;
import com.facebook.imagepipeline.image.QualityInfo;
import javax.annotation.Nullable;
/**
* SVG example that defines all classes required to decode and render SVG images.
* See: https://github.com/facebook/fresco/blob/master/samples/showcase/src/main/java/com/facebook/fresco/samples/showcase/imageformat/svg/SvgDecoderExample.java
*/
public class SvgDecoder {
public static final ImageFormat SVG_FORMAT = new ImageFormat("SVG_FORMAT", "svg");
// We do not include the closing ">" since there can be additional information
private static final String HEADER_TAG = "<?xml";
public static class SvgFormatChecker implements ImageFormat.FormatChecker {
public static final byte[] HEADER = ImageFormatCheckerUtils.asciiBytes(HEADER_TAG);
@Override
public int getHeaderSize() {
return HEADER.length;
}
@Nullable
@Override
public ImageFormat determineFormat(byte[] headerBytes, int headerSize) {
if (headerSize < getHeaderSize()) {
return null;
}
if (ImageFormatCheckerUtils.startsWithPattern(headerBytes, HEADER)) {
return SVG_FORMAT;
}
return null;
}
}
public static class CloseableSvgImage extends CloseableImage {
private final SVG mSvg;
private boolean mClosed = false;
public CloseableSvgImage(SVG svg) {
mSvg = svg;
}
public SVG getSvg() {
return mSvg;
}
@Override
public int getSizeInBytes() {
return 0;
}
@Override
public void close() {
mClosed = true;
}
@Override
public boolean isClosed() {
return mClosed;
}
@Override
public int getWidth() {
return 0;
}
@Override
public int getHeight() {
return 0;
}
}
/**
* Decodes a SVG_FORMAT image
*/
public static class Decoder implements ImageDecoder {
@Override
public CloseableImage decode(
EncodedImage encodedImage,
int length,
QualityInfo qualityInfo,
ImageDecodeOptions options) {
try {
SVG svg = SVG.getFromInputStream(encodedImage.getInputStream());
return new CloseableSvgImage(svg);
} catch (SVGParseException e) {
e.printStackTrace();
}
return null;
}
}
/**
* SVG drawable factory that creates {@link PictureDrawable}s for SVG images.
*/
public static class SvgDrawableFactory implements DrawableFactory {
@Override
public boolean supportsImageType(CloseableImage image) {
return image instanceof CloseableSvgImage;
}
@Nullable
@Override
public Drawable createDrawable(CloseableImage image) {
return new SvgPictureDrawable(((CloseableSvgImage) image).getSvg());
}
}
public static class SvgPictureDrawable extends PictureDrawable {
private final SVG mSvg;
public SvgPictureDrawable(SVG svg) {
super(null);
mSvg = svg;
}
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
setPicture(mSvg.renderToPicture(bounds.width(), bounds.height()));
}
}
}
\ No newline at end of file
package chat.rocket.android.widget.helper
import android.graphics.drawable.Drawable
import android.net.Uri
import android.support.graphics.drawable.VectorDrawableCompat
import chat.rocket.android.widget.R
......@@ -8,24 +9,25 @@ import com.facebook.drawee.drawable.ProgressBarDrawable
import com.facebook.drawee.generic.GenericDraweeHierarchy
import com.facebook.drawee.view.SimpleDraweeView
class FrescoHelper {
companion object {
@JvmStatic fun loadImage(draweeView: SimpleDraweeView, imageUri: String) {
draweeView.setImageURI(imageUri)
object FrescoHelper {
fun loadImage(simpleDraweeView: SimpleDraweeView, imageUri: String, placeholderDrawable: Drawable) {
simpleDraweeView.hierarchy.setPlaceholderImage(placeholderDrawable)
simpleDraweeView.controller = Fresco.newDraweeControllerBuilder().setUri(imageUri).setAutoPlayAnimations(true).build()
}
/** TODO
* Replace with:
* @JvmStatic fun loadImageWithCustomization(draweeView: SimpleDraweeView,
* fun loadImageWithCustomization(draweeView: SimpleDraweeView,
* imageUri: String,
* placeholderImageDrawableId : Int = R.drawable.image_dummy,
failureImageDrawableId: Int = R.drawable.image_error) {
* failureImageDrawableId: Int = R.drawable.image_error) {
* [...]
* }
* It is need to convert java files which uses loadImageWithCustomization(...) method to use the above method signature.
* See: https://kotlinlang.org/docs/reference/functions.html#default-arguments.
*/
@JvmStatic fun loadImageWithCustomization(draweeView: SimpleDraweeView, imageUri: String) {
fun loadImageWithCustomization(draweeView: SimpleDraweeView, imageUri: String) {
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))
......@@ -39,5 +41,4 @@ class FrescoHelper {
draweeView.controller = controller
}
}
}
\ No newline at end of file
package chat.rocket.android.widget.helper
import android.content.Context
import android.graphics.Typeface
import android.graphics.drawable.Drawable
import chat.rocket.android.widget.AbsoluteUrl
import com.amulyakhare.textdrawable.TextDrawable
import java.net.URLEncoder
object UserAvatarHelper {
/**
* Returns the user avatar URI.
*
* REMARK: This is often a SVG image (Rocket.Chat:server/startup/avatar.js).
*
* @param hostname The server's hostname.
* @param username The username.
* @return The user avatar URI.
*/
fun getUri(hostname : String, username: String): String {
return "https://" +
hostname.replace("http://", "").replace("https://", "") +
"/avatar/" +
URLEncoder.encode(username, "UTF-8")
}
/**
* Returns the user avatar absolute URI.
*
* REMARK: This is often a SVG image (Rocket.Chat:server/startup/avatar.js).
*
* @param absoluteUrl The AbsoluteUrl.
* @param username The username.
* @return The user avatar absolute URI.
*/
fun getAbsoluteUri(absoluteUrl: AbsoluteUrl, username: String): String {
val avatarUri = "/avatar/" + URLEncoder.encode(username, "UTF-8")
return absoluteUrl.from(avatarUri)
}
/**
* Returns a drawable with username initials.
*
* @param username The username.
* @param context The context.
* @return A drawable with username initials.
* @see getUsernameInitials
*/
fun getTextDrawable(username: String, context: Context): Drawable {
val round = (4 * context.resources.displayMetrics.density).toInt()
return TextDrawable.builder()
.beginConfig()
.useFont(Typeface.SANS_SERIF)
.endConfig()
.buildRoundRect(getUsernameInitials(username), getUserAvatarBackgroundColor(username), round)
}
/**
* Returns a string with the username initials. For example: username John.Doe returns JD initials.
*
* @param username The username.
* @return A string with username initials.
*/
fun getUsernameInitials(username: String): String {
if (username.isEmpty()) {
return "?"
}
val splitUsername = username.split(".")
if (splitUsername.size > 1) {
return (splitUsername[0].substring(0, 1) + splitUsername[splitUsername.size - 1].substring(0, 1)).toUpperCase()
} else {
if (username.length > 1) {
return username.substring(0, 2).toUpperCase()
} else {
return username.substring(0, 1).toUpperCase()
}
}
}
/**
* Returns a background color to be rendered on the user avatar (Rocket.Chat:server/startup/avatar.js).
*
* @param username The username.
* @return A hexadecimal color.
*/
fun getUserAvatarBackgroundColor(username: String): Int {
return COLORS[username.length % COLORS.size]
}
private val COLORS = intArrayOf(
0xFFF44336.toInt(), 0xFFE91E63.toInt(), 0xFF9C27B0.toInt(), 0xFF673AB7.toInt(), 0xFF3F51B5.toInt(),
0xFF2196F3.toInt(), 0xFF03A9F4.toInt(), 0xFF00BCD4.toInt(), 0xFF009688.toInt(), 0xFF4CAF50.toInt(),
0xFF8BC34A.toInt(), 0xFFCDDC39.toInt(), 0xFFFFC107.toInt(), 0xFFFF9800.toInt(), 0xFFFF5722.toInt(),
0xFF795548.toInt(), 0xFF9E9E9E.toInt(), 0xFF607D8B.toInt())
}
\ No newline at end of file
......@@ -119,8 +119,7 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout {
authorBox.setVisibility(VISIBLE);
FrescoHelper
.loadImageWithCustomization((SimpleDraweeView) attachmentView.findViewById(R.id.author_icon), absolutize(author.getIconUrl()));
FrescoHelper.INSTANCE.loadImageWithCustomization((SimpleDraweeView) attachmentView.findViewById(R.id.author_icon), absolutize(author.getIconUrl()));
final TextView authorName = (TextView) attachmentView.findViewById(R.id.author_name);
authorName.setText(author.getName());
......@@ -187,8 +186,7 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout {
thumbImage.setVisibility(GONE);
} else {
thumbImage.setVisibility(VISIBLE);
FrescoHelper
.loadImageWithCustomization(thumbImage, absolutize(thumbUrl));
FrescoHelper.INSTANCE.loadImageWithCustomization(thumbImage, absolutize(thumbUrl));
}
final TextView refText = (TextView) refBox.findViewById(R.id.text);
......@@ -253,8 +251,7 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout {
boolean autoloadImage) {
if (autoloadImage) {
load.setVisibility(GONE);
FrescoHelper
.loadImageWithCustomization(drawee, url);
FrescoHelper.INSTANCE.loadImageWithCustomization(drawee, url);
return;
}
......@@ -263,8 +260,7 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout {
public void onClick(View v) {
load.setVisibility(GONE);
load.setOnClickListener(null);
FrescoHelper
.loadImageWithCustomization(drawee, url);
FrescoHelper.INSTANCE.loadImageWithCustomization(drawee, url);
}
});
}
......
......@@ -95,8 +95,7 @@ public class RocketChatMessageUrlsLayout extends LinearLayout {
if (TextUtils.isEmpty(imageURL)) {
image.setVisibility(View.GONE);
} else {
FrescoHelper
.loadImageWithCustomization(image, imageURL);
FrescoHelper.INSTANCE.loadImageWithCustomization(image, imageURL);
image.setVisibility(View.VISIBLE);
}
......@@ -144,8 +143,7 @@ public class RocketChatMessageUrlsLayout extends LinearLayout {
boolean autoloadImage) {
if (autoloadImage) {
load.setVisibility(GONE);
FrescoHelper
.loadImageWithCustomization(drawee, url);
FrescoHelper.INSTANCE.loadImageWithCustomization(drawee, url);
return;
}
......@@ -154,8 +152,7 @@ public class RocketChatMessageUrlsLayout extends LinearLayout {
public void onClick(View v) {
load.setVisibility(GONE);
load.setOnClickListener(null);
FrescoHelper
.loadImageWithCustomization(drawee, url);
FrescoHelper.INSTANCE.loadImageWithCustomization(drawee, url);
}
});
}
......
package chat.rocket.android.widget.message.autocomplete.user;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import chat.rocket.android.widget.AbsoluteUrl;
import chat.rocket.android.widget.R;
import chat.rocket.android.widget.RocketChatAvatar;
import chat.rocket.android.widget.helper.UserAvatarHelper;
import chat.rocket.android.widget.message.autocomplete.AutocompleteViewHolder;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
public class UserViewHolder extends AutocompleteViewHolder<UserItem> {
private final TextView titleTextView;
private final RocketChatAvatar avatar;
private final ImageView status;
......@@ -44,7 +45,9 @@ public class UserViewHolder extends AutocompleteViewHolder<UserItem> {
}
if (avatar != null) {
avatar.loadImage(getImageUrl(suggestion, userItem.getAbsoluteUrl()));
String absoluteUri = UserAvatarHelper.INSTANCE.getAbsoluteUri(userItem.getAbsoluteUrl(), suggestion);
Drawable placeholderDrawable = UserAvatarHelper.INSTANCE.getTextDrawable(suggestion, itemView.getContext());
avatar.loadImage(absoluteUri, placeholderDrawable);
}
if (status != null) {
......@@ -58,19 +61,4 @@ public class UserViewHolder extends AutocompleteViewHolder<UserItem> {
avatar.setVisibility(View.GONE);
titleTextView.setText(R.string.no_user_found);
}
private String getImageUrl(String username, AbsoluteUrl absoluteUrl) {
//from Rocket.Chat:packages/rocketchat-ui/lib/avatar.coffee
//REMARK! this is often SVG image! (see: Rocket.Chat:server/startup/avatar.coffee)
try {
final String avatarUrl = "/avatar/" + URLEncoder.encode(username, "UTF-8");
// TODO why absoluteUrl is nullable? By allowing that, the app tries to load non-existing images
if (absoluteUrl == null) {
return avatarUrl;
}
return absoluteUrl.from(avatarUrl);
} catch (UnsupportedEncodingException exception) {
return null;
}
}
}
\ No newline at end of file
......@@ -4,5 +4,5 @@
android:id="@+id/drawee_avatar"
android:layout_width="match_parent"
android:layout_height="match_parent"
fresco:actualImageScaleType="fitCenter"
fresco:actualImageScaleType="fitXY"
fresco:roundedCornerRadius="5dp" />
\ No newline at end of file
import chat.rocket.android.widget.helper.UserAvatarHelper
import org.junit.Test
class UserAvatarHelperTest {
@Test
fun getUsernameInitialsTest() {
assert(UserAvatarHelper.getUsernameInitials("") == "?")
assert(UserAvatarHelper.getUsernameInitials("?") == "?")
assert(UserAvatarHelper.getUsernameInitials("f") == "F")
assert(UserAvatarHelper.getUsernameInitials("B") == "B")
assert(UserAvatarHelper.getUsernameInitials("fo") == "FO")
assert(UserAvatarHelper.getUsernameInitials("FO") == "FO")
assert(UserAvatarHelper.getUsernameInitials("fOo") == "FO")
assert(UserAvatarHelper.getUsernameInitials("FOO") == "FO")
assert(UserAvatarHelper.getUsernameInitials("F.O") == "FO")
assert(UserAvatarHelper.getUsernameInitials("F.o") == "FO")
assert(UserAvatarHelper.getUsernameInitials("Foo.bar") == "FB")
assert(UserAvatarHelper.getUsernameInitials("Foobar.bar") == "FB")
assert(UserAvatarHelper.getUsernameInitials("Foobar.bar.zab") == "FZ")
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment