Commit 11a70451 authored by Rafael Kellermann Streit's avatar Rafael Kellermann Streit Committed by GitHub

Merge branch 'develop' into fix/websocket-drops-keeping-bolts

parents 3827fdf0 e33a2b19
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'me.tatarka.retrolambda' apply plugin: 'me.tatarka.retrolambda'
apply plugin: 'com.jakewharton.hugo' apply plugin: 'com.jakewharton.hugo'
apply plugin: 'com.github.triplet.play' apply plugin: 'com.github.triplet.play'
...@@ -11,6 +12,7 @@ buildscript { ...@@ -11,6 +12,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:2.3.3' classpath 'com.android.tools.build:gradle:2.3.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$rootProject.ext.kotlinVersion"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files
...@@ -92,12 +94,12 @@ dependencies { ...@@ -92,12 +94,12 @@ dependencies {
compile "com.android.support:appcompat-v7:$rootProject.ext.supportLibraryVersion" compile "com.android.support:appcompat-v7:$rootProject.ext.supportLibraryVersion"
compile "com.android.support:design:$rootProject.ext.supportLibraryVersion" compile "com.android.support:design:$rootProject.ext.supportLibraryVersion"
compile "com.android.support:support-annotations:$rootProject.ext.supportLibraryVersion" compile "com.android.support:support-annotations:$rootProject.ext.supportLibraryVersion"
compile 'com.android.support.constraint:constraint-layout:1.0.2' compile 'com.android.support.constraint:constraint-layout:1.0.2'
compile 'com.android.support:multidex:1.0.1' compile 'com.android.support:multidex:1.0.1'
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$rootProject.ext.kotlinVersion"
compile "com.google.firebase:firebase-core:$playLibVersion" compile "com.google.firebase:firebase-core:$playLibVersion"
compile "com.google.firebase:firebase-crash:$playLibVersion" compile "com.google.firebase:firebase-crash:$playLibVersion"
......
...@@ -225,7 +225,7 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain ...@@ -225,7 +225,7 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain
private void onRenderCurrentUser(User user, RocketChatAbsoluteUrl absoluteUrl) { private void onRenderCurrentUser(User user, RocketChatAbsoluteUrl absoluteUrl) {
if (user != null && absoluteUrl != null) { if (user != null && absoluteUrl != null) {
new UserRenderer(getContext(), user) new UserRenderer(getContext(), user)
.avatarInto(rootView.findViewById(R.id.current_user_avatar), absoluteUrl, false) .avatarInto(rootView.findViewById(R.id.current_user_avatar), absoluteUrl)
.usernameInto(rootView.findViewById(R.id.current_user_name)) .usernameInto(rootView.findViewById(R.id.current_user_name))
.statusColorInto(rootView.findViewById(R.id.current_user_status)); .statusColorInto(rootView.findViewById(R.id.current_user_status));
} }
......
package chat.rocket.android.helper;
import chat.rocket.android.log.RCLog;
import chat.rocket.android.widget.AbsoluteUrl;
import chat.rocket.android.widget.RocketChatAvatar;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
/**
* Helper for rendering user avatar image.
*/
public class Avatar {
private final AbsoluteUrl absoluteUrl;
private final String username;
public Avatar(AbsoluteUrl absoluteUrl, String username) {
this.absoluteUrl = absoluteUrl;
this.username = username;
}
private String getImageUrl() {
//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");
if (absoluteUrl == null) {
return avatarUrl;
}
return absoluteUrl.from(avatarUrl);
} catch (UnsupportedEncodingException exception) {
RCLog.e(exception, "failed to get URL for user: %s", username);
return null;
}
}
/**
* render avatar into RocketChatAvatar.
*/
public void into(final RocketChatAvatar rocketChatAvatar, boolean showFailureImage) {
if (showFailureImage) {
rocketChatAvatar.showFailureImage();
} else {
rocketChatAvatar.loadImage(getImageUrl());
}
}
}
\ No newline at end of file
package chat.rocket.android.helper
import chat.rocket.android.widget.AbsoluteUrl
import chat.rocket.android.widget.RocketChatAvatar
import java.net.URLEncoder
class Avatar(val absoluteUrl: AbsoluteUrl?, val username: String) {
val imageUrl: String
/** REMARK
* This is often a SVG image (see Rocket.Chat:server/startup/avatar.js)
*/
get() {
val avatarUrl = "/avatar/" + URLEncoder.encode(username, "UTF-8")
if (absoluteUrl == null) {
return avatarUrl
}
return absoluteUrl.from("/avatar/" + URLEncoder.encode(username, "UTF-8"))
}
/**
* render avatar into RocketChatAvatar.
*/
fun into(rocketChatAvatar: RocketChatAvatar) {
rocketChatAvatar.loadImage(imageUrl)
}
}
\ No newline at end of file
...@@ -2,6 +2,7 @@ package chat.rocket.android.layouthelper.chatroom; ...@@ -2,6 +2,7 @@ package chat.rocket.android.layouthelper.chatroom;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.view.View; import android.view.View;
import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import chat.rocket.android.R; import chat.rocket.android.R;
import chat.rocket.android.helper.DateTime; import chat.rocket.android.helper.DateTime;
...@@ -12,6 +13,7 @@ import chat.rocket.core.SyncState; ...@@ -12,6 +13,7 @@ import chat.rocket.core.SyncState;
public abstract class AbstractMessageViewHolder extends ModelViewHolder<PairedMessage> { public abstract class AbstractMessageViewHolder extends ModelViewHolder<PairedMessage> {
protected final RocketChatAvatar avatar; protected final RocketChatAvatar avatar;
protected final ImageView errorImageView;
protected final TextView username; protected final TextView username;
protected final TextView subUsername; protected final TextView subUsername;
protected final TextView timestamp; protected final TextView timestamp;
...@@ -26,6 +28,7 @@ public abstract class AbstractMessageViewHolder extends ModelViewHolder<PairedMe ...@@ -26,6 +28,7 @@ public abstract class AbstractMessageViewHolder extends ModelViewHolder<PairedMe
public AbstractMessageViewHolder(View itemView, AbsoluteUrl absoluteUrl) { public AbstractMessageViewHolder(View itemView, AbsoluteUrl absoluteUrl) {
super(itemView); super(itemView);
avatar = itemView.findViewById(R.id.user_avatar); avatar = itemView.findViewById(R.id.user_avatar);
errorImageView = itemView.findViewById(R.id.errorImageView);
username = itemView.findViewById(R.id.username); username = itemView.findViewById(R.id.username);
subUsername = itemView.findViewById(R.id.sub_username); subUsername = itemView.findViewById(R.id.sub_username);
timestamp = itemView.findViewById(R.id.timestamp); timestamp = itemView.findViewById(R.id.timestamp);
...@@ -39,11 +42,10 @@ public abstract class AbstractMessageViewHolder extends ModelViewHolder<PairedMe ...@@ -39,11 +42,10 @@ public abstract class AbstractMessageViewHolder extends ModelViewHolder<PairedMe
* bind the view model. * bind the view model.
*/ */
public final void bind(PairedMessage pairedMessage, boolean autoloadImages) { public final void bind(PairedMessage pairedMessage, boolean autoloadImages) {
if (pairedMessage.target.getSyncState() != SyncState.SYNCED) { if (pairedMessage.target.getSyncState() == SyncState.FAILED) {
itemView.setAlpha(0.6f); errorImageView.setVisibility(View.VISIBLE);
} } else {
else { errorImageView.setVisibility(View.GONE);
itemView.setAlpha(1.0f);
} }
bindMessage(pairedMessage, autoloadImages); bindMessage(pairedMessage, autoloadImages);
...@@ -69,10 +71,11 @@ public abstract class AbstractMessageViewHolder extends ModelViewHolder<PairedMe ...@@ -69,10 +71,11 @@ public abstract class AbstractMessageViewHolder extends ModelViewHolder<PairedMe
private void setSequential(boolean sequential) { private void setSequential(boolean sequential) {
if (avatar != null) { if (avatar != null) {
if (sequential) if (sequential) {
avatar.setVisibility(View.GONE); avatar.setVisibility(View.GONE);
else } else {
avatar.setVisibility(View.VISIBLE); avatar.setVisibility(View.VISIBLE);
}
} }
if (userAndTimeContainer != null) { if (userAndTimeContainer != null) {
......
...@@ -58,12 +58,12 @@ public class RoomUserAdapter extends RecyclerView.Adapter<RoomUserViewHolder> { ...@@ -58,12 +58,12 @@ public class RoomUserAdapter extends RecyclerView.Adapter<RoomUserViewHolder> {
.setUtcOffset(0) .setUtcOffset(0)
.build(); .build();
new UserRenderer(context, user) new UserRenderer(context, user)
.avatarInto(holder.avatar, absoluteUrl, false) .avatarInto(holder.avatar, absoluteUrl)
.usernameInto(holder.username); .usernameInto(holder.username);
} else { } else {
new UserRenderer(context, realmUser.asUser()) new UserRenderer(context, realmUser.asUser())
.statusColorInto(holder.status) .statusColorInto(holder.status)
.avatarInto(holder.avatar, absoluteUrl, false) .avatarInto(holder.avatar, absoluteUrl)
.usernameInto(holder.username); .usernameInto(holder.username);
} }
} }
......
...@@ -2,7 +2,6 @@ package chat.rocket.android.layouthelper.sidebar.dialog; ...@@ -2,7 +2,6 @@ package chat.rocket.android.layouthelper.sidebar.dialog;
import android.content.Context; import android.content.Context;
import android.view.View; import android.view.View;
import android.widget.ImageView;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
...@@ -11,7 +10,6 @@ import chat.rocket.android.widget.AbsoluteUrl; ...@@ -11,7 +10,6 @@ import chat.rocket.android.widget.AbsoluteUrl;
import chat.rocket.persistence.realm.models.ddp.RealmUser; import chat.rocket.persistence.realm.models.ddp.RealmUser;
import chat.rocket.persistence.realm.RealmAutoCompleteAdapter; import chat.rocket.persistence.realm.RealmAutoCompleteAdapter;
import chat.rocket.android.renderer.UserRenderer; import chat.rocket.android.renderer.UserRenderer;
import chat.rocket.android.widget.RocketChatAvatar;
/** /**
* adapter to suggest user names. * adapter to suggest user names.
...@@ -27,8 +25,8 @@ public class SuggestUserAdapter extends RealmAutoCompleteAdapter<RealmUser> { ...@@ -27,8 +25,8 @@ public class SuggestUserAdapter extends RealmAutoCompleteAdapter<RealmUser> {
@Override @Override
protected void onBindItemView(View itemView, RealmUser user) { protected void onBindItemView(View itemView, RealmUser user) {
new UserRenderer(itemView.getContext(), user.asUser()) new UserRenderer(itemView.getContext(), user.asUser())
.statusColorInto((ImageView) itemView.findViewById(R.id.room_user_status)) .statusColorInto(itemView.findViewById(R.id.room_user_status))
.avatarInto((RocketChatAvatar) itemView.findViewById(R.id.room_user_avatar), absoluteUrl, false); .avatarInto(itemView.findViewById(R.id.room_user_avatar), absoluteUrl);
} }
@Override @Override
......
...@@ -21,7 +21,6 @@ import java.util.List; ...@@ -21,7 +21,6 @@ import java.util.List;
* Renderer for RealmMessage model. * Renderer for RealmMessage model.
*/ */
public class MessageRenderer extends AbstractRenderer<Message> { public class MessageRenderer extends AbstractRenderer<Message> {
private final UserRenderer userRenderer; private final UserRenderer userRenderer;
private final boolean autoloadImages; private final boolean autoloadImages;
...@@ -39,17 +38,11 @@ public class MessageRenderer extends AbstractRenderer<Message> { ...@@ -39,17 +38,11 @@ public class MessageRenderer extends AbstractRenderer<Message> {
return this; return this;
} }
switch (object.getSyncState()){ if (TextUtils.isEmpty(object.getAvatar())) {
case SyncState.FAILED: userRenderer.avatarInto(rocketChatAvatar, absoluteUrl);
userRenderer.avatarInto(rocketChatAvatar, absoluteUrl, true); // Avatar from oauth providers
break; } else {
default: rocketChatAvatar.loadImage(object.getAvatar());
if (TextUtils.isEmpty(object.getAvatar())) {
userRenderer.avatarInto(rocketChatAvatar, absoluteUrl, false);
} else {
rocketChatAvatar.loadImage(object.getAvatar());
}
break;
} }
return this; return this;
} }
......
...@@ -21,14 +21,14 @@ public class UserRenderer extends AbstractRenderer<User> { ...@@ -21,14 +21,14 @@ public class UserRenderer extends AbstractRenderer<User> {
/** /**
* show Avatar image * show Avatar image
*/ */
public UserRenderer avatarInto(RocketChatAvatar rocketChatAvatar, AbsoluteUrl absoluteUrl, boolean showFailureImage) { public UserRenderer avatarInto(RocketChatAvatar rocketChatAvatar, AbsoluteUrl absoluteUrl) {
if (!shouldHandle(rocketChatAvatar)) { if (!shouldHandle(rocketChatAvatar)) {
return this; return this;
} }
if (!TextUtils.isEmpty(object.getUsername())) { if (!TextUtils.isEmpty(object.getUsername())) {
new Avatar(absoluteUrl, object.getUsername()) new Avatar(absoluteUrl, object.getUsername())
.into(rocketChatAvatar, showFailureImage); .into(rocketChatAvatar);
} }
return this; return this;
} }
......
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:viewportWidth="24.0"> android:viewportHeight="24.0">
<path <path
android:fillColor="#C2D1DA" android:fillColor="#FF000000"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-2h2v2zM13,13h-2L11,7h2v6z"/> android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-2h2v2zM13,13h-2L11,7h2v6z"/>
</vector> </vector>
\ No newline at end of file
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
android:id="@+id/activity_main_container" android:id="@+id/activity_main_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@color/white" android:background="@android:color/white"
app:layout_behavior="@string/appbar_scrolling_view_behavior" /> app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout> </android.support.design.widget.CoordinatorLayout>
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:background="@color/white" android:background="@android:color/white"
android:minWidth="288dp" android:minWidth="288dp"
android:orientation="vertical" android:orientation="vertical"
android:padding="@dimen/margin_24"> android:padding="@dimen/margin_24">
......
...@@ -5,15 +5,16 @@ ...@@ -5,15 +5,16 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView <android.support.v7.widget.RecyclerView
android:id="@+id/messageRecyclerView" android:id="@+id/messageRecyclerView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_above="@+id/messageComposer" /> android:scrollbars="vertical"
android:layout_above="@+id/messageComposer" />
<chat.rocket.android.widget.message.MessageFormLayout <chat.rocket.android.widget.message.MessageFormLayout
android:id="@+id/messageComposer" android:id="@+id/messageComposer"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentBottom="true" android:layout_alignParentBottom="true"
android:theme="@style/Theme.AppCompat.Light" /> android:theme="@style/Theme.AppCompat.Light" />
</RelativeLayout> </RelativeLayout>
\ No newline at end of file
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:background="@color/white" android:background="@android:color/white"
android:minWidth="288dp" android:minWidth="288dp"
android:orientation="vertical" android:orientation="vertical"
android:padding="@dimen/margin_24"> android:padding="@dimen/margin_24">
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" xmlns:tools="http://schemas.android.com/tools"
android:layout_height="wrap_content" android:layout_width="match_parent"
android:orientation="vertical" android:layout_height="wrap_content"
android:theme="@style/AppTheme"> android:orientation="vertical"
android:theme="@style/AppTheme">
<include layout="@layout/list_item_message_newday" /> <include layout="@layout/list_item_message_newday" />
<FrameLayout <FrameLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="2dp"> android:layout_marginBottom="2dp">
<chat.rocket.android.widget.RocketChatAvatar <chat.rocket.android.widget.RocketChatAvatar
android:id="@+id/user_avatar" android:id="@+id/user_avatar"
android:layout_width="32dp" android:layout_width="32dp"
android:layout_height="32dp" android:layout_height="32dp"
android:layout_margin="8dp" /> android:layout_margin="8dp" />
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="8dp" android:layout_marginEnd="8dp"
android:layout_marginStart="48dp" android:layout_marginStart="48dp"
android:orientation="vertical" android:orientation="vertical"
android:layout_marginRight="8dp" android:layout_marginRight="8dp"
android:layout_marginLeft="48dp"> android:layout_marginLeft="48dp">
<LinearLayout <LinearLayout
android:id="@+id/user_and_timestamp_container" android:id="@+id/user_and_timestamp_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal"> android:orientation="horizontal">
<TextView <TextView
android:id="@+id/username" android:id="@+id/username"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.RocketChat.Message.Username" android:textAppearance="@style/TextAppearance.RocketChat.Message.Username"
tools:text="John Doe" /> tools:text="John Doe" />
<Space <Space
android:layout_width="4dp" android:layout_width="4dp"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<TextView <TextView
android:id="@+id/sub_username" android:id="@+id/sub_username"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.RocketChat.Message.SubUsername" android:textAppearance="@style/TextAppearance.RocketChat.Message.SubUsername"
tools:text="\@John Doe" /> tools:text="\@John Doe" />
<Space <Space
android:layout_width="@dimen/margin_8" android:layout_width="@dimen/margin_8"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<TextView <TextView
android:id="@+id/timestamp" android:id="@+id/timestamp"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:enabled="false" android:enabled="false"
tools:text="12:34" /> tools:text="12:34" />
</LinearLayout>
<chat.rocket.android.widget.message.RocketChatMessageLayout <View
android:id="@+id/message_body" android:layout_width="0dp"
android:layout_width="match_parent" android:layout_height="0dp"
android:layout_height="wrap_content" /> android:layout_weight="1" />
<chat.rocket.android.widget.message.RocketChatMessageUrlsLayout <ImageView
android:id="@+id/message_urls" android:id="@+id/errorImageView"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="wrap_content" /> android:layout_height="16dp"
android:layout_gravity="end"
android:gravity="end"
android:tint="@color/colorRed400"
app:srcCompat="@drawable/ic_error_black_24dp"
android:visibility="gone" />
</LinearLayout>
<chat.rocket.android.widget.message.RocketChatMessageAttachmentsLayout <chat.rocket.android.widget.message.RocketChatMessageLayout
android:id="@+id/message_attachments" android:id="@+id/message_body"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
</LinearLayout>
</FrameLayout> <chat.rocket.android.widget.message.RocketChatMessageUrlsLayout
android:id="@+id/message_urls"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<chat.rocket.android.widget.message.RocketChatMessageAttachmentsLayout
android:id="@+id/message_attachments"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</FrameLayout>
</LinearLayout> </LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" xmlns:tools="http://schemas.android.com/tools"
android:layout_height="wrap_content" android:layout_width="match_parent"
android:orientation="vertical" android:layout_height="wrap_content"
android:theme="@style/AppTheme"> android:orientation="vertical"
android:theme="@style/AppTheme">
<include layout="@layout/list_item_message_newday" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include layout="@layout/list_item_message_newday" /> <chat.rocket.android.widget.RocketChatAvatar
android:id="@+id/user_avatar"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_margin="8dp" />
<FrameLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="48dp"
android:orientation="vertical"
android:layout_marginRight="8dp"
android:layout_marginLeft="48dp">
<chat.rocket.android.widget.RocketChatAvatar <LinearLayout
android:id="@+id/user_avatar" android:id="@+id/user_and_timestamp_container"
android:layout_width="32dp" android:layout_width="match_parent"
android:layout_height="32dp" android:layout_height="wrap_content"
android:layout_margin="8dp" /> android:orientation="horizontal">
<LinearLayout <TextView
android:layout_width="match_parent" android:id="@+id/username"
android:layout_height="wrap_content" android:layout_width="wrap_content"
android:layout_marginEnd="8dp" android:layout_height="wrap_content"
android:layout_marginStart="48dp" android:textAppearance="@style/TextAppearance.RocketChat.Message.Username"
android:orientation="vertical" tools:text="John Doe" />
android:layout_marginRight="8dp"
android:layout_marginLeft="48dp">
<LinearLayout <Space
android:id="@+id/user_and_timestamp_container" android:layout_width="@dimen/margin_8"
android:layout_width="match_parent" android:layout_height="wrap_content" />
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView <TextView
android:id="@+id/username" android:id="@+id/timestamp"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.RocketChat.Message.Username" android:enabled="false"
tools:text="John Doe" /> tools:text="12:34" />
<Space <View
android:layout_width="@dimen/margin_8" android:layout_width="0dp"
android:layout_height="wrap_content" /> android:layout_height="0dp"
android:layout_weight="1" />
<TextView <ImageView
android:id="@+id/timestamp" android:id="@+id/errorImageView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="16dp"
android:enabled="false" android:layout_gravity="end"
tools:text="12:34" /> android:gravity="end"
</LinearLayout> android:tint="@color/colorRed400"
app:srcCompat="@drawable/ic_error_black_24dp"
android:visibility="gone" />
</LinearLayout>
<TextView <TextView
android:id="@+id/message_body" android:id="@+id/message_body"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Body1" android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:textStyle="italic" android:textStyle="italic"
android:enabled="false" /> android:enabled="false" />
</LinearLayout> </LinearLayout>
</FrameLayout> </FrameLayout>
</LinearLayout> </LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<color name="colorPrimary">#044b76</color> <color name="colorPrimary">#044b76</color>
<color name="colorPrimaryDark">#FF04436a</color> <color name="colorPrimaryDark">#FF04436a</color>
<color name="colorAccent">#FF2D91FA</color> <color name="colorAccent">#FF2D91FA</color>
<color name="colorAccentLight">#FF6CB1FA</color> <color name="colorAccentLight">#FF6CB1FA</color>
<color name="colorAccentDark">#FF287DD7</color> <color name="colorAccentDark">#FF287DD7</color>
<color name="colorAccent_a40">#662D91FA</color> <color name="colorAccent_a40">#662D91FA</color>
<color name="textColorLink">#008ce3</color> <color name="textColorLink">#008ce3</color>
<color name="white">#FFFEFEFF</color> <color name="colorRed400">#FFEF5350</color>
</resources> </resources>
\ No newline at end of file
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<resources> <resources>
<style name="Widget.RocketChat.RoomToolbar" parent="Widget.AppCompat.Toolbar"> <style name="Widget.RocketChat.RoomToolbar" parent="Widget.AppCompat.Toolbar">
<item name="titleTextAppearance">@style/TextAppearance.Widget.RocketChat.RoomToolbar.Title</item> <item name="titleTextAppearance">@style/TextAppearance.Widget.RocketChat.RoomToolbar.Title</item>
<item name="android:background">@color/white</item> <item name="android:background">@android:color/white</item>
</style> </style>
<style name="TextAppearance.Widget.RocketChat.RoomToolbar.Title" <style name="TextAppearance.Widget.RocketChat.RoomToolbar.Title"
......
...@@ -33,7 +33,7 @@ android { ...@@ -33,7 +33,7 @@ android {
} }
ext { ext {
frescoVersion = '1.3.0' frescoVersion = '1.4.0'
rxbindingVersion = '2.0.0' rxbindingVersion = '2.0.0'
} }
......
...@@ -6,7 +6,7 @@ import android.os.Build; ...@@ -6,7 +6,7 @@ import android.os.Build;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import chat.rocket.android.widget.helper.FrescoAvatarHelper; import chat.rocket.android.widget.helper.FrescoHelper;
import com.facebook.drawee.view.SimpleDraweeView; import com.facebook.drawee.view.SimpleDraweeView;
public class RocketChatAvatar extends FrameLayout { public class RocketChatAvatar extends FrameLayout {
...@@ -41,13 +41,8 @@ public class RocketChatAvatar extends FrameLayout { ...@@ -41,13 +41,8 @@ public class RocketChatAvatar extends FrameLayout {
draweeView = findViewById(R.id.drawee_avatar); draweeView = findViewById(R.id.drawee_avatar);
} }
public void loadImage(String imageUrl) { public void loadImage(String imageUri) {
FrescoAvatarHelper FrescoHelper
.loadImage(draweeView, imageUrl); .loadImage(draweeView, imageUri);
}
public void showFailureImage() {
FrescoAvatarHelper
.showFailureImage(draweeView);
} }
} }
\ No newline at end of file
...@@ -2,24 +2,36 @@ package chat.rocket.android.widget; ...@@ -2,24 +2,36 @@ package chat.rocket.android.widget;
import android.content.Context; import android.content.Context;
import chat.rocket.android.widget.fresco.CustomImageFormatConfigurator; import chat.rocket.android.widget.fresco.CustomImageFormatConfigurator;
import com.facebook.common.logging.FLog;
import com.facebook.drawee.backends.pipeline.DraweeConfig; import com.facebook.drawee.backends.pipeline.DraweeConfig;
import com.facebook.drawee.backends.pipeline.Fresco; import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.imagepipeline.backends.okhttp3.OkHttpImagePipelineConfigFactory; import com.facebook.imagepipeline.backends.okhttp3.OkHttpImagePipelineConfigFactory;
import com.facebook.imagepipeline.core.ImagePipelineConfig; import com.facebook.imagepipeline.core.ImagePipelineConfig;
import com.facebook.imagepipeline.listener.RequestListener;
import com.facebook.imagepipeline.listener.RequestLoggingListener;
import java.util.HashSet;
import java.util.Set;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
public class RocketChatWidgets { public class RocketChatWidgets {
public static void initialize(Context context, OkHttpClient okHttpClient) { public static void initialize(Context context, OkHttpClient okHttpClient) {
ImagePipelineConfig config = OkHttpImagePipelineConfigFactory FLog.setMinimumLoggingLevel(FLog.VERBOSE);
Set<RequestListener> listeners = new HashSet<>();
listeners.add(new RequestLoggingListener());
ImagePipelineConfig imagePipelineConfig = OkHttpImagePipelineConfigFactory
.newBuilder(context, okHttpClient) .newBuilder(context, okHttpClient)
.setDownsampleEnabled(true) .setRequestListeners(listeners)
.setImageDecoderConfig(CustomImageFormatConfigurator.createImageDecoderConfig()) .setImageDecoderConfig(CustomImageFormatConfigurator.createImageDecoderConfig())
.setDownsampleEnabled(true)
.experiment().setBitmapPrepareToDraw(true)
.experiment().setPartialImageCachingEnabled(true)
.build(); .build();
DraweeConfig.Builder draweeConfigBuilder = DraweeConfig.newBuilder(); DraweeConfig.Builder draweeConfigBuilder = DraweeConfig.newBuilder();
CustomImageFormatConfigurator.addCustomDrawableFactories(draweeConfigBuilder); CustomImageFormatConfigurator.addCustomDrawableFactories(draweeConfigBuilder);
Fresco.initialize(context, config, draweeConfigBuilder.build()); Fresco.initialize(context, imagePipelineConfig, draweeConfigBuilder.build());
} }
} }
\ No newline at end of file
...@@ -5,7 +5,7 @@ import android.graphics.drawable.Drawable; ...@@ -5,7 +5,7 @@ import android.graphics.drawable.Drawable;
import android.support.annotation.ColorInt; import android.support.annotation.ColorInt;
import android.support.v4.graphics.ColorUtils; import android.support.v4.graphics.ColorUtils;
import com.facebook.common.internal.ByteStreams; import com.facebook.common.internal.ByteStreams;
import com.facebook.drawee.backends.pipeline.DrawableFactory; import com.facebook.imagepipeline.drawable.DrawableFactory;
import com.facebook.imageformat.ImageFormat; import com.facebook.imageformat.ImageFormat;
import com.facebook.imageformat.ImageFormatCheckerUtils; import com.facebook.imageformat.ImageFormatCheckerUtils;
import com.facebook.imagepipeline.common.ImageDecodeOptions; import com.facebook.imagepipeline.common.ImageDecodeOptions;
......
...@@ -5,7 +5,7 @@ import android.graphics.drawable.Drawable; ...@@ -5,7 +5,7 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.PictureDrawable; import android.graphics.drawable.PictureDrawable;
import com.caverock.androidsvg.SVG; import com.caverock.androidsvg.SVG;
import com.caverock.androidsvg.SVGParseException; import com.caverock.androidsvg.SVGParseException;
import com.facebook.drawee.backends.pipeline.DrawableFactory; import com.facebook.imagepipeline.drawable.DrawableFactory;
import com.facebook.imageformat.ImageFormat; import com.facebook.imageformat.ImageFormat;
import com.facebook.imageformat.ImageFormatCheckerUtils; import com.facebook.imageformat.ImageFormatCheckerUtils;
import com.facebook.imagepipeline.common.ImageDecodeOptions; import com.facebook.imagepipeline.common.ImageDecodeOptions;
......
package chat.rocket.android.widget.helper;
import android.net.Uri;
import android.support.graphics.drawable.VectorDrawableCompat;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.drawable.ProgressBarDrawable;
import com.facebook.drawee.generic.GenericDraweeHierarchy;
import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.view.SimpleDraweeView;
import chat.rocket.android.widget.R;
public class FrescoHelper {
private FrescoHelper() {
}
public static void setupDraweeAndLoadImage(String imageUrl, SimpleDraweeView draweeView) {
setupDrawee(draweeView);
loadImage(imageUrl, draweeView);
}
public static void setupDrawee(SimpleDraweeView draweeView) {
final GenericDraweeHierarchy hierarchy = draweeView.getHierarchy();
hierarchy.setPlaceholderImage(VectorDrawableCompat.create(draweeView.getResources(), R.drawable.image_dummy, null));
hierarchy.setFailureImage(VectorDrawableCompat.create(draweeView.getResources(), R.drawable.image_error, null));
hierarchy.setProgressBarImage(new ProgressBarDrawable());
}
public static void loadImage(String imageUrl, SimpleDraweeView draweeView) {
final DraweeController controller = Fresco.newDraweeControllerBuilder()
.setUri(Uri.parse(imageUrl))
.setAutoPlayAnimations(true)
.setTapToRetryEnabled(true)
.build();
draweeView.setController(controller);
}
}
\ No newline at end of file
...@@ -5,33 +5,36 @@ import android.support.graphics.drawable.VectorDrawableCompat ...@@ -5,33 +5,36 @@ import android.support.graphics.drawable.VectorDrawableCompat
import chat.rocket.android.widget.R import chat.rocket.android.widget.R
import com.facebook.drawee.backends.pipeline.Fresco import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.drawee.drawable.ProgressBarDrawable import com.facebook.drawee.drawable.ProgressBarDrawable
import com.facebook.drawee.generic.GenericDraweeHierarchy
import com.facebook.drawee.view.SimpleDraweeView import com.facebook.drawee.view.SimpleDraweeView
class FrescoAvatarHelper { class FrescoHelper {
companion object { companion object {
@JvmStatic fun loadImage(draweeView: SimpleDraweeView, imageUri: String) {
@JvmStatic fun loadImage(draweeView: SimpleDraweeView, imageUrl: String) { draweeView.setImageURI(imageUri)
val hierarchy = draweeView.hierarchy
hierarchy.setPlaceholderImage(VectorDrawableCompat.create(draweeView.resources, R.drawable.ic_avatar_placeholder, null))
hierarchy.setFailureImage(VectorDrawableCompat.create(draweeView.resources, R.drawable.ic_avatar_failure, null))
hierarchy.setProgressBarImage(ProgressBarDrawable())
val controller = Fresco.newDraweeControllerBuilder()
.setUri(Uri.parse(imageUrl))
.setOldController(draweeView.controller)
.build()
draweeView.controller = controller
} }
@JvmStatic fun showFailureImage(draweeView: SimpleDraweeView) { /** TODO
val hierarchy = draweeView.hierarchy * Replace with:
hierarchy.setPlaceholderImage(VectorDrawableCompat.create(draweeView.resources, R.drawable.ic_avatar_failure, null)) * @JvmStatic fun loadImageWithCustomization(draweeView: SimpleDraweeView,
hierarchy.setFailureImage(VectorDrawableCompat.create(draweeView.resources, R.drawable.ic_avatar_failure, null)) * 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())
val controller = Fresco.newDraweeControllerBuilder() val controller = Fresco.newDraweeControllerBuilder()
.setUri(Uri.parse(imageUri))
.setAutoPlayAnimations(true) .setAutoPlayAnimations(true)
.setTapToRetryEnabled(true)
.build() .build()
draweeView.controller = controller draweeView.controller = controller
......
...@@ -14,9 +14,6 @@ import android.view.View; ...@@ -14,9 +14,6 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import com.facebook.drawee.view.SimpleDraweeView;
import java.util.List;
import chat.rocket.android.widget.AbsoluteUrl; import chat.rocket.android.widget.AbsoluteUrl;
import chat.rocket.android.widget.R; import chat.rocket.android.widget.R;
import chat.rocket.android.widget.helper.FrescoHelper; import chat.rocket.android.widget.helper.FrescoHelper;
...@@ -24,6 +21,8 @@ import chat.rocket.core.models.Attachment; ...@@ -24,6 +21,8 @@ import chat.rocket.core.models.Attachment;
import chat.rocket.core.models.AttachmentAuthor; import chat.rocket.core.models.AttachmentAuthor;
import chat.rocket.core.models.AttachmentField; import chat.rocket.core.models.AttachmentField;
import chat.rocket.core.models.AttachmentTitle; import chat.rocket.core.models.AttachmentTitle;
import com.facebook.drawee.view.SimpleDraweeView;
import java.util.List;
/** /**
*/ */
...@@ -120,8 +119,8 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout { ...@@ -120,8 +119,8 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout {
authorBox.setVisibility(VISIBLE); authorBox.setVisibility(VISIBLE);
FrescoHelper.setupDraweeAndLoadImage(absolutize(author.getIconUrl()), FrescoHelper
(SimpleDraweeView) attachmentView.findViewById(R.id.author_icon)); .loadImageWithCustomization((SimpleDraweeView) attachmentView.findViewById(R.id.author_icon), absolutize(author.getIconUrl()));
final TextView authorName = (TextView) attachmentView.findViewById(R.id.author_name); final TextView authorName = (TextView) attachmentView.findViewById(R.id.author_name);
authorName.setText(author.getName()); authorName.setText(author.getName());
...@@ -188,7 +187,8 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout { ...@@ -188,7 +187,8 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout {
thumbImage.setVisibility(GONE); thumbImage.setVisibility(GONE);
} else { } else {
thumbImage.setVisibility(VISIBLE); thumbImage.setVisibility(VISIBLE);
FrescoHelper.setupDraweeAndLoadImage(absolutize(thumbUrl), thumbImage); FrescoHelper
.loadImageWithCustomization(thumbImage, absolutize(thumbUrl));
} }
final TextView refText = (TextView) refBox.findViewById(R.id.text); final TextView refText = (TextView) refBox.findViewById(R.id.text);
...@@ -253,17 +253,18 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout { ...@@ -253,17 +253,18 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout {
boolean autoloadImage) { boolean autoloadImage) {
if (autoloadImage) { if (autoloadImage) {
load.setVisibility(GONE); load.setVisibility(GONE);
FrescoHelper.setupDraweeAndLoadImage(url, drawee); FrescoHelper
.loadImageWithCustomization(drawee, url);
return; return;
} }
FrescoHelper.setupDrawee(drawee);
load.setOnClickListener(new OnClickListener() { load.setOnClickListener(new OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
load.setVisibility(GONE); load.setVisibility(GONE);
load.setOnClickListener(null); load.setOnClickListener(null);
FrescoHelper.loadImage(url, drawee); FrescoHelper
.loadImageWithCustomization(drawee, url);
} }
}); });
} }
......
...@@ -11,12 +11,12 @@ import android.view.LayoutInflater; ...@@ -11,12 +11,12 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import chat.rocket.android.widget.helper.FrescoHelper;
import com.facebook.drawee.view.SimpleDraweeView; import com.facebook.drawee.view.SimpleDraweeView;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import chat.rocket.android.widget.R; import chat.rocket.android.widget.R;
import chat.rocket.android.widget.helper.FrescoHelper;
import chat.rocket.android.widget.helper.ImageFormat; import chat.rocket.android.widget.helper.ImageFormat;
import chat.rocket.core.models.WebContent; import chat.rocket.core.models.WebContent;
import chat.rocket.core.models.WebContentHeaders; import chat.rocket.core.models.WebContentHeaders;
...@@ -95,7 +95,8 @@ public class RocketChatMessageUrlsLayout extends LinearLayout { ...@@ -95,7 +95,8 @@ public class RocketChatMessageUrlsLayout extends LinearLayout {
if (TextUtils.isEmpty(imageURL)) { if (TextUtils.isEmpty(imageURL)) {
image.setVisibility(View.GONE); image.setVisibility(View.GONE);
} else { } else {
FrescoHelper.setupDraweeAndLoadImage(imageURL, image); FrescoHelper
.loadImageWithCustomization(image, imageURL);
image.setVisibility(View.VISIBLE); image.setVisibility(View.VISIBLE);
} }
...@@ -143,17 +144,18 @@ public class RocketChatMessageUrlsLayout extends LinearLayout { ...@@ -143,17 +144,18 @@ public class RocketChatMessageUrlsLayout extends LinearLayout {
boolean autoloadImage) { boolean autoloadImage) {
if (autoloadImage) { if (autoloadImage) {
load.setVisibility(GONE); load.setVisibility(GONE);
FrescoHelper.setupDraweeAndLoadImage(url, drawee); FrescoHelper
.loadImageWithCustomization(drawee, url);
return; return;
} }
FrescoHelper.setupDrawee(drawee);
load.setOnClickListener(new OnClickListener() { load.setOnClickListener(new OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
load.setVisibility(GONE); load.setVisibility(GONE);
load.setOnClickListener(null); load.setOnClickListener(null);
FrescoHelper.loadImage(url, drawee); FrescoHelper
.loadImageWithCustomization(drawee, url);
} }
}); });
} }
......
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:pathData="M3,0L21,0A3,3 0,0 1,24 3L24,21A3,3 0,0 1,21 24L3,24A3,3 0,0 1,0 21L0,3A3,3 0,0 1,3 0z"
android:fillColor="#C2D1DA"/>
<path
android:pathData="M11.594,11.869C12.928,11.869 14.01,10.555 14.01,8.934C14.01,7.314 13.655,6 11.594,6C9.534,6 9.178,7.314 9.178,8.934C9.178,10.555 10.26,11.869 11.594,11.869Z"
android:fillColor="#5D8298"/>
<path
android:pathData="M16.152,16.231C16.107,13.408 15.739,12.603 12.917,12.094C12.917,12.094 12.52,12.6 11.594,12.6C10.669,12.6 10.271,12.094 10.271,12.094C7.481,12.598 7.089,13.39 7.038,16.139C7.034,16.364 7.032,16.375 7.031,16.349C7.031,16.398 7.032,16.488 7.032,16.646C7.032,16.646 7.703,18 11.594,18C15.485,18 16.157,16.646 16.157,16.646C16.157,16.545 16.157,16.474 16.157,16.426C16.156,16.443 16.155,16.411 16.152,16.231Z"
android:fillColor="#5D8298"/>
</vector>
\ No newline at end of file
...@@ -106,6 +106,7 @@ ...@@ -106,6 +106,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="150dp" android:layout_height="150dp"
android:layout_marginBottom="8dp" android:layout_marginBottom="8dp"
fresco:placeholderImage="@drawable/image_dummy"
fresco:actualImageScaleType="fitStart" /> fresco:actualImageScaleType="fitStart" />
<TextView <TextView
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
android:id="@+id/message_inline_image" android:id="@+id/message_inline_image"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="150dp" android:layout_height="150dp"
fresco:placeholderImage="@drawable/image_dummy"
fresco:actualImageScaleType="fitStart" /> fresco:actualImageScaleType="fitStart" />
<TextView <TextView
......
...@@ -8,7 +8,7 @@ apply plugin: 'java' ...@@ -8,7 +8,7 @@ apply plugin: 'java'
dependencies { dependencies {
compile fileTree(dir: 'libs', include: ['*.jar']) compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'org.jetbrains.kotlin:kotlin-stdlib-jre7:1.1.2-3' compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$rootProject.ext.kotlinVersion"
compile 'com.google.code.findbugs:jsr305:3.0.1' compile 'com.google.code.findbugs:jsr305:3.0.1'
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment