Skip to content

Commit cd81dc4

Browse files
author
Carter Hudson
committed
Implement imgur view holder & factory for java & kotlin projects
1 parent 058a8c8 commit cd81dc4

25 files changed

+265
-247
lines changed

samplejava/build.gradle

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ android {
2727
targetCompatibility JavaVersion.VERSION_1_8
2828
}
2929

30+
buildFeatures {
31+
viewBinding true
32+
}
33+
3034
packagingOptions {
3135
exclude 'META-INF/*.kotlin_module'
3236
}
@@ -35,10 +39,12 @@ android {
3539
dependencies {
3640
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
3741
implementation "io.getstream:stream-chat-android-ui-components:4.5.0"
38-
implementation "io.coil-kt:coil:1.1.1"
42+
implementation 'io.coil-kt:coil:1.1.1'
3943

40-
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0-rc01"
44+
implementation "androidx.recyclerview:recyclerview:1.1.0"
45+
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0-rc01'
4146
implementation "androidx.appcompat:appcompat:1.2.0"
4247
implementation "androidx.constraintlayout:constraintlayout:2.0.4"
4348
implementation 'androidx.activity:activity-ktx:1.1.0'
49+
implementation "com.google.android.material:material:1.2.1"
4450
}

samplejava/src/main/java/com/example/chattutorialjava/AttachmentViewHolderImgur.java

Lines changed: 0 additions & 51 deletions
This file was deleted.

samplejava/src/main/java/com/example/chattutorialjava/ChannelActivity2.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
5858
MessageInputViewModel messageInputViewModel = provider.get(MessageInputViewModel.class);
5959

6060
// Set custom AttachmentViewHolderFactory
61-
// messageListView.setAttachmentViewHolderFactory(new MyAttachmentViewHolderFactory());
61+
messageListView.setMessageViewHolderFactory(new ImgurAttachmentViewHolderFactory());
6262

6363
// Step 2 - Bind the view and ViewModels, they are loosely coupled so it's easy to customize
6464
ChannelHeaderViewModelBinding.bind(channelHeaderViewModel, channelHeaderView, this);

samplejava/src/main/java/com/example/chattutorialjava/ChannelActivity3.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
6666
MessageInputViewModel messageInputViewModel = provider.get(MessageInputViewModel.class);
6767

6868
// Set custom AttachmentViewHolderFactory
69-
// messageListView.setAttachmentViewHolderFactory(new MyAttachmentViewHolderFactory());
69+
messageListView.setMessageViewHolderFactory(new ImgurAttachmentViewHolderFactory());
7070

7171
// Step 2 - Bind the view and ViewModels, they are loosely coupled so it's easy to customize
7272
ChannelHeaderViewModelBinding.bind(channelHeaderViewModel, channelHeaderView, this);

samplejava/src/main/java/com/example/chattutorialjava/ChannelActivity4.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,13 @@
1111
import androidx.appcompat.app.AppCompatActivity;
1212
import androidx.lifecycle.ViewModelProvider;
1313

14-
import com.getstream.sdk.chat.view.ChannelHeaderView;
15-
import com.getstream.sdk.chat.view.MessageListView;
16-
import com.getstream.sdk.chat.view.messageinput.MessageInputView;
1714
import com.getstream.sdk.chat.viewmodel.ChannelHeaderViewModel;
18-
import com.getstream.sdk.chat.viewmodel.ChannelHeaderViewModelBinding;
1915
import com.getstream.sdk.chat.viewmodel.MessageInputViewModel;
20-
import com.getstream.sdk.chat.viewmodel.MessageInputViewModelBinding;
2116
import com.getstream.sdk.chat.viewmodel.factory.ChannelViewModelFactory;
2217
import com.getstream.sdk.chat.viewmodel.messages.MessageListViewModel;
2318
import com.getstream.sdk.chat.viewmodel.messages.MessageListViewModel.Mode.Normal;
2419
import com.getstream.sdk.chat.viewmodel.messages.MessageListViewModel.Mode.Thread;
2520
import com.getstream.sdk.chat.viewmodel.messages.MessageListViewModel.State.NavigateUp;
26-
import com.getstream.sdk.chat.viewmodel.messages.MessageListViewModelBinding;
2721

2822
import java.util.HashSet;
2923
import java.util.Set;
@@ -33,6 +27,12 @@
3327
import io.getstream.chat.android.client.events.TypingStopEvent;
3428
import io.getstream.chat.android.client.models.Channel;
3529
import io.getstream.chat.android.client.models.User;
30+
import io.getstream.chat.android.ui.messages.header.ChannelHeaderViewModelBinding;
31+
import io.getstream.chat.android.ui.messages.header.MessagesHeaderView;
32+
import io.getstream.chat.android.ui.messages.view.MessageListView;
33+
import io.getstream.chat.android.ui.messages.view.MessageListViewModelBinding;
34+
import io.getstream.chat.android.ui.textinput.MessageInputView;
35+
import io.getstream.chat.android.ui.textinput.MessageInputViewModelBinding;
3636
import kotlin.Unit;
3737

3838
public class ChannelActivity4 extends AppCompatActivity {
@@ -56,7 +56,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
5656

5757
// Step 0 - Get View references
5858
MessageListView messageListView = findViewById(R.id.messageListView);
59-
ChannelHeaderView channelHeaderView = findViewById(R.id.channelHeaderView);
59+
MessagesHeaderView channelHeaderView = findViewById(R.id.channelHeaderView);
6060
MessageInputView messageInputView = findViewById(R.id.messageInputView);
6161

6262
// Step 1 - Create 3 separate ViewModels for the views so it's easy to customize one of the components
@@ -67,7 +67,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
6767
MessageInputViewModel messageInputViewModel = provider.get(MessageInputViewModel.class);
6868

6969
// Set custom AttachmentViewHolderFactory
70-
messageListView.setAttachmentViewHolderFactory(new MyAttachmentViewHolderFactory());
70+
messageListView.setMessageViewHolderFactory(new ImgurAttachmentViewHolderFactory());
7171

7272
// Step 2 - Bind the view and ViewModels, they are loosely coupled so it's easy to customize
7373
ChannelHeaderViewModelBinding.bind(channelHeaderViewModel, channelHeaderView, this);
@@ -97,14 +97,14 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
9797
});
9898

9999
// Step 6 - Handle back button behaviour correctly when you're in a thread
100-
channelHeaderView.setOnBackClick(() -> {
100+
MessagesHeaderView.OnClickListener backHandler = () -> {
101101
messageListViewModel.onEvent(MessageListViewModel.Event.BackButtonPressed.INSTANCE);
102-
return Unit.INSTANCE;
103-
});
102+
};
103+
channelHeaderView.setBackButtonClickListener(backHandler);
104104
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
105105
@Override
106106
public void handleOnBackPressed() {
107-
channelHeaderView.getOnBackClick().invoke();
107+
backHandler.onClick();
108108
}
109109
});
110110

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package com.example.chattutorialjava;
2+
3+
import android.content.Context;
4+
import android.view.LayoutInflater;
5+
import android.view.ViewGroup;
6+
import android.widget.ImageView;
7+
8+
import androidx.constraintlayout.widget.ConstraintLayout;
9+
import androidx.constraintlayout.widget.ConstraintSet;
10+
11+
import com.example.chattutorialjava.databinding.ViewHolderImgurAttachmentBinding;
12+
import com.getstream.sdk.chat.adapter.MessageListItem;
13+
import com.google.android.material.shape.ShapeAppearanceModel;
14+
15+
import org.jetbrains.annotations.NotNull;
16+
import org.jetbrains.annotations.Nullable;
17+
18+
import java.util.List;
19+
20+
import coil.Coil;
21+
import coil.request.ImageRequest;
22+
import io.getstream.chat.android.client.models.Attachment;
23+
import io.getstream.chat.android.ui.messages.adapter.BaseMessageItemViewHolder;
24+
import io.getstream.chat.android.ui.messages.adapter.MessageListItemPayloadDiff;
25+
26+
class ImgurAttachmentViewHolder extends BaseMessageItemViewHolder<MessageListItem.MessageItem> {
27+
28+
ViewHolderImgurAttachmentBinding binding;
29+
30+
public static ImgurAttachmentViewHolder create(ViewGroup parent) {
31+
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
32+
ViewHolderImgurAttachmentBinding binding = ViewHolderImgurAttachmentBinding.inflate(inflater, parent, false);
33+
return new ImgurAttachmentViewHolder(binding);
34+
}
35+
36+
private ImgurAttachmentViewHolder(@NotNull ViewHolderImgurAttachmentBinding binding) {
37+
super(binding.getRoot());
38+
39+
float cornerRadius = binding.getRoot()
40+
.getResources()
41+
.getDimension(R.dimen.stream_ui_selected_attachment_corner_radius);
42+
43+
ShapeAppearanceModel model = binding.ivMediaThumb.getShapeAppearanceModel()
44+
.toBuilder()
45+
.setAllCornerSizes(cornerRadius)
46+
.build();
47+
48+
binding.ivMediaThumb.setShapeAppearanceModel(model);
49+
binding.ivMediaThumb.setScaleType(ImageView.ScaleType.CENTER_CROP);
50+
51+
this.binding = binding;
52+
}
53+
54+
@Override
55+
public void bindData(
56+
@NotNull MessageListItem.MessageItem data,
57+
@Nullable MessageListItemPayloadDiff diff
58+
) {
59+
List<Attachment> attachments = data.getMessage().getAttachments();
60+
String imageUrl = attachments.get(0).getImageUrl();
61+
Context context = getContext();
62+
63+
ImageRequest imageRequest = new ImageRequest.Builder(context)
64+
.data(imageUrl)
65+
.allowHardware(false)
66+
.target(binding.ivMediaThumb)
67+
.build();
68+
69+
Coil.imageLoader(context).enqueue(imageRequest);
70+
71+
align(data);
72+
}
73+
74+
private void align(MessageListItem.MessageItem data) {
75+
ConstraintSet set = new ConstraintSet();
76+
ConstraintLayout root = binding.getRoot();
77+
set.clone(root);
78+
Integer pinnedPosition = getPinnedPosition(data.isMine());
79+
Integer clearedPosition = getPinnedPosition(!data.isMine());
80+
int imageViewId = binding.ivMediaThumb.getId();
81+
set.clear(imageViewId, clearedPosition);
82+
set.connect(
83+
imageViewId,
84+
pinnedPosition,
85+
ConstraintSet.PARENT_ID,
86+
pinnedPosition,
87+
(int) root.getResources().getDimension(R.dimen.stream_ui_spacing_small)
88+
);
89+
set.applyTo(root);
90+
}
91+
92+
private Integer getPinnedPosition(Boolean isMine) {
93+
return isMine ? ConstraintSet.END : ConstraintSet.START;
94+
}
95+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package com.example.chattutorialjava;
2+
3+
import android.view.ViewGroup;
4+
5+
import com.getstream.sdk.chat.adapter.MessageListItem;
6+
7+
import org.jetbrains.annotations.NotNull;
8+
9+
import java.util.List;
10+
11+
import io.getstream.chat.android.client.models.Attachment;
12+
import io.getstream.chat.android.client.models.Message;
13+
import io.getstream.chat.android.ui.messages.adapter.BaseMessageItemViewHolder;
14+
import io.getstream.chat.android.ui.messages.adapter.MessageListItemViewHolderFactory;
15+
16+
class ImgurAttachmentViewHolderFactory extends MessageListItemViewHolderFactory {
17+
18+
private static final Integer IMGUR = 999;
19+
20+
@Override
21+
public int getItemViewType(@NotNull MessageListItem item) {
22+
23+
boolean isMessageItem = item instanceof MessageListItem.MessageItem;
24+
if (!isMessageItem) {
25+
return super.getItemViewType(item);
26+
}
27+
28+
Message message = ((MessageListItem.MessageItem) item).getMessage();
29+
List<Attachment> attachments = message.getAttachments();
30+
31+
if (attachments == null || attachments.isEmpty()) {
32+
return super.getItemViewType(item);
33+
}
34+
35+
Attachment attachment = attachments.get(0);
36+
if (attachment == null) {
37+
return super.getItemViewType(item);
38+
}
39+
40+
String imageUrl = attachment.getImageUrl();
41+
if (imageUrl == null) {
42+
return super.getItemViewType(item);
43+
}
44+
45+
boolean isImgur = imageUrl.contains("imgur");
46+
if (isImgur) {
47+
return IMGUR;
48+
}
49+
50+
return super.getItemViewType(item);
51+
}
52+
53+
@NotNull
54+
@Override
55+
public BaseMessageItemViewHolder<? extends MessageListItem> createViewHolder(@NotNull ViewGroup parentView, int viewType) {
56+
boolean isImgur = viewType == IMGUR;
57+
return isImgur ? ImgurAttachmentViewHolder.create(parentView) : super.createViewHolder(parentView, viewType);
58+
}
59+
}

samplejava/src/main/java/com/example/chattutorialjava/MyAttachmentViewHolderFactory.java

Lines changed: 0 additions & 38 deletions
This file was deleted.

samplejava/src/main/res/layout/activity_channel.xml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616
android:id="@+id/messageListView"
1717
android:layout_width="0dp"
1818
android:layout_height="0dp"
19-
android:clipToPadding="false"
20-
android:paddingBottom="16dp"
2119
app:layout_constraintBottom_toTopOf="@+id/messageInputView"
2220
app:layout_constraintEnd_toEndOf="parent"
2321
app:layout_constraintStart_toStartOf="parent"

samplejava/src/main/res/layout/activity_channel_2.xml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,18 @@
99
android:layout_width="match_parent"
1010
android:layout_height="wrap_content"
1111
app:layout_constraintEnd_toEndOf="parent"
12+
app:layout_constraintHorizontal_bias="0.5"
1213
app:layout_constraintStart_toStartOf="parent"
1314
app:layout_constraintTop_toTopOf="parent" />
1415

1516
<io.getstream.chat.android.ui.messages.view.MessageListView
1617
android:id="@+id/messageListView"
17-
android:layout_width="0dp"
18+
android:layout_width="match_parent"
1819
android:layout_height="0dp"
1920
android:background="#f3f5f8"
20-
android:clipToPadding="false"
21-
android:paddingBottom="16dp"
2221
app:layout_constraintBottom_toTopOf="@+id/messageInputView"
2322
app:layout_constraintEnd_toEndOf="parent"
23+
app:layout_constraintHorizontal_bias="0.5"
2424
app:layout_constraintStart_toStartOf="parent"
2525
app:layout_constraintTop_toBottomOf="@+id/channelHeaderView" />
2626

@@ -30,5 +30,6 @@
3030
android:layout_height="wrap_content"
3131
app:layout_constraintBottom_toBottomOf="parent"
3232
app:layout_constraintEnd_toEndOf="parent"
33+
app:layout_constraintHorizontal_bias="0.5"
3334
app:layout_constraintStart_toStartOf="parent" />
3435
</androidx.constraintlayout.widget.ConstraintLayout>

0 commit comments

Comments
 (0)