Skip to content

Commit eb31322

Browse files
committed
Revert changes from empty template
1 parent 0b84877 commit eb31322

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1742
-122
lines changed

LICENSE

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
BSD 3-Clause License
2+
3+
Copyright (c) 2020, Stream.io Inc
4+
All rights reserved.
5+
6+
Redistribution and use in source and binary forms, with or without
7+
modification, are permitted provided that the following conditions are met:
8+
9+
1. Redistributions of source code must retain the above copyright notice, this
10+
list of conditions and the following disclaimer.
11+
12+
2. Redistributions in binary form must reproduce the above copyright notice,
13+
this list of conditions and the following disclaimer in the documentation
14+
and/or other materials provided with the distribution.
15+
16+
3. Neither the name of the copyright holder nor the names of its
17+
contributors may be used to endorse or promote products derived from
18+
this software without specific prior written permission.
19+
20+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Android Chat Tutorial Sample
2+
3+
This repository allows you to check the result after completing each step described in the [Android Chat Tutorial](https://getstream.io/tutorials/android-chat/#kotlin). It contains samples written in both **Kotlin** (_samplekotlin_ module) and **Java** (_samplejava_ module). For more Android Chat examples, see the [Github repo for UX/Views and its Sample app](https://github.com/GetStream/stream-chat-android).
4+
5+
The project is pre-configured with a shared [Stream](https://getstream.io) account for testing purposes. You can learn more about Stream Chat [here](https://getstream.io/chat/), and then sign up for an account and obtain your own keys [here](https://getstream.io/chat/trial).
6+
7+
## Quick start
8+
9+
1. Clone the repository
10+
2. Open the project in Android Studio
11+
3. Run the _samplekotlin_ or _samplejava_ configuration
12+
4. Make sure to check the [Details](#details) section below for customizations
13+
14+
## Details
15+
16+
The sample apps consist of two screens:
17+
18+
* `MainActivity`: Shows the list of available channels.
19+
* `ChannelActivity`: Shows the selected channel view, which includes the header, message list, and message input view.
20+
21+
Each module contains multiple `ChannelActivity` implementations, which correspond to the steps of the tutorial. You can easily swap them by changing the `setOnChannelClickListener` located in `MainActivity`:
22+
23+
```kotlin
24+
channelListView.setOnChannelClickListener { channel ->
25+
// open the channel activity
26+
startActivity(ChannelActivity.newIntent(this, channel))
27+
}
28+
```
29+
30+
Currently, you can choose from four different `ChannelActivity` implementations:
31+
<!-- TODO: Add links when the new version of the Android Tutorial is published -->
32+
* `ChannelActivity` - a basic _Message List_ implementation
33+
* `ChannelActivity2` - includes a new _MessageListView_ style and custom attachment type
34+
* `ChannelActivity3` - includes a custom _Typing Header_ component created with the [LiveData&Offline](https://github.com/GetStream/stream-chat-android-livedata) library
35+
* `ChannelActivity4` - includes a custom _Typing Header_ component created with the [Low-Level Client](https://github.com/GetStream/stream-chat-android-client) library

build.gradle

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// Top-level build file where you can add configuration options common to all sub-projects/modules.
21
buildscript {
32
ext.kotlin_version = "1.4.30"
43
repositories {
@@ -8,15 +7,14 @@ buildscript {
87
dependencies {
98
classpath "com.android.tools.build:gradle:4.1.2"
109
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11-
12-
// NOTE: Do not place your application dependencies here; they belong
13-
// in the individual module build.gradle files
1410
}
1511
}
1612

1713
allprojects {
1814
repositories {
1915
google()
16+
mavenCentral()
17+
maven { url "https://jitpack.io" }
2018
jcenter()
2119
}
2220
}

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
1212
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
1313
# org.gradle.parallel=true
1414
# AndroidX package structure to make it clearer which packages are bundled with the
15-
# Android operating system, and which are packaged with your app"s APK
15+
# Android operating system, and which are packaged with your app's APK
1616
# https://developer.android.com/topic/libraries/support-library/androidx-rn
1717
android.useAndroidX=true
1818
# Automatically convert third-party libraries to use AndroidX
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
#Tue Feb 16 00:16:53 MSK 2021
1+
#Wed Oct 28 11:57:55 MDT 2020
22
distributionBase=GRADLE_USER_HOME
33
distributionPath=wrapper/dists
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists
6-
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
6+
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
7+

samplejava/build.gradle

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,18 @@ android {
2626
sourceCompatibility JavaVersion.VERSION_1_8
2727
targetCompatibility JavaVersion.VERSION_1_8
2828
}
29+
30+
// Enable ViewBinding
31+
buildFeatures {
32+
viewBinding true
33+
}
2934
}
3035

3136
dependencies {
37+
// Add new dependencies
38+
implementation "io.getstream:stream-chat-android-ui-components:4.5.5"
39+
implementation 'io.coil-kt:coil:1.1.1'
40+
3241
implementation 'androidx.appcompat:appcompat:1.2.0'
3342
implementation 'com.google.android.material:material:1.3.0'
3443
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'

samplejava/src/androidTest/java/com/example/chattutorialjava/ExampleInstrumentedTest.java

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

samplejava/src/main/AndroidManifest.xml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,18 @@
88
android:label="@string/app_name"
99
android:roundIcon="@mipmap/ic_launcher_round"
1010
android:supportsRtl="true"
11-
android:theme="@style/Theme.TestJava">
11+
android:theme="@style/Theme.ChatTutorial">
1212
<activity android:name=".MainActivity">
1313
<intent-filter>
1414
<action android:name="android.intent.action.MAIN" />
1515

1616
<category android:name="android.intent.category.LAUNCHER" />
1717
</intent-filter>
1818
</activity>
19+
<activity android:name=".ChannelActivity" />
20+
<activity android:name=".ChannelActivity2" />
21+
<activity android:name=".ChannelActivity3" />
22+
<activity android:name=".ChannelActivity4" />
1923
</application>
2024

2125
</manifest>
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package com.example.chattutorialjava;
2+
3+
import android.content.Context;
4+
import android.content.Intent;
5+
import android.os.Bundle;
6+
7+
import androidx.activity.OnBackPressedCallback;
8+
import androidx.annotation.Nullable;
9+
import androidx.appcompat.app.AppCompatActivity;
10+
import androidx.lifecycle.ViewModelProvider;
11+
12+
import com.example.chattutorialjava.databinding.ActivityChannelBinding;
13+
import com.getstream.sdk.chat.viewmodel.MessageInputViewModel;
14+
import com.getstream.sdk.chat.viewmodel.messages.MessageListViewModel;
15+
import com.getstream.sdk.chat.viewmodel.messages.MessageListViewModel.Mode.Normal;
16+
import com.getstream.sdk.chat.viewmodel.messages.MessageListViewModel.Mode.Thread;
17+
import com.getstream.sdk.chat.viewmodel.messages.MessageListViewModel.State.NavigateUp;
18+
19+
import io.getstream.chat.android.client.models.Channel;
20+
import io.getstream.chat.android.ui.message.input.viewmodel.MessageInputViewModelBinding;
21+
import io.getstream.chat.android.ui.message.list.header.MessageListHeaderView;
22+
import io.getstream.chat.android.ui.message.list.header.viewmodel.MessageListHeaderViewModel;
23+
import io.getstream.chat.android.ui.message.list.header.viewmodel.MessageListHeaderViewModelBinding;
24+
import io.getstream.chat.android.ui.message.list.viewmodel.MessageListViewModelBinding;
25+
import io.getstream.chat.android.ui.message.list.viewmodel.factory.MessageListViewModelFactory;
26+
27+
public class ChannelActivity extends AppCompatActivity {
28+
29+
private final static String CID_KEY = "key:cid";
30+
31+
public static Intent newIntent(Context context, Channel channel) {
32+
final Intent intent = new Intent(context, ChannelActivity.class);
33+
intent.putExtra(CID_KEY, channel.getCid());
34+
return intent;
35+
}
36+
37+
@Override
38+
protected void onCreate(@Nullable Bundle savedInstanceState) {
39+
super.onCreate(savedInstanceState);
40+
41+
// Step 0 - inflate binding
42+
ActivityChannelBinding binding = ActivityChannelBinding.inflate(getLayoutInflater());
43+
setContentView(binding.getRoot());
44+
45+
String cid = getIntent().getStringExtra(CID_KEY);
46+
if (cid == null) {
47+
throw new IllegalStateException("Specifying a channel id is required when starting ChannelActivity");
48+
}
49+
50+
// Step 1 - Create 3 separate ViewModels for the views so it's easy to customize one of the components
51+
MessageListViewModelFactory factory = new MessageListViewModelFactory(cid);
52+
ViewModelProvider provider = new ViewModelProvider(this, factory);
53+
MessageListHeaderViewModel channelHeaderViewModel = provider.get(MessageListHeaderViewModel.class);
54+
MessageListViewModel messageListViewModel = provider.get(MessageListViewModel.class);
55+
MessageInputViewModel messageInputViewModel = provider.get(MessageInputViewModel.class);
56+
57+
// TODO set custom Imgur attachment View Holder Factory
58+
59+
// Step 2 - Bind the view and ViewModels, they are loosely coupled so it's easy to customize
60+
MessageListHeaderViewModelBinding.bind(channelHeaderViewModel, binding.messageListHeaderView, this);
61+
MessageListViewModelBinding.bind(messageListViewModel, binding.messageListView, this);
62+
MessageInputViewModelBinding.bind(messageInputViewModel, binding.messageInputView, this);
63+
64+
// Step 3 - Let the message input know when we open a thread
65+
messageListViewModel.getMode().observe(this, mode -> {
66+
if (mode instanceof Thread) {
67+
messageInputViewModel.setActiveThread(((Thread) mode).getParentMessage());
68+
} else if (mode instanceof Normal) {
69+
messageInputViewModel.resetThread();
70+
}
71+
});
72+
73+
// Step 4 - Let the message input know when we are editing a message
74+
binding.messageListView.setMessageEditHandler(message -> {
75+
messageInputViewModel.getEditMessage().postValue(message);
76+
});
77+
78+
// Step 5 - Handle navigate up state
79+
messageListViewModel.getState().observe(this, state -> {
80+
if (state instanceof NavigateUp) {
81+
finish();
82+
}
83+
});
84+
85+
// Step 6 - Handle back button behaviour correctly when you're in a thread
86+
MessageListHeaderView.OnClickListener backHandler = () -> {
87+
messageListViewModel.onEvent(MessageListViewModel.Event.BackButtonPressed.INSTANCE);
88+
};
89+
90+
binding.messageListHeaderView.setBackButtonClickListener(backHandler);
91+
92+
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
93+
@Override
94+
public void handleOnBackPressed() {
95+
backHandler.onClick();
96+
}
97+
});
98+
}
99+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package com.example.chattutorialjava;
2+
3+
import android.content.Context;
4+
import android.content.Intent;
5+
import android.os.Bundle;
6+
7+
import androidx.activity.OnBackPressedCallback;
8+
import androidx.annotation.Nullable;
9+
import androidx.appcompat.app.AppCompatActivity;
10+
import androidx.lifecycle.ViewModelProvider;
11+
12+
import com.example.chattutorialjava.databinding.ActivityChannel2Binding;
13+
import com.getstream.sdk.chat.viewmodel.MessageInputViewModel;
14+
import com.getstream.sdk.chat.viewmodel.messages.MessageListViewModel;
15+
import com.getstream.sdk.chat.viewmodel.messages.MessageListViewModel.Mode.Normal;
16+
import com.getstream.sdk.chat.viewmodel.messages.MessageListViewModel.Mode.Thread;
17+
import com.getstream.sdk.chat.viewmodel.messages.MessageListViewModel.State.NavigateUp;
18+
19+
import io.getstream.chat.android.client.models.Channel;
20+
import io.getstream.chat.android.ui.message.input.viewmodel.MessageInputViewModelBinding;
21+
import io.getstream.chat.android.ui.message.list.header.MessageListHeaderView;
22+
import io.getstream.chat.android.ui.message.list.header.viewmodel.MessageListHeaderViewModel;
23+
import io.getstream.chat.android.ui.message.list.header.viewmodel.MessageListHeaderViewModelBinding;
24+
import io.getstream.chat.android.ui.message.list.viewmodel.MessageListViewModelBinding;
25+
import io.getstream.chat.android.ui.message.list.viewmodel.factory.MessageListViewModelFactory;
26+
27+
public class ChannelActivity2 extends AppCompatActivity {
28+
29+
private final static String CID_KEY = "key:cid";
30+
31+
public static Intent newIntent(Context context, Channel channel) {
32+
final Intent intent = new Intent(context, ChannelActivity2.class);
33+
intent.putExtra(CID_KEY, channel.getCid());
34+
return intent;
35+
}
36+
37+
@Override
38+
protected void onCreate(@Nullable Bundle savedInstanceState) {
39+
super.onCreate(savedInstanceState);
40+
41+
// Step 0 - inflate binding
42+
ActivityChannel2Binding binding = ActivityChannel2Binding.inflate(getLayoutInflater());
43+
setContentView(binding.getRoot());
44+
45+
String cid = getIntent().getStringExtra(CID_KEY);
46+
if (cid == null) {
47+
throw new IllegalStateException("Specifying a channel id is required when starting ChannelActivity2");
48+
}
49+
50+
// Step 1 - Create 3 separate ViewModels for the views so it's easy to customize one of the components
51+
MessageListViewModelFactory factory = new MessageListViewModelFactory(cid);
52+
ViewModelProvider provider = new ViewModelProvider(this, factory);
53+
MessageListHeaderViewModel channelHeaderViewModel = provider.get(MessageListHeaderViewModel.class);
54+
MessageListViewModel messageListViewModel = provider.get(MessageListViewModel.class);
55+
MessageInputViewModel messageInputViewModel = provider.get(MessageInputViewModel.class);
56+
57+
// Set view holder factory for Imgur attachments
58+
binding.messageListView.setMessageViewHolderFactory(new ImgurAttachmentViewHolderFactory());
59+
60+
// Step 2 - Bind the view and ViewModels, they are loosely coupled so it's easy to customize
61+
MessageListHeaderViewModelBinding.bind(channelHeaderViewModel, binding.messageListHeaderView, this);
62+
MessageListViewModelBinding.bind(messageListViewModel, binding.messageListView, this);
63+
MessageInputViewModelBinding.bind(messageInputViewModel, binding.messageInputView, this);
64+
65+
// Step 3 - Let the message input know when we open a thread
66+
messageListViewModel.getMode().observe(this, mode -> {
67+
if (mode instanceof Thread) {
68+
messageInputViewModel.setActiveThread(((Thread) mode).getParentMessage());
69+
} else if (mode instanceof Normal) {
70+
messageInputViewModel.resetThread();
71+
}
72+
});
73+
74+
// Step 4 - Handle navigate up state
75+
messageListViewModel.getState().observe(this, state -> {
76+
if (state instanceof NavigateUp) {
77+
finish();
78+
}
79+
});
80+
81+
// Step 5 - Let the message input know when we are editing a message
82+
binding.messageListView.setMessageEditHandler(message -> {
83+
messageInputViewModel.getEditMessage().postValue(message);
84+
});
85+
86+
// Step 6 - Handle back button behaviour correctly when you're in a thread
87+
MessageListHeaderView.OnClickListener backHandler = () -> {
88+
messageListViewModel.onEvent(MessageListViewModel.Event.BackButtonPressed.INSTANCE);
89+
};
90+
91+
binding.messageListHeaderView.setBackButtonClickListener(backHandler);
92+
93+
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
94+
@Override
95+
public void handleOnBackPressed() {
96+
backHandler.onClick();
97+
}
98+
});
99+
}
100+
}

0 commit comments

Comments
 (0)