|
3 | 3 | import android.content.Context; |
4 | 4 | import android.content.Intent; |
5 | 5 | import android.os.Bundle; |
6 | | -import android.text.TextUtils; |
7 | | -import android.widget.TextView; |
8 | 6 |
|
9 | 7 | import androidx.activity.OnBackPressedCallback; |
| 8 | +import androidx.annotation.NonNull; |
10 | 9 | import androidx.annotation.Nullable; |
11 | 10 | import androidx.appcompat.app.AppCompatActivity; |
| 11 | +import androidx.lifecycle.FlowLiveDataConversions; |
| 12 | +import androidx.lifecycle.LiveData; |
| 13 | +import androidx.lifecycle.Transformations; |
12 | 14 | import androidx.lifecycle.ViewModelProvider; |
13 | 15 |
|
14 | 16 | import com.example.chattutorial.databinding.ActivityChannel3Binding; |
|
18 | 20 | import com.getstream.sdk.chat.viewmodel.messages.MessageListViewModel.Mode.Thread; |
19 | 21 | import com.getstream.sdk.chat.viewmodel.messages.MessageListViewModel.State.NavigateUp; |
20 | 22 |
|
21 | | -import java.util.LinkedList; |
| 23 | +import java.util.ArrayList; |
22 | 24 | import java.util.List; |
23 | 25 |
|
| 26 | +import io.getstream.chat.android.client.ChatClient; |
24 | 27 | import io.getstream.chat.android.client.models.Channel; |
25 | 28 | import io.getstream.chat.android.client.models.Message; |
26 | | -import io.getstream.chat.android.client.models.User; |
27 | | -import io.getstream.chat.android.livedata.ChatDomain; |
28 | | -import io.getstream.chat.android.livedata.controller.ChannelController; |
| 29 | +import io.getstream.chat.android.client.models.TypingEvent; |
| 30 | +import io.getstream.chat.android.offline.extensions.ChatClientExtensions; |
| 31 | +import io.getstream.chat.android.offline.plugin.state.channel.ChannelState; |
29 | 32 | import io.getstream.chat.android.ui.message.input.viewmodel.MessageInputViewModelBinding; |
| 33 | +import io.getstream.chat.android.ui.message.list.adapter.viewholder.attachment.AttachmentFactoryManager; |
30 | 34 | import io.getstream.chat.android.ui.message.list.header.MessageListHeaderView; |
31 | 35 | import io.getstream.chat.android.ui.message.list.header.viewmodel.MessageListHeaderViewModel; |
32 | 36 | import io.getstream.chat.android.ui.message.list.header.viewmodel.MessageListHeaderViewModelBinding; |
33 | 37 | import io.getstream.chat.android.ui.message.list.viewmodel.MessageListViewModelBinding; |
34 | 38 | import io.getstream.chat.android.ui.message.list.viewmodel.factory.MessageListViewModelFactory; |
| 39 | +import kotlinx.coroutines.Dispatchers; |
| 40 | +import kotlinx.coroutines.flow.Flow; |
| 41 | +import kotlinx.coroutines.flow.FlowKt; |
35 | 42 |
|
36 | 43 | public class ChannelActivity3 extends AppCompatActivity { |
37 | 44 |
|
@@ -64,12 +71,18 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { |
64 | 71 | MessageListViewModel messageListViewModel = provider.get(MessageListViewModel.class); |
65 | 72 | MessageInputViewModel messageInputViewModel = provider.get(MessageInputViewModel.class); |
66 | 73 |
|
67 | | - // Set view factory for Imgur attachments |
68 | | - binding.messageListView.setAttachmentViewFactory(new ImgurAttachmentViewFactory()); |
| 74 | + // Set a view factory manager for Imgur attachments |
| 75 | + ImgurAttachmentFactory imgurAttachmentFactory = new ImgurAttachmentFactory(); |
| 76 | + |
| 77 | + List<ImgurAttachmentFactory> imgurAttachmentViewFactories = new ArrayList<ImgurAttachmentFactory>(); |
| 78 | + imgurAttachmentViewFactories.add(imgurAttachmentFactory); |
| 79 | + |
| 80 | + AttachmentFactoryManager attachmentFactoryManager = new AttachmentFactoryManager(imgurAttachmentViewFactories); |
| 81 | + binding.messageListView.setAttachmentFactoryManager(attachmentFactoryManager); |
69 | 82 |
|
70 | 83 | // Step 2 - Bind the view and ViewModels, they are loosely coupled so it's easy to customize |
71 | 84 | MessageListHeaderViewModelBinding.bind(messageListHeaderViewModel, binding.messageListHeaderView, this); |
72 | | - MessageListViewModelBinding.bind(messageListViewModel, binding.messageListView, this); |
| 85 | + MessageListViewModelBinding.bind(messageListViewModel, binding.messageListView, this, true); |
73 | 86 | MessageInputViewModelBinding.bind(messageInputViewModel, binding.messageInputView, this); |
74 | 87 |
|
75 | 88 | // Step 3 - Let both MessageListHeaderView and MessageInputView know when we open a thread |
@@ -107,29 +120,43 @@ public void handleOnBackPressed() { |
107 | 120 | }); |
108 | 121 |
|
109 | 122 | // Custom typing info header bar |
110 | | - TextView typingHeaderView = findViewById(R.id.typingHeaderView); |
111 | 123 | String nobodyTyping = "nobody is typing"; |
112 | | - typingHeaderView.setText(nobodyTyping); |
113 | | - |
114 | | - // Obtain a ChannelController |
115 | | - ChatDomain.instance() |
116 | | - .getChannelController(cid) |
117 | | - .enqueue((result) -> { |
118 | | - ChannelController channelController = result.data(); |
119 | | - |
120 | | - // Observe typing users |
121 | | - channelController.getTyping().observe(this, typingState -> { |
122 | | - if (typingState.getUsers().isEmpty()) { |
123 | | - typingHeaderView.setText(nobodyTyping); |
124 | | - } else { |
125 | | - List<String> userNames = new LinkedList<>(); |
126 | | - for (User user : typingState.getUsers()) { |
127 | | - userNames.add(user.getName()); |
128 | | - } |
129 | | - String typing = "typing: " + TextUtils.join(", ", userNames); |
130 | | - typingHeaderView.setText(typing); |
131 | | - } |
132 | | - }); |
133 | | - }); |
| 124 | + binding.typingHeaderView.setText(nobodyTyping); |
| 125 | + |
| 126 | + // Observe typing events and update typing header depending on its state. |
| 127 | + Flow<ChannelState> channelStateFlow = ChatClientExtensions.watchChannelAsState(ChatClient.instance(), cid, 30); |
| 128 | + LiveData<TypingEvent> typingEventLiveData = Transformations.switchMap( |
| 129 | + FlowLiveDataConversions.asLiveData(channelStateFlow), |
| 130 | + channelState -> FlowLiveDataConversions.asLiveData(channelState.getTyping()) |
| 131 | + ); |
| 132 | + |
| 133 | + typingEventLiveData.observe(this, typingEvent -> { |
| 134 | + String headerText; |
| 135 | + |
| 136 | + if (typingEvent.getUsers().size() != 0) { |
| 137 | + headerText = "typing: " + joinTypingUpdatesToUserNames(typingEvent); |
| 138 | + } else { |
| 139 | + headerText = nobodyTyping; |
| 140 | + } |
| 141 | + |
| 142 | + binding.typingHeaderView.setText(headerText); |
| 143 | + }); |
| 144 | + } |
| 145 | + |
| 146 | + // Helper method that transforms typing updates into a string |
| 147 | + // containing typing member's names |
| 148 | + @NonNull |
| 149 | + private String joinTypingUpdatesToUserNames(@NonNull TypingEvent typingEvent) { |
| 150 | + StringBuilder joinedString = new StringBuilder(); |
| 151 | + |
| 152 | + for (int i = 0; i < typingEvent.getUsers().size(); i++) { |
| 153 | + if (i < typingEvent.getUsers().size() - 1) { |
| 154 | + joinedString.append(typingEvent.getUsers().get(i).getName()).append(", "); |
| 155 | + } else { |
| 156 | + joinedString.append(typingEvent.getUsers().get(i).getName()); |
| 157 | + } |
| 158 | + } |
| 159 | + |
| 160 | + return joinedString.toString(); |
134 | 161 | } |
135 | 162 | } |
0 commit comments