├── .gitattributes ├── .gitignore ├── .idea ├── .name ├── codeStyles │ └── Project.xml ├── gradle.xml ├── misc.xml ├── runConfigurations.xml └── vcs.xml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── google-services.json ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── theroboticsforum │ │ └── trfchat │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── theroboticsforum │ │ │ └── trfchat │ │ │ ├── ChatActivity.java │ │ │ ├── CustomAdapter.java │ │ │ ├── LoginActivity.java │ │ │ ├── MainActivity.java │ │ │ ├── Message.java │ │ │ └── RegisterActivity.java │ └── res │ │ ├── drawable-v24 │ │ ├── ic_launcher_foreground.xml │ │ ├── rectangle.xml │ │ ├── signout.png │ │ └── trflogo6.png │ │ ├── drawable │ │ ├── circle.xml │ │ ├── ic_add_black_24dp.xml │ │ ├── ic_launcher_background.xml │ │ └── ic_send_white_24dp.xml │ │ ├── layout │ │ ├── activity_chat.xml │ │ ├── activity_login.xml │ │ ├── activity_main.xml │ │ ├── activity_register.xml │ │ └── layout_message.xml │ │ ├── menu │ │ └── main_menu.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── theroboticsforum │ └── trfchat │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | TRF Chat -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | xmlns:android 14 | 15 | ^$ 16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 | xmlns:.* 25 | 26 | ^$ 27 | 28 | 29 | BY_NAME 30 | 31 |
32 |
33 | 34 | 35 | 36 | .*:id 37 | 38 | http://schemas.android.com/apk/res/android 39 | 40 | 41 | 42 |
43 |
44 | 45 | 46 | 47 | .*:name 48 | 49 | http://schemas.android.com/apk/res/android 50 | 51 | 52 | 53 |
54 |
55 | 56 | 57 | 58 | name 59 | 60 | ^$ 61 | 62 | 63 | 64 |
65 |
66 | 67 | 68 | 69 | style 70 | 71 | ^$ 72 | 73 | 74 | 75 |
76 |
77 | 78 | 79 | 80 | .* 81 | 82 | ^$ 83 | 84 | 85 | BY_NAME 86 | 87 |
88 |
89 | 90 | 91 | 92 | .* 93 | 94 | http://schemas.android.com/apk/res/android 95 | 96 | 97 | ANDROID_ATTRIBUTE_ORDER 98 | 99 |
100 |
101 | 102 | 103 | 104 | .* 105 | 106 | .* 107 | 108 | 109 | BY_NAME 110 | 111 |
112 |
113 |
114 |
115 |
116 |
-------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at robotics.forum@vit.edu. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guidelines 2 | 3 | All contributions are welcome. Please follow the guidelines given below to get started. 4 | 5 | - To file an issue or a feature request, use the [GitHub Issue Tracker](https://github.com/The-Robotics-Forum/workshop-android/issues) and describe briefly what you are expecting. 6 | - To raise a Pull Request: 7 | 1. Fork the repository 8 | 2. Create a branch. Preferable name it the same as the issue you want to solve. Eg name `issue-712`. 9 | 3. Commit your changes to the new branch you created in your forked repository. 10 | 4. Raise a Pull Request to the `develop` branch of this repository. 11 | 12 | ## Before you raise a PR 13 | **Make sure to follow these guidelines** 14 | 15 | 1. Run `gradlew check` or `./gradlew check` locally before pushing any commits or creating a Pull Request. 16 | - If `gradlew check` is failing locally, your Pull Request will also fail and won't be able to merge. 17 | 2. If you are taking up any issue from the issue tracker, please name your commits in this form. This will automatically link the Issue to your commit. 18 | - `Fix #{Issue Number}: Whatever change you did` 19 | - Example commit message: `Fix #9: Added a new function` 20 | 3. Give "easy to understand" names to the branches you create in your forked repository 21 | 4. While creating a Pull Request, explain in brief what changes you made. 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 The Robotics Forum, VIT Pune 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TRF Chat | Android App | TRF RoboDroid Workshop 2 | 3 | TRF Chat is the Android Application that TRF developed during RoboDroid Workshop 2020. 4 | 5 | # Contribution Guidelines 6 | 7 | This is an Open Source Project. All contributions are welcome. Please follow the steps below for contributing. 8 | 9 | - To file an issue or a feature request, use the [GitHub Issue Tracker](https://github.com/The-Robotics-Forum/workshop-android/issues) and describe briefly what you are expecting. 10 | - To raise a Pull Request: 11 | 1. Fork the repository 12 | 2. Create a branch. Preferable name it the same as the issue you want to solve. Eg name `issue-712`. 13 | 3. Commit your changes to the new branch you created in your forked repository. 14 | 4. Raise a Pull Request to the `develop` branch of this repository. 15 | 16 | **Make sure to follow these guidelines** 17 | 1. Run `gradlew check` or `./gradlew check` locally before pushing any commits or creating a Pull Request. 18 | - If `gradlew check` is failing locally, your Pull Request will also fail and won't be able to merge. 19 | 2. If you are taking up any issue from the issue tracker, please name your commits in this form. This will automatically link the Issue to your commit. 20 | - `Fix #{Issue Number}: Whatever change you did` 21 | - Example commit message: `Fix #9: Added a new function` 22 | 3. Give "easy to understand" names to the branches you create in your forked repository 23 | 4. While creating a Pull Request, explain in brief what changes you made. 24 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'com.google.gms.google-services' 3 | 4 | android { 5 | compileSdkVersion 29 6 | buildToolsVersion "29.0.2" 7 | defaultConfig { 8 | applicationId "com.theroboticsforum.trfchat" 9 | minSdkVersion 21 10 | targetSdkVersion 29 11 | versionCode 1 12 | versionName "1.0" 13 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | } 22 | 23 | dependencies { 24 | implementation fileTree(dir: 'libs', include: ['*.jar']) 25 | implementation 'androidx.appcompat:appcompat:1.0.2' 26 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 27 | 28 | //firebase authentication 29 | implementation 'com.google.firebase:firebase-auth:16.0.5' 30 | //firebase realtime database 31 | implementation 'com.google.firebase:firebase-database:16.0.4' 32 | //Android Support Design Library 33 | //noinspection GradleCompatible 34 | implementation 'com.android.support:design:27.1.1' 35 | implementation 'androidx.recyclerview:recyclerview:1.0.0' 36 | testImplementation 'junit:junit:4.12' 37 | androidTestImplementation 'androidx.test.ext:junit:1.1.0' 38 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' 39 | } 40 | -------------------------------------------------------------------------------- /app/google-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_info": { 3 | "project_number": "911339125790", 4 | "firebase_url": "https://trf-chat.firebaseio.com", 5 | "project_id": "trf-chat", 6 | "storage_bucket": "trf-chat.appspot.com" 7 | }, 8 | "client": [ 9 | { 10 | "client_info": { 11 | "mobilesdk_app_id": "1:911339125790:android:ff276b5456bbdf7499020f", 12 | "android_client_info": { 13 | "package_name": "com.google.firebase.codelab.friendlychat" 14 | } 15 | }, 16 | "oauth_client": [ 17 | { 18 | "client_id": "911339125790-eh0668tu54nu620apv85e9db05bl4h9p.apps.googleusercontent.com", 19 | "client_type": 3 20 | } 21 | ], 22 | "api_key": [ 23 | { 24 | "current_key": "AIzaSyD3IjrlC_L8wcps1tpZ60y1SL0bnesjKy0" 25 | } 26 | ], 27 | "services": { 28 | "appinvite_service": { 29 | "other_platform_oauth_client": [ 30 | { 31 | "client_id": "911339125790-eh0668tu54nu620apv85e9db05bl4h9p.apps.googleusercontent.com", 32 | "client_type": 3 33 | } 34 | ] 35 | } 36 | } 37 | }, 38 | { 39 | "client_info": { 40 | "mobilesdk_app_id": "1:911339125790:android:5217652ce6cd1a6499020f", 41 | "android_client_info": { 42 | "package_name": "com.theroboticsforum.trfchat" 43 | } 44 | }, 45 | "oauth_client": [ 46 | { 47 | "client_id": "911339125790-h98q1596pq7fenugm15571tvl1n0n92f.apps.googleusercontent.com", 48 | "client_type": 1, 49 | "android_info": { 50 | "package_name": "com.theroboticsforum.trfchat", 51 | "certificate_hash": "bf376e0843fef2c4accbcc82b0f5009c8c10f9e3" 52 | } 53 | }, 54 | { 55 | "client_id": "911339125790-eh0668tu54nu620apv85e9db05bl4h9p.apps.googleusercontent.com", 56 | "client_type": 3 57 | } 58 | ], 59 | "api_key": [ 60 | { 61 | "current_key": "AIzaSyD3IjrlC_L8wcps1tpZ60y1SL0bnesjKy0" 62 | } 63 | ], 64 | "services": { 65 | "appinvite_service": { 66 | "other_platform_oauth_client": [ 67 | { 68 | "client_id": "911339125790-eh0668tu54nu620apv85e9db05bl4h9p.apps.googleusercontent.com", 69 | "client_type": 3 70 | } 71 | ] 72 | } 73 | } 74 | } 75 | ], 76 | "configuration_version": "1" 77 | } -------------------------------------------------------------------------------- /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 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/theroboticsforum/trfchat/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.theroboticsforum.trfchat; 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 | 25 | assertEquals("com.theroboticsforum.trfchat", appContext.getPackageName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/theroboticsforum/trfchat/ChatActivity.java: -------------------------------------------------------------------------------- 1 | package com.theroboticsforum.trfchat; 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.os.Bundle; 9 | import android.util.Log; 10 | import android.view.View; 11 | import android.widget.Button; 12 | import android.widget.EditText; 13 | import android.widget.Toast; 14 | 15 | import com.google.android.gms.tasks.OnSuccessListener; 16 | import com.google.android.material.floatingactionbutton.FloatingActionButton; 17 | import com.google.firebase.auth.FirebaseAuth; 18 | import com.google.firebase.auth.FirebaseUser; 19 | import com.google.firebase.database.DataSnapshot; 20 | import com.google.firebase.database.DatabaseError; 21 | import com.google.firebase.database.DatabaseReference; 22 | import com.google.firebase.database.FirebaseDatabase; 23 | import com.google.firebase.database.ValueEventListener; 24 | 25 | import java.util.ArrayList; 26 | 27 | public class ChatActivity extends AppCompatActivity { 28 | 29 | //vars 30 | private static final String TAG = "ChatActivity"; 31 | private String chatKey; 32 | private ArrayList chats; 33 | private String senderEmail; 34 | private String receiverEmail; 35 | 36 | //firebase database 37 | private DatabaseReference mChatData; 38 | private FirebaseUser currentUser; 39 | 40 | //widgets 41 | private RecyclerView mRecyclerView; 42 | private EditText mMessage; 43 | private FloatingActionButton sendBtn; 44 | 45 | //custom adapter 46 | private CustomAdapter adapter; 47 | 48 | 49 | 50 | 51 | @Override 52 | protected void onCreate(Bundle savedInstanceState) { 53 | super.onCreate(savedInstanceState); 54 | setContentView(R.layout.activity_chat); 55 | 56 | //appBar settings 57 | getSupportActionBar().setTitle("Chats"); 58 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 59 | getSupportActionBar().setDisplayShowHomeEnabled(true); 60 | 61 | //get the current user object 62 | currentUser = FirebaseAuth.getInstance().getCurrentUser(); 63 | 64 | //get the chatkey and create a reference to it 65 | chatKey = getIntent().getStringExtra("chatKey"); 66 | mChatData = FirebaseDatabase.getInstance().getReference().child("chats").child(chatKey); 67 | 68 | //find the widgets from the layout 69 | chats = new ArrayList<>(); 70 | mRecyclerView = findViewById(R.id.recycler_view); 71 | mMessage = findViewById(R.id.messageEdt); 72 | sendBtn = findViewById(R.id.sendBtn); 73 | 74 | 75 | 76 | //setup the recycler view 77 | adapter = new CustomAdapter(this , chats); 78 | mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); 79 | mRecyclerView.setAdapter(adapter); 80 | 81 | //set onClickListener to sendBtn 82 | sendBtn.setOnClickListener( 83 | new View.OnClickListener() { 84 | @Override 85 | public void onClick(View view) { 86 | sendMsg(); 87 | } 88 | } 89 | ); 90 | 91 | //get chats from firebase 92 | getChats(); 93 | 94 | } 95 | 96 | 97 | private void getChats() 98 | { 99 | mChatData.child("messages").addValueEventListener( 100 | new ValueEventListener() { 101 | @Override 102 | public void onDataChange(@NonNull DataSnapshot dataSnapshot) { 103 | Log.d(TAG, "onDataChange: Getting the chats for key:" + chatKey); 104 | //clear the arraylist orelse the chats will repeat 105 | chats.clear(); 106 | for(DataSnapshot msg : dataSnapshot.getChildren()) 107 | { 108 | if(msg.exists()) 109 | { 110 | Message message = msg.getValue(Message.class); 111 | chats.add(message); 112 | } 113 | } 114 | //notifyDatasetChange(); 115 | adapter.notifyItemChanged(chats.size()); 116 | 117 | } 118 | 119 | @Override 120 | public void onCancelled(@NonNull DatabaseError databaseError) { 121 | Log.e(TAG, "onCancelled: ",databaseError.toException() ); 122 | } 123 | } 124 | ); 125 | } 126 | 127 | private void sendMsg() 128 | { 129 | final String msg = mMessage.getText().toString().trim(); 130 | //check if the messageEdt is empty 131 | if(msg.equals("")) 132 | { 133 | //edit text is empty 134 | Toast.makeText(this, "Type a message", Toast.LENGTH_SHORT).show(); 135 | } 136 | else 137 | { 138 | //editTxt is not empty and we are good to go 139 | //clear the editText 140 | mMessage.setText(""); 141 | String id = mChatData.child("messages").push().getKey(); 142 | 143 | Message message = new Message(msg , currentUser.getEmail()); 144 | 145 | 146 | mChatData.child("messages").child(id).setValue(message). 147 | addOnSuccessListener( 148 | new OnSuccessListener() { 149 | @Override 150 | public void onSuccess(Void aVoid) { 151 | Log.d(TAG, "onSuccess: message sent at chat key" + chatKey+ "\nmessage:" + msg); 152 | } 153 | } 154 | ); 155 | 156 | //getChats(); 157 | } 158 | } 159 | 160 | @Override 161 | protected void onStart() { 162 | super.onStart(); 163 | getChats(); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /app/src/main/java/com/theroboticsforum/trfchat/CustomAdapter.java: -------------------------------------------------------------------------------- 1 | package com.theroboticsforum.trfchat; 2 | 3 | import android.content.Context; 4 | import android.text.Layout; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.TextView; 9 | 10 | import androidx.annotation.NonNull; 11 | import androidx.recyclerview.widget.RecyclerView; 12 | 13 | 14 | 15 | import java.util.ArrayList; 16 | 17 | public class CustomAdapter extends RecyclerView.Adapter { 18 | 19 | private Context mCtx; 20 | private ArrayList chats; 21 | 22 | public CustomAdapter(Context mCtx, ArrayList chats) { 23 | this.mCtx = mCtx; 24 | this.chats = chats; 25 | } 26 | 27 | @NonNull 28 | @Override 29 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 30 | LayoutInflater inflater = LayoutInflater.from(parent.getContext()); 31 | View v = inflater.inflate(R.layout.layout_message , parent , false); 32 | 33 | return new ViewHolder(v); 34 | } 35 | 36 | @Override 37 | public void onBindViewHolder(@NonNull ViewHolder holder, int position) { 38 | 39 | TextView nameTextView = holder.nameTextView; 40 | TextView message = holder.messageTextView; 41 | 42 | Message msg = chats.get(position); 43 | 44 | String[] names = msg.getSenderEmail().split("@"); 45 | 46 | nameTextView.setText(names[0]); 47 | message.setText(msg.getMessage()); 48 | 49 | } 50 | 51 | @Override 52 | public int getItemCount() { 53 | return chats.size(); 54 | } 55 | 56 | public class ViewHolder extends RecyclerView.ViewHolder { 57 | private TextView nameTextView; 58 | private TextView messageTextView; 59 | 60 | public ViewHolder(@NonNull View itemView) { 61 | super(itemView); 62 | 63 | nameTextView = itemView.findViewById(R.id.senderEmail); 64 | messageTextView = itemView.findViewById(R.id.messageTextView); 65 | 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/com/theroboticsforum/trfchat/LoginActivity.java: -------------------------------------------------------------------------------- 1 | package com.theroboticsforum.trfchat; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.appcompat.app.AppCompatActivity; 5 | 6 | import android.app.Dialog; 7 | import android.content.Intent; 8 | import android.os.Bundle; 9 | import android.util.Log; 10 | import android.view.View; 11 | import android.widget.Button; 12 | import android.widget.EditText; 13 | import android.widget.ProgressBar; 14 | import android.widget.Toast; 15 | 16 | import com.google.android.gms.common.ConnectionResult; 17 | import com.google.android.gms.common.GoogleApiAvailability; 18 | import com.google.android.gms.tasks.OnCompleteListener; 19 | import com.google.android.gms.tasks.OnFailureListener; 20 | import com.google.android.gms.tasks.Task; 21 | import com.google.firebase.auth.AuthResult; 22 | import com.google.firebase.auth.FirebaseAuth; 23 | import com.google.firebase.auth.FirebaseUser; 24 | 25 | public class LoginActivity extends AppCompatActivity implements View.OnClickListener { 26 | 27 | //vars 28 | private static final String TAG = "LoginActivity"; 29 | private static final int ERROR_DIALOG_REQUEST = 9001; 30 | 31 | 32 | //widgets 33 | private Button mLoginButton, mRegisterButton; 34 | private EditText mUsername, mPassword; 35 | private ProgressBar mProgressBar; 36 | 37 | //firebase 38 | private FirebaseAuth.AuthStateListener mAuthListener; 39 | 40 | 41 | @Override 42 | protected void onCreate(Bundle savedInstanceState) { 43 | super.onCreate(savedInstanceState); 44 | setContentView(R.layout.activity_login); 45 | 46 | getSupportActionBar().hide(); 47 | mLoginButton = findViewById(R.id.login); 48 | mRegisterButton = findViewById(R.id.register); 49 | mUsername = findViewById(R.id.username); 50 | mPassword = findViewById(R.id.password); 51 | mProgressBar = findViewById(R.id.loading); 52 | mProgressBar.setVisibility(View.INVISIBLE); 53 | 54 | mRegisterButton.setOnClickListener( 55 | new View.OnClickListener() { 56 | @Override 57 | public void onClick(View view) { 58 | startActivity(new Intent(LoginActivity.this , RegisterActivity.class )); 59 | finish(); 60 | } 61 | } 62 | ); 63 | 64 | setupFirebaseAuth(); 65 | if(servicesOK()){ 66 | mLoginButton.setOnClickListener(this); 67 | } 68 | 69 | 70 | } 71 | 72 | private void setupFirebaseAuth() { 73 | Log.d(TAG, "setupFirebaseAuth: started."); 74 | 75 | mAuthListener = new FirebaseAuth.AuthStateListener() { 76 | @Override 77 | public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { 78 | FirebaseUser user = firebaseAuth.getCurrentUser(); 79 | if (user != null) { 80 | //someone is logged in... 81 | Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid()); 82 | Toast.makeText(LoginActivity.this, "Signed in", Toast.LENGTH_SHORT).show(); 83 | 84 | Intent intent = new Intent(LoginActivity.this, MainActivity.class); 85 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 86 | startActivity(intent); 87 | finish(); 88 | 89 | 90 | } else { 91 | // User is signed out 92 | Log.d(TAG, "onAuthStateChanged:signed_out"); 93 | } 94 | } 95 | }; 96 | } 97 | 98 | //this is a commit 99 | //this is another comment 100 | 101 | public boolean servicesOK(){ 102 | Log.d(TAG, "servicesOK: Checking Google Services."); 103 | 104 | int isAvailable = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(LoginActivity.this); 105 | 106 | if(isAvailable == ConnectionResult.SUCCESS){ 107 | //everything is ok and the user can make mapping requests 108 | Log.d(TAG, "servicesOK: Play Services is OK"); 109 | return true; 110 | } 111 | else if(GoogleApiAvailability.getInstance().isUserResolvableError(isAvailable)){ 112 | //an error occured, but it's resolvable 113 | Log.d(TAG, "servicesOK: an error occured, but it's resolvable."); 114 | Dialog dialog = GoogleApiAvailability.getInstance().getErrorDialog(LoginActivity.this, isAvailable, ERROR_DIALOG_REQUEST); 115 | dialog.show(); 116 | } 117 | else{ 118 | //erroe cannot be resolved 119 | Toast.makeText(this, "Can't connect to services", Toast.LENGTH_SHORT).show(); 120 | } 121 | 122 | return false; 123 | } 124 | 125 | private boolean isEmpty(String string){ 126 | return string.equals(""); 127 | } 128 | 129 | @Override 130 | public void onClick(View view) { 131 | mProgressBar.setVisibility(View.VISIBLE); 132 | if(view.getId() == R.id.login){ 133 | //check if the fields are filled out 134 | if(!isEmpty(mUsername.getText().toString().trim()) 135 | && !isEmpty(mPassword.getText().toString().trim())){ 136 | Log.d(TAG, "onClick: attempting to authenticate."); 137 | 138 | showDialog(); 139 | 140 | FirebaseAuth.getInstance().signInWithEmailAndPassword(mUsername.getText().toString(), 141 | mPassword.getText().toString()) 142 | .addOnCompleteListener(new OnCompleteListener() { 143 | @Override 144 | public void onComplete(@NonNull Task task) { 145 | 146 | hideDialog(); 147 | 148 | } 149 | }).addOnFailureListener(new OnFailureListener() { 150 | @Override 151 | public void onFailure(@NonNull Exception e) { 152 | Toast.makeText(LoginActivity.this, "Error" + e.toString(), Toast.LENGTH_SHORT).show(); 153 | hideDialog(); 154 | } 155 | }); 156 | }else{ 157 | Toast.makeText(this, "Fill in all the details.", Toast.LENGTH_SHORT).show(); 158 | } 159 | } 160 | } 161 | 162 | private void hideDialog(){ 163 | if(mProgressBar.getVisibility() == View.VISIBLE){ 164 | mProgressBar.setVisibility(View.INVISIBLE); 165 | } 166 | } 167 | 168 | private void showDialog(){ 169 | mProgressBar.setVisibility(View.VISIBLE); 170 | 171 | } 172 | 173 | @Override 174 | public void onStart() { 175 | super.onStart(); 176 | FirebaseAuth.getInstance().addAuthStateListener(mAuthListener); 177 | } 178 | 179 | @Override 180 | public void onStop() { 181 | super.onStop(); 182 | if (mAuthListener != null) { 183 | FirebaseAuth.getInstance().removeAuthStateListener(mAuthListener); 184 | } 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /app/src/main/java/com/theroboticsforum/trfchat/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.theroboticsforum.trfchat; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.appcompat.app.AppCompatActivity; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.util.Log; 8 | import android.view.Menu; 9 | import android.view.MenuItem; 10 | import android.view.View; 11 | import android.widget.Button; 12 | import android.widget.EditText; 13 | import android.widget.ProgressBar; 14 | import android.widget.Toast; 15 | import com.google.firebase.FirebaseApp; 16 | import com.google.firebase.auth.FirebaseAuth; 17 | import com.google.firebase.auth.FirebaseUser; 18 | import com.google.firebase.database.DataSnapshot; 19 | import com.google.firebase.database.DatabaseError; 20 | import com.google.firebase.database.DatabaseReference; 21 | import com.google.firebase.database.FirebaseDatabase; 22 | import com.google.firebase.database.ValueEventListener; 23 | 24 | 25 | public class MainActivity extends AppCompatActivity { 26 | 27 | //widgets 28 | private EditText mUsername; 29 | private Button mSendButton, mRequestButton; 30 | private ProgressBar mProgressBar; 31 | 32 | //vars 33 | private static final String TAG = "MainActivity"; 34 | 35 | 36 | //firebase authetication 37 | private FirebaseAuth.AuthStateListener mAuthListener; 38 | private FirebaseUser currentUser; 39 | 40 | 41 | //Firebase Database 42 | private DatabaseReference mChatData = FirebaseDatabase.getInstance().getReference("chats"); 43 | 44 | @Override 45 | protected void onCreate(Bundle savedInstanceState) { 46 | super.onCreate(savedInstanceState); 47 | setContentView(R.layout.activity_main); 48 | 49 | 50 | 51 | setupFirebaseAuth(); 52 | currentUser = FirebaseAuth.getInstance().getCurrentUser(); 53 | getSupportActionBar().setTitle("TRF Chat"); 54 | 55 | 56 | mUsername = findViewById(R.id.username); 57 | mSendButton = findViewById(R.id.sendBtn); 58 | mRequestButton = findViewById(R.id.see_request_btn); 59 | mProgressBar = findViewById(R.id.loading); 60 | mProgressBar.setVisibility(View.INVISIBLE); 61 | 62 | 63 | mRequestButton.setOnClickListener( 64 | new View.OnClickListener() { 65 | @Override 66 | public void onClick(View view) { 67 | //check if the user has any requests 68 | //check if user is receiver of any chatRequests 69 | checkRequests(); 70 | } 71 | } 72 | ); 73 | 74 | mSendButton.setOnClickListener( 75 | new View.OnClickListener() { 76 | @Override 77 | public void onClick(View view) { 78 | //send the request to the user 79 | //make user the sender of the chatRequest 80 | sendRequest(); 81 | } 82 | } 83 | ); 84 | 85 | } 86 | 87 | @Override 88 | public boolean onCreateOptionsMenu(Menu menu) { 89 | getMenuInflater().inflate(R.menu.main_menu , menu); 90 | return true; 91 | } 92 | 93 | @Override 94 | public boolean onOptionsItemSelected(@NonNull MenuItem item) { 95 | 96 | if(item.getItemId() == R.id.sign_out) 97 | { 98 | //signOut button is pressed 99 | signOut(); 100 | } 101 | return true; 102 | } 103 | 104 | private void signOut() { 105 | Log.d(TAG, "signOut: sigining out."); 106 | FirebaseAuth.getInstance().signOut(); 107 | Toast.makeText(this, "Bye! Bye! ", Toast.LENGTH_SHORT).show(); 108 | Log.d(TAG, "signOut: User signed out"); 109 | startActivity(new Intent(this, LoginActivity.class)); 110 | } 111 | 112 | private void setupFirebaseAuth(){ 113 | Log.d(TAG, "setupFirebaseAuth: started."); 114 | FirebaseApp.initializeApp(this); 115 | 116 | mAuthListener = new FirebaseAuth.AuthStateListener() { 117 | @Override 118 | public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { 119 | FirebaseUser user = firebaseAuth.getCurrentUser(); 120 | if (user != null) { 121 | //user is signed in 122 | Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid()); 123 | 124 | } else { 125 | //user is signed out... revert to login page 126 | Log.d(TAG, "onAuthStateChanged:signed_out"); 127 | Toast.makeText(MainActivity.this, "Please Login", Toast.LENGTH_SHORT).show(); 128 | Intent intent = new Intent(MainActivity.this, LoginActivity.class); 129 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 130 | startActivity(intent); 131 | finish(); 132 | } 133 | } 134 | }; 135 | } 136 | 137 | @Override 138 | public void onStart() { 139 | super.onStart(); 140 | 141 | FirebaseAuth.getInstance().addAuthStateListener(mAuthListener);//most important line of the code 142 | //checkRequests(); 143 | 144 | } 145 | 146 | @Override 147 | public void onStop() { 148 | super.onStop(); 149 | if (mAuthListener != null) { 150 | FirebaseAuth.getInstance().removeAuthStateListener(mAuthListener); 151 | } 152 | } 153 | 154 | private boolean isEmpty(String string){ return string.equals("");} 155 | 156 | private void sendRequest() 157 | { 158 | final String receiverEmail = mUsername.getText().toString().trim(); 159 | String senderEmail = currentUser.getEmail(); 160 | 161 | //check if the editTExt is empty 162 | if(isEmpty(receiverEmail)) 163 | { 164 | //edit text is empty 165 | Toast.makeText(this, "Enter the email", Toast.LENGTH_SHORT).show(); 166 | } 167 | else { 168 | //email field is not empty, we are good ot go 169 | mProgressBar.setVisibility(View.VISIBLE); 170 | 171 | //create a chatkey and push 172 | String chatKey = mChatData.push().getKey(); 173 | mChatData.child(chatKey).child("sender").setValue(senderEmail); 174 | mChatData.child(chatKey).child("receiver").setValue(receiverEmail); 175 | 176 | Intent i = new Intent(MainActivity.this , ChatActivity.class); 177 | i.putExtra("chatKey" , chatKey); 178 | startActivity(i); 179 | finish(); 180 | } 181 | 182 | } 183 | 184 | private void checkRequests() 185 | { 186 | //check for requests 187 | mProgressBar.setVisibility(View.VISIBLE); 188 | 189 | //firebasecheck if the request exits in chatDatabase 190 | mChatData.addValueEventListener(new ValueEventListener() { 191 | @Override 192 | public void onDataChange(@NonNull DataSnapshot dataSnapshot) { 193 | for(DataSnapshot chatRoom : dataSnapshot.getChildren()) 194 | { 195 | if(chatRoom.exists()) 196 | { 197 | String receiverEmail = (String) chatRoom.child("receiver").getValue(); 198 | //check if the chatRoom sender is equal to our email 199 | if(receiverEmail.equals(currentUser.getEmail())) 200 | { 201 | //chat request exists and chatroom already exists 202 | Intent i = new Intent(MainActivity.this , ChatActivity.class); 203 | i.putExtra("chatKey" , chatRoom.getKey()); 204 | startActivity(i); 205 | //finish(); 206 | 207 | } 208 | 209 | } 210 | } 211 | } 212 | 213 | @Override 214 | public void onCancelled(@NonNull DatabaseError databaseError) { 215 | Log.e(TAG, "onCancelled: ",databaseError.toException() ); 216 | } 217 | }); 218 | 219 | mProgressBar.setVisibility(View.INVISIBLE); 220 | //if the control reaches here.. that means, no request has been found 221 | //indicate the user using a simple Toast message 222 | Toast.makeText(this, "No requests found", Toast.LENGTH_SHORT).show(); 223 | 224 | } 225 | 226 | 227 | } 228 | -------------------------------------------------------------------------------- /app/src/main/java/com/theroboticsforum/trfchat/Message.java: -------------------------------------------------------------------------------- 1 | package com.theroboticsforum.trfchat; 2 | 3 | import java.util.Date; 4 | 5 | public class Message { 6 | private String message; 7 | private String senderEmail; 8 | 9 | public Message() 10 | { 11 | //necessary no-argument contructor 12 | } 13 | 14 | 15 | public Message(String message, String senderEmail) { 16 | this.message = message; 17 | this.senderEmail = senderEmail; 18 | } 19 | 20 | public String getMessage() { 21 | return message; 22 | } 23 | 24 | public String getSenderEmail() { 25 | return senderEmail; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/theroboticsforum/trfchat/RegisterActivity.java: -------------------------------------------------------------------------------- 1 | package com.theroboticsforum.trfchat; 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.View; 10 | import android.widget.Button; 11 | import android.widget.ProgressBar; 12 | import android.widget.TextView; 13 | import android.widget.Toast; 14 | 15 | import com.google.android.gms.tasks.OnFailureListener; 16 | import com.google.android.gms.tasks.OnSuccessListener; 17 | import com.google.firebase.auth.AuthResult; 18 | import com.google.firebase.auth.FirebaseAuth; 19 | 20 | 21 | 22 | public class RegisterActivity extends AppCompatActivity { 23 | 24 | //widgets 25 | private Button mSignInButton, mRegisterButton; 26 | private TextView mEmail,mPassword; 27 | private ProgressBar mProgress; 28 | 29 | //firebase authentication 30 | private FirebaseAuth mAuth; 31 | 32 | 33 | 34 | //vars 35 | private static final String TAG = "RegisterActivity"; 36 | 37 | 38 | 39 | 40 | @Override 41 | protected void onCreate(Bundle savedInstanceState) { 42 | super.onCreate(savedInstanceState); 43 | setContentView(R.layout.activity_register); 44 | 45 | getSupportActionBar().hide(); 46 | 47 | mSignInButton = findViewById(R.id.signIn); 48 | mRegisterButton = findViewById(R.id.register); 49 | mEmail = findViewById(R.id.username); 50 | mPassword = findViewById(R.id.password); 51 | mProgress = findViewById(R.id.loading); 52 | 53 | mProgress.setVisibility(View.INVISIBLE); 54 | 55 | 56 | mSignInButton.setOnClickListener( 57 | new View.OnClickListener() { 58 | @Override 59 | public void onClick(View view) { 60 | signIn(); 61 | } 62 | } 63 | ); 64 | 65 | mRegisterButton.setOnClickListener( 66 | new View.OnClickListener() { 67 | @Override 68 | public void onClick(View view) { 69 | register(); 70 | } 71 | } 72 | ); 73 | 74 | 75 | } 76 | 77 | private void register() 78 | { 79 | //register the new user here 80 | mAuth = FirebaseAuth.getInstance(); 81 | final String email,password; 82 | email = mEmail.getText().toString().trim(); 83 | password = mPassword.getText().toString().trim(); 84 | 85 | if(!isEmpty(email) && !isEmpty(password)) 86 | { 87 | //none of the field is empty... Can continue with registration 88 | 89 | mAuth.createUserWithEmailAndPassword(email,password). 90 | addOnSuccessListener( 91 | new OnSuccessListener() { 92 | @Override 93 | public void onSuccess(AuthResult authResult) { 94 | //registration is successfull... direct user to MAinActivity 95 | Log.d(TAG, "onSuccess: Registration Successfull"); 96 | Toast.makeText(RegisterActivity.this, "Welcome!!", Toast.LENGTH_SHORT).show(); 97 | startActivity(new Intent(RegisterActivity.this , MainActivity.class)); 98 | 99 | } 100 | } 101 | ).addOnFailureListener( 102 | new OnFailureListener() { 103 | @Override 104 | public void onFailure(@NonNull Exception e) { 105 | Log.e(TAG, "onFailure: Registration Failed!! ",e ); 106 | Toast.makeText(RegisterActivity.this, "Cannot Register", Toast.LENGTH_SHORT).show(); 107 | } 108 | } 109 | ); 110 | } 111 | 112 | else 113 | { 114 | //one of the email or password field is empty 115 | if(isEmpty(email)) 116 | { 117 | //email field is empty 118 | Toast.makeText(this, "Enter valid Email", Toast.LENGTH_SHORT).show(); 119 | } 120 | else{ 121 | //password field is empty 122 | Toast.makeText(this, "Enter the password", Toast.LENGTH_SHORT).show(); 123 | } 124 | } 125 | } 126 | 127 | private void signIn() 128 | { 129 | //move the user to the LogIn activity 130 | startActivity(new Intent(this, LoginActivity.class)); 131 | } 132 | 133 | private boolean isEmpty(String string) {return string.equals("");} 134 | 135 | 136 | } 137 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/rectangle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | android:shape="rectangle" > 4 | 5 | 6 | 9 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/signout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/The-Robotics-Forum/TRF-Chat/8519f67f58e56db8a53b335880fe399c8122da3c/app/src/main/res/drawable-v24/signout.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/trflogo6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/The-Robotics-Forum/TRF-Chat/8519f67f58e56db8a53b335880fe399c8122da3c/app/src/main/res/drawable-v24/trflogo6.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/circle.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_add_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /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/ic_send_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_chat.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 26 | 27 | 37 | 38 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_login.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 21 | 22 | 29 | 30 | 31 | 32 | 33 | 46 | 47 | 48 | 63 | 64 |