From 4d84c1ebcebdb9f43fba43e104181bc68cc1707a Mon Sep 17 00:00:00 2001 From: Filipe de Lima Brito Date: Tue, 1 Aug 2017 09:56:17 -0300 Subject: [PATCH 01/29] Add getContentType(...) and getDefaultHttpClient() method. --- .../rocket/android/helper/OkHttpHelper.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) 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..a57e879740 100644 --- a/app/src/main/java/chat/rocket/android/helper/OkHttpHelper.java +++ b/app/src/main/java/chat/rocket/android/helper/OkHttpHelper.java @@ -1,21 +1,36 @@ package chat.rocket.android.helper; import android.content.Context; +import android.support.annotation.NonNull; import com.facebook.stetho.okhttp3.StethoInterceptor; +import java.io.IOException; import java.util.concurrent.TimeUnit; import chat.rocket.android.RocketChatCache; import chat.rocket.android.api.rest.CookieInterceptor; import chat.rocket.android.api.rest.DefaultCookieProvider; +import okhttp3.Call; +import okhttp3.Callback; import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; /** * Helper class for OkHttp client. */ public class OkHttpHelper { + private static OkHttpClient defaultHttpClient; private static OkHttpClient httpClientForUploadFile; private static OkHttpClient httpClientForDownloadFile; private static OkHttpClient httpClientForWS; + private static String contentType; + + public static OkHttpClient getDefaultHttpClient() { + if (defaultHttpClient == null) { + defaultHttpClient = new OkHttpClient(); + } + return defaultHttpClient; + } public static OkHttpClient getClientForDownloadFile(Context context) { if (httpClientForDownloadFile == null) { @@ -48,4 +63,28 @@ public static OkHttpClient getClientForWebSocket() { } return httpClientForWS; } + + public static String getContentType(String uri) { + Request request = new Request.Builder() + .url(uri) + .head() + .build(); + getDefaultHttpClient().newCall(request).enqueue(new Callback() { + @Override + public void onFailure(@NonNull Call call, @NonNull IOException ioException) { + ioException.printStackTrace(); + } + + @Override + public void onResponse(@NonNull Call call, @NonNull final Response response) + throws IOException { + if (!response.isSuccessful()) { + throw new IOException("Unexpected code: " + response); + } else { + contentType = response.header("Content-Type"); + } + } + }); + return contentType; + } } From 4ec4fff24785ba4d212fb40e950e92ba6ed7cbd5 Mon Sep 17 00:00:00 2001 From: Filipe de Lima Brito Date: Tue, 1 Aug 2017 10:00:39 -0300 Subject: [PATCH 02/29] Update RocketChatUserAvatar. Since it is a helper, we don't need to instantiate the RocketChatUserAvatar to each use. This commit adds methods to get a drawable with username initials. --- .../android/helper/RocketChatUserAvatar.kt | 96 ++++++++++++++++--- 1 file changed, 85 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/chat/rocket/android/helper/RocketChatUserAvatar.kt b/app/src/main/java/chat/rocket/android/helper/RocketChatUserAvatar.kt index ce8966b17f..324b3fe938 100644 --- a/app/src/main/java/chat/rocket/android/helper/RocketChatUserAvatar.kt +++ b/app/src/main/java/chat/rocket/android/helper/RocketChatUserAvatar.kt @@ -1,17 +1,91 @@ package chat.rocket.android.helper +import android.content.Context +import android.graphics.Typeface +import android.graphics.drawable.Drawable +import com.amulyakhare.textdrawable.TextDrawable 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") +object RocketChatUserAvatar { + + /** + * 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. + * @see getImageFormat + */ + fun getUri(hostname : String, username: String): String { + return "https://" + + hostname.replace("http://", "").replace("https://", "") + + "/avatar/" + + URLEncoder.encode(username, "UTF-8") + } + + /** + * Returns the user avatar image format. + * + * @param uri The user avatar image URI to get the image format. + * @return The user avatar image format. Possible values are: "image/jpeg", "image/png" and "image/svg+xml". + * @see getUri + */ + fun getImageFormat(uri: String): String { + return OkHttpHelper.getContentType(uri) + } + + /** + * 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 { + val name = username + .replace("[^A-Za-z0-9]", ".") + .replace("\\.+", ".") + .replace("(^\\.)|(\\.$)", "") + val initials = name.split(".") + if (initials.size > 1) { + return (initials[0].substring(0, 1) + initials[initials.size - 1].substring(0, 1)).toUpperCase() + } else { + return (name.replace("[^A-Za-z0-9]", "").substring(0, 2)).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 From f9af22f300708a19a235e39f6b1d14b7c1f52dac Mon Sep 17 00:00:00 2001 From: Filipe de Lima Brito Date: Tue, 1 Aug 2017 10:08:21 -0300 Subject: [PATCH 03/29] Add an imageView to be used with avatars in svg format. --- .../layouthelper/chatroom/AbstractMessageViewHolder.java | 2 ++ .../layouthelper/chatroom/MessageNormalViewHolder.java | 2 +- .../layouthelper/chatroom/MessageSystemViewHolder.java | 2 +- app/src/main/res/layout/list_item_normal_message.xml | 7 +++++++ app/src/main/res/layout/list_item_system_message.xml | 7 +++++++ 5 files changed, 18 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/chat/rocket/android/layouthelper/chatroom/AbstractMessageViewHolder.java b/app/src/main/java/chat/rocket/android/layouthelper/chatroom/AbstractMessageViewHolder.java index 0aa891e4b0..d071ed253c 100644 --- a/app/src/main/java/chat/rocket/android/layouthelper/chatroom/AbstractMessageViewHolder.java +++ b/app/src/main/java/chat/rocket/android/layouthelper/chatroom/AbstractMessageViewHolder.java @@ -14,6 +14,7 @@ public abstract class AbstractMessageViewHolder extends ModelViewHolder { protected final RocketChatAvatar avatar; protected final ImageView userNotFoundAvatarImageView; + protected final ImageView imageViewSvgUserAvatar; protected final ImageView errorImageView; protected final TextView username; protected final TextView subUsername; @@ -31,6 +32,7 @@ public AbstractMessageViewHolder(View itemView, AbsoluteUrl absoluteUrl, String super(itemView); avatar = itemView.findViewById(R.id.user_avatar); userNotFoundAvatarImageView = itemView.findViewById(R.id.userNotFoundAvatarImageView); + imageViewSvgUserAvatar = itemView.findViewById(R.id.image_svg_user_avatar); errorImageView = itemView.findViewById(R.id.errorImageView); username = itemView.findViewById(R.id.username); subUsername = itemView.findViewById(R.id.sub_username); diff --git a/app/src/main/java/chat/rocket/android/layouthelper/chatroom/MessageNormalViewHolder.java b/app/src/main/java/chat/rocket/android/layouthelper/chatroom/MessageNormalViewHolder.java index 0b754a10cc..3a92037aee 100644 --- a/app/src/main/java/chat/rocket/android/layouthelper/chatroom/MessageNormalViewHolder.java +++ b/app/src/main/java/chat/rocket/android/layouthelper/chatroom/MessageNormalViewHolder.java @@ -29,7 +29,7 @@ public MessageNormalViewHolder(View itemView, AbsoluteUrl absoluteUrl, String ho @Override protected void bindMessage(PairedMessage pairedMessage, boolean autoloadImages) { MessageRenderer messageRenderer = new MessageRenderer(pairedMessage.target, autoloadImages); - messageRenderer.showAvatar(avatar, hostname, userNotFoundAvatarImageView); + messageRenderer.showAvatar(avatar, hostname, userNotFoundAvatarImageView, imageViewSvgUserAvatar); messageRenderer.showUsername(username, subUsername); messageRenderer.showTimestampOrMessageState(timestamp); messageRenderer.showBody(body); diff --git a/app/src/main/java/chat/rocket/android/layouthelper/chatroom/MessageSystemViewHolder.java b/app/src/main/java/chat/rocket/android/layouthelper/chatroom/MessageSystemViewHolder.java index 995577ad14..5aaf9db4d7 100644 --- a/app/src/main/java/chat/rocket/android/layouthelper/chatroom/MessageSystemViewHolder.java +++ b/app/src/main/java/chat/rocket/android/layouthelper/chatroom/MessageSystemViewHolder.java @@ -24,7 +24,7 @@ public MessageSystemViewHolder(View itemView, AbsoluteUrl absoluteUrl, String ho @Override protected void bindMessage(PairedMessage pairedMessage, boolean autoloadImages) { MessageRenderer messageRenderer = new MessageRenderer(pairedMessage.target, autoloadImages); - messageRenderer.showAvatar(avatar, hostname, userNotFoundAvatarImageView); + messageRenderer.showAvatar(avatar, hostname, userNotFoundAvatarImageView, imageViewSvgUserAvatar); messageRenderer.showUsername(username, subUsername); messageRenderer.showTimestampOrMessageState(timestamp); if (pairedMessage.target != null) { diff --git a/app/src/main/res/layout/list_item_normal_message.xml b/app/src/main/res/layout/list_item_normal_message.xml index 50d9a0f6d5..803f776413 100644 --- a/app/src/main/res/layout/list_item_normal_message.xml +++ b/app/src/main/res/layout/list_item_normal_message.xml @@ -28,6 +28,13 @@ app:srcCompat="@drawable/ic_user_not_found_avatar_black_24dp" android:visibility="gone" /> + + + + Date: Tue, 1 Aug 2017 10:08:54 -0300 Subject: [PATCH 04/29] Update UserRenderer.kt --- app/src/main/java/chat/rocket/android/renderer/UserRenderer.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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..c288078de9 100644 --- a/app/src/main/java/chat/rocket/android/renderer/UserRenderer.kt +++ b/app/src/main/java/chat/rocket/android/renderer/UserRenderer.kt @@ -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(RocketChatUserAvatar.getUri(hostname, username)) } else { rocketChatAvatarWidget.visibility = View.GONE } From d794b5b8c63b6b0be879f60b8a6b5b73e7190565 Mon Sep 17 00:00:00 2001 From: Filipe de Lima Brito Date: Tue, 1 Aug 2017 10:09:29 -0300 Subject: [PATCH 05/29] Update MessageRenderer.kt --- .../rocket/android/renderer/MessageRenderer.kt | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) 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..0ecb1c4373 100644 --- a/app/src/main/java/chat/rocket/android/renderer/MessageRenderer.kt +++ b/app/src/main/java/chat/rocket/android/renderer/MessageRenderer.kt @@ -5,6 +5,7 @@ import android.widget.ImageView import android.widget.TextView import chat.rocket.android.R import chat.rocket.android.helper.DateTime +import chat.rocket.android.helper.OkHttpHelper import chat.rocket.android.helper.RocketChatUserAvatar import chat.rocket.android.widget.AbsoluteUrl import chat.rocket.android.widget.RocketChatAvatar @@ -19,18 +20,27 @@ class MessageRenderer(val message: Message, val autoLoadImage: Boolean) { /** * Show user's avatar image in RocketChatAvatar widget. */ - fun showAvatar(rocketChatAvatarWidget: RocketChatAvatar, hostname: String, userNotFoundAvatarImageView: ImageView) { + fun showAvatar(rocketChatAvatarWidget: RocketChatAvatar, hostname: String, userNotFoundAvatarImageView: ImageView, userAvatarSvgImage: 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 userAvatarUri = RocketChatUserAvatar.getUri(hostname, username) + val userAvatarImageContentType = OkHttpHelper.getContentType(userAvatarUri) + if (userAvatarImageContentType == "image/svg+xml") { + rocketChatAvatarWidget.visibility = View.GONE + userAvatarSvgImage.setImageDrawable(RocketChatUserAvatar.getTextDrawable(username, userAvatarSvgImage.context)) + userAvatarSvgImage.visibility = View.VISIBLE + } else { + userAvatarSvgImage.visibility = View.GONE + rocketChatAvatarWidget.loadImage(userAvatarUri) + rocketChatAvatarWidget.visibility = View.VISIBLE + } } else { + userAvatarSvgImage.visibility = View.GONE rocketChatAvatarWidget.visibility = View.GONE userNotFoundAvatarImageView.visibility = View.VISIBLE } From 3b24532e3237528ad1fd71508bfe481a94c9ccde Mon Sep 17 00:00:00 2001 From: Filipe de Lima Brito Date: Tue, 1 Aug 2017 10:10:13 -0300 Subject: [PATCH 06/29] Update RocketChatAvatar.java --- .../java/chat/rocket/android/widget/RocketChatAvatar.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) 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..479ea6ac40 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 @@ -35,14 +35,11 @@ public RocketChatAvatar(Context context, AttributeSet attrs, int defStyleAttr, i } private void initialize(Context context, AttributeSet attrs) { - LayoutInflater - .from(context) - .inflate(R.layout.message_avatar, this, true); + LayoutInflater.from(context).inflate(R.layout.message_avatar, this, true); draweeView = findViewById(R.id.drawee_avatar); } public void loadImage(String imageUri) { - FrescoHelper - .loadImage(draweeView, imageUri); + FrescoHelper.loadImage(draweeView, imageUri); } } \ No newline at end of file From a891e28b491fab2baef79fdaf6ec80ef577dc142 Mon Sep 17 00:00:00 2001 From: Filipe de Lima Brito Date: Tue, 1 Aug 2017 16:49:36 -0300 Subject: [PATCH 07/29] Update Kotlin version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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) { From ed0f72dcc1593b081c977119fbbc78328175f12c Mon Sep 17 00:00:00 2001 From: Filipe de Lima Brito Date: Tue, 1 Aug 2017 16:54:40 -0300 Subject: [PATCH 08/29] Add tests dependencies and Kotlin tests directories --- app/build.gradle | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 65b780c002..fb6031263a 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,29 @@ android { signingConfig signingConfigs.release } } + + sourceSets { + test.java.srcDirs += 'src/test/kotlin' + androidTest.java.srcDirs += 'src/androidTest/kotlin' + } + 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}" @@ -99,6 +110,8 @@ dependencies { compile 'com.android.support:multidex:1.0.1' 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 "com.google.firebase:firebase-core:$playLibVersion" compile "com.google.firebase:firebase-crash:$playLibVersion" From c54a4144f25e3e19e8b026615440fd1eca4cc742 Mon Sep 17 00:00:00 2001 From: Filipe de Lima Brito Date: Tue, 1 Aug 2017 20:54:11 -0300 Subject: [PATCH 09/29] Update RocketChatUserAvatar.kt --- .../android/helper/RocketChatUserAvatar.kt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/chat/rocket/android/helper/RocketChatUserAvatar.kt b/app/src/main/java/chat/rocket/android/helper/RocketChatUserAvatar.kt index 324b3fe938..443a1ec536 100644 --- a/app/src/main/java/chat/rocket/android/helper/RocketChatUserAvatar.kt +++ b/app/src/main/java/chat/rocket/android/helper/RocketChatUserAvatar.kt @@ -61,15 +61,15 @@ object RocketChatUserAvatar { * @return A string with username initials. */ fun getUsernameInitials(username: String): String { - val name = username - .replace("[^A-Za-z0-9]", ".") - .replace("\\.+", ".") - .replace("(^\\.)|(\\.$)", "") - val initials = name.split(".") - if (initials.size > 1) { - return (initials[0].substring(0, 1) + initials[initials.size - 1].substring(0, 1)).toUpperCase() + 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 { - return (name.replace("[^A-Za-z0-9]", "").substring(0, 2)).toUpperCase() + return username.toUpperCase() } } From cfc8d79bb24c014acae5533d70ee5ed987070e1f Mon Sep 17 00:00:00 2001 From: Filipe de Lima Brito Date: Tue, 1 Aug 2017 20:54:53 -0300 Subject: [PATCH 10/29] Add RocketChatUserAvatarTest.kt --- .../test/kotlin/RocketChatUserAvatarTest.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 app/src/test/kotlin/RocketChatUserAvatarTest.kt diff --git a/app/src/test/kotlin/RocketChatUserAvatarTest.kt b/app/src/test/kotlin/RocketChatUserAvatarTest.kt new file mode 100644 index 0000000000..54fb9ef4f7 --- /dev/null +++ b/app/src/test/kotlin/RocketChatUserAvatarTest.kt @@ -0,0 +1,22 @@ +import chat.rocket.android.helper.RocketChatUserAvatar +import org.junit.Test + +class RocketChatUserAvatarTest { + + @Test + fun `Test username initials`() { + assert(RocketChatUserAvatar.getUsernameInitials("") == "?") + assert(RocketChatUserAvatar.getUsernameInitials("?") == "?") + assert(RocketChatUserAvatar.getUsernameInitials("f") == "F") + assert(RocketChatUserAvatar.getUsernameInitials("B") == "B") + assert(RocketChatUserAvatar.getUsernameInitials("fo") == "FO") + assert(RocketChatUserAvatar.getUsernameInitials("FO") == "FO") + assert(RocketChatUserAvatar.getUsernameInitials("fOo") == "FO") + assert(RocketChatUserAvatar.getUsernameInitials("FOO") == "FO") + assert(RocketChatUserAvatar.getUsernameInitials("F.O") == "FO") + assert(RocketChatUserAvatar.getUsernameInitials("F.o") == "FO") + assert(RocketChatUserAvatar.getUsernameInitials("Foo.bar") == "FB") + assert(RocketChatUserAvatar.getUsernameInitials("Foobar.bar") == "FB") + assert(RocketChatUserAvatar.getUsernameInitials("Foobar.bar.zab") == "FZ") + } +} \ No newline at end of file From 281ac8a39afa664b04cc3bf0e0674818f049682c Mon Sep 17 00:00:00 2001 From: Filipe de Lima Brito Date: Tue, 1 Aug 2017 21:28:56 -0300 Subject: [PATCH 11/29] Update method name declaration. --- app/src/test/kotlin/RocketChatUserAvatarTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/test/kotlin/RocketChatUserAvatarTest.kt b/app/src/test/kotlin/RocketChatUserAvatarTest.kt index 54fb9ef4f7..0ca6fb3bc9 100644 --- a/app/src/test/kotlin/RocketChatUserAvatarTest.kt +++ b/app/src/test/kotlin/RocketChatUserAvatarTest.kt @@ -4,7 +4,7 @@ import org.junit.Test class RocketChatUserAvatarTest { @Test - fun `Test username initials`() { + fun getUsernameInitialsTest() { assert(RocketChatUserAvatar.getUsernameInitials("") == "?") assert(RocketChatUserAvatar.getUsernameInitials("?") == "?") assert(RocketChatUserAvatar.getUsernameInitials("f") == "F") @@ -19,4 +19,4 @@ class RocketChatUserAvatarTest { assert(RocketChatUserAvatar.getUsernameInitials("Foobar.bar") == "FB") assert(RocketChatUserAvatar.getUsernameInitials("Foobar.bar.zab") == "FZ") } -} \ No newline at end of file +} From 4f636c27013fec6d15f2a5276d32aac9c4287b44 Mon Sep 17 00:00:00 2001 From: Filipe de Lima Brito Date: Wed, 2 Aug 2017 18:50:27 -0300 Subject: [PATCH 12/29] Update RocketChatUserAvatar.kt --- .../java/chat/rocket/android/helper/RocketChatUserAvatar.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/chat/rocket/android/helper/RocketChatUserAvatar.kt b/app/src/main/java/chat/rocket/android/helper/RocketChatUserAvatar.kt index 443a1ec536..c2f8525476 100644 --- a/app/src/main/java/chat/rocket/android/helper/RocketChatUserAvatar.kt +++ b/app/src/main/java/chat/rocket/android/helper/RocketChatUserAvatar.kt @@ -69,7 +69,11 @@ object RocketChatUserAvatar { if (splitUsername.size > 1) { return (splitUsername[0].substring(0, 1) + splitUsername[splitUsername.size - 1].substring(0, 1)).toUpperCase() } else { - return username.toUpperCase() + if (username.length > 1) { + return username.substring(0, 2).toUpperCase() + } else { + return username.substring(0, 1).toUpperCase() + } } } From f35ab1419bdafa8dfc6a9c64be67127e489216bb Mon Sep 17 00:00:00 2001 From: Filipe de Lima Brito Date: Wed, 2 Aug 2017 18:53:52 -0300 Subject: [PATCH 13/29] Delete image_svg_user_avatar/imageViewSvgUserAvatar --- .../layouthelper/chatroom/AbstractMessageViewHolder.java | 2 -- .../layouthelper/chatroom/MessageNormalViewHolder.java | 2 +- .../layouthelper/chatroom/MessageSystemViewHolder.java | 2 +- app/src/main/res/layout/list_item_normal_message.xml | 7 ------- app/src/main/res/layout/list_item_system_message.xml | 7 ------- 5 files changed, 2 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/chat/rocket/android/layouthelper/chatroom/AbstractMessageViewHolder.java b/app/src/main/java/chat/rocket/android/layouthelper/chatroom/AbstractMessageViewHolder.java index d071ed253c..0aa891e4b0 100644 --- a/app/src/main/java/chat/rocket/android/layouthelper/chatroom/AbstractMessageViewHolder.java +++ b/app/src/main/java/chat/rocket/android/layouthelper/chatroom/AbstractMessageViewHolder.java @@ -14,7 +14,6 @@ public abstract class AbstractMessageViewHolder extends ModelViewHolder { protected final RocketChatAvatar avatar; protected final ImageView userNotFoundAvatarImageView; - protected final ImageView imageViewSvgUserAvatar; protected final ImageView errorImageView; protected final TextView username; protected final TextView subUsername; @@ -32,7 +31,6 @@ public AbstractMessageViewHolder(View itemView, AbsoluteUrl absoluteUrl, String super(itemView); avatar = itemView.findViewById(R.id.user_avatar); userNotFoundAvatarImageView = itemView.findViewById(R.id.userNotFoundAvatarImageView); - imageViewSvgUserAvatar = itemView.findViewById(R.id.image_svg_user_avatar); errorImageView = itemView.findViewById(R.id.errorImageView); username = itemView.findViewById(R.id.username); subUsername = itemView.findViewById(R.id.sub_username); diff --git a/app/src/main/java/chat/rocket/android/layouthelper/chatroom/MessageNormalViewHolder.java b/app/src/main/java/chat/rocket/android/layouthelper/chatroom/MessageNormalViewHolder.java index 3a92037aee..0b754a10cc 100644 --- a/app/src/main/java/chat/rocket/android/layouthelper/chatroom/MessageNormalViewHolder.java +++ b/app/src/main/java/chat/rocket/android/layouthelper/chatroom/MessageNormalViewHolder.java @@ -29,7 +29,7 @@ public MessageNormalViewHolder(View itemView, AbsoluteUrl absoluteUrl, String ho @Override protected void bindMessage(PairedMessage pairedMessage, boolean autoloadImages) { MessageRenderer messageRenderer = new MessageRenderer(pairedMessage.target, autoloadImages); - messageRenderer.showAvatar(avatar, hostname, userNotFoundAvatarImageView, imageViewSvgUserAvatar); + messageRenderer.showAvatar(avatar, hostname, userNotFoundAvatarImageView); messageRenderer.showUsername(username, subUsername); messageRenderer.showTimestampOrMessageState(timestamp); messageRenderer.showBody(body); diff --git a/app/src/main/java/chat/rocket/android/layouthelper/chatroom/MessageSystemViewHolder.java b/app/src/main/java/chat/rocket/android/layouthelper/chatroom/MessageSystemViewHolder.java index 5aaf9db4d7..995577ad14 100644 --- a/app/src/main/java/chat/rocket/android/layouthelper/chatroom/MessageSystemViewHolder.java +++ b/app/src/main/java/chat/rocket/android/layouthelper/chatroom/MessageSystemViewHolder.java @@ -24,7 +24,7 @@ public MessageSystemViewHolder(View itemView, AbsoluteUrl absoluteUrl, String ho @Override protected void bindMessage(PairedMessage pairedMessage, boolean autoloadImages) { MessageRenderer messageRenderer = new MessageRenderer(pairedMessage.target, autoloadImages); - messageRenderer.showAvatar(avatar, hostname, userNotFoundAvatarImageView, imageViewSvgUserAvatar); + messageRenderer.showAvatar(avatar, hostname, userNotFoundAvatarImageView); messageRenderer.showUsername(username, subUsername); messageRenderer.showTimestampOrMessageState(timestamp); if (pairedMessage.target != null) { diff --git a/app/src/main/res/layout/list_item_normal_message.xml b/app/src/main/res/layout/list_item_normal_message.xml index 803f776413..50d9a0f6d5 100644 --- a/app/src/main/res/layout/list_item_normal_message.xml +++ b/app/src/main/res/layout/list_item_normal_message.xml @@ -28,13 +28,6 @@ app:srcCompat="@drawable/ic_user_not_found_avatar_black_24dp" android:visibility="gone" /> - - - - Date: Wed, 2 Aug 2017 18:55:24 -0300 Subject: [PATCH 14/29] Add placeholder image. --- .../android/renderer/MessageRenderer.kt | 35 ++++++--------- .../rocket/android/renderer/UserRenderer.kt | 2 +- .../android/widget/RocketChatAvatar.java | 19 ++++---- .../android/widget/helper/FrescoHelper.kt | 6 ++- .../autocomplete/user/UserViewHolder.java | 43 ++++++++++++++++++- 5 files changed, 69 insertions(+), 36 deletions(-) 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 0ecb1c4373..ea4a658649 100644 --- a/app/src/main/java/chat/rocket/android/renderer/MessageRenderer.kt +++ b/app/src/main/java/chat/rocket/android/renderer/MessageRenderer.kt @@ -5,7 +5,6 @@ import android.widget.ImageView import android.widget.TextView import chat.rocket.android.R import chat.rocket.android.helper.DateTime -import chat.rocket.android.helper.OkHttpHelper import chat.rocket.android.helper.RocketChatUserAvatar import chat.rocket.android.widget.AbsoluteUrl import chat.rocket.android.widget.RocketChatAvatar @@ -20,30 +19,20 @@ class MessageRenderer(val message: Message, val autoLoadImage: Boolean) { /** * Show user's avatar image in RocketChatAvatar widget. */ - fun showAvatar(rocketChatAvatarWidget: RocketChatAvatar, hostname: String, userNotFoundAvatarImageView: ImageView, userAvatarSvgImage: 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) { - userNotFoundAvatarImageView.visibility = View.GONE - val userAvatarUri = RocketChatUserAvatar.getUri(hostname, username) - val userAvatarImageContentType = OkHttpHelper.getContentType(userAvatarUri) - if (userAvatarImageContentType == "image/svg+xml") { - rocketChatAvatarWidget.visibility = View.GONE - userAvatarSvgImage.setImageDrawable(RocketChatUserAvatar.getTextDrawable(username, userAvatarSvgImage.context)) - userAvatarSvgImage.visibility = View.VISIBLE - } else { - userAvatarSvgImage.visibility = View.GONE - rocketChatAvatarWidget.loadImage(userAvatarUri) - rocketChatAvatarWidget.visibility = View.VISIBLE - } + fun showAvatar(rocketChatAvatarWidget: RocketChatAvatar, hostname: String, userNotFoundAvatarImageView: ImageView) { + val username: String? = message.user?.username + if (username != null) { + userNotFoundAvatarImageView.visibility = View.GONE + val placeholderDrawable = RocketChatUserAvatar.getTextDrawable(username, rocketChatAvatarWidget.context) + if (message.avatar != null) { + // Load user's avatar image from Oauth provider URI. + rocketChatAvatarWidget.loadImage(message.avatar, placeholderDrawable) } else { - userAvatarSvgImage.visibility = View.GONE - rocketChatAvatarWidget.visibility = View.GONE - userNotFoundAvatarImageView.visibility = View.VISIBLE + rocketChatAvatarWidget.loadImage(RocketChatUserAvatar.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 c288078de9..50630dc041 100644 --- a/app/src/main/java/chat/rocket/android/renderer/UserRenderer.kt +++ b/app/src/main/java/chat/rocket/android/renderer/UserRenderer.kt @@ -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.getUri(hostname, username)) + rocketChatAvatarWidget.loadImage(RocketChatUserAvatar.getUri(hostname, username), RocketChatUserAvatar.getTextDrawable(username, rocketChatAvatarWidget.context)) } else { rocketChatAvatarWidget.visibility = View.GONE } 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 479ea6ac40..057f46b916 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,35 +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) { + private void initialize(Context context) { LayoutInflater.from(context).inflate(R.layout.message_avatar, this, true); - draweeView = findViewById(R.id.drawee_avatar); + simpleDraweeViewAvatar = findViewById(R.id.drawee_avatar); } - public void loadImage(String imageUri) { - FrescoHelper.loadImage(draweeView, imageUri); + public void loadImage(String imageUri, Drawable placeholderDrawable) { + FrescoHelper.loadImage(simpleDraweeViewAvatar, imageUri, placeholderDrawable); } } \ No newline at end of file diff --git a/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/helper/FrescoHelper.kt b/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/helper/FrescoHelper.kt index ad48d0e71e..ba7ba2cfdc 100644 --- a/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/helper/FrescoHelper.kt +++ b/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/helper/FrescoHelper.kt @@ -1,5 +1,6 @@ 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 @@ -10,8 +11,9 @@ import com.facebook.drawee.view.SimpleDraweeView class FrescoHelper { companion object { - @JvmStatic fun loadImage(draweeView: SimpleDraweeView, imageUri: String) { - draweeView.setImageURI(imageUri) + @JvmStatic fun loadImage(simpleDraweeView: SimpleDraweeView, imageUri: String, placeholderDrawable: Drawable) { + simpleDraweeView.hierarchy.setPlaceholderImage(placeholderDrawable) + simpleDraweeView.controller = Fresco.newDraweeControllerBuilder().setUri(imageUri).setAutoPlayAnimations(true).build() } /** TODO 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..30a388b381 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,5 +1,8 @@ package chat.rocket.android.widget.message.autocomplete.user; +import android.content.Context; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; import android.view.View; import android.widget.ImageView; import android.widget.TextView; @@ -7,6 +10,7 @@ import chat.rocket.android.widget.R; import chat.rocket.android.widget.RocketChatAvatar; import chat.rocket.android.widget.message.autocomplete.AutocompleteViewHolder; +import com.amulyakhare.textdrawable.TextDrawable; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; @@ -16,6 +20,12 @@ public class UserViewHolder extends AutocompleteViewHolder { private final RocketChatAvatar avatar; private final ImageView status; + private static final int[] COLORS = new int[] { + 0xFFF44336, 0xFFE91E63, 0xFF9C27B0, 0xFF673AB7, 0xFF3F51B5, 0xFF2196F3, + 0xFF03A9F4, 0xFF00BCD4, 0xFF009688, 0xFF4CAF50, 0xFF8BC34A, 0xFFCDDC39, + 0xFFFFC107, 0xFFFF9800, 0xFFFF5722, 0xFF795548, 0xFF9E9E9E, 0xFF607D8B + }; + public UserViewHolder(View itemView, final AutocompleteViewHolder.OnClickListener onClickListener) { super(itemView); @@ -44,7 +54,7 @@ public void bind(UserItem userItem) { } if (avatar != null) { - avatar.loadImage(getImageUrl(suggestion, userItem.getAbsoluteUrl())); + avatar.loadImage(getImageUrl(suggestion, userItem.getAbsoluteUrl()), getTextDrawable(itemView.getContext(), suggestion)); } if (status != null) { @@ -73,4 +83,35 @@ private String getImageUrl(String username, AbsoluteUrl absoluteUrl) { return null; } } + + private Drawable getTextDrawable(Context context, String username) { + int round = (int) (4 * context.getResources().getDisplayMetrics().density); + + return TextDrawable.builder() + .beginConfig() + .useFont(Typeface.SANS_SERIF) + .endConfig() + .buildRoundRect(getUsernameInitials(username), getUserAvatarBackgroundColor(username), round); + } + + private String getUsernameInitials(String username) { + if (username.isEmpty()) { + return "?"; + } + + String[] splitUsername = username.split("."); + if (splitUsername.length > 1) { + return (splitUsername[0].substring(0, 1) + splitUsername[splitUsername.length - 1].substring(0, 1)).toUpperCase(); + } else { + if (username.length() > 1) { + return username.substring(0, 2).toUpperCase(); + } else { + return username.substring(0, 1).toUpperCase(); + } + } + } + + private int getUserAvatarBackgroundColor(String username) { + return COLORS[username.length() % COLORS.length]; + } } \ No newline at end of file From 52a0d836d3c60b858b61e42fe94662d635b697d3 Mon Sep 17 00:00:00 2001 From: Filipe de Lima Brito Date: Wed, 2 Aug 2017 18:56:23 -0300 Subject: [PATCH 15/29] Update message_avatar.xml --- .../src/main/res/layout/message_avatar.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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..9e022c4642 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 From 827ada1b398a4c307743dbdeb1fb82dd7cb59f13 Mon Sep 17 00:00:00 2001 From: Filipe de Lima Brito Date: Wed, 2 Aug 2017 18:57:06 -0300 Subject: [PATCH 16/29] Disable SVG support. --- .../java/chat/rocket/android/widget/RocketChatWidgets.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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..23d49e4143 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 @@ -18,6 +18,11 @@ public class RocketChatWidgets { + /** + * TODO + * The SVG support (by setImageDecoderConfig method) should be enabled after RC servers are stable. + * Info about that: https://github.com/RocketChat/Rocket.Chat/pull/7572 + */ public static void initialize(Context context, OkHttpClient okHttpClient) { FLog.setMinimumLoggingLevel(FLog.VERBOSE); Set listeners = new HashSet<>(); @@ -26,7 +31,7 @@ public static void initialize(Context context, OkHttpClient okHttpClient) { ImagePipelineConfig imagePipelineConfig = OkHttpImagePipelineConfigFactory .newBuilder(context, okHttpClient) .setRequestListeners(listeners) - .setImageDecoderConfig(CustomImageFormatConfigurator.createImageDecoderConfig()) +// .setImageDecoderConfig(CustomImageFormatConfigurator.createImageDecoderConfig()) .setDownsampleEnabled(true) .experiment().setBitmapPrepareToDraw(true) .experiment().setPartialImageCachingEnabled(true) From 60074daf411ac5a8c54778bc34eb32c1c53c4750 Mon Sep 17 00:00:00 2001 From: Filipe de Lima Brito Date: Wed, 2 Aug 2017 18:57:26 -0300 Subject: [PATCH 17/29] Delete blank line. --- app/src/test/kotlin/RocketChatUserAvatarTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/test/kotlin/RocketChatUserAvatarTest.kt b/app/src/test/kotlin/RocketChatUserAvatarTest.kt index 0ca6fb3bc9..8d4add8eff 100644 --- a/app/src/test/kotlin/RocketChatUserAvatarTest.kt +++ b/app/src/test/kotlin/RocketChatUserAvatarTest.kt @@ -19,4 +19,4 @@ class RocketChatUserAvatarTest { assert(RocketChatUserAvatar.getUsernameInitials("Foobar.bar") == "FB") assert(RocketChatUserAvatar.getUsernameInitials("Foobar.bar.zab") == "FZ") } -} +} \ No newline at end of file From 8b18a0f2b47656d70a9bde11d7e4de37b40fe492 Mon Sep 17 00:00:00 2001 From: Filipe de Lima Brito Date: Wed, 2 Aug 2017 23:11:51 -0300 Subject: [PATCH 18/29] Delete RocketChatUserAvatar and RocketChatUserAvatarTest class. --- .../android/helper/RocketChatUserAvatar.kt | 95 ------------------- .../test/kotlin/RocketChatUserAvatarTest.kt | 22 ----- 2 files changed, 117 deletions(-) delete mode 100644 app/src/main/java/chat/rocket/android/helper/RocketChatUserAvatar.kt delete mode 100644 app/src/test/kotlin/RocketChatUserAvatarTest.kt 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 c2f8525476..0000000000 --- a/app/src/main/java/chat/rocket/android/helper/RocketChatUserAvatar.kt +++ /dev/null @@ -1,95 +0,0 @@ -package chat.rocket.android.helper - -import android.content.Context -import android.graphics.Typeface -import android.graphics.drawable.Drawable -import com.amulyakhare.textdrawable.TextDrawable -import java.net.URLEncoder - -object RocketChatUserAvatar { - - /** - * 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. - * @see getImageFormat - */ - fun getUri(hostname : String, username: String): String { - return "https://" + - hostname.replace("http://", "").replace("https://", "") + - "/avatar/" + - URLEncoder.encode(username, "UTF-8") - } - - /** - * Returns the user avatar image format. - * - * @param uri The user avatar image URI to get the image format. - * @return The user avatar image format. Possible values are: "image/jpeg", "image/png" and "image/svg+xml". - * @see getUri - */ - fun getImageFormat(uri: String): String { - return OkHttpHelper.getContentType(uri) - } - - /** - * 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 diff --git a/app/src/test/kotlin/RocketChatUserAvatarTest.kt b/app/src/test/kotlin/RocketChatUserAvatarTest.kt deleted file mode 100644 index 8d4add8eff..0000000000 --- a/app/src/test/kotlin/RocketChatUserAvatarTest.kt +++ /dev/null @@ -1,22 +0,0 @@ -import chat.rocket.android.helper.RocketChatUserAvatar -import org.junit.Test - -class RocketChatUserAvatarTest { - - @Test - fun getUsernameInitialsTest() { - assert(RocketChatUserAvatar.getUsernameInitials("") == "?") - assert(RocketChatUserAvatar.getUsernameInitials("?") == "?") - assert(RocketChatUserAvatar.getUsernameInitials("f") == "F") - assert(RocketChatUserAvatar.getUsernameInitials("B") == "B") - assert(RocketChatUserAvatar.getUsernameInitials("fo") == "FO") - assert(RocketChatUserAvatar.getUsernameInitials("FO") == "FO") - assert(RocketChatUserAvatar.getUsernameInitials("fOo") == "FO") - assert(RocketChatUserAvatar.getUsernameInitials("FOO") == "FO") - assert(RocketChatUserAvatar.getUsernameInitials("F.O") == "FO") - assert(RocketChatUserAvatar.getUsernameInitials("F.o") == "FO") - assert(RocketChatUserAvatar.getUsernameInitials("Foo.bar") == "FB") - assert(RocketChatUserAvatar.getUsernameInitials("Foobar.bar") == "FB") - assert(RocketChatUserAvatar.getUsernameInitials("Foobar.bar.zab") == "FZ") - } -} \ No newline at end of file From 3756ee1c97d41aed5508bb9e3be4c8e6450f49f1 Mon Sep 17 00:00:00 2001 From: Filipe de Lima Brito Date: Wed, 2 Aug 2017 23:12:34 -0300 Subject: [PATCH 19/29] Update build.gradle --- app/build.gradle | 7 ------- rocket-chat-android-widgets/build.gradle | 8 ++++++++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index eeeee49f14..33e25c03f9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -60,11 +60,6 @@ android { } } - sourceSets { - test.java.srcDirs += 'src/test/kotlin' - androidTest.java.srcDirs += 'src/androidTest/kotlin' - } - packagingOptions { exclude 'META-INF/LICENSE.txt' exclude 'META-INF/NOTICE.txt' @@ -110,8 +105,6 @@ dependencies { compile 'com.android.support:multidex:1.0.1' 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 "com.google.firebase:firebase-core:$playLibVersion" compile "com.google.firebase:firebase-crash:$playLibVersion" 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' From 1cdd442dcc38bc1382055659cd8ee9ca303c3992 Mon Sep 17 00:00:00 2001 From: Filipe de Lima Brito Date: Wed, 2 Aug 2017 23:13:05 -0300 Subject: [PATCH 20/29] Add UserAvatarHelper and UserAvatarHelperTest class. --- .../android/widget/helper/UserAvatarHelper.kt | 98 +++++++++++++++++++ .../src/test/kotlin/UserAvatarHelperTest.kt | 22 +++++ 2 files changed, 120 insertions(+) create mode 100644 rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/helper/UserAvatarHelper.kt create mode 100644 rocket-chat-android-widgets/src/test/kotlin/UserAvatarHelperTest.kt diff --git a/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/helper/UserAvatarHelper.kt b/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/helper/UserAvatarHelper.kt new file mode 100644 index 0000000000..590479b8d8 --- /dev/null +++ b/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/helper/UserAvatarHelper.kt @@ -0,0 +1,98 @@ +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 diff --git a/rocket-chat-android-widgets/src/test/kotlin/UserAvatarHelperTest.kt b/rocket-chat-android-widgets/src/test/kotlin/UserAvatarHelperTest.kt new file mode 100644 index 0000000000..f0c4ee4952 --- /dev/null +++ b/rocket-chat-android-widgets/src/test/kotlin/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 From 5efbd8ed659903588fbce3085f55e5bffe851eda Mon Sep 17 00:00:00 2001 From: Filipe de Lima Brito Date: Wed, 2 Aug 2017 23:15:51 -0300 Subject: [PATCH 21/29] Delete classes. --- .../android/widget/fresco/ColorImage.java | 187 ------------------ .../fresco/CustomImageFormatConfigurator.java | 24 --- .../android/widget/fresco/SvgDecoder.java | 144 -------------- 3 files changed, 355 deletions(-) delete mode 100644 rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/fresco/ColorImage.java delete mode 100644 rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/fresco/CustomImageFormatConfigurator.java delete mode 100644 rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/fresco/SvgDecoder.java 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 = " Date: Wed, 2 Aug 2017 23:16:21 -0300 Subject: [PATCH 22/29] Update RocketChatWidgets.java --- .../rocket/android/widget/RocketChatWidgets.java | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) 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 23d49e4143..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,16 +12,10 @@ import java.util.HashSet; import java.util.Set; -import chat.rocket.android.widget.fresco.CustomImageFormatConfigurator; import okhttp3.OkHttpClient; public class RocketChatWidgets { - /** - * TODO - * The SVG support (by setImageDecoderConfig method) should be enabled after RC servers are stable. - * Info about that: https://github.com/RocketChat/Rocket.Chat/pull/7572 - */ public static void initialize(Context context, OkHttpClient okHttpClient) { FLog.setMinimumLoggingLevel(FLog.VERBOSE); Set listeners = new HashSet<>(); @@ -31,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 From 3e43f04a9eb22e7c2042b781654fe3ecb4339961 Mon Sep 17 00:00:00 2001 From: Filipe de Lima Brito Date: Wed, 2 Aug 2017 23:16:56 -0300 Subject: [PATCH 23/29] Update FrescoHelper class. --- .../android/widget/helper/FrescoHelper.kt | 57 +++++++++---------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/helper/FrescoHelper.kt b/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/helper/FrescoHelper.kt index ba7ba2cfdc..8023a3b2f4 100644 --- a/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/helper/FrescoHelper.kt +++ b/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/helper/FrescoHelper.kt @@ -9,37 +9,36 @@ 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(simpleDraweeView: SimpleDraweeView, imageUri: String, placeholderDrawable: Drawable) { - simpleDraweeView.hierarchy.setPlaceholderImage(placeholderDrawable) - simpleDraweeView.controller = Fresco.newDraweeControllerBuilder().setUri(imageUri).setAutoPlayAnimations(true).build() - } +object FrescoHelper { - /** TODO - * Replace with: - * @JvmStatic fun loadImageWithCustomization(draweeView: SimpleDraweeView, - * imageUri: String, - * placeholderImageDrawableId : Int = R.drawable.image_dummy, - 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) { - 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.setProgressBarImage(ProgressBarDrawable()) + fun loadImage(simpleDraweeView: SimpleDraweeView, imageUri: String, placeholderDrawable: Drawable) { + simpleDraweeView.hierarchy.setPlaceholderImage(placeholderDrawable) + simpleDraweeView.controller = Fresco.newDraweeControllerBuilder().setUri(imageUri).setAutoPlayAnimations(true).build() + } + + /** TODO + * Replace with: + * fun loadImageWithCustomization(draweeView: SimpleDraweeView, + * imageUri: String, + * placeholderImageDrawableId : Int = R.drawable.image_dummy, + * 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. + */ + 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)) + hierarchy.setProgressBarImage(ProgressBarDrawable()) - val controller = Fresco.newDraweeControllerBuilder() - .setUri(Uri.parse(imageUri)) - .setAutoPlayAnimations(true) - .setTapToRetryEnabled(true) - .build() + val controller = Fresco.newDraweeControllerBuilder() + .setUri(Uri.parse(imageUri)) + .setAutoPlayAnimations(true) + .setTapToRetryEnabled(true) + .build() - draweeView.controller = controller - } + draweeView.controller = controller } } \ No newline at end of file From 8471796e6c5ef05733a18814d4f0c705d45622ce Mon Sep 17 00:00:00 2001 From: Filipe de Lima Brito Date: Wed, 2 Aug 2017 23:17:17 -0300 Subject: [PATCH 24/29] Update UserViewHolder class. --- .../autocomplete/user/UserViewHolder.java | 61 ++----------------- 1 file changed, 4 insertions(+), 57 deletions(-) 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 30a388b381..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,7 +1,5 @@ package chat.rocket.android.widget.message.autocomplete.user; -import android.content.Context; -import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.view.View; import android.widget.ImageView; @@ -9,23 +7,16 @@ 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 com.amulyakhare.textdrawable.TextDrawable; 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; - private static final int[] COLORS = new int[] { - 0xFFF44336, 0xFFE91E63, 0xFF9C27B0, 0xFF673AB7, 0xFF3F51B5, 0xFF2196F3, - 0xFF03A9F4, 0xFF00BCD4, 0xFF009688, 0xFF4CAF50, 0xFF8BC34A, 0xFFCDDC39, - 0xFFFFC107, 0xFFFF9800, 0xFFFF5722, 0xFF795548, 0xFF9E9E9E, 0xFF607D8B - }; - public UserViewHolder(View itemView, final AutocompleteViewHolder.OnClickListener onClickListener) { super(itemView); @@ -54,7 +45,9 @@ public void bind(UserItem userItem) { } if (avatar != null) { - avatar.loadImage(getImageUrl(suggestion, userItem.getAbsoluteUrl()), getTextDrawable(itemView.getContext(), suggestion)); + String absoluteUri = UserAvatarHelper.INSTANCE.getAbsoluteUri(userItem.getAbsoluteUrl(), suggestion); + Drawable placeholderDrawable = UserAvatarHelper.INSTANCE.getTextDrawable(suggestion, itemView.getContext()); + avatar.loadImage(absoluteUri, placeholderDrawable); } if (status != null) { @@ -68,50 +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; - } - } - - private Drawable getTextDrawable(Context context, String username) { - int round = (int) (4 * context.getResources().getDisplayMetrics().density); - - return TextDrawable.builder() - .beginConfig() - .useFont(Typeface.SANS_SERIF) - .endConfig() - .buildRoundRect(getUsernameInitials(username), getUserAvatarBackgroundColor(username), round); - } - - private String getUsernameInitials(String username) { - if (username.isEmpty()) { - return "?"; - } - - String[] splitUsername = username.split("."); - if (splitUsername.length > 1) { - return (splitUsername[0].substring(0, 1) + splitUsername[splitUsername.length - 1].substring(0, 1)).toUpperCase(); - } else { - if (username.length() > 1) { - return username.substring(0, 2).toUpperCase(); - } else { - return username.substring(0, 1).toUpperCase(); - } - } - } - - private int getUserAvatarBackgroundColor(String username) { - return COLORS[username.length() % COLORS.length]; - } } \ No newline at end of file From 539016644cd36a458b0bf878268ac41efad418a8 Mon Sep 17 00:00:00 2001 From: Filipe de Lima Brito Date: Wed, 2 Aug 2017 23:18:13 -0300 Subject: [PATCH 25/29] Update classes. --- .../chat/rocket/android/renderer/MessageRenderer.kt | 6 +++--- .../chat/rocket/android/renderer/UserRenderer.kt | 4 ++-- .../chat/rocket/android/widget/RocketChatAvatar.java | 2 +- .../message/RocketChatMessageAttachmentsLayout.java | 12 ++++-------- .../widget/message/RocketChatMessageUrlsLayout.java | 9 +++------ 5 files changed, 13 insertions(+), 20 deletions(-) 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 ea4a658649..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 @@ -23,12 +23,12 @@ class MessageRenderer(val message: Message, val autoLoadImage: Boolean) { val username: String? = message.user?.username if (username != null) { userNotFoundAvatarImageView.visibility = View.GONE - val placeholderDrawable = RocketChatUserAvatar.getTextDrawable(username, rocketChatAvatarWidget.context) + 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(RocketChatUserAvatar.getUri(hostname, username), placeholderDrawable) + rocketChatAvatarWidget.loadImage(UserAvatarHelper.getUri(hostname, username), placeholderDrawable) } } else { rocketChatAvatarWidget.visibility = View.GONE 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 50630dc041..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.getUri(hostname, username), RocketChatUserAvatar.getTextDrawable(username, rocketChatAvatarWidget.context)) + rocketChatAvatarWidget.loadImage(UserAvatarHelper.getUri(hostname, username), UserAvatarHelper.getTextDrawable(username, rocketChatAvatarWidget.context)) } else { rocketChatAvatarWidget.visibility = View.GONE } 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 057f46b916..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 @@ -41,6 +41,6 @@ private void initialize(Context context) { } public void loadImage(String imageUri, Drawable placeholderDrawable) { - FrescoHelper.loadImage(simpleDraweeViewAvatar, imageUri, 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/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); } }); } From c9975c10c5a3c90ab74c3b1930cc1631ca103d36 Mon Sep 17 00:00:00 2001 From: Filipe de Lima Brito Date: Thu, 3 Aug 2017 11:01:37 -0300 Subject: [PATCH 26/29] Update UserAvatarHelper.kt --- .../java/chat/rocket/android/widget/helper/UserAvatarHelper.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/helper/UserAvatarHelper.kt b/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/helper/UserAvatarHelper.kt index 590479b8d8..94026b3da6 100644 --- a/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/helper/UserAvatarHelper.kt +++ b/rocket-chat-android-widgets/src/main/java/chat/rocket/android/widget/helper/UserAvatarHelper.kt @@ -58,7 +58,7 @@ object UserAvatarHelper { } /** - * Returns a string with the username initials. For example: username John Doe returns JD initials. + * 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. From d07d6f95c8a908846865615f09cc67c913f5ff25 Mon Sep 17 00:00:00 2001 From: Filipe de Lima Brito Date: Thu, 3 Aug 2017 11:01:54 -0300 Subject: [PATCH 27/29] Update message_avatar.xml --- .../src/main/res/layout/message_avatar.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 9e022c4642..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 From 7a81eb12465bc0d6b4dc06f012d59e360b464e52 Mon Sep 17 00:00:00 2001 From: Filipe de Lima Brito Date: Thu, 3 Aug 2017 11:02:44 -0300 Subject: [PATCH 28/29] Update package. --- .../rocket/android/widget/helper}/UserAvatarHelperTest.kt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename rocket-chat-android-widgets/src/test/kotlin/{ => chat/rocket/android/widget/helper}/UserAvatarHelperTest.kt (100%) diff --git a/rocket-chat-android-widgets/src/test/kotlin/UserAvatarHelperTest.kt b/rocket-chat-android-widgets/src/test/kotlin/chat/rocket/android/widget/helper/UserAvatarHelperTest.kt similarity index 100% rename from rocket-chat-android-widgets/src/test/kotlin/UserAvatarHelperTest.kt rename to rocket-chat-android-widgets/src/test/kotlin/chat/rocket/android/widget/helper/UserAvatarHelperTest.kt From 9b37d89369236a0c114063b3f43b2b2966282329 Mon Sep 17 00:00:00 2001 From: Filipe de Lima Brito Date: Thu, 3 Aug 2017 17:42:09 -0300 Subject: [PATCH 29/29] Delete unused methods. --- .../rocket/android/helper/OkHttpHelper.java | 41 +------------------ 1 file changed, 1 insertion(+), 40 deletions(-) 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 a57e879740..dfdc9b8304 100644 --- a/app/src/main/java/chat/rocket/android/helper/OkHttpHelper.java +++ b/app/src/main/java/chat/rocket/android/helper/OkHttpHelper.java @@ -1,36 +1,21 @@ package chat.rocket.android.helper; import android.content.Context; -import android.support.annotation.NonNull; import com.facebook.stetho.okhttp3.StethoInterceptor; -import java.io.IOException; import java.util.concurrent.TimeUnit; import chat.rocket.android.RocketChatCache; import chat.rocket.android.api.rest.CookieInterceptor; import chat.rocket.android.api.rest.DefaultCookieProvider; -import okhttp3.Call; -import okhttp3.Callback; import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; /** * Helper class for OkHttp client. */ public class OkHttpHelper { - private static OkHttpClient defaultHttpClient; private static OkHttpClient httpClientForUploadFile; private static OkHttpClient httpClientForDownloadFile; private static OkHttpClient httpClientForWS; - private static String contentType; - - public static OkHttpClient getDefaultHttpClient() { - if (defaultHttpClient == null) { - defaultHttpClient = new OkHttpClient(); - } - return defaultHttpClient; - } public static OkHttpClient getClientForDownloadFile(Context context) { if (httpClientForDownloadFile == null) { @@ -63,28 +48,4 @@ public static OkHttpClient getClientForWebSocket() { } return httpClientForWS; } - - public static String getContentType(String uri) { - Request request = new Request.Builder() - .url(uri) - .head() - .build(); - getDefaultHttpClient().newCall(request).enqueue(new Callback() { - @Override - public void onFailure(@NonNull Call call, @NonNull IOException ioException) { - ioException.printStackTrace(); - } - - @Override - public void onResponse(@NonNull Call call, @NonNull final Response response) - throws IOException { - if (!response.isSuccessful()) { - throw new IOException("Unexpected code: " + response); - } else { - contentType = response.header("Content-Type"); - } - } - }); - return contentType; - } -} +} \ No newline at end of file