Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:8.13.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.21"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:2.2.0"
}
}

Expand Down
18 changes: 11 additions & 7 deletions samplejava/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ plugins {
}

android {
compileSdk 35
compileSdk 36
namespace "com.example.chattutorial"

defaultConfig {
applicationId "com.example.chattutorial"
minSdk 21
targetSdk 34
minSdk 24
targetSdk 36
versionCode 1
versionName "1.0"

Expand All @@ -27,14 +27,18 @@ android {
buildFeatures {
viewBinding true
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
}

dependencies {
// Add new dependencies
implementation "io.getstream:stream-chat-android-ui-components:6.28.0"
implementation "io.getstream:stream-chat-android-offline:6.28.0"
// Add the dependency
implementation "io.getstream:stream-chat-android-ui-components:7.3.0"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.8.7"
implementation "com.google.android.material:material:1.12.0"
implementation "androidx.activity:activity-ktx:1.10.1"
implementation "io.coil-kt:coil:2.7.0"
implementation "io.coil-kt.coil3:coil:3.1.0"
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@
import io.getstream.chat.android.models.Message;
import io.getstream.chat.android.ui.common.state.messages.Edit;
import io.getstream.chat.android.ui.common.state.messages.MessageMode;
import io.getstream.chat.android.ui.feature.messages.header.MessageListHeaderView;
import io.getstream.chat.android.ui.feature.messages.header.ChannelHeaderView;
import io.getstream.chat.android.ui.viewmodel.messages.MessageComposerViewModel;
import io.getstream.chat.android.ui.viewmodel.messages.MessageComposerViewModelBinding;
import io.getstream.chat.android.ui.viewmodel.messages.MessageListHeaderViewModel;
import io.getstream.chat.android.ui.viewmodel.messages.MessageListHeaderViewModelBinding;
import io.getstream.chat.android.ui.viewmodel.messages.ChannelHeaderViewModel;
import io.getstream.chat.android.ui.viewmodel.messages.ChannelHeaderViewModelBinding;
import io.getstream.chat.android.ui.viewmodel.messages.MessageListViewModel;
import io.getstream.chat.android.ui.viewmodel.messages.MessageListViewModelBinding;
import io.getstream.chat.android.ui.viewmodel.messages.MessageListViewModelFactory;
import io.getstream.chat.android.ui.viewmodel.messages.ChannelViewModelFactory;

public class ChannelActivity extends AppCompatActivity {

Expand All @@ -38,59 +38,61 @@ public static Intent newIntent(Context context, Channel channel) {
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// Step 0 - inflate binding
// inflate binding
ActivityChannelBinding binding = ActivityChannelBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());

EdgeToEdge.applySystemBarInsetsAsPadding(binding.getRoot());

String cid = getIntent().getStringExtra(CID_KEY);
if (cid == null) {
throw new IllegalStateException("Specifying a channel id is required when starting ChannelActivity");
}

// Step 1 - Create three separate ViewModels for the views so it's easy
// to customize them individually
ViewModelProvider.Factory factory = new MessageListViewModelFactory.Builder(this)
// Create three separate ViewModels for the views so it's easy
// to customize them individually
ViewModelProvider.Factory factory = new ChannelViewModelFactory.Builder(this)
.cid(cid)
.build();
ViewModelProvider provider = new ViewModelProvider(this, factory);
MessageListHeaderViewModel messageListHeaderViewModel = provider.get(MessageListHeaderViewModel.class);
ChannelHeaderViewModel channelHeaderViewModel = provider.get(ChannelHeaderViewModel.class);
MessageListViewModel messageListViewModel = provider.get(MessageListViewModel.class);
MessageComposerViewModel messageComposerViewModel = provider.get(MessageComposerViewModel.class);

// TODO set custom Imgur attachment factory

// Step 2 - Bind the view and ViewModels, they are loosely coupled so it's easy to customize
MessageListHeaderViewModelBinding.bind(messageListHeaderViewModel, binding.messageListHeaderView, this);
// Bind the view and ViewModels, they are loosely coupled so it's easy to customize
ChannelHeaderViewModelBinding.bind(channelHeaderViewModel, binding.channelHeaderView, this);
MessageListViewModelBinding.bind(messageListViewModel, binding.messageListView, this);
MessageComposerViewModelBinding.bind(messageComposerViewModel, binding.messageComposerView, this);

// Step 3 - Let both MessageListHeaderView and MessageComposerView know when we open a thread
// Let both ChannelHeaderView and MessageComposerView know when we open a thread
messageListViewModel.getMode().observe(this, mode -> {
if (mode instanceof MessageMode.MessageThread) {
Message parentMessage = ((MessageMode.MessageThread) mode).getParentMessage();
messageListHeaderViewModel.setActiveThread(parentMessage);
channelHeaderViewModel.setActiveThread(parentMessage);
messageComposerViewModel.setMessageMode(new MessageMode.MessageThread(parentMessage));
} else if (mode instanceof MessageMode.Normal) {
messageListHeaderViewModel.resetThread();
channelHeaderViewModel.resetThread();
messageComposerViewModel.leaveThread();
}
});

// Step 4 - Let the message input know when we are editing a message
// Let the message input know when we are editing a message
binding.messageListView.setMessageEditHandler(message -> {
messageComposerViewModel.performMessageAction(new Edit(message));
});

// Step 5 - Handle navigate up state
// Handle navigate up state
messageListViewModel.getState().observe(this, state -> {
if (state instanceof MessageListViewModel.State.NavigateUp) {
finish();
}
});

// Step 6 - Handle back button behaviour correctly when you're in a thread
MessageListHeaderView.OnClickListener backHandler = () -> messageListViewModel.onEvent(MessageListViewModel.Event.BackButtonPressed.INSTANCE);
binding.messageListHeaderView.setBackButtonClickListener(backHandler);
// Handle back button behaviour correctly when you're in a thread
ChannelHeaderView.OnClickListener backHandler = () -> messageListViewModel.onEvent(MessageListViewModel.Event.BackButtonPressed.INSTANCE);
binding.channelHeaderView.setBackButtonClickListener(backHandler);
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@
import io.getstream.chat.android.models.Message;
import io.getstream.chat.android.ui.common.state.messages.Edit;
import io.getstream.chat.android.ui.common.state.messages.MessageMode;
import io.getstream.chat.android.ui.feature.messages.header.MessageListHeaderView;
import io.getstream.chat.android.ui.feature.messages.header.ChannelHeaderView;
import io.getstream.chat.android.ui.feature.messages.list.adapter.viewholder.attachment.AttachmentFactoryManager;
import io.getstream.chat.android.ui.viewmodel.messages.MessageComposerViewModel;
import io.getstream.chat.android.ui.viewmodel.messages.MessageComposerViewModelBinding;
import io.getstream.chat.android.ui.viewmodel.messages.MessageListHeaderViewModel;
import io.getstream.chat.android.ui.viewmodel.messages.MessageListHeaderViewModelBinding;
import io.getstream.chat.android.ui.viewmodel.messages.ChannelHeaderViewModel;
import io.getstream.chat.android.ui.viewmodel.messages.ChannelHeaderViewModelBinding;
import io.getstream.chat.android.ui.viewmodel.messages.MessageListViewModel;
import io.getstream.chat.android.ui.viewmodel.messages.MessageListViewModelBinding;
import io.getstream.chat.android.ui.viewmodel.messages.MessageListViewModelFactory;
import io.getstream.chat.android.ui.viewmodel.messages.ChannelViewModelFactory;

public class ChannelActivity2 extends AppCompatActivity {

Expand All @@ -42,22 +42,24 @@ public static Intent newIntent(Context context, Channel channel) {
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// Step 0 - inflate binding
// inflate binding
ActivityChannel2Binding binding = ActivityChannel2Binding.inflate(getLayoutInflater());
setContentView(binding.getRoot());

EdgeToEdge.applySystemBarInsetsAsPadding(binding.getRoot());

String cid = getIntent().getStringExtra(CID_KEY);
if (cid == null) {
throw new IllegalStateException("Specifying a channel id is required when starting ChannelActivity2");
}

// Step 1 - Create three separate ViewModels for the views so it's easy
// to customize them individually
ViewModelProvider.Factory factory = new MessageListViewModelFactory.Builder(this)
// Create three separate ViewModels for the views so it's easy
// to customize them individually
ViewModelProvider.Factory factory = new ChannelViewModelFactory.Builder(this)
.cid(cid)
.build();
ViewModelProvider provider = new ViewModelProvider(this, factory);
MessageListHeaderViewModel messageListHeaderViewModel = provider.get(MessageListHeaderViewModel.class);
ChannelHeaderViewModel channelHeaderViewModel = provider.get(ChannelHeaderViewModel.class);
MessageListViewModel messageListViewModel = provider.get(MessageListViewModel.class);
MessageComposerViewModel messageComposerViewModel = provider.get(MessageComposerViewModel.class);

Expand All @@ -70,38 +72,38 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
AttachmentFactoryManager attachmentFactoryManager = new AttachmentFactoryManager(imgurAttachmentViewFactories);
binding.messageListView.setAttachmentFactoryManager(attachmentFactoryManager);

// Step 2 - Bind the view and ViewModels, they are loosely coupled so it's easy to customize
MessageListHeaderViewModelBinding.bind(messageListHeaderViewModel, binding.messageListHeaderView, this);
// Bind the view and ViewModels, they are loosely coupled so it's easy to customize
ChannelHeaderViewModelBinding.bind(channelHeaderViewModel, binding.channelHeaderView, this);
MessageListViewModelBinding.bind(messageListViewModel, binding.messageListView, this);
MessageComposerViewModelBinding.bind(messageComposerViewModel, binding.messageComposerView, this);

// Step 3 - Let both MessageListHeaderView and MessageComposerView know when we open a thread
// Let both ChannelHeaderView and MessageComposerView know when we open a thread
messageListViewModel.getMode().observe(this, mode -> {
if (mode instanceof MessageMode.MessageThread) {
Message parentMessage = ((MessageMode.MessageThread) mode).getParentMessage();
messageListHeaderViewModel.setActiveThread(parentMessage);
channelHeaderViewModel.setActiveThread(parentMessage);
messageComposerViewModel.setMessageMode(new MessageMode.MessageThread(parentMessage));
} else if (mode instanceof MessageMode.Normal) {
messageListHeaderViewModel.resetThread();
channelHeaderViewModel.resetThread();
messageComposerViewModel.leaveThread();
}
});

// Step 4 - Let the message input know when we are editing a message
// Let the message input know when we are editing a message
binding.messageListView.setMessageEditHandler(message -> {
messageComposerViewModel.performMessageAction(new Edit(message));
});

// Step 5 - Handle navigate up state
// Handle navigate up state
messageListViewModel.getState().observe(this, state -> {
if (state instanceof MessageListViewModel.State.NavigateUp) {
finish();
}
});

// Step 6 - Handle back button behaviour correctly when you're in a thread
MessageListHeaderView.OnClickListener backHandler = () -> messageListViewModel.onEvent(MessageListViewModel.Event.BackButtonPressed.INSTANCE);
binding.messageListHeaderView.setBackButtonClickListener(backHandler);
// Handle back button behaviour correctly when you're in a thread
ChannelHeaderView.OnClickListener backHandler = () -> messageListViewModel.onEvent(MessageListViewModel.Event.BackButtonPressed.INSTANCE);
binding.channelHeaderView.setBackButtonClickListener(backHandler);
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,18 @@
import io.getstream.chat.android.models.Channel;
import io.getstream.chat.android.models.Message;
import io.getstream.chat.android.models.TypingEvent;
import io.getstream.chat.android.state.extensions.ChatClientExtensions;
import io.getstream.chat.android.client.api.state.ChatClientExtensions;
import io.getstream.chat.android.ui.common.state.messages.Edit;
import io.getstream.chat.android.ui.common.state.messages.MessageMode;
import io.getstream.chat.android.ui.feature.messages.header.MessageListHeaderView;
import io.getstream.chat.android.ui.feature.messages.header.ChannelHeaderView;
import io.getstream.chat.android.ui.feature.messages.list.adapter.viewholder.attachment.AttachmentFactoryManager;
import io.getstream.chat.android.ui.viewmodel.messages.MessageComposerViewModel;
import io.getstream.chat.android.ui.viewmodel.messages.MessageComposerViewModelBinding;
import io.getstream.chat.android.ui.viewmodel.messages.MessageListHeaderViewModel;
import io.getstream.chat.android.ui.viewmodel.messages.MessageListHeaderViewModelBinding;
import io.getstream.chat.android.ui.viewmodel.messages.ChannelHeaderViewModel;
import io.getstream.chat.android.ui.viewmodel.messages.ChannelHeaderViewModelBinding;
import io.getstream.chat.android.ui.viewmodel.messages.MessageListViewModel;
import io.getstream.chat.android.ui.viewmodel.messages.MessageListViewModelBinding;
import io.getstream.chat.android.ui.viewmodel.messages.MessageListViewModelFactory;
import io.getstream.chat.android.ui.viewmodel.messages.ChannelViewModelFactory;
import kotlinx.coroutines.flow.Flow;

public class ChannelActivity3 extends AppCompatActivity {
Expand All @@ -51,22 +51,24 @@ public static Intent newIntent(Context context, Channel channel) {
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// Step 0 - inflate binding
// inflate binding
ActivityChannel3Binding binding = ActivityChannel3Binding.inflate(getLayoutInflater());
setContentView(binding.getRoot());

EdgeToEdge.applySystemBarInsetsAsPadding(binding.getRoot());

String cid = getIntent().getStringExtra(CID_KEY);
if (cid == null) {
throw new IllegalStateException("Specifying a channel id is required when starting ChannelActivity3");
}

// Step 1 - Create three separate ViewModels for the views so it's easy
// to customize them individually
ViewModelProvider.Factory factory = new MessageListViewModelFactory.Builder(this)
// Create three separate ViewModels for the views so it's easy
// to customize them individually
ViewModelProvider.Factory factory = new ChannelViewModelFactory.Builder(this)
.cid(cid)
.build();
ViewModelProvider provider = new ViewModelProvider(this, factory);
MessageListHeaderViewModel messageListHeaderViewModel = provider.get(MessageListHeaderViewModel.class);
ChannelHeaderViewModel channelHeaderViewModel = provider.get(ChannelHeaderViewModel.class);
MessageListViewModel messageListViewModel = provider.get(MessageListViewModel.class);
MessageComposerViewModel messageComposerViewModel = provider.get(MessageComposerViewModel.class);

Expand All @@ -79,38 +81,38 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
AttachmentFactoryManager attachmentFactoryManager = new AttachmentFactoryManager(imgurAttachmentViewFactories);
binding.messageListView.setAttachmentFactoryManager(attachmentFactoryManager);

// Step 2 - Bind the view and ViewModels, they are loosely coupled so it's easy to customize
MessageListHeaderViewModelBinding.bind(messageListHeaderViewModel, binding.messageListHeaderView, this);
// Bind the view and ViewModels, they are loosely coupled so it's easy to customize
ChannelHeaderViewModelBinding.bind(channelHeaderViewModel, binding.channelHeaderView, this);
MessageListViewModelBinding.bind(messageListViewModel, binding.messageListView, this);
MessageComposerViewModelBinding.bind(messageComposerViewModel, binding.messageComposerView, this);

// Step 3 - Let both MessageListHeaderView and MessageComposerView know when we open a thread
// Let both ChannelHeaderView and MessageComposerView know when we open a thread
messageListViewModel.getMode().observe(this, mode -> {
if (mode instanceof MessageMode.MessageThread) {
Message parentMessage = ((MessageMode.MessageThread) mode).getParentMessage();
messageListHeaderViewModel.setActiveThread(parentMessage);
channelHeaderViewModel.setActiveThread(parentMessage);
messageComposerViewModel.setMessageMode(new MessageMode.MessageThread(parentMessage));
} else if (mode instanceof MessageMode.Normal) {
messageListHeaderViewModel.resetThread();
channelHeaderViewModel.resetThread();
messageComposerViewModel.leaveThread();
}
});

// Step 4 - Let the message input know when we are editing a message
// Let the message input know when we are editing a message
binding.messageListView.setMessageEditHandler(message -> {
messageComposerViewModel.performMessageAction(new Edit(message));
});

// Step 5 - Handle navigate up state
// Handle navigate up state
messageListViewModel.getState().observe(this, state -> {
if (state instanceof MessageListViewModel.State.NavigateUp) {
finish();
}
});

// Step 6 - Handle back button behaviour correctly when you're in a thread
MessageListHeaderView.OnClickListener backHandler = () -> messageListViewModel.onEvent(MessageListViewModel.Event.BackButtonPressed.INSTANCE);
binding.messageListHeaderView.setBackButtonClickListener(backHandler);
// Handle back button behaviour correctly when you're in a thread
ChannelHeaderView.OnClickListener backHandler = () -> messageListViewModel.onEvent(MessageListViewModel.Event.BackButtonPressed.INSTANCE);
binding.channelHeaderView.setBackButtonClickListener(backHandler);
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
Expand Down
Loading
Loading