├── .gitignore
├── README.md
├── app
├── .gitignore
├── build.gradle
├── google-services.json
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── example
│ │ └── easychat
│ │ └── ExampleInstrumentedTest.java
│ ├── debug
│ ├── ic_launcher-playstore.png
│ └── res
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ └── ic_launcher_background.xml
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── example
│ │ │ └── easychat
│ │ │ ├── ChatActivity.java
│ │ │ ├── ChatFragment.java
│ │ │ ├── FCMNotificationService.java
│ │ │ ├── LoginOtpActivity.java
│ │ │ ├── LoginPhoneNumberActivity.java
│ │ │ ├── LoginUsernameActivity.java
│ │ │ ├── MainActivity.java
│ │ │ ├── ProfileFragment.java
│ │ │ ├── SearchUserActivity.java
│ │ │ ├── SplashActivity.java
│ │ │ ├── adapter
│ │ │ ├── ChatRecyclerAdapter.java
│ │ │ ├── RecentChatRecyclerAdapter.java
│ │ │ └── SearchUserRecyclerAdapter.java
│ │ │ ├── model
│ │ │ ├── ChatMessageModel.java
│ │ │ ├── ChatroomModel.java
│ │ │ └── UserModel.java
│ │ │ └── utils
│ │ │ ├── AndroidUtil.java
│ │ │ └── FirebaseUtil.java
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ ├── btn_rounded_corner.xml
│ │ ├── chat_icon.xml
│ │ ├── circular_bg.xml
│ │ ├── edit_text_rounded_corner.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── icon_back.xml
│ │ ├── icon_search.xml
│ │ ├── icon_send.xml
│ │ ├── launcher_icon.png
│ │ ├── otp_icon.xml
│ │ ├── person_icon.xml
│ │ └── phone_icon.xml
│ │ ├── layout
│ │ ├── activity_chat.xml
│ │ ├── activity_login_otp.xml
│ │ ├── activity_login_phone_number.xml
│ │ ├── activity_login_username.xml
│ │ ├── activity_main.xml
│ │ ├── activity_search_user.xml
│ │ ├── activity_splash.xml
│ │ ├── chat_message_recycler_row.xml
│ │ ├── fragment_chat.xml
│ │ ├── fragment_profile.xml
│ │ ├── profile_pic_view.xml
│ │ ├── recent_chat_recycler_row.xml
│ │ └── search_user_recycler_row.xml
│ │ ├── menu
│ │ └── bottom_navigation_menu.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── values-night
│ │ └── themes.xml
│ │ ├── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ │ └── xml
│ │ ├── backup_rules.xml
│ │ └── data_extraction_rules.xml
│ └── test
│ └── java
│ └── com
│ └── example
│ └── easychat
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Firebase Chat App
2 |
3 | Welcome to the Firebase Chat App repository! This app enables real-time chat functionality using Firebase as the backend. Below is a list of key files and their functionalities:
4 |
5 | ## Activity Files
6 |
7 | - `ChatActivity.java`: The main activity for individual chat conversations.
8 | - `LoginOtpActivity.java`: Handles user authentication using OTP.
9 | - `LoginPhoneNumberActivity.java`: Manages phone number-based user login.
10 | - `LoginUsernameActivity.java`: Controls user login using a username.
11 | - `MainActivity.java`: The app's entry point and primary navigation hub.
12 | - `SearchUserActivity.java`: Allows users to search for other users to initiate chats.
13 | - `SplashActivity.java`: Displays a splash screen while the app initializes.
14 |
15 | ## Fragment Files
16 |
17 | - `ChatFragment.java`: Manages chat UI and logic within the chat activity.
18 | - `ProfileFragment.java`: Handles user profile display and editing.
19 | - `SearchUserFragment.java`: Displays user search results and options for starting a chat.
20 |
21 | ## Service File
22 |
23 | - `FCMNotificationService.java`: Integrates Firebase Cloud Messaging for push notifications.
24 |
25 | Feel free to explore these files to understand the structure of the app and how different components interact. The app leverages Firebase Authentication, Realtime Database, and Firebase Cloud Messaging to provide seamless chat functionality.
26 |
27 | ## Getting Started
28 |
29 | To use this app:
30 |
31 | 1. Clone or download the repository.
32 | 2. Set up your Firebase project and update the `google-services.json` file.
33 | 3. Build and run the app on your Android device or emulator.
34 |
35 | ## Notes
36 |
37 | - This repository provides a basic structure for a Firebase-based chat app. You can extend and customize it as per your requirements.
38 | - Make sure to handle security and privacy aspects when implementing user authentication and chat features.
39 |
40 | For more details about Firebase services and Android app development, refer to the official [Firebase Documentation](https://firebase.google.com/docs) and [Android Documentation](https://developer.android.com/docs).
41 |
42 | Happy coding!
43 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'com.google.gms.google-services'
4 | }
5 |
6 | android {
7 | namespace 'com.example.easychat'
8 | compileSdk 33
9 |
10 | defaultConfig {
11 | applicationId "com.example.easychat"
12 | minSdk 26
13 | targetSdk 33
14 | versionCode 1
15 | versionName "1.0"
16 |
17 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
18 | }
19 |
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 | compileOptions {
27 | sourceCompatibility JavaVersion.VERSION_1_8
28 | targetCompatibility JavaVersion.VERSION_1_8
29 | }
30 | }
31 |
32 | dependencies {
33 |
34 | implementation 'androidx.appcompat:appcompat:1.6.1'
35 | implementation 'com.google.android.material:material:1.8.0'
36 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
37 | implementation 'com.google.firebase:firebase-firestore-ktx:24.4.4'
38 | implementation 'com.google.firebase:firebase-storage-ktx:20.1.0'
39 | implementation 'com.google.firebase:firebase-messaging-ktx:23.1.2'
40 | testImplementation 'junit:junit:4.13.2'
41 | androidTestImplementation 'androidx.test.ext:junit:1.1.5'
42 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
43 | implementation 'com.hbb20:ccp:2.5.0'
44 |
45 | implementation platform('com.google.firebase:firebase-bom:31.3.0')
46 | implementation 'com.google.firebase:firebase-auth'
47 | implementation 'com.firebaseui:firebase-ui-firestore:8.0.2'
48 | implementation 'com.github.dhaval2404:imagepicker:2.1'
49 | implementation 'com.github.bumptech.glide:glide:4.15.1'
50 | implementation("com.squareup.okhttp3:okhttp:4.10.0")
51 |
52 | }
--------------------------------------------------------------------------------
/app/google-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_info": {
3 | "project_number": "745155540833",
4 | "project_id": "easy-chat-backend",
5 | "storage_bucket": "easy-chat-backend.appspot.com"
6 | },
7 | "client": [
8 | {
9 | "client_info": {
10 | "mobilesdk_app_id": "1:745155540833:android:8d8356e6c4a882ecde7720",
11 | "android_client_info": {
12 | "package_name": "com.example.easychat"
13 | }
14 | },
15 | "oauth_client": [
16 | {
17 | "client_id": "745155540833-fvdk5u97tdl1i3nje2hr4n0pnnlc9q4f.apps.googleusercontent.com",
18 | "client_type": 3
19 | }
20 | ],
21 | "api_key": [
22 | {
23 | "current_key": "AIzaSyAkXBuJqEYHZJ00fpHgKcLGocgZ3ZXMWo0"
24 | }
25 | ],
26 | "services": {
27 | "appinvite_service": {
28 | "other_platform_oauth_client": [
29 | {
30 | "client_id": "745155540833-fvdk5u97tdl1i3nje2hr4n0pnnlc9q4f.apps.googleusercontent.com",
31 | "client_type": 3
32 | }
33 | ]
34 | }
35 | }
36 | }
37 | ],
38 | "configuration_version": "1"
39 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/example/easychat/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.example.easychat;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.platform.app.InstrumentationRegistry;
6 | import androidx.test.ext.junit.runners.AndroidJUnit4;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import static org.junit.Assert.*;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24 | assertEquals("com.example.easychat", appContext.getPackageName());
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/debug/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/debug/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/debug/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/debug/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/debug/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/debug/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/debug/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/debug/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/debug/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/debug/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/debug/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/debug/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/debug/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/debug/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/debug/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
15 |
16 |
18 |
20 |
21 |
24 |
27 |
28 |
31 |
34 |
35 |
38 |
41 |
42 |
45 |
48 |
49 |
52 |
55 |
56 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
68 |
69 |
72 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/easychat/ChatActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.easychat;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.appcompat.app.AppCompatActivity;
5 | import androidx.recyclerview.widget.LinearLayoutManager;
6 | import androidx.recyclerview.widget.RecyclerView;
7 |
8 | import android.net.Uri;
9 | import android.os.Bundle;
10 | import android.util.Log;
11 | import android.widget.EditText;
12 | import android.widget.ImageButton;
13 | import android.widget.ImageView;
14 | import android.widget.TextView;
15 |
16 | import com.example.easychat.adapter.ChatRecyclerAdapter;
17 | import com.example.easychat.adapter.SearchUserRecyclerAdapter;
18 | import com.example.easychat.model.ChatMessageModel;
19 | import com.example.easychat.model.ChatroomModel;
20 | import com.example.easychat.model.UserModel;
21 | import com.example.easychat.utils.AndroidUtil;
22 | import com.example.easychat.utils.FirebaseUtil;
23 | import com.firebase.ui.firestore.FirestoreRecyclerOptions;
24 | import com.google.android.gms.tasks.OnCompleteListener;
25 | import com.google.android.gms.tasks.Task;
26 | import com.google.firebase.Timestamp;
27 | import com.google.firebase.firestore.DocumentReference;
28 | import com.google.firebase.firestore.DocumentSnapshot;
29 | import com.google.firebase.firestore.Query;
30 |
31 | import org.checkerframework.checker.units.qual.C;
32 | import org.json.JSONObject;
33 |
34 | import java.io.IOException;
35 | import java.sql.Time;
36 | import java.util.Arrays;
37 |
38 | import okhttp3.Call;
39 | import okhttp3.Callback;
40 | import okhttp3.MediaType;
41 | import okhttp3.OkHttpClient;
42 | import okhttp3.Request;
43 | import okhttp3.RequestBody;
44 | import okhttp3.Response;
45 |
46 | public class ChatActivity extends AppCompatActivity {
47 |
48 | UserModel otherUser;
49 | String chatroomId;
50 | ChatroomModel chatroomModel;
51 | ChatRecyclerAdapter adapter;
52 |
53 | EditText messageInput;
54 | ImageButton sendMessageBtn;
55 | ImageButton backBtn;
56 | TextView otherUsername;
57 | RecyclerView recyclerView;
58 | ImageView imageView;
59 |
60 |
61 | @Override
62 | protected void onCreate(Bundle savedInstanceState) {
63 | super.onCreate(savedInstanceState);
64 | setContentView(R.layout.activity_chat);
65 |
66 | //get UserModel
67 | otherUser = AndroidUtil.getUserModelFromIntent(getIntent());
68 | chatroomId = FirebaseUtil.getChatroomId(FirebaseUtil.currentUserId(),otherUser.getUserId());
69 |
70 | messageInput = findViewById(R.id.chat_message_input);
71 | sendMessageBtn = findViewById(R.id.message_send_btn);
72 | backBtn = findViewById(R.id.back_btn);
73 | otherUsername = findViewById(R.id.other_username);
74 | recyclerView = findViewById(R.id.chat_recycler_view);
75 | imageView = findViewById(R.id.profile_pic_image_view);
76 |
77 | FirebaseUtil.getOtherProfilePicStorageRef(otherUser.getUserId()).getDownloadUrl()
78 | .addOnCompleteListener(t -> {
79 | if(t.isSuccessful()){
80 | Uri uri = t.getResult();
81 | AndroidUtil.setProfilePic(this,uri,imageView);
82 | }
83 | });
84 |
85 | backBtn.setOnClickListener((v)->{
86 | onBackPressed();
87 | });
88 | otherUsername.setText(otherUser.getUsername());
89 |
90 | sendMessageBtn.setOnClickListener((v -> {
91 | String message = messageInput.getText().toString().trim();
92 | if(message.isEmpty())
93 | return;
94 | sendMessageToUser(message);
95 | }));
96 |
97 | getOrCreateChatroomModel();
98 | setupChatRecyclerView();
99 | }
100 |
101 | void setupChatRecyclerView(){
102 | Query query = FirebaseUtil.getChatroomMessageReference(chatroomId)
103 | .orderBy("timestamp", Query.Direction.DESCENDING);
104 |
105 | FirestoreRecyclerOptions options = new FirestoreRecyclerOptions.Builder()
106 | .setQuery(query,ChatMessageModel.class).build();
107 |
108 | adapter = new ChatRecyclerAdapter(options,getApplicationContext());
109 | LinearLayoutManager manager = new LinearLayoutManager(this);
110 | manager.setReverseLayout(true);
111 | recyclerView.setLayoutManager(manager);
112 | recyclerView.setAdapter(adapter);
113 | adapter.startListening();
114 | adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
115 | @Override
116 | public void onItemRangeInserted(int positionStart, int itemCount) {
117 | super.onItemRangeInserted(positionStart, itemCount);
118 | recyclerView.smoothScrollToPosition(0);
119 | }
120 | });
121 | }
122 |
123 | void sendMessageToUser(String message){
124 |
125 | chatroomModel.setLastMessageTimestamp(Timestamp.now());
126 | chatroomModel.setLastMessageSenderId(FirebaseUtil.currentUserId());
127 | chatroomModel.setLastMessage(message);
128 | FirebaseUtil.getChatroomReference(chatroomId).set(chatroomModel);
129 |
130 | ChatMessageModel chatMessageModel = new ChatMessageModel(message,FirebaseUtil.currentUserId(),Timestamp.now());
131 | FirebaseUtil.getChatroomMessageReference(chatroomId).add(chatMessageModel)
132 | .addOnCompleteListener(new OnCompleteListener() {
133 | @Override
134 | public void onComplete(@NonNull Task task) {
135 | if(task.isSuccessful()){
136 | messageInput.setText("");
137 | sendNotification(message);
138 | }
139 | }
140 | });
141 | }
142 |
143 | void getOrCreateChatroomModel(){
144 | FirebaseUtil.getChatroomReference(chatroomId).get().addOnCompleteListener(task -> {
145 | if(task.isSuccessful()){
146 | chatroomModel = task.getResult().toObject(ChatroomModel.class);
147 | if(chatroomModel==null){
148 | //first time chat
149 | chatroomModel = new ChatroomModel(
150 | chatroomId,
151 | Arrays.asList(FirebaseUtil.currentUserId(),otherUser.getUserId()),
152 | Timestamp.now(),
153 | ""
154 | );
155 | FirebaseUtil.getChatroomReference(chatroomId).set(chatroomModel);
156 | }
157 | }
158 | });
159 | }
160 |
161 | void sendNotification(String message){
162 |
163 | FirebaseUtil.currentUserDetails().get().addOnCompleteListener(task -> {
164 | if(task.isSuccessful()){
165 | UserModel currentUser = task.getResult().toObject(UserModel.class);
166 | try{
167 | JSONObject jsonObject = new JSONObject();
168 |
169 | JSONObject notificationObj = new JSONObject();
170 | notificationObj.put("title",currentUser.getUsername());
171 | notificationObj.put("body",message);
172 |
173 | JSONObject dataObj = new JSONObject();
174 | dataObj.put("userId",currentUser.getUserId());
175 |
176 | jsonObject.put("notification",notificationObj);
177 | jsonObject.put("data",dataObj);
178 | jsonObject.put("to",otherUser.getFcmToken());
179 |
180 | callApi(jsonObject);
181 |
182 |
183 | }catch (Exception e){
184 |
185 | }
186 |
187 | }
188 | });
189 |
190 | }
191 |
192 | void callApi(JSONObject jsonObject){
193 | MediaType JSON = MediaType.get("application/json; charset=utf-8");
194 | OkHttpClient client = new OkHttpClient();
195 | String url = "https://fcm.googleapis.com/fcm/send";
196 | RequestBody body = RequestBody.create(jsonObject.toString(),JSON);
197 | Request request = new Request.Builder()
198 | .url(url)
199 | .post(body)
200 | .header("Authorization","Bearer YOUR_API_KEY")
201 | .build();
202 | client.newCall(request).enqueue(new Callback() {
203 | @Override
204 | public void onFailure(@NonNull Call call, @NonNull IOException e) {
205 |
206 | }
207 |
208 | @Override
209 | public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
210 |
211 | }
212 | });
213 |
214 | }
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/easychat/ChatFragment.java:
--------------------------------------------------------------------------------
1 | package com.example.easychat;
2 |
3 | import android.os.Bundle;
4 |
5 | import androidx.fragment.app.Fragment;
6 | import androidx.recyclerview.widget.LinearLayoutManager;
7 | import androidx.recyclerview.widget.RecyclerView;
8 |
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 |
13 | import com.example.easychat.adapter.RecentChatRecyclerAdapter;
14 | import com.example.easychat.adapter.SearchUserRecyclerAdapter;
15 | import com.example.easychat.model.ChatroomModel;
16 | import com.example.easychat.model.UserModel;
17 | import com.example.easychat.utils.FirebaseUtil;
18 | import com.firebase.ui.firestore.FirestoreRecyclerOptions;
19 | import com.google.firebase.firestore.Query;
20 |
21 | public class ChatFragment extends Fragment {
22 |
23 | RecyclerView recyclerView;
24 | RecentChatRecyclerAdapter adapter;
25 |
26 |
27 | public ChatFragment() {
28 | }
29 | @Override
30 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
31 | Bundle savedInstanceState) {
32 | View view = inflater.inflate(R.layout.fragment_chat, container, false);
33 | recyclerView = view.findViewById(R.id.recyler_view);
34 | setupRecyclerView();
35 |
36 | return view;
37 | }
38 |
39 | void setupRecyclerView(){
40 |
41 | Query query = FirebaseUtil.allChatroomCollectionReference()
42 | .whereArrayContains("userIds",FirebaseUtil.currentUserId())
43 | .orderBy("lastMessageTimestamp",Query.Direction.DESCENDING);
44 |
45 | FirestoreRecyclerOptions options = new FirestoreRecyclerOptions.Builder()
46 | .setQuery(query,ChatroomModel.class).build();
47 |
48 | adapter = new RecentChatRecyclerAdapter(options,getContext());
49 | recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
50 | recyclerView.setAdapter(adapter);
51 | adapter.startListening();
52 |
53 | }
54 |
55 | @Override
56 | public void onStart() {
57 | super.onStart();
58 | if(adapter!=null)
59 | adapter.startListening();
60 | }
61 |
62 | @Override
63 | public void onStop() {
64 | super.onStop();
65 | if(adapter!=null)
66 | adapter.stopListening();
67 | }
68 |
69 | @Override
70 | public void onResume() {
71 | super.onResume();
72 | if(adapter!=null)
73 | adapter.notifyDataSetChanged();
74 | }
75 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/easychat/FCMNotificationService.java:
--------------------------------------------------------------------------------
1 | package com.example.easychat;
2 |
3 | import com.google.firebase.messaging.FirebaseMessagingService;
4 |
5 | public class FCMNotificationService extends FirebaseMessagingService {
6 | }
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/easychat/LoginOtpActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.easychat;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.appcompat.app.AppCompatActivity;
5 |
6 | import android.content.Intent;
7 | import android.os.Bundle;
8 | import android.view.View;
9 | import android.widget.Button;
10 | import android.widget.EditText;
11 | import android.widget.ProgressBar;
12 | import android.widget.TextView;
13 | import android.widget.Toast;
14 |
15 | import com.example.easychat.utils.AndroidUtil;
16 | import com.google.android.gms.tasks.OnCompleteListener;
17 | import com.google.android.gms.tasks.Task;
18 | import com.google.firebase.FirebaseException;
19 | import com.google.firebase.auth.AuthResult;
20 | import com.google.firebase.auth.FirebaseAuth;
21 | import com.google.firebase.auth.PhoneAuthCredential;
22 | import com.google.firebase.auth.PhoneAuthOptions;
23 | import com.google.firebase.auth.PhoneAuthProvider;
24 | import com.google.firebase.firestore.FirebaseFirestore;
25 |
26 | import org.w3c.dom.Text;
27 |
28 | import java.util.HashMap;
29 | import java.util.Map;
30 | import java.util.Timer;
31 | import java.util.TimerTask;
32 | import java.util.concurrent.TimeUnit;
33 |
34 | public class LoginOtpActivity extends AppCompatActivity {
35 |
36 | String phoneNumber;
37 | Long timeoutSeconds = 60L;
38 | String verificationCode;
39 | PhoneAuthProvider.ForceResendingToken resendingToken;
40 |
41 | EditText otpInput;
42 | Button nextBtn;
43 | ProgressBar progressBar;
44 | TextView resendOtpTextView;
45 | FirebaseAuth mAuth = FirebaseAuth.getInstance();
46 |
47 | @Override
48 | protected void onCreate(Bundle savedInstanceState) {
49 | super.onCreate(savedInstanceState);
50 | setContentView(R.layout.activity_login_otp);
51 |
52 | otpInput = findViewById(R.id.login_otp);
53 | nextBtn = findViewById(R.id.login_next_btn);
54 | progressBar = findViewById(R.id.login_progress_bar);
55 | resendOtpTextView = findViewById(R.id.resend_otp_textview);
56 |
57 | phoneNumber = getIntent().getExtras().getString("phone");
58 |
59 | sendOtp(phoneNumber,false);
60 |
61 | nextBtn.setOnClickListener(v -> {
62 | String enteredOtp = otpInput.getText().toString();
63 | PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationCode,enteredOtp);
64 | signIn(credential);
65 | });
66 |
67 | resendOtpTextView.setOnClickListener((v)->{
68 | sendOtp(phoneNumber,true);
69 | });
70 |
71 | }
72 |
73 | void sendOtp(String phoneNumber,boolean isResend){
74 | startResendTimer();
75 | setInProgress(true);
76 | PhoneAuthOptions.Builder builder =
77 | PhoneAuthOptions.newBuilder(mAuth)
78 | .setPhoneNumber(phoneNumber)
79 | .setTimeout(timeoutSeconds, TimeUnit.SECONDS)
80 | .setActivity(this)
81 | .setCallbacks(new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
82 | @Override
83 | public void onVerificationCompleted(@NonNull PhoneAuthCredential phoneAuthCredential) {
84 | signIn(phoneAuthCredential);
85 | setInProgress(false);
86 | }
87 |
88 | @Override
89 | public void onVerificationFailed(@NonNull FirebaseException e) {
90 | AndroidUtil.showToast(getApplicationContext(),"OTP verification failed");
91 | setInProgress(false);
92 | }
93 |
94 | @Override
95 | public void onCodeSent(@NonNull String s, @NonNull PhoneAuthProvider.ForceResendingToken forceResendingToken) {
96 | super.onCodeSent(s, forceResendingToken);
97 | verificationCode = s;
98 | resendingToken = forceResendingToken;
99 | AndroidUtil.showToast(getApplicationContext(),"OTP sent successfully");
100 | setInProgress(false);
101 | }
102 | });
103 | if(isResend){
104 | PhoneAuthProvider.verifyPhoneNumber(builder.setForceResendingToken(resendingToken).build());
105 | }else{
106 | PhoneAuthProvider.verifyPhoneNumber(builder.build());
107 | }
108 |
109 | }
110 |
111 | void setInProgress(boolean inProgress){
112 | if(inProgress){
113 | progressBar.setVisibility(View.VISIBLE);
114 | nextBtn.setVisibility(View.GONE);
115 | }else{
116 | progressBar.setVisibility(View.GONE);
117 | nextBtn.setVisibility(View.VISIBLE);
118 | }
119 | }
120 |
121 | void signIn(PhoneAuthCredential phoneAuthCredential){
122 | //login and go to next activity
123 | setInProgress(true);
124 | mAuth.signInWithCredential(phoneAuthCredential).addOnCompleteListener(new OnCompleteListener() {
125 | @Override
126 | public void onComplete(@NonNull Task task) {
127 | setInProgress(false);
128 | if(task.isSuccessful()){
129 | Intent intent = new Intent(LoginOtpActivity.this,LoginUsernameActivity.class);
130 | intent.putExtra("phone",phoneNumber);
131 | startActivity(intent);
132 | }else{
133 | AndroidUtil.showToast(getApplicationContext(),"OTP verification failed");
134 | }
135 | }
136 | });
137 |
138 |
139 | }
140 |
141 | void startResendTimer(){
142 | resendOtpTextView.setEnabled(false);
143 | Timer timer = new Timer();
144 | timer.scheduleAtFixedRate(new TimerTask() {
145 | @Override
146 | public void run() {
147 | timeoutSeconds--;
148 | resendOtpTextView.setText("Resend OTP in "+timeoutSeconds +" seconds");
149 | if(timeoutSeconds<=0){
150 | timeoutSeconds =60L;
151 | timer.cancel();
152 | runOnUiThread(() -> {
153 | resendOtpTextView.setEnabled(true);
154 | });
155 | }
156 | }
157 | },0,1000);
158 | }
159 |
160 |
161 | }
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/easychat/LoginPhoneNumberActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.easychat;
2 |
3 | import androidx.appcompat.app.AppCompatActivity;
4 |
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import android.view.View;
8 | import android.widget.Button;
9 | import android.widget.EditText;
10 | import android.widget.ProgressBar;
11 |
12 | import com.hbb20.CountryCodePicker;
13 |
14 | public class LoginPhoneNumberActivity extends AppCompatActivity {
15 |
16 | CountryCodePicker countryCodePicker;
17 | EditText phoneInput;
18 | Button sendOtpBtn;
19 | ProgressBar progressBar;
20 |
21 | @Override
22 | protected void onCreate(Bundle savedInstanceState) {
23 | super.onCreate(savedInstanceState);
24 | setContentView(R.layout.activity_login_phone_number);
25 |
26 | countryCodePicker = findViewById(R.id.login_countrycode);
27 | phoneInput = findViewById(R.id.login_mobile_number);
28 | sendOtpBtn = findViewById(R.id.send_otp_btn);
29 | progressBar = findViewById(R.id.login_progress_bar);
30 |
31 | progressBar.setVisibility(View.GONE);
32 |
33 | countryCodePicker.registerCarrierNumberEditText(phoneInput);
34 | sendOtpBtn.setOnClickListener((v)->{
35 | if(!countryCodePicker.isValidFullNumber()){
36 | phoneInput.setError("Phone number not valid");
37 | return;
38 | }
39 | Intent intent = new Intent(LoginPhoneNumberActivity.this,LoginOtpActivity.class);
40 | intent.putExtra("phone",countryCodePicker.getFullNumberWithPlus());
41 | startActivity(intent);
42 | });
43 | }
44 |
45 |
46 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/easychat/LoginUsernameActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.easychat;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.appcompat.app.AppCompatActivity;
5 |
6 | import android.content.Intent;
7 | import android.os.Bundle;
8 | import android.view.View;
9 | import android.widget.Button;
10 | import android.widget.EditText;
11 | import android.widget.ProgressBar;
12 |
13 | import com.example.easychat.model.UserModel;
14 | import com.example.easychat.utils.FirebaseUtil;
15 | import com.google.android.gms.tasks.OnCompleteListener;
16 | import com.google.android.gms.tasks.Task;
17 | import com.google.firebase.Timestamp;
18 | import com.google.firebase.firestore.DocumentSnapshot;
19 |
20 | public class LoginUsernameActivity extends AppCompatActivity {
21 |
22 | EditText usernameInput;
23 | Button letMeInBtn;
24 | ProgressBar progressBar;
25 | String phoneNumber;
26 | UserModel userModel;
27 |
28 | @Override
29 | protected void onCreate(Bundle savedInstanceState) {
30 | super.onCreate(savedInstanceState);
31 | setContentView(R.layout.activity_login_username);
32 |
33 | usernameInput = findViewById(R.id.login_username);
34 | letMeInBtn = findViewById(R.id.login_let_me_in_btn);
35 | progressBar =findViewById(R.id.login_progress_bar);
36 |
37 | phoneNumber = getIntent().getExtras().getString("phone");
38 | getUsername();
39 |
40 | letMeInBtn.setOnClickListener((v -> {
41 | setUsername();
42 | }));
43 |
44 |
45 | }
46 |
47 | void setUsername(){
48 |
49 | String username = usernameInput.getText().toString();
50 | if(username.isEmpty() || username.length()<3){
51 | usernameInput.setError("Username length should be at least 3 chars");
52 | return;
53 | }
54 | setInProgress(true);
55 | if(userModel!=null){
56 | userModel.setUsername(username);
57 | }else{
58 | userModel = new UserModel(phoneNumber,username, Timestamp.now(),FirebaseUtil.currentUserId());
59 | }
60 |
61 | FirebaseUtil.currentUserDetails().set(userModel).addOnCompleteListener(new OnCompleteListener() {
62 | @Override
63 | public void onComplete(@NonNull Task task) {
64 | setInProgress(false);
65 | if(task.isSuccessful()){
66 | Intent intent = new Intent(LoginUsernameActivity.this,MainActivity.class);
67 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK );
68 | startActivity(intent);
69 | }
70 | }
71 | });
72 |
73 | }
74 |
75 | void getUsername(){
76 | setInProgress(true);
77 | FirebaseUtil.currentUserDetails().get().addOnCompleteListener(new OnCompleteListener() {
78 | @Override
79 | public void onComplete(@NonNull Task task) {
80 | setInProgress(false);
81 | if(task.isSuccessful()){
82 | userModel = task.getResult().toObject(UserModel.class);
83 | if(userModel!=null){
84 | usernameInput.setText(userModel.getUsername());
85 | }
86 | }
87 | }
88 | });
89 | }
90 |
91 | void setInProgress(boolean inProgress){
92 | if(inProgress){
93 | progressBar.setVisibility(View.VISIBLE);
94 | letMeInBtn.setVisibility(View.GONE);
95 | }else{
96 | progressBar.setVisibility(View.GONE);
97 | letMeInBtn.setVisibility(View.VISIBLE);
98 | }
99 | }
100 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/easychat/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.easychat;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.appcompat.app.AppCompatActivity;
5 |
6 | import android.content.Intent;
7 | import android.os.Bundle;
8 | import android.util.Log;
9 | import android.view.MenuItem;
10 | import android.widget.ImageButton;
11 |
12 | import com.example.easychat.utils.FirebaseUtil;
13 | import com.google.android.gms.tasks.OnCompleteListener;
14 | import com.google.android.gms.tasks.Task;
15 | import com.google.android.material.bottomnavigation.BottomNavigationView;
16 | import com.google.android.material.navigation.NavigationBarView;
17 | import com.google.firebase.messaging.FirebaseMessaging;
18 |
19 | public class MainActivity extends AppCompatActivity {
20 |
21 | BottomNavigationView bottomNavigationView;
22 | ImageButton searchButton;
23 |
24 | ChatFragment chatFragment;
25 | ProfileFragment profileFragment;
26 |
27 | @Override
28 | protected void onCreate(Bundle savedInstanceState) {
29 | super.onCreate(savedInstanceState);
30 | setContentView(R.layout.activity_main);
31 |
32 | chatFragment = new ChatFragment();
33 | profileFragment = new ProfileFragment();
34 |
35 | bottomNavigationView = findViewById(R.id.bottom_navigation);
36 | searchButton = findViewById(R.id.main_search_btn);
37 |
38 | searchButton.setOnClickListener((v)->{
39 | startActivity(new Intent(MainActivity.this,SearchUserActivity.class));
40 | });
41 |
42 | bottomNavigationView.setOnItemSelectedListener(new NavigationBarView.OnItemSelectedListener() {
43 | @Override
44 | public boolean onNavigationItemSelected(@NonNull MenuItem item) {
45 | if(item.getItemId()==R.id.menu_chat){
46 | getSupportFragmentManager().beginTransaction().replace(R.id.main_frame_layout,chatFragment).commit();
47 | }
48 | if(item.getItemId()==R.id.menu_profile){
49 | getSupportFragmentManager().beginTransaction().replace(R.id.main_frame_layout,profileFragment).commit();
50 | }
51 | return true;
52 | }
53 | });
54 | bottomNavigationView.setSelectedItemId(R.id.menu_chat);
55 |
56 | getFCMToken();
57 |
58 | }
59 |
60 | void getFCMToken(){
61 | FirebaseMessaging.getInstance().getToken().addOnCompleteListener(task -> {
62 | if(task.isSuccessful()){
63 | String token = task.getResult();
64 | FirebaseUtil.currentUserDetails().update("fcmToken",token);
65 |
66 | }
67 | });
68 | }
69 | }
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/easychat/ProfileFragment.java:
--------------------------------------------------------------------------------
1 | package com.example.easychat;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.net.Uri;
6 | import android.os.Bundle;
7 |
8 | import androidx.activity.result.ActivityResultLauncher;
9 | import androidx.activity.result.contract.ActivityResultContracts;
10 | import androidx.annotation.NonNull;
11 | import androidx.annotation.Nullable;
12 | import androidx.fragment.app.Fragment;
13 |
14 | import android.view.LayoutInflater;
15 | import android.view.View;
16 | import android.view.ViewGroup;
17 | import android.widget.Button;
18 | import android.widget.EditText;
19 | import android.widget.ImageView;
20 | import android.widget.ProgressBar;
21 | import android.widget.TextView;
22 |
23 | import com.example.easychat.model.UserModel;
24 | import com.example.easychat.utils.AndroidUtil;
25 | import com.example.easychat.utils.FirebaseUtil;
26 | import com.github.dhaval2404.imagepicker.ImagePicker;
27 | import com.google.android.gms.tasks.OnCompleteListener;
28 | import com.google.android.gms.tasks.Task;
29 | import com.google.firebase.firestore.DocumentSnapshot;
30 | import com.google.firebase.messaging.FirebaseMessaging;
31 | import com.google.firebase.storage.UploadTask;
32 |
33 | import kotlin.Unit;
34 | import kotlin.jvm.functions.Function1;
35 |
36 | public class ProfileFragment extends Fragment {
37 |
38 | ImageView profilePic;
39 | EditText usernameInput;
40 | EditText phoneInput;
41 | Button updateProfileBtn;
42 | ProgressBar progressBar;
43 | TextView logoutBtn;
44 |
45 | UserModel currentUserModel;
46 | ActivityResultLauncher imagePickLauncher;
47 | Uri selectedImageUri;
48 |
49 | public ProfileFragment() {
50 |
51 | }
52 |
53 | @Override
54 | public void onCreate(@Nullable Bundle savedInstanceState) {
55 | super.onCreate(savedInstanceState);
56 | imagePickLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
57 | result -> {
58 | if(result.getResultCode() == Activity.RESULT_OK){
59 | Intent data = result.getData();
60 | if(data!=null && data.getData()!=null){
61 | selectedImageUri = data.getData();
62 | AndroidUtil.setProfilePic(getContext(),selectedImageUri,profilePic);
63 | }
64 | }
65 | }
66 | );
67 | }
68 |
69 | @Override
70 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
71 | Bundle savedInstanceState) {
72 | View view = inflater.inflate(R.layout.fragment_profile, container, false);
73 | profilePic = view.findViewById(R.id.profile_image_view);
74 | usernameInput = view.findViewById(R.id.profile_username);
75 | phoneInput = view.findViewById(R.id.profile_phone);
76 | updateProfileBtn = view.findViewById(R.id.profle_update_btn);
77 | progressBar = view.findViewById(R.id.profile_progress_bar);
78 | logoutBtn = view.findViewById(R.id.logout_btn);
79 |
80 | getUserData();
81 |
82 | updateProfileBtn.setOnClickListener((v -> {
83 | updateBtnClick();
84 | }));
85 |
86 | logoutBtn.setOnClickListener((v)->{
87 | FirebaseMessaging.getInstance().deleteToken().addOnCompleteListener(new OnCompleteListener() {
88 | @Override
89 | public void onComplete(@NonNull Task task) {
90 | if(task.isSuccessful()){
91 | FirebaseUtil.logout();
92 | Intent intent = new Intent(getContext(),SplashActivity.class);
93 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
94 | startActivity(intent);
95 | }
96 | }
97 | });
98 |
99 |
100 |
101 | });
102 |
103 | profilePic.setOnClickListener((v)->{
104 | ImagePicker.with(this).cropSquare().compress(512).maxResultSize(512,512)
105 | .createIntent(new Function1() {
106 | @Override
107 | public Unit invoke(Intent intent) {
108 | imagePickLauncher.launch(intent);
109 | return null;
110 | }
111 | });
112 | });
113 |
114 | return view;
115 | }
116 |
117 | void updateBtnClick(){
118 | String newUsername = usernameInput.getText().toString();
119 | if(newUsername.isEmpty() || newUsername.length()<3){
120 | usernameInput.setError("Username length should be at least 3 chars");
121 | return;
122 | }
123 | currentUserModel.setUsername(newUsername);
124 | setInProgress(true);
125 |
126 |
127 | if(selectedImageUri!=null){
128 | FirebaseUtil.getCurrentProfilePicStorageRef().putFile(selectedImageUri)
129 | .addOnCompleteListener(task -> {
130 | updateToFirestore();
131 | });
132 | }else{
133 | updateToFirestore();
134 | }
135 |
136 |
137 |
138 |
139 |
140 | }
141 |
142 | void updateToFirestore(){
143 | FirebaseUtil.currentUserDetails().set(currentUserModel)
144 | .addOnCompleteListener(task -> {
145 | setInProgress(false);
146 | if(task.isSuccessful()){
147 | AndroidUtil.showToast(getContext(),"Updated successfully");
148 | }else{
149 | AndroidUtil.showToast(getContext(),"Updated failed");
150 | }
151 | });
152 | }
153 |
154 |
155 |
156 | void getUserData(){
157 | setInProgress(true);
158 |
159 | FirebaseUtil.getCurrentProfilePicStorageRef().getDownloadUrl()
160 | .addOnCompleteListener(task -> {
161 | if(task.isSuccessful()){
162 | Uri uri = task.getResult();
163 | AndroidUtil.setProfilePic(getContext(),uri,profilePic);
164 | }
165 | });
166 |
167 | FirebaseUtil.currentUserDetails().get().addOnCompleteListener(task -> {
168 | setInProgress(false);
169 | currentUserModel = task.getResult().toObject(UserModel.class);
170 | usernameInput.setText(currentUserModel.getUsername());
171 | phoneInput.setText(currentUserModel.getPhone());
172 | });
173 | }
174 |
175 |
176 | void setInProgress(boolean inProgress){
177 | if(inProgress){
178 | progressBar.setVisibility(View.VISIBLE);
179 | updateProfileBtn.setVisibility(View.GONE);
180 | }else{
181 | progressBar.setVisibility(View.GONE);
182 | updateProfileBtn.setVisibility(View.VISIBLE);
183 | }
184 | }
185 | }
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/easychat/SearchUserActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.easychat;
2 |
3 | import androidx.appcompat.app.AppCompatActivity;
4 | import androidx.recyclerview.widget.LinearLayoutManager;
5 | import androidx.recyclerview.widget.RecyclerView;
6 |
7 | import android.os.Bundle;
8 | import android.widget.EditText;
9 | import android.widget.ImageButton;
10 |
11 | import com.example.easychat.adapter.SearchUserRecyclerAdapter;
12 | import com.example.easychat.model.UserModel;
13 | import com.example.easychat.utils.FirebaseUtil;
14 | import com.firebase.ui.firestore.FirestoreRecyclerOptions;
15 | import com.google.firebase.firestore.Query;
16 |
17 | public class SearchUserActivity extends AppCompatActivity {
18 |
19 | EditText searchInput;
20 | ImageButton searchButton;
21 | ImageButton backButton;
22 | RecyclerView recyclerView;
23 |
24 | SearchUserRecyclerAdapter adapter;
25 |
26 | @Override
27 | protected void onCreate(Bundle savedInstanceState) {
28 | super.onCreate(savedInstanceState);
29 | setContentView(R.layout.activity_search_user);
30 |
31 | searchInput = findViewById(R.id.seach_username_input);
32 | searchButton = findViewById(R.id.search_user_btn);
33 | backButton = findViewById(R.id.back_btn);
34 | recyclerView = findViewById(R.id.search_user_recycler_view);
35 |
36 | searchInput.requestFocus();
37 |
38 |
39 | backButton.setOnClickListener(v -> {
40 | onBackPressed();
41 | });
42 |
43 | searchButton.setOnClickListener(v -> {
44 | String searchTerm = searchInput.getText().toString();
45 | if(searchTerm.isEmpty() || searchTerm.length()<3){
46 | searchInput.setError("Invalid Username");
47 | return;
48 | }
49 | setupSearchRecyclerView(searchTerm);
50 | });
51 | }
52 |
53 | void setupSearchRecyclerView(String searchTerm){
54 |
55 | Query query = FirebaseUtil.allUserCollectionReference()
56 | .whereGreaterThanOrEqualTo("username",searchTerm)
57 | .whereLessThanOrEqualTo("username",searchTerm+'\uf8ff');
58 |
59 | FirestoreRecyclerOptions options = new FirestoreRecyclerOptions.Builder()
60 | .setQuery(query,UserModel.class).build();
61 |
62 | adapter = new SearchUserRecyclerAdapter(options,getApplicationContext());
63 | recyclerView.setLayoutManager(new LinearLayoutManager(this));
64 | recyclerView.setAdapter(adapter);
65 | adapter.startListening();
66 |
67 | }
68 |
69 | @Override
70 | protected void onStart() {
71 | super.onStart();
72 | if(adapter!=null)
73 | adapter.startListening();
74 | }
75 |
76 | @Override
77 | protected void onStop() {
78 | super.onStop();
79 | if(adapter!=null)
80 | adapter.stopListening();
81 | }
82 |
83 | @Override
84 | protected void onResume() {
85 | super.onResume();
86 | if(adapter!=null)
87 | adapter.startListening();
88 | }
89 | }
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/easychat/SplashActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.easychat;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.appcompat.app.AppCompatActivity;
5 |
6 | import android.content.Intent;
7 | import android.os.Bundle;
8 | import android.os.Handler;
9 |
10 | import com.example.easychat.model.UserModel;
11 | import com.example.easychat.utils.AndroidUtil;
12 | import com.example.easychat.utils.FirebaseUtil;
13 | import com.google.android.gms.tasks.OnCompleteListener;
14 | import com.google.android.gms.tasks.Task;
15 | import com.google.firebase.firestore.DocumentSnapshot;
16 |
17 | public class SplashActivity extends AppCompatActivity {
18 |
19 | @Override
20 | protected void onCreate(Bundle savedInstanceState) {
21 | super.onCreate(savedInstanceState);
22 | setContentView(R.layout.activity_splash);
23 |
24 | if(getIntent().getExtras()!=null){
25 | //from notification
26 | String userId = getIntent().getExtras().getString("userId");
27 | FirebaseUtil.allUserCollectionReference().document(userId).get()
28 | .addOnCompleteListener(task -> {
29 | if(task.isSuccessful()){
30 | UserModel model = task.getResult().toObject(UserModel.class);
31 |
32 | Intent mainIntent = new Intent(this,MainActivity.class);
33 | mainIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
34 | startActivity(mainIntent);
35 |
36 | Intent intent = new Intent(this, ChatActivity.class);
37 | AndroidUtil.passUserModelAsIntent(intent,model);
38 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
39 | startActivity(intent);
40 | finish();
41 | }
42 | });
43 |
44 |
45 | }else{
46 | new Handler().postDelayed(new Runnable() {
47 | @Override
48 | public void run() {
49 | if(FirebaseUtil.isLoggedIn()){
50 | startActivity(new Intent(SplashActivity.this,MainActivity.class));
51 | }else{
52 | startActivity(new Intent(SplashActivity.this,LoginPhoneNumberActivity.class));
53 | }
54 | finish();
55 | }
56 | },1000);
57 | }
58 | }
59 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/easychat/adapter/ChatRecyclerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.example.easychat.adapter;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.util.Log;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.ImageView;
10 | import android.widget.LinearLayout;
11 | import android.widget.TextView;
12 |
13 | import androidx.annotation.NonNull;
14 | import androidx.recyclerview.widget.RecyclerView;
15 |
16 | import com.example.easychat.ChatActivity;
17 | import com.example.easychat.R;
18 | import com.example.easychat.model.ChatMessageModel;
19 | import com.example.easychat.utils.AndroidUtil;
20 | import com.example.easychat.utils.FirebaseUtil;
21 | import com.firebase.ui.firestore.FirestoreRecyclerAdapter;
22 | import com.firebase.ui.firestore.FirestoreRecyclerOptions;
23 |
24 | public class ChatRecyclerAdapter extends FirestoreRecyclerAdapter {
25 |
26 | Context context;
27 |
28 | public ChatRecyclerAdapter(@NonNull FirestoreRecyclerOptions options,Context context) {
29 | super(options);
30 | this.context = context;
31 | }
32 |
33 | @Override
34 | protected void onBindViewHolder(@NonNull ChatModelViewHolder holder, int position, @NonNull ChatMessageModel model) {
35 | Log.i("haushd","asjd");
36 | if(model.getSenderId().equals(FirebaseUtil.currentUserId())){
37 | holder.leftChatLayout.setVisibility(View.GONE);
38 | holder.rightChatLayout.setVisibility(View.VISIBLE);
39 | holder.rightChatTextview.setText(model.getMessage());
40 | }else{
41 | holder.rightChatLayout.setVisibility(View.GONE);
42 | holder.leftChatLayout.setVisibility(View.VISIBLE);
43 | holder.leftChatTextview.setText(model.getMessage());
44 | }
45 | }
46 |
47 | @NonNull
48 | @Override
49 | public ChatModelViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
50 | View view = LayoutInflater.from(context).inflate(R.layout.chat_message_recycler_row,parent,false);
51 | return new ChatModelViewHolder(view);
52 | }
53 |
54 | class ChatModelViewHolder extends RecyclerView.ViewHolder{
55 |
56 | LinearLayout leftChatLayout,rightChatLayout;
57 | TextView leftChatTextview,rightChatTextview;
58 |
59 | public ChatModelViewHolder(@NonNull View itemView) {
60 | super(itemView);
61 |
62 | leftChatLayout = itemView.findViewById(R.id.left_chat_layout);
63 | rightChatLayout = itemView.findViewById(R.id.right_chat_layout);
64 | leftChatTextview = itemView.findViewById(R.id.left_chat_textview);
65 | rightChatTextview = itemView.findViewById(R.id.right_chat_textview);
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/easychat/adapter/RecentChatRecyclerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.example.easychat.adapter;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.net.Uri;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.ImageView;
10 | import android.widget.RelativeLayout;
11 | import android.widget.TextView;
12 |
13 | import androidx.annotation.NonNull;
14 | import androidx.recyclerview.widget.RecyclerView;
15 |
16 | import com.example.easychat.ChatActivity;
17 | import com.example.easychat.R;
18 | import com.example.easychat.model.ChatroomModel;
19 | import com.example.easychat.model.UserModel;
20 | import com.example.easychat.utils.AndroidUtil;
21 | import com.example.easychat.utils.FirebaseUtil;
22 | import com.firebase.ui.firestore.FirestoreRecyclerAdapter;
23 | import com.firebase.ui.firestore.FirestoreRecyclerOptions;
24 | import com.google.android.gms.tasks.OnCompleteListener;
25 | import com.google.android.gms.tasks.Task;
26 | import com.google.firebase.firestore.DocumentSnapshot;
27 |
28 | public class RecentChatRecyclerAdapter extends FirestoreRecyclerAdapter {
29 |
30 | Context context;
31 |
32 | public RecentChatRecyclerAdapter(@NonNull FirestoreRecyclerOptions options,Context context) {
33 | super(options);
34 | this.context = context;
35 | }
36 |
37 | @Override
38 | protected void onBindViewHolder(@NonNull ChatroomModelViewHolder holder, int position, @NonNull ChatroomModel model) {
39 | FirebaseUtil.getOtherUserFromChatroom(model.getUserIds())
40 | .get().addOnCompleteListener(task -> {
41 | if(task.isSuccessful()){
42 | boolean lastMessageSentByMe = model.getLastMessageSenderId().equals(FirebaseUtil.currentUserId());
43 |
44 |
45 | UserModel otherUserModel = task.getResult().toObject(UserModel.class);
46 |
47 | FirebaseUtil.getOtherProfilePicStorageRef(otherUserModel.getUserId()).getDownloadUrl()
48 | .addOnCompleteListener(t -> {
49 | if(t.isSuccessful()){
50 | Uri uri = t.getResult();
51 | AndroidUtil.setProfilePic(context,uri,holder.profilePic);
52 | }
53 | });
54 |
55 | holder.usernameText.setText(otherUserModel.getUsername());
56 | if(lastMessageSentByMe)
57 | holder.lastMessageText.setText("You : "+model.getLastMessage());
58 | else
59 | holder.lastMessageText.setText(model.getLastMessage());
60 | holder.lastMessageTime.setText(FirebaseUtil.timestampToString(model.getLastMessageTimestamp()));
61 |
62 | holder.itemView.setOnClickListener(v -> {
63 | //navigate to chat activity
64 | Intent intent = new Intent(context, ChatActivity.class);
65 | AndroidUtil.passUserModelAsIntent(intent,otherUserModel);
66 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
67 | context.startActivity(intent);
68 | });
69 |
70 | }
71 | });
72 | }
73 |
74 | @NonNull
75 | @Override
76 | public ChatroomModelViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
77 | View view = LayoutInflater.from(context).inflate(R.layout.recent_chat_recycler_row,parent,false);
78 | return new ChatroomModelViewHolder(view);
79 | }
80 |
81 | class ChatroomModelViewHolder extends RecyclerView.ViewHolder{
82 | TextView usernameText;
83 | TextView lastMessageText;
84 | TextView lastMessageTime;
85 | ImageView profilePic;
86 |
87 | public ChatroomModelViewHolder(@NonNull View itemView) {
88 | super(itemView);
89 | usernameText = itemView.findViewById(R.id.user_name_text);
90 | lastMessageText = itemView.findViewById(R.id.last_message_text);
91 | lastMessageTime = itemView.findViewById(R.id.last_message_time_text);
92 | profilePic = itemView.findViewById(R.id.profile_pic_image_view);
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/easychat/adapter/SearchUserRecyclerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.example.easychat.adapter;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.net.Uri;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.ImageView;
10 | import android.widget.TextView;
11 |
12 | import androidx.annotation.NonNull;
13 | import androidx.recyclerview.widget.RecyclerView;
14 |
15 | import com.example.easychat.ChatActivity;
16 | import com.example.easychat.R;
17 | import com.example.easychat.model.UserModel;
18 | import com.example.easychat.utils.AndroidUtil;
19 | import com.example.easychat.utils.FirebaseUtil;
20 | import com.firebase.ui.firestore.FirestoreRecyclerAdapter;
21 | import com.firebase.ui.firestore.FirestoreRecyclerOptions;
22 |
23 | public class SearchUserRecyclerAdapter extends FirestoreRecyclerAdapter {
24 |
25 | Context context;
26 |
27 | public SearchUserRecyclerAdapter(@NonNull FirestoreRecyclerOptions options,Context context) {
28 | super(options);
29 | this.context = context;
30 | }
31 |
32 | @Override
33 | protected void onBindViewHolder(@NonNull UserModelViewHolder holder, int position, @NonNull UserModel model) {
34 | holder.usernameText.setText(model.getUsername());
35 | holder.phoneText.setText(model.getPhone());
36 | if(model.getUserId().equals(FirebaseUtil.currentUserId())){
37 | holder.usernameText.setText(model.getUsername()+" (Me)");
38 | }
39 |
40 | FirebaseUtil.getOtherProfilePicStorageRef(model.getUserId()).getDownloadUrl()
41 | .addOnCompleteListener(t -> {
42 | if(t.isSuccessful()){
43 | Uri uri = t.getResult();
44 | AndroidUtil.setProfilePic(context,uri,holder.profilePic);
45 | }
46 | });
47 |
48 | holder.itemView.setOnClickListener(v -> {
49 | //navigate to chat activity
50 | Intent intent = new Intent(context, ChatActivity.class);
51 | AndroidUtil.passUserModelAsIntent(intent,model);
52 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
53 | context.startActivity(intent);
54 | });
55 | }
56 |
57 | @NonNull
58 | @Override
59 | public UserModelViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
60 | View view = LayoutInflater.from(context).inflate(R.layout.search_user_recycler_row,parent,false);
61 | return new UserModelViewHolder(view);
62 | }
63 |
64 | class UserModelViewHolder extends RecyclerView.ViewHolder{
65 | TextView usernameText;
66 | TextView phoneText;
67 | ImageView profilePic;
68 |
69 | public UserModelViewHolder(@NonNull View itemView) {
70 | super(itemView);
71 | usernameText = itemView.findViewById(R.id.user_name_text);
72 | phoneText = itemView.findViewById(R.id.phone_text);
73 | profilePic = itemView.findViewById(R.id.profile_pic_image_view);
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/easychat/model/ChatMessageModel.java:
--------------------------------------------------------------------------------
1 | package com.example.easychat.model;
2 |
3 | import com.google.firebase.Timestamp;
4 |
5 | public class ChatMessageModel {
6 | private String message;
7 | private String senderId;
8 | private Timestamp timestamp;
9 |
10 | public ChatMessageModel() {
11 | }
12 |
13 | public ChatMessageModel(String message, String senderId, Timestamp timestamp) {
14 | this.message = message;
15 | this.senderId = senderId;
16 | this.timestamp = timestamp;
17 | }
18 |
19 | public String getMessage() {
20 | return message;
21 | }
22 |
23 | public void setMessage(String message) {
24 | this.message = message;
25 | }
26 |
27 | public String getSenderId() {
28 | return senderId;
29 | }
30 |
31 | public void setSenderId(String senderId) {
32 | this.senderId = senderId;
33 | }
34 |
35 | public Timestamp getTimestamp() {
36 | return timestamp;
37 | }
38 |
39 | public void setTimestamp(Timestamp timestamp) {
40 | this.timestamp = timestamp;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/easychat/model/ChatroomModel.java:
--------------------------------------------------------------------------------
1 | package com.example.easychat.model;
2 |
3 | import com.google.firebase.Timestamp;
4 |
5 | import java.util.List;
6 |
7 | public class ChatroomModel {
8 | String chatroomId;
9 | List userIds;
10 | Timestamp lastMessageTimestamp;
11 | String lastMessageSenderId;
12 | String lastMessage;
13 |
14 | public ChatroomModel() {
15 | }
16 |
17 | public ChatroomModel(String chatroomId, List userIds, Timestamp lastMessageTimestamp, String lastMessageSenderId) {
18 | this.chatroomId = chatroomId;
19 | this.userIds = userIds;
20 | this.lastMessageTimestamp = lastMessageTimestamp;
21 | this.lastMessageSenderId = lastMessageSenderId;
22 | }
23 |
24 | public String getChatroomId() {
25 | return chatroomId;
26 | }
27 |
28 | public void setChatroomId(String chatroomId) {
29 | this.chatroomId = chatroomId;
30 | }
31 |
32 | public List getUserIds() {
33 | return userIds;
34 | }
35 |
36 | public void setUserIds(List userIds) {
37 | this.userIds = userIds;
38 | }
39 |
40 | public Timestamp getLastMessageTimestamp() {
41 | return lastMessageTimestamp;
42 | }
43 |
44 | public void setLastMessageTimestamp(Timestamp lastMessageTimestamp) {
45 | this.lastMessageTimestamp = lastMessageTimestamp;
46 | }
47 |
48 | public String getLastMessageSenderId() {
49 | return lastMessageSenderId;
50 | }
51 |
52 | public void setLastMessageSenderId(String lastMessageSenderId) {
53 | this.lastMessageSenderId = lastMessageSenderId;
54 | }
55 |
56 | public String getLastMessage() {
57 | return lastMessage;
58 | }
59 |
60 | public void setLastMessage(String lastMessage) {
61 | this.lastMessage = lastMessage;
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/easychat/model/UserModel.java:
--------------------------------------------------------------------------------
1 | package com.example.easychat.model;
2 |
3 | import com.google.firebase.Timestamp;
4 |
5 | public class UserModel {
6 | private String phone;
7 | private String username;
8 | private Timestamp createdTimestamp;
9 | private String userId;
10 | private String fcmToken;
11 |
12 | public UserModel() {
13 | }
14 |
15 | public UserModel(String phone, String username, Timestamp createdTimestamp,String userId) {
16 | this.phone = phone;
17 | this.username = username;
18 | this.createdTimestamp = createdTimestamp;
19 | this.userId = userId;
20 | }
21 |
22 | public String getPhone() {
23 | return phone;
24 | }
25 |
26 | public void setPhone(String phone) {
27 | this.phone = phone;
28 | }
29 |
30 | public String getUsername() {
31 | return username;
32 | }
33 |
34 | public void setUsername(String username) {
35 | this.username = username;
36 | }
37 |
38 | public Timestamp getCreatedTimestamp() {
39 | return createdTimestamp;
40 | }
41 |
42 | public void setCreatedTimestamp(Timestamp createdTimestamp) {
43 | this.createdTimestamp = createdTimestamp;
44 | }
45 |
46 | public String getUserId() {
47 | return userId;
48 | }
49 |
50 | public void setUserId(String userId) {
51 | this.userId = userId;
52 | }
53 |
54 | public String getFcmToken() {
55 | return fcmToken;
56 | }
57 |
58 | public void setFcmToken(String fcmToken) {
59 | this.fcmToken = fcmToken;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/easychat/utils/AndroidUtil.java:
--------------------------------------------------------------------------------
1 | package com.example.easychat.utils;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.net.Uri;
6 | import android.widget.ImageView;
7 | import android.widget.Toast;
8 |
9 | import com.bumptech.glide.Glide;
10 | import com.bumptech.glide.request.RequestOptions;
11 | import com.example.easychat.model.UserModel;
12 | import com.google.firebase.firestore.auth.User;
13 |
14 | public class AndroidUtil {
15 |
16 | public static void showToast(Context context,String message){
17 | Toast.makeText(context,message,Toast.LENGTH_LONG).show();
18 | }
19 |
20 | public static void passUserModelAsIntent(Intent intent, UserModel model){
21 | intent.putExtra("username",model.getUsername());
22 | intent.putExtra("phone",model.getPhone());
23 | intent.putExtra("userId",model.getUserId());
24 | intent.putExtra("fcmToken",model.getFcmToken());
25 |
26 | }
27 |
28 | public static UserModel getUserModelFromIntent(Intent intent){
29 | UserModel userModel = new UserModel();
30 | userModel.setUsername(intent.getStringExtra("username"));
31 | userModel.setPhone(intent.getStringExtra("phone"));
32 | userModel.setUserId(intent.getStringExtra("userId"));
33 | userModel.setFcmToken(intent.getStringExtra("fcmToken"));
34 | return userModel;
35 | }
36 |
37 | public static void setProfilePic(Context context, Uri imageUri, ImageView imageView){
38 | Glide.with(context).load(imageUri).apply(RequestOptions.circleCropTransform()).into(imageView);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/easychat/utils/FirebaseUtil.java:
--------------------------------------------------------------------------------
1 | package com.example.easychat.utils;
2 |
3 | import com.google.firebase.Timestamp;
4 | import com.google.firebase.auth.FirebaseAuth;
5 | import com.google.firebase.firestore.CollectionReference;
6 | import com.google.firebase.firestore.DocumentReference;
7 | import com.google.firebase.firestore.FirebaseFirestore;
8 | import com.google.firebase.storage.FirebaseStorage;
9 | import com.google.firebase.storage.StorageReference;
10 |
11 | import java.text.SimpleDateFormat;
12 | import java.util.List;
13 |
14 | public class FirebaseUtil {
15 |
16 | public static String currentUserId(){
17 | return FirebaseAuth.getInstance().getUid();
18 | }
19 |
20 | public static boolean isLoggedIn(){
21 | if(currentUserId()!=null){
22 | return true;
23 | }
24 | return false;
25 | }
26 |
27 | public static DocumentReference currentUserDetails(){
28 | return FirebaseFirestore.getInstance().collection("users").document(currentUserId());
29 | }
30 |
31 | public static CollectionReference allUserCollectionReference(){
32 | return FirebaseFirestore.getInstance().collection("users");
33 | }
34 |
35 | public static DocumentReference getChatroomReference(String chatroomId){
36 | return FirebaseFirestore.getInstance().collection("chatrooms").document(chatroomId);
37 | }
38 |
39 | public static CollectionReference getChatroomMessageReference(String chatroomId){
40 | return getChatroomReference(chatroomId).collection("chats");
41 | }
42 |
43 | public static String getChatroomId(String userId1,String userId2){
44 | if(userId1.hashCode() userIds){
56 | if(userIds.get(0).equals(FirebaseUtil.currentUserId())){
57 | return allUserCollectionReference().document(userIds.get(1));
58 | }else{
59 | return allUserCollectionReference().document(userIds.get(0));
60 | }
61 | }
62 |
63 | public static String timestampToString(Timestamp timestamp){
64 | return new SimpleDateFormat("HH:MM").format(timestamp.toDate());
65 | }
66 |
67 | public static void logout(){
68 | FirebaseAuth.getInstance().signOut();
69 | }
70 |
71 | public static StorageReference getCurrentProfilePicStorageRef(){
72 | return FirebaseStorage.getInstance().getReference().child("profile_pic")
73 | .child(FirebaseUtil.currentUserId());
74 | }
75 |
76 | public static StorageReference getOtherProfilePicStorageRef(String otherUserId){
77 | return FirebaseStorage.getInstance().getReference().child("profile_pic")
78 | .child(otherUserId);
79 | }
80 |
81 |
82 | }
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_rounded_corner.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/chat_icon.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/circular_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_text_rounded_corner.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_back.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_search.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_send.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/main/res/drawable/launcher_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/otp_icon.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/person_icon.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/phone_icon.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_chat.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
28 |
29 |
36 |
37 |
45 |
46 |
47 |
48 |
54 |
55 |
61 |
62 |
76 |
77 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_login_otp.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
18 |
24 |
25 |
32 |
33 |
39 |
40 |
47 |
48 |
54 |
55 |
62 |
63 |
64 |
65 |
72 |
73 |
82 |
83 |
89 |
90 |
91 |
92 |
104 |
105 |
106 |
107 |
113 |
119 |
125 |
126 |
127 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_login_phone_number.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
18 |
24 |
25 |
32 |
33 |
39 |
40 |
47 |
48 |
54 |
55 |
62 |
63 |
64 |
65 |
72 |
73 |
82 |
83 |
89 |
90 |
96 |
97 |
108 |
109 |
110 |
111 |
117 |
123 |
129 |
130 |
131 |
132 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_login_username.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
18 |
24 |
25 |
32 |
33 |
39 |
40 |
47 |
48 |
54 |
55 |
62 |
63 |
64 |
65 |
72 |
73 |
82 |
83 |
89 |
90 |
91 |
92 |
103 |
104 |
105 |
106 |
112 |
118 |
124 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
25 |
26 |
36 |
37 |
38 |
39 |
45 |
46 |
51 |
52 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_search_user.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
26 |
27 |
35 |
36 |
37 |
38 |
44 |
45 |
56 |
67 |
68 |
69 |
70 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
16 |
21 |
30 |
31 |
34 |
35 |
36 |
37 |
38 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/chat_message_recycler_row.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
16 |
23 |
24 |
33 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_chat.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_profile.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
20 |
21 |
32 |
44 |
45 |
51 |
57 |
63 |
64 |
65 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/profile_pic_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/recent_chat_recycler_row.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
22 |
25 |
32 |
39 |
40 |
41 |
46 |
47 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/search_user_recycler_row.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
21 |
28 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/bottom_navigation_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #FF5964
5 | #FFE74C
6 |
7 | #FF000000
8 | #FFFFFFFF
9 |
10 | #FAFAFA
11 | #C3C3C3
12 |
13 | #1E88E5
14 | #7CB342
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Easy Chat
3 |
4 | Hello blank fragment
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/app/src/test/java/com/example/easychat/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.example.easychat;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | dependencies {
3 | classpath 'com.google.gms:google-services:4.3.15'
4 | }
5 | }// Top-level build file where you can add configuration options common to all sub-projects/modules.
6 | plugins {
7 | id 'com.android.application' version '7.3.0' apply false
8 | id 'com.android.library' version '7.3.0' apply false
9 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # 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
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Enables namespacing of each library's R class so that its R class includes only the
19 | # resources declared in the library itself and none from the library's dependencies,
20 | # thereby reducing the size of the R class for that library
21 | android.nonTransitiveRClass=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bimalkaf/Android_Chat_Application/88e4537ed17e5a812a403b2c30849a35481b49b2/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Mar 22 12:50:53 IST 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | google()
5 | mavenCentral()
6 | }
7 | }
8 | dependencyResolutionManagement {
9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
10 | repositories {
11 | google()
12 | mavenCentral()
13 | maven { url "https://jitpack.io" }
14 | }
15 | }
16 | rootProject.name = "Easy Chat"
17 | include ':app'
18 |
--------------------------------------------------------------------------------