diff --git a/app/build.gradle b/app/build.gradle index 06b0d77791..33e25c03f9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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,20 +59,24 @@ 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}" diff --git a/app/src/main/java/chat/rocket/android/helper/OkHttpHelper.java b/app/src/main/java/chat/rocket/android/helper/OkHttpHelper.java index a4cf9b5cf3..dfdc9b8304 100644 --- a/app/src/main/java/chat/rocket/android/helper/OkHttpHelper.java +++ b/app/src/main/java/chat/rocket/android/helper/OkHttpHelper.java @@ -48,4 +48,4 @@ public static OkHttpClient getClientForWebSocket() { } return httpClientForWS; } -} +} \ No newline at end of file diff --git a/app/src/main/java/chat/rocket/android/helper/RocketChatUserAvatar.kt b/app/src/main/java/chat/rocket/android/helper/RocketChatUserAvatar.kt deleted file mode 100644 index ce8966b17f..0000000000 --- a/app/src/main/java/chat/rocket/android/helper/RocketChatUserAvatar.kt +++ /dev/null @@ -1,17 +0,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 diff --git a/app/src/main/java/chat/rocket/android/renderer/MessageRenderer.kt b/app/src/main/java/chat/rocket/android/renderer/MessageRenderer.kt index a3138cefa1..d0576bf6b9 100644 --- a/app/src/main/java/chat/rocket/android/renderer/MessageRenderer.kt +++ b/app/src/main/java/chat/rocket/android/renderer/MessageRenderer.kt @@ -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,20 +20,19 @@ 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 username: String? = message.user?.username + if (username != null) { + userNotFoundAvatarImageView.visibility = View.GONE + 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.visibility = View.GONE - userNotFoundAvatarImageView.visibility = View.VISIBLE + rocketChatAvatarWidget.loadImage(UserAvatarHelper.getUri(hostname, username), placeholderDrawable) } + } else { + rocketChatAvatarWidget.visibility = View.GONE + userNotFoundAvatarImageView.visibility = View.VISIBLE } } diff --git a/app/src/main/java/chat/rocket/android/renderer/UserRenderer.kt b/app/src/main/java/chat/rocket/android/renderer/UserRenderer.kt index 87fd272644..3264861386 100644 --- a/app/src/main/java/chat/rocket/android/renderer/UserRenderer.kt +++ b/app/src/main/java/chat/rocket/android/renderer/UserRenderer.kt @@ -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 } diff --git a/build.gradle b/build.gradle index a845dc6fb2..085cc87a9e 100644 --- a/build.gradle +++ b/build.gradle @@ -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) { diff --git a/rocket-chat-android-widgets/build.gradle b/rocket-chat-android-widgets/build.gradle index b6cb1cadfa..2c831c5bb3 100644 --- a/rocket-chat-android-widgets/build.gradle +++ b/rocket-chat-android-widgets/build.gradle @@ -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' diff --git a/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/RocketChatAvatar.java b/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/RocketChatAvatar.java index baba0679c7..1ecd492715 100644 --- a/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/RocketChatAvatar.java +++ b/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/RocketChatAvatar.java @@ -2,6 +2,7 @@ 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 @@ 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 diff --git a/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/RocketChatWidgets.java b/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/RocketChatWidgets.java index ea6c3c8483..c9f4a4d791 100644 --- a/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/RocketChatWidgets.java +++ b/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/RocketChatWidgets.java @@ -3,7 +3,6 @@ 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 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 static void initialize(Context context, OkHttpClient okHttpClient) { 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 diff --git a/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/fresco/ColorImage.java b/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/fresco/ColorImage.java deleted file mode 100644 index e7f74c36e1..0000000000 --- a/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/fresco/ColorImage.java +++ /dev/null @@ -1,187 +0,0 @@ -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: - * - * #FF5722 - * - * 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 = ""; - - /** - * 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: #rrggbb - */ - 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 "#" - 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()); - } - } - -} diff --git a/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/fresco/CustomImageFormatConfigurator.java b/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/fresco/CustomImageFormatConfigurator.java deleted file mode 100644 index f5312953c9..0000000000 --- a/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/fresco/CustomImageFormatConfigurator.java +++ /dev/null @@ -1,24 +0,0 @@ -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 diff --git a/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/fresco/SvgDecoder.java b/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/fresco/SvgDecoder.java deleted file mode 100644 index d991faf96e..0000000000 --- a/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/fresco/SvgDecoder.java +++ /dev/null @@ -1,144 +0,0 @@ -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 = " 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 diff --git a/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/RocketChatMessageAttachmentsLayout.java b/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/RocketChatMessageAttachmentsLayout.java index b680888fe1..861062ca74 100644 --- a/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/RocketChatMessageAttachmentsLayout.java +++ b/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/RocketChatMessageAttachmentsLayout.java @@ -119,8 +119,7 @@ private void showAuthorAttachment(Attachment attachment, View attachmentView) { 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 @@ private void showReferenceAttachment(Attachment attachment, View attachmentView) 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 @@ private void loadImage(final String url, final SimpleDraweeView drawee, final Vi boolean autoloadImage) { if (autoloadImage) { load.setVisibility(GONE); - FrescoHelper - .loadImageWithCustomization(drawee, url); + FrescoHelper.INSTANCE.loadImageWithCustomization(drawee, url); return; } @@ -263,8 +260,7 @@ private void loadImage(final String url, final SimpleDraweeView drawee, final Vi public void onClick(View v) { load.setVisibility(GONE); load.setOnClickListener(null); - FrescoHelper - .loadImageWithCustomization(drawee, url); + FrescoHelper.INSTANCE.loadImageWithCustomization(drawee, url); } }); } diff --git a/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/RocketChatMessageUrlsLayout.java b/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/RocketChatMessageUrlsLayout.java index 47a76379b8..c2eca3430e 100644 --- a/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/RocketChatMessageUrlsLayout.java +++ b/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/RocketChatMessageUrlsLayout.java @@ -95,8 +95,7 @@ private void appendUrlView(WebContent webContent, boolean autoloadImages) { 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 @@ private void loadImage(final String url, final SimpleDraweeView drawee, final Vi boolean autoloadImage) { if (autoloadImage) { load.setVisibility(GONE); - FrescoHelper - .loadImageWithCustomization(drawee, url); + FrescoHelper.INSTANCE.loadImageWithCustomization(drawee, url); return; } @@ -154,8 +152,7 @@ private void loadImage(final String url, final SimpleDraweeView drawee, final Vi public void onClick(View v) { load.setVisibility(GONE); load.setOnClickListener(null); - FrescoHelper - .loadImageWithCustomization(drawee, url); + FrescoHelper.INSTANCE.loadImageWithCustomization(drawee, url); } }); } diff --git a/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/autocomplete/user/UserViewHolder.java b/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/autocomplete/user/UserViewHolder.java index 5f4c0afb00..21e17bf2d8 100644 --- a/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/autocomplete/user/UserViewHolder.java +++ b/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/message/autocomplete/user/UserViewHolder.java @@ -1,17 +1,18 @@ 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 { - private final TextView titleTextView; private final RocketChatAvatar avatar; private final ImageView status; @@ -44,7 +45,9 @@ public void bind(UserItem 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 void showAsEmpty() { 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 diff --git a/rocket-chat-android-widgets/src/main/res/layout/message_avatar.xml b/rocket-chat-android-widgets/src/main/res/layout/message_avatar.xml index f33eabc509..8c8c0c53d9 100644 --- a/rocket-chat-android-widgets/src/main/res/layout/message_avatar.xml +++ b/rocket-chat-android-widgets/src/main/res/layout/message_avatar.xml @@ -1,8 +1,8 @@ \ No newline at end of file + xmlns:fresco="http://schemas.android.com/apk/res-auto" + android:id="@+id/drawee_avatar" + android:layout_width="match_parent" + android:layout_height="match_parent" + fresco:actualImageScaleType="fitXY" + fresco:roundedCornerRadius="5dp" /> \ No newline at end of file diff --git a/rocket-chat-android-widgets/src/test/kotlin/chat/rocket/android/widget/helper/UserAvatarHelperTest.kt b/rocket-chat-android-widgets/src/test/kotlin/chat/rocket/android/widget/helper/UserAvatarHelperTest.kt new file mode 100644 index 0000000000..f0c4ee4952 --- /dev/null +++ b/rocket-chat-android-widgets/src/test/kotlin/chat/rocket/android/widget/helper/UserAvatarHelperTest.kt @@ -0,0 +1,22 @@ +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