├── CHANGELOG.md
├── LICENSE
├── PRIVACY_POLICY.md
├── README.md
├── TERMS_AND_CONDITIONS.md
├── THIRD_PARTY_NOTICES.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── github
│ │ └── h01d
│ │ └── chatapp
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── ic_launcher-web.png
│ ├── java
│ │ └── com
│ │ │ └── github
│ │ │ └── h01d
│ │ │ └── chatapp
│ │ │ ├── MainActivity.java
│ │ │ ├── activities
│ │ │ ├── ChatActivity.java
│ │ │ ├── FullScreenActivity.java
│ │ │ ├── ProfileActivity.java
│ │ │ ├── UsersActivity.java
│ │ │ └── WelcomeActivity.java
│ │ │ ├── adapters
│ │ │ └── MessageAdapter.java
│ │ │ ├── fragments
│ │ │ ├── ChatFragment.java
│ │ │ ├── FriendsFragment.java
│ │ │ └── RequestsFragment.java
│ │ │ ├── holders
│ │ │ ├── ChatHolder.java
│ │ │ ├── FriendHolder.java
│ │ │ ├── MessageHolder.java
│ │ │ ├── RequestHolder.java
│ │ │ └── UserHolder.java
│ │ │ ├── models
│ │ │ ├── Chat.java
│ │ │ ├── Friend.java
│ │ │ ├── Message.java
│ │ │ ├── Request.java
│ │ │ └── User.java
│ │ │ └── utils
│ │ │ ├── Capabilities.java
│ │ │ ├── FirebaseMessagingService.java
│ │ │ └── TouchImageView.java
│ └── res
│ │ ├── drawable
│ │ ├── circle.xml
│ │ ├── corner.xml
│ │ ├── ic_add_white_24dp.xml
│ │ ├── ic_block_white_24dp.xml
│ │ ├── ic_cancel_white_24dp.xml
│ │ ├── ic_edit_white_24dp.xml
│ │ ├── ic_email_black_24dp.xml
│ │ ├── ic_filter_hdr_white_24dp.xml
│ │ ├── ic_group_white_24dp.xml
│ │ ├── ic_image_black_24dp.xml
│ │ ├── ic_image_white_24dp.xml
│ │ ├── ic_lock_black_24dp.xml
│ │ ├── ic_message_white_24dp.xml
│ │ ├── ic_person_add_white_24dp.xml
│ │ ├── ic_person_black_24dp.xml
│ │ ├── ic_person_white_24dp.xml
│ │ ├── ic_remove_circle_white_24dp.xml
│ │ ├── ic_send_black_24dp.xml
│ │ ├── logo.png
│ │ ├── logo_cover.png
│ │ ├── logo_shadow.png
│ │ ├── message_background.xml
│ │ └── user.png
│ │ ├── layout
│ │ ├── activity_chat.xml
│ │ ├── activity_full_screen.xml
│ │ ├── activity_main.xml
│ │ ├── activity_profile.xml
│ │ ├── activity_users.xml
│ │ ├── activity_welcome.xml
│ │ ├── app_bar.xml
│ │ ├── chat_bar.xml
│ │ ├── fragment_chat.xml
│ │ ├── fragment_friends.xml
│ │ ├── fragment_request.xml
│ │ ├── message.xml
│ │ ├── status_dialog.xml
│ │ └── user.xml
│ │ ├── menu
│ │ └── main_menu.xml
│ │ ├── 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
│ │ ├── colors.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── github
│ └── h01d
│ └── chatapp
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── index.js
└── settings.gradle
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 |
4 | ## Version 1.1 _(13/03/2018)_
5 |
6 | - Added option to change Cover Image in Profile.
7 | - Added Notification when someone accepts Friend Request.
8 | - Added image sending in Chat.
9 | - Added image full screen option in profile.
10 | - Added Menu with View Profile, Accept Request in Requests.
11 | - Added Ripple Effect and Deviders in Lists of Request/Chat/Friends Tab as well as Users.
12 |
13 | - Fixed bug when minimizing Chat would not update messages after re-opening.
14 | - Fixed bug where Android Versions with API 26+ would not receive Notifications.
15 |
16 | - Changed Friends Tab and now friends are sorted by date.
17 | - Changed logo of Friend Request notification.
18 | - Changed Chat overall typing experiance and now will not drop keyboard after sending message.
19 | - Changed Login/Registers boxes to maxLine=1 so they can work properly with enter.
20 |
21 | - Removed enter-key send message.
22 |
23 | ## Version 1.0 _(26/02/2018)_
24 |
25 | - Initial Release.
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright 2018 Raf.
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/PRIVACY_POLICY.md:
--------------------------------------------------------------------------------
1 | # Privacy Policy
2 |
3 | *Last Revised: 27/02/2018*
4 |
5 | We built the ChatApp app as an Open Source app. This SERVICE is provided at no cost and is intended for use as is.
6 |
7 | This page is used to inform Service users regarding our policies with the collection, use, and disclosure of Personal Information if anyone decided to use our Service.
8 |
9 | If you choose to use our Service, then you agree to the collection and use of information in relation to this policy. The Personal Information that we collect is used for providing and improving the Service. We will not use or share your information with anyone except as described in this Privacy Policy.
10 |
11 | The terms used in this Privacy Policy have the same meanings as in our [Terms and Conditions](TERMS_AND_CONDITIONS.md), which is accessible at ChatApp unless otherwise defined in this Privacy Policy.
12 |
13 | ## Information Collection and Use
14 |
15 | For a better experience, while using our Service, we may require you to provide us with certain personally identifiable information, including but not limited to Email, Username, Password, Profile Picture. The information that we request are retained on Google Servers and accessed only but us.
16 |
17 | The app does use third party services that may collect information used to identify you.
18 |
19 | Link to privacy policy of third party service providers used by the app
20 |
21 | - [Google Play Services](https://www.google.com/policies/privacy/)
22 | - [Firebase](https://www.firebase.com/terms/terms-of-service.html)
23 |
24 | Other third party libraries used by the app
25 |
26 | - [Third Party Notices](THIRD_PARTY_NOTICES.md)
27 |
28 | ## Crash Reporting
29 |
30 | We want to inform you that whenever you use our Service, in a case of an error in the app we collect data and information (through third party products) so we can fix or avoid it. This report may include information such as your device Internet Protocol (“IP”) address, device name, operating system version, the configuration of the app when utilizing our Service, the time and date of your use of the Service, and other statistics.
31 |
32 | ## Service Providers
33 |
34 | We may employ third-party companies and individuals due to the following reasons:
35 |
36 | - To facilitate our Service;
37 | - To provide the Service on our behalf;
38 | - To perform Service-related services; or
39 | - To assist us in analyzing how our Service is used.
40 |
41 | We want to inform users of this Service that these third parties have access to your Personal Information. The reason is to perform the tasks assigned to them on our behalf. However, they are obligated not to disclose or use the information for any other purpose.
42 |
43 | ## Security
44 |
45 | We value your trust in providing us your Personal Information, thus we are striving to use commercially acceptable means of protecting it. But remember that no method of transmission over the internet, or method of electronic storage is 100% secure and reliable, and we cannot guarantee its absolute security.
46 |
47 | ## Privacy
48 |
49 | These Services do not address anyone under the age of 13. We do not knowingly collect personally identifiable information from children under 13. In the case we discover that a child under 13 has provided me with personal information, we immediately delete this from our servers. If you are a parent or guardian and you are aware that your child has provided us with personal information, please contact us so that we will be able to do necessary actions.
50 |
51 | ## Changes to this Privacy Policy
52 |
53 | We may update our Privacy Policy from time to time. Thus, you are advised to review this page periodically for any changes. We will notify you of any changes by posting the new Privacy Policy on this page. These changes are effective immediately after they are posted on this page.
54 |
55 | ## Contact Us
56 |
57 | If you have any questions or suggestions about our Privacy Policy, do not hesitate to contact us at rafaellos.g9@gmail.com.
58 |
59 | *This privacy policy page was created at [privacypolicytemplate.net](https://privacypolicytemplate.net) and modified/generated by [App Privacy Policy Generator](https://app-privacy-policy-generator.firebaseapp.com), Raf.*
60 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ChatApp v1.1
2 |
3 | ChatApp is a project that I started to improve my Android Development knowledge. Later on I have decided to make it public, open source and publish it on Play Store.
4 |
5 | It uses [Firebase's](https://firebase.google.com) Authentication/Database/Storage/Messaging/CrashReporting libraries for it's implementation and several other libraries that they are listed on [Third Party Notices](THIRD_PARTY_NOTICES.md).
6 |
7 | Make sure you read App's [Privacy Policy](PRIVACY_POLICY.md) and [Terms and Conditions](TERMS_AND_CONDITIONS.md) before using it.
8 |
9 | _Based on [Lapit Chat](https://github.com/akshayejh/Lapit---Android-Firebase-Chat-App) Youtube Series which can be found [here](https://www.youtube.com/playlist?list=PLGCjwl1RrtcQ3o2jmZtwu2wXEA4OIIq53)._
10 |
11 | **DOWNLOAD LINK:** [Play Store](https://play.google.com/store/apps/details?id=com.github.h01d.chatapp)
12 |
13 | ## Preview
14 |
15 | 
16 |
17 | _Browse all preview pictures [here](https://imgur.com/a/HQhKw)._
18 |
19 | ## Features
20 |
21 | - Messaging
22 | - Send and Receive messages with users
23 | - Send pictures
24 | - Lists
25 | - List with your Requests
26 | - List with your Messages
27 | - List with your Friends
28 | - List with all Users
29 | - Friends
30 | - Accept or Remove Friends
31 | - Requests
32 | - Send or Cancel Friend Request to users
33 | - Profile
34 | - Update your Profile Picture
35 | - Update your Status
36 | - Update your Cover Picture
37 | - View other users profile
38 | - Notifications
39 | - Notification when you have a new message
40 | - Notification when you have a new friend request
41 | - Notification when someone accepts your request
42 |
43 | **Upcoming**
44 |
45 | - Blocking
46 | - Block user from sending messages
47 |
48 | ## Changelog
49 |
50 | Read all Changelog [HERE](CHANGELOG.md).
51 |
52 | ## Installation
53 |
54 | *Setting up project*
55 |
56 | - Download Project
57 | - Create a new [Firebase](https://firebase.google.com) Project in console
58 | - Connect project with Firebase `(Tools/Firebase)` in Android Studio
59 | - Generate, download, paste `google-services.json` into the project
60 |
61 | *Setting up notifications back-end*
62 |
63 | - Create a folder on your Desktop and open it
64 | - Start CMD (for Windows) or Terminal (for MacOS/Linux)
65 | - Login on Firebase CLI using `firebase login`
66 | - Type `firebase init`, select `Functions` using the `Space` key and hit `Enter`
67 | - Select your App, then `javascript`, `N` on ESLint, and `Y`on dependendcies with npm.
68 | - Navigate `functions` folder and replace `index.js` with [this](note.js)
69 | - Type `firebase deploy` and you are all set
70 |
71 | **NOTE:** make sure you read project's [LICENSE](LICENSE) before start playing with it.
72 |
73 | ## License
74 |
75 | ```
76 | Copyright 2018 Raf.
77 |
78 | Licensed under the Apache License, Version 2.0 (the "License");
79 | you may not use this file except in compliance with the License.
80 | You may obtain a copy of the License at
81 |
82 | http://www.apache.org/licenses/LICENSE-2.0
83 |
84 | Unless required by applicable law or agreed to in writing, software
85 | distributed under the License is distributed on an "AS IS" BASIS,
86 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
87 | See the License for the specific language governing permissions and
88 | limitations under the License.
89 |
--------------------------------------------------------------------------------
/TERMS_AND_CONDITIONS.md:
--------------------------------------------------------------------------------
1 | # Terms and conditions
2 |
3 | *Last Revised: 27/02/2018*
4 |
5 | These terms and conditions ("Terms", "Agreement") are an agreement between ChatApp Operator ("ChatApp Operator", "us", "we" or "our") and you ("User", "you" or "your"). This Agreement sets forth the general terms and conditions of your use of the ChatApp application and any of its products or services (collectively, "Application" or "Services").
6 |
7 | ## Accounts
8 |
9 | You must be at least 13 years of age to use this Application. By using this Application and by agreeing to this Agreement you warrant and represent that you are at least 13 years of age. If you create an account on the Application, you are responsible for maintaining the security of your account and you are fully responsible for all activities that occur under the account and any other actions taken in connection with it. Providing false information of any kind may result in the termination of your account. You must immediately notify us of any unauthorized uses of your account or any other breaches of security. We will not be liable for any acts or omissions by you, including any damages of any kind incurred as a result of such acts or omissions. We may suspend, disable, or delete your account (or any part thereof) if we determine that you have violated any provision of this Agreement or that your conduct or content would tend to damage our reputation and goodwill. If we delete your account for the foregoing reasons, you may not re-register for the our Services.
10 |
11 | ## User content
12 |
13 | We do not own any data, information or material ("Content") that you submit on the Application in the course of using the Service. You shall have sole responsibility for the accuracy, quality, integrity, legality, reliability, appropriateness, and intellectual property ownership or right to use of all submitted Content. We may, but have no obligation to, monitor Content on the Application submitted or created using our Services by you. Unless specifically permitted by you, your use of the Application does not grant us the license to use, reproduce, adapt, modify, publish or distribute the Content created by you or stored in your user account for commercial, marketing or any similar purpose. But you grant us permission to access, copy, distribute, store, transmit, reformat, display and perform the Content of your user account solely as required for the purpose of providing the Services to you. Without limiting any of those representations or warranties, we have the right, though not the obligation, to, in our own sole discretion, refuse or remove any Content that, in our reasonable opinion, violates any of our policies or is in any way harmful or objectionable.
14 |
15 | ## Changes
16 |
17 | We reserve the right to modify this Agreement or its policies relating the Application or Services at any time, effective upon posting of an updated version of this Agreement on the Website. When we do we will revise the updated date at the top of this page. Continued use of the Website after any such changes shall constitute your consent to such changes.
18 |
19 | ## Acceptance of these terms
20 |
21 | You acknowledge that you have read this Agreement and agree to all its terms and conditions. By using the Application or its Services you agree to be bound by this Agreement. If you do not agree to abide by the terms of this Agreement, you are not authorized to use or access the Application and its Services.
22 |
23 | ## Contact Us
24 |
25 | If you have any questions or suggestions about our Terms and Conditions, do not hesitate to contact us at rafaellos.g9@gmail.com.
26 |
27 | *This terms and conditions page was generated by [Website Policies](https://www.websitepolicies.com) and modified by Raf.*
28 |
--------------------------------------------------------------------------------
/THIRD_PARTY_NOTICES.md:
--------------------------------------------------------------------------------
1 | # Third Party Notices
2 |
3 | ## **[Picasso](https://github.com/square/picasso)**
4 |
5 | Copyright 2013 Square, Inc.
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 |
19 | ## **[OkHttp](https://github.com/square/okhttp)**
20 |
21 | Licensed under the Apache License, Version 2.0 (the "License");
22 | you may not use this file except in compliance with the License.
23 | You may obtain a copy of the License at
24 |
25 | http://www.apache.org/licenses/LICENSE-2.0
26 |
27 | Unless required by applicable law or agreed to in writing, software
28 | distributed under the License is distributed on an "AS IS" BASIS,
29 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
30 | See the License for the specific language governing permissions and
31 | limitations under the License.
32 |
33 | ## **[CircleImageView](https://github.com/hdodenhof/CircleImageView)**
34 |
35 | Copyright 2014 - 2017 Henning Dodenhof
36 |
37 | Licensed under the Apache License, Version 2.0 (the "License");
38 | you may not use this file except in compliance with the License.
39 | You may obtain a copy of the License at
40 |
41 | http://www.apache.org/licenses/LICENSE-2.0
42 |
43 | Unless required by applicable law or agreed to in writing, software
44 | distributed under the License is distributed on an "AS IS" BASIS,
45 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
46 | See the License for the specific language governing permissions and
47 | limitations under the License.
48 |
49 | ## **[AndroidSlidingUpPanel](https://github.com/umano/AndroidSlidingUpPanel)**
50 |
51 | Copyright 2015 Anton Lopyrev
52 |
53 | Licensed under the Apache License, Version 2.0 (the "License");
54 | you may not use this file except in compliance with the License.
55 | You may obtain a copy of the License at
56 |
57 | http://www.apache.org/licenses/LICENSE-2.0
58 |
59 | Unless required by applicable law or agreed to in writing, software
60 | distributed under the License is distributed on an "AS IS" BASIS,
61 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
62 | See the License for the specific language governing permissions and
63 | limitations under the License.
64 |
65 | ## **[DiagonalLayout](https://github.com/florent37/DiagonalLayout)**
66 |
67 | Copyright 2016 florent37, Inc.
68 |
69 | Licensed under the Apache License, Version 2.0 (the "License");
70 | you may not use this file except in compliance with the License.
71 | You may obtain a copy of the License at
72 |
73 | http://www.apache.org/licenses/LICENSE-2.0
74 |
75 | Unless required by applicable law or agreed to in writing, software
76 | distributed under the License is distributed on an "AS IS" BASIS,
77 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
78 | See the License for the specific language governing permissions and
79 | limitations under the License.
80 |
81 | ## **[KenBurnsView](https://github.com/flavioarfaria/KenBurnsView)**
82 |
83 | Copyright {yyyy} {name of copyright owner}
84 |
85 | Licensed under the Apache License, Version 2.0 (the "License");
86 | you may not use this file except in compliance with the License.
87 | You may obtain a copy of the License at
88 |
89 | http://www.apache.org/licenses/LICENSE-2.0
90 |
91 | Unless required by applicable law or agreed to in writing, software
92 | distributed under the License is distributed on an "AS IS" BASIS,
93 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
94 | See the License for the specific language governing permissions and
95 | limitations under the License.
96 |
97 | ## **[SmartTabLayout](https://github.com/ogaclejapan/SmartTabLayout)**
98 |
99 | Copyright (C) 2015 ogaclejapan
100 | Copyright (C) 2013 The Android Open Source Project
101 |
102 | Licensed under the Apache License, Version 2.0 (the "License");
103 | you may not use this file except in compliance with the License.
104 | You may obtain a copy of the License at
105 |
106 | http://www.apache.org/licenses/LICENSE-2.0
107 |
108 | Unless required by applicable law or agreed to in writing, software
109 | distributed under the License is distributed on an "AS IS" BASIS,
110 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
111 | See the License for the specific language governing permissions and
112 | limitations under the License.
113 |
114 | ## **[FABsMenu](https://github.com/jahirfiquitiva/FABsMenu)**
115 |
116 | Copyright (c) 2014 Jerzy Chalupski
117 |
118 | Licensed under the Apache License, Version 2.0 (the "License");
119 | you may not use this file except in compliance with the License.
120 | You may obtain a copy of the License at
121 |
122 | http://www.apache.org/licenses/LICENSE-2.0
123 |
124 | Unless required by applicable law or agreed to in writing, software
125 | distributed under the License is distributed on an "AS IS" BASIS,
126 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
127 | See the License for the specific language governing permissions and
128 | limitations under the License.
129 |
130 | ## **[android-process-button](https://github.com/dmytrodanylyk/android-process-button)**
131 |
132 | The MIT License (MIT)
133 |
134 | Copyright (c) 2014 Danylyk Dmytro
135 |
136 | Permission is hereby granted, free of charge, to any person obtaining a copy
137 | of this software and associated documentation files (the "Software"), to deal
138 | in the Software without restriction, including without limitation the rights
139 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
140 | copies of the Software, and to permit persons to whom the Software is
141 | furnished to do so, subject to the following conditions:
142 |
143 | The above copyright notice and this permission notice shall be included in all
144 | copies or substantial portions of the Software.
145 |
146 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
147 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
148 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
149 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
150 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
151 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
152 | SOFTWARE.
153 |
154 | ## **[CircularAnim](https://github.com/XunMengWinter/CircularAnim)**
155 |
156 | Library under no license.
157 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | googl
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | /**
4 | * This is a part of ChatApp Project (https://github.com/h01d/ChatApp)
5 | * Licensed under Apache License 2.0
6 | *
7 | * @author Raf (https://github.com/h01d)
8 | * @version 1.1
9 | * @since 27/02/2018
10 | */
11 |
12 | android {
13 | compileSdkVersion 27
14 | defaultConfig {
15 | applicationId "com.github.h01d.chatapp"
16 | minSdkVersion 21
17 | targetSdkVersion 27
18 | versionCode 2
19 | versionName "1.1"
20 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
21 | }
22 | buildTypes {
23 | release {
24 | minifyEnabled false
25 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
26 | }
27 | }
28 | }
29 |
30 | dependencies {
31 | implementation fileTree(dir: 'libs', include: ['*.jar'])
32 | implementation 'com.android.support:appcompat-v7:27.0.2'
33 | implementation 'com.android.support:support-v4:27.0.2'
34 | implementation 'com.android.support:design:27.0.2'
35 | implementation 'com.android.support.constraint:constraint-layout:1.0.2'
36 |
37 | implementation 'com.google.firebase:firebase-auth:11.8.0'
38 | implementation 'com.google.firebase:firebase-database:11.8.0'
39 | implementation 'com.google.firebase:firebase-storage:11.8.0'
40 | implementation 'com.firebaseui:firebase-ui-database:3.1.0'
41 | implementation 'com.google.firebase:firebase-messaging:11.8.0'
42 | implementation 'com.google.firebase:firebase-crash:11.8.0'
43 |
44 | testImplementation 'junit:junit:4.12'
45 | androidTestImplementation 'com.android.support.test:runner:1.0.1'
46 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
47 |
48 | compile 'com.squareup.picasso:picasso:2.5.2'
49 | //https://github.com/square/picasso (Apache License 2.0)
50 | compile 'com.squareup.okhttp:okhttp:2.5.0'
51 | //https://github.com/square/okhttp (Apache License 2.0)
52 | compile 'de.hdodenhof:circleimageview:2.2.0'
53 | //https://github.com/hdodenhof/CircleImageView (Apache License 2.0)
54 | compile 'com.sothree.slidinguppanel:library:3.4.0'
55 | //https://github.com/umano/AndroidSlidingUpPanel (Apache License 2.0)
56 | compile 'com.github.dmytrodanylyk.android-process-button:library:1.0.4'
57 | //https://github.com/dmytrodanylyk/android-process-button (MIT)
58 | compile 'com.github.XunMengWinter:CircularAnim:0.3.4'
59 | //https://github.com/XunMengWinter/CircularAnim (No license)
60 | compile 'com.github.florent37:diagonallayout:1.0.8'
61 | //https://github.com/florent37/DiagonalLayout (Apache License 2.0)
62 | compile 'com.flaviofaria:kenburnsview:1.0.7'
63 | //https://github.com/flavioarfaria/KenBurnsView (Apache License 2.0)
64 | compile 'com.ogaclejapan.smarttablayout:library:1.6.1@aar'
65 | //https://github.com/ogaclejapan/SmartTabLayout (Apache License 2.0)
66 | compile 'com.ogaclejapan.smarttablayout:utils-v4:1.6.1@aar'
67 | //https://github.com/ogaclejapan/SmartTabLayout (Apache License 2.0)
68 | compile 'me.jahirfiquitiva:FABsMenu:1.1.1'
69 | //https://github.com/jahirfiquitiva/FABsMenu (Apache License 2.0)
70 | }
71 |
72 |
73 | apply plugin: 'com.google.gms.google-services'
--------------------------------------------------------------------------------
/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/github/h01d/chatapp/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.github.h01d.chatapp;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest
19 | {
20 | @Test
21 | public void useAppContext() throws Exception
22 | {
23 | // Context of the app under test.
24 | Context appContext = InstrumentationRegistry.getTargetContext();
25 |
26 | assertEquals("com.example.kappa.chatapp", appContext.getPackageName());
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
10 |
12 |
13 |
14 |
15 |
16 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
32 |
33 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
46 |
47 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
61 |
62 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamraf/ChatApp/6d10109408041905ef344582b7894e8a509e33f7/app/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/app/src/main/java/com/github/h01d/chatapp/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.github.h01d.chatapp;
2 |
3 | import android.content.DialogInterface;
4 | import android.content.Intent;
5 | import android.graphics.Color;
6 | import android.net.Uri;
7 | import android.support.v4.view.ViewPager;
8 | import android.support.v7.app.AlertDialog;
9 | import android.support.v7.app.AppCompatActivity;
10 | import android.os.Bundle;
11 | import android.support.v7.widget.Toolbar;
12 | import android.view.Menu;
13 | import android.view.MenuItem;
14 |
15 | import com.github.h01d.chatapp.activities.ProfileActivity;
16 | import com.github.h01d.chatapp.activities.UsersActivity;
17 | import com.github.h01d.chatapp.activities.WelcomeActivity;
18 | import com.github.h01d.chatapp.fragments.ChatFragment;
19 | import com.github.h01d.chatapp.fragments.FriendsFragment;
20 | import com.github.h01d.chatapp.fragments.RequestsFragment;
21 | import com.google.firebase.auth.FirebaseAuth;
22 | import com.google.firebase.auth.FirebaseUser;
23 | import com.google.firebase.database.FirebaseDatabase;
24 | import com.google.firebase.database.ServerValue;
25 | import com.ogaclejapan.smarttablayout.SmartTabLayout;
26 | import com.ogaclejapan.smarttablayout.utils.v4.FragmentPagerItemAdapter;
27 | import com.ogaclejapan.smarttablayout.utils.v4.FragmentPagerItems;
28 |
29 | /**
30 | * This is a part of ChatApp Project (https://github.com/h01d/ChatApp)
31 | * Licensed under Apache License 2.0
32 | *
33 | * @author Raf (https://github.com/h01d)
34 | * @version 1.1
35 | * @since 27/02/2018
36 | */
37 |
38 | public class MainActivity extends AppCompatActivity
39 | {
40 | @Override
41 | protected void onCreate(Bundle savedInstanceState)
42 | {
43 | super.onCreate(savedInstanceState);
44 | setContentView(R.layout.activity_main);
45 |
46 | // Action bar related
47 |
48 | Toolbar toolbar = findViewById(R.id.main_app_bar);
49 | toolbar.setTitleTextColor(Color.WHITE);
50 | setSupportActionBar(toolbar);
51 | getSupportActionBar().setTitle("ChatApp");
52 |
53 | // Fragments handler using SmartTabLayout
54 |
55 | FragmentPagerItemAdapter adapter = new FragmentPagerItemAdapter(
56 | getSupportFragmentManager(), FragmentPagerItems.with(this)
57 | .add("Requests", RequestsFragment.class)
58 | .add("Chat", ChatFragment.class)
59 | .add("Friends", FriendsFragment.class)
60 | .create());
61 |
62 | ViewPager viewPager = findViewById(R.id.viewpager);
63 | viewPager.setAdapter(adapter);
64 | viewPager.setCurrentItem(1);
65 |
66 | SmartTabLayout viewPagerTab = findViewById(R.id.viewpagertab);
67 | viewPagerTab.setViewPager(viewPager);
68 | }
69 |
70 | @Override
71 | public void onStart()
72 | {
73 | super.onStart();
74 |
75 | if(FirebaseAuth.getInstance().getCurrentUser() == null)
76 | {
77 | // If no logged in user send them to login/register
78 |
79 | Intent welcomeIntent = new Intent(MainActivity.this, WelcomeActivity.class);
80 | startActivity(welcomeIntent);
81 | finish();
82 | }
83 | }
84 |
85 | @Override
86 | protected void onResume()
87 | {
88 | super.onResume();
89 |
90 | FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser();
91 |
92 | if(currentUser != null)
93 | {
94 | FirebaseDatabase.getInstance().getReference().child("Users").child(currentUser.getUid()).child("online").setValue("true");
95 | }
96 | }
97 |
98 | @Override
99 | protected void onPause()
100 | {
101 | super.onPause();
102 |
103 | FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser();
104 |
105 | if(currentUser != null)
106 | {
107 | FirebaseDatabase.getInstance().getReference().child("Users").child(currentUser.getUid()).child("online").setValue(ServerValue.TIMESTAMP);
108 | }
109 | }
110 |
111 | @Override
112 | public void onBackPressed()
113 | {
114 | AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
115 | builder.setTitle("Exit");
116 | builder.setMessage("Are you sure you want to close the application?");
117 | builder.setPositiveButton("YES", new DialogInterface.OnClickListener()
118 | {
119 | public void onClick(DialogInterface dialog, int id)
120 | {
121 | finish();
122 | Intent intent = new Intent(Intent.ACTION_MAIN);
123 | intent.addCategory(Intent.CATEGORY_HOME);
124 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
125 | startActivity(intent);
126 | }
127 | });
128 | builder.setNegativeButton("NO", new DialogInterface.OnClickListener()
129 | {
130 | public void onClick(DialogInterface dialog, int id)
131 | {
132 | dialog.dismiss();
133 | }
134 | });
135 | AlertDialog dialog = builder.create();
136 | dialog.show();
137 | }
138 |
139 | @Override
140 | public boolean onCreateOptionsMenu(Menu menu)
141 | {
142 | super.onCreateOptionsMenu(menu);
143 |
144 | getMenuInflater().inflate(R.menu.main_menu, menu);
145 | return true;
146 | }
147 |
148 | @Override
149 | public boolean onOptionsItemSelected(MenuItem item)
150 | {
151 | super.onOptionsItemSelected(item);
152 |
153 | switch(item.getItemId())
154 | {
155 | case R.id.menuLogout:
156 | AlertDialog.Builder logoutBuilder = new AlertDialog.Builder(MainActivity.this);
157 | logoutBuilder.setTitle("Logout");
158 | logoutBuilder.setMessage("Are you sure you want to logout?");
159 | logoutBuilder.setPositiveButton("YES", new DialogInterface.OnClickListener()
160 | {
161 | public void onClick(DialogInterface dialog, int id)
162 | {
163 | FirebaseDatabase.getInstance().getReference().child("Users").child(FirebaseAuth.getInstance().getCurrentUser().getUid()).child("online").setValue(ServerValue.TIMESTAMP);
164 |
165 | FirebaseAuth.getInstance().signOut();
166 |
167 | Intent welcomeIntent = new Intent(MainActivity.this, WelcomeActivity.class);
168 | startActivity(welcomeIntent);
169 | finish();
170 | }
171 | });
172 | logoutBuilder.setNegativeButton("NO", new DialogInterface.OnClickListener()
173 | {
174 | public void onClick(DialogInterface dialog, int id)
175 | {
176 | dialog.dismiss();
177 | }
178 | });
179 | AlertDialog logoutDialog = logoutBuilder.create();
180 | logoutDialog.show();
181 | return true;
182 | case R.id.menuChangelog:
183 | startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/h01d/ChatApp/blob/master/CHANGELOG.md")));
184 | return true;
185 | case R.id.menuAbout:
186 | AlertDialog.Builder aboutBuilder = new AlertDialog.Builder(MainActivity.this);
187 | aboutBuilder.setTitle("ChatApp v1.1");
188 | aboutBuilder.setMessage("Project is open source and released under Apache License 2.0.\n\nMake sure you read all Legal content.\n\nRaf, 2018. All Rights Reserved.");
189 | aboutBuilder.setNegativeButton("Close", new DialogInterface.OnClickListener()
190 | {
191 | public void onClick(DialogInterface dialog, int id)
192 | {
193 | dialog.dismiss();
194 | }
195 | });
196 | AlertDialog aboutDialog = aboutBuilder.create();
197 | aboutDialog.show();
198 | return true;
199 | case R.id.menuLegal:
200 | AlertDialog.Builder legalBuilder = new AlertDialog.Builder(this);
201 | legalBuilder.setTitle("Legal");
202 | legalBuilder.setItems(new CharSequence[]{"License", "Privacy Policy", "Terms and Conditions", "Third Party Notices"}, new DialogInterface.OnClickListener()
203 | {
204 | @Override
205 | public void onClick(DialogInterface dialogInterface, int position)
206 | {
207 | switch(position)
208 | {
209 | case 0:
210 | startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/h01d/ChatApp/blob/master/LICENSE")));
211 | break;
212 | case 1:
213 | startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/h01d/ChatApp/blob/master/PRIVACY_POLICY.md")));
214 | break;
215 | case 2:
216 | startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/h01d/ChatApp/blob/master/TERMS_AND_CONDITIONS.md")));
217 | break;
218 | case 3:
219 | startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/h01d/ChatApp/blob/master/THIRD_PARTY_NOTICES.md")));
220 | break;
221 | }
222 | }
223 | });
224 |
225 | AlertDialog legalDialog = legalBuilder.create();
226 | legalDialog.show();
227 | return true;
228 | case R.id.menuProfile:
229 | Intent profileIntent = new Intent(MainActivity.this, ProfileActivity.class);
230 | profileIntent.putExtra("userid", FirebaseAuth.getInstance().getCurrentUser().getUid());
231 | startActivity(profileIntent);
232 | return true;
233 | case R.id.menuSearch:
234 | Intent usersIntent = new Intent(MainActivity.this, UsersActivity.class);
235 | startActivity(usersIntent);
236 | return true;
237 | default:
238 | return super.onOptionsItemSelected(item);
239 | }
240 | }
241 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/github/h01d/chatapp/activities/FullScreenActivity.java:
--------------------------------------------------------------------------------
1 | package com.github.h01d.chatapp.activities;
2 |
3 | /**
4 | * This is a part of ChatApp Project (https://github.com/h01d/ChatApp)
5 | * Licensed under Apache License 2.0
6 | *
7 | * @author Raf (https://github.com/h01d)
8 | * @version 1.1
9 | * @since 27/02/2018
10 | */
11 |
12 | import android.support.v7.app.AppCompatActivity;
13 | import android.os.Bundle;
14 | import android.view.View;
15 | import android.widget.ImageView;
16 | import android.widget.TextView;
17 |
18 | import com.github.h01d.chatapp.R;
19 | import com.squareup.picasso.Callback;
20 | import com.squareup.picasso.NetworkPolicy;
21 | import com.squareup.picasso.Picasso;
22 |
23 | public class FullScreenActivity extends AppCompatActivity
24 | {
25 | @Override
26 | protected void onCreate(Bundle savedInstanceState)
27 | {
28 | super.onCreate(savedInstanceState);
29 | setContentView(R.layout.activity_full_screen);
30 |
31 | final String url = getIntent().getStringExtra("imageUrl");
32 |
33 | final ImageView image= findViewById(R.id.a_fullscreen_image);
34 | final TextView message = findViewById(R.id.a_fullscreen_message);
35 |
36 | message.setText("Loading Picture...");
37 | message.setVisibility(View.VISIBLE);
38 |
39 | Picasso.with(getApplicationContext())
40 | .load(url)
41 | .networkPolicy(NetworkPolicy.OFFLINE)
42 | .into(image, new Callback()
43 | {
44 | @Override
45 | public void onSuccess()
46 | {
47 | message.setVisibility(View.GONE);
48 | }
49 |
50 | @Override
51 | public void onError()
52 | {
53 | Picasso.with(getApplicationContext())
54 | .load(url)
55 | .into(image, new Callback()
56 | {
57 | @Override
58 | public void onSuccess()
59 | {
60 | message.setVisibility(View.GONE);
61 | }
62 |
63 | @Override
64 | public void onError()
65 | {
66 | message.setVisibility(View.VISIBLE);
67 | message.setText("Error: Could not load picture.");
68 | }
69 | });
70 | }
71 | });
72 |
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/h01d/chatapp/activities/UsersActivity.java:
--------------------------------------------------------------------------------
1 | package com.github.h01d.chatapp.activities;
2 |
3 | import android.content.Intent;
4 | import android.support.v4.app.NavUtils;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.os.Bundle;
7 | import android.support.v7.widget.DividerItemDecoration;
8 | import android.support.v7.widget.LinearLayoutManager;
9 | import android.support.v7.widget.RecyclerView;
10 | import android.view.LayoutInflater;
11 | import android.view.MenuItem;
12 | import android.view.View;
13 | import android.view.ViewGroup;
14 |
15 | import com.firebase.ui.database.FirebaseRecyclerAdapter;
16 | import com.firebase.ui.database.FirebaseRecyclerOptions;
17 | import com.github.h01d.chatapp.R;
18 | import com.github.h01d.chatapp.holders.UserHolder;
19 | import com.github.h01d.chatapp.models.User;
20 | import com.google.firebase.auth.FirebaseAuth;
21 | import com.google.firebase.database.DatabaseReference;
22 | import com.google.firebase.database.FirebaseDatabase;
23 | import com.google.firebase.database.ServerValue;
24 |
25 | /**
26 | * This is a part of ChatApp Project (https://github.com/h01d/ChatApp)
27 | * Licensed under Apache License 2.0
28 | *
29 | * @author Raf (https://github.com/h01d)
30 | * @version 1.1
31 | * @since 27/02/2018
32 | */
33 |
34 | public class UsersActivity extends AppCompatActivity
35 | {
36 | private final String TAG = "CA/UsersActivity";
37 |
38 | private FirebaseRecyclerAdapter adapter;
39 |
40 | @Override
41 | protected void onCreate(Bundle savedInstanceState)
42 | {
43 | super.onCreate(savedInstanceState);
44 | setContentView(R.layout.activity_users);
45 |
46 | // RecyclerView related
47 |
48 | LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getApplicationContext());
49 |
50 | RecyclerView recyclerView = findViewById(R.id.users_recycler);
51 | recyclerView.setHasFixedSize(true);
52 | recyclerView.setLayoutManager(linearLayoutManager);
53 |
54 | DividerItemDecoration mDividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), linearLayoutManager.getOrientation());
55 | recyclerView.addItemDecoration(mDividerItemDecoration);
56 |
57 | // Initializing Users database
58 |
59 | DatabaseReference usersDatabase = FirebaseDatabase.getInstance().getReference().child("Users");
60 | usersDatabase.keepSynced(true); // For offline use
61 |
62 | // Initializing adapter
63 |
64 | FirebaseRecyclerOptions options = new FirebaseRecyclerOptions.Builder().setQuery(usersDatabase.orderByChild("name"), User.class).build();
65 |
66 | adapter = new FirebaseRecyclerAdapter(options)
67 | {
68 | @Override
69 | protected void onBindViewHolder(final UserHolder holder, int position, User model)
70 | {
71 | final String userid = getRef(position).getKey();
72 |
73 | holder.setHolder(userid);
74 | holder.getView().setOnClickListener(new View.OnClickListener()
75 | {
76 | @Override
77 | public void onClick(View view)
78 | {
79 | Intent userProfileIntent = new Intent(UsersActivity.this, ProfileActivity.class);
80 | userProfileIntent.putExtra("userid", userid);
81 | startActivity(userProfileIntent);
82 | }
83 | });
84 | }
85 |
86 | @Override
87 | public UserHolder onCreateViewHolder(ViewGroup parent, int viewType)
88 | {
89 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.user, parent, false);
90 |
91 | return new UserHolder(UsersActivity.this, view, getApplicationContext());
92 | }
93 | };
94 |
95 | recyclerView.setAdapter(adapter);
96 | }
97 |
98 | @Override
99 | protected void onStart()
100 | {
101 | super.onStart();
102 |
103 | adapter.startListening();
104 | }
105 |
106 | @Override
107 | protected void onResume()
108 | {
109 | super.onResume();
110 |
111 | FirebaseDatabase.getInstance().getReference().child("Users").child(FirebaseAuth.getInstance().getCurrentUser().getUid()).child("online").setValue("true");
112 | }
113 |
114 | @Override
115 | protected void onPause()
116 | {
117 | super.onPause();
118 |
119 | FirebaseDatabase.getInstance().getReference().child("Users").child(FirebaseAuth.getInstance().getCurrentUser().getUid()).child("online").setValue(ServerValue.TIMESTAMP);
120 | }
121 |
122 | @Override
123 | protected void onStop()
124 | {
125 | super.onStop();
126 |
127 | adapter.stopListening();
128 | }
129 |
130 | @Override
131 | public void onBackPressed()
132 | {
133 | NavUtils.navigateUpFromSameTask(this);
134 | }
135 |
136 | @Override
137 | public boolean onOptionsItemSelected(MenuItem item)
138 | {
139 | switch(item.getItemId())
140 | {
141 | case android.R.id.home:
142 | NavUtils.navigateUpFromSameTask(this);
143 | break;
144 | }
145 | return super.onOptionsItemSelected(item);
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/h01d/chatapp/activities/WelcomeActivity.java:
--------------------------------------------------------------------------------
1 | package com.github.h01d.chatapp.activities;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.net.Uri;
6 | import android.os.Handler;
7 | import android.support.annotation.NonNull;
8 | import android.support.v7.app.AppCompatActivity;
9 | import android.os.Bundle;
10 | import android.util.Log;
11 | import android.view.KeyEvent;
12 | import android.view.View;
13 | import android.view.inputmethod.InputMethodManager;
14 | import android.widget.EditText;
15 | import android.widget.TextView;
16 | import android.widget.Toast;
17 |
18 | import com.dd.processbutton.iml.ActionProcessButton;
19 | import com.github.h01d.chatapp.MainActivity;
20 | import com.github.h01d.chatapp.R;
21 | import com.google.android.gms.tasks.OnCompleteListener;
22 | import com.google.android.gms.tasks.Task;
23 | import com.google.firebase.auth.AuthResult;
24 | import com.google.firebase.auth.FirebaseAuth;
25 | import com.google.firebase.auth.FirebaseUser;
26 | import com.google.firebase.database.FirebaseDatabase;
27 | import com.google.firebase.database.ServerValue;
28 | import com.google.firebase.iid.FirebaseInstanceId;
29 | import com.sothree.slidinguppanel.SlidingUpPanelLayout;
30 |
31 | import java.util.HashMap;
32 | import java.util.Map;
33 |
34 | import top.wefor.circularanim.CircularAnim;
35 |
36 | /**
37 | * This is a part of ChatApp Project (https://github.com/h01d/ChatApp)
38 | * Licensed under Apache License 2.0
39 | *
40 | * @author Raf (https://github.com/h01d)
41 | * @version 1.1
42 | * @since 27/02/2018
43 | */
44 |
45 | public class WelcomeActivity extends AppCompatActivity
46 | {
47 | private final String TAG = "CA/WelcomeActivity";
48 |
49 | @Override
50 | protected void onCreate(Bundle savedInstanceState)
51 | {
52 | super.onCreate(savedInstanceState);
53 | setContentView(R.layout.activity_welcome);
54 |
55 | // activity_welcome views
56 |
57 | final EditText loginEmail = findViewById(R.id.login_email_text);
58 | final EditText loginPassword = findViewById(R.id.login_password_text);
59 |
60 | final EditText registerName = findViewById(R.id.register_name_text);
61 | final EditText registerEmail = findViewById(R.id.register_email_text);
62 | final EditText registerPassword = findViewById(R.id.register_password_text);
63 |
64 | // Setting up login button work
65 |
66 | final ActionProcessButton loginButton = findViewById(R.id.login_button);
67 | loginButton.setProgress(0);
68 | loginButton.setMode(ActionProcessButton.Mode.ENDLESS);
69 | loginButton.setOnClickListener(new View.OnClickListener()
70 | {
71 | @Override
72 | public void onClick(View view)
73 | {
74 | loginButton.setClickable(false);
75 |
76 | loginEmail.clearFocus();
77 | loginPassword.clearFocus();
78 |
79 | // Hiding the soft keyboard
80 |
81 | InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
82 | imm.hideSoftInputFromWindow(loginPassword.getWindowToken(), 0);
83 |
84 | if(loginEmail.getText().length() == 0 || loginPassword.getText().length() == 0)
85 | {
86 | Toast.makeText(getApplicationContext(), "Fields cannot be empty.", Toast.LENGTH_SHORT).show();
87 |
88 | loginButton.setProgress(-1);
89 | loginButton.setClickable(true);
90 | }
91 | else
92 | {
93 | loginButton.setProgress(1);
94 |
95 | // Loggin user with data he gave us
96 |
97 | FirebaseAuth.getInstance().signInWithEmailAndPassword(loginEmail.getText().toString(), loginPassword.getText().toString()).addOnCompleteListener(new OnCompleteListener()
98 | {
99 | @Override
100 | public void onComplete(@NonNull Task task)
101 | {
102 | if(task.isSuccessful())
103 | {
104 | String token = FirebaseInstanceId.getInstance().getToken();
105 | String userid = FirebaseAuth.getInstance().getCurrentUser().getUid();
106 |
107 | // Updating user device token
108 |
109 | FirebaseDatabase.getInstance().getReference().child("Users").child(userid).child("token").setValue(token).addOnCompleteListener(new OnCompleteListener()
110 | {
111 | @Override
112 | public void onComplete(@NonNull Task task)
113 | {
114 | if(task.isSuccessful())
115 | {
116 | loginButton.setProgress(100);
117 |
118 | if(FirebaseAuth.getInstance().getCurrentUser().isEmailVerified())
119 | {
120 | // Show animation and start activity
121 |
122 | new Handler().postDelayed(new Runnable()
123 | {
124 | @Override
125 | public void run()
126 | {
127 | CircularAnim.fullActivity(WelcomeActivity.this, loginButton)
128 | .colorOrImageRes(R.color.colorGreen)
129 | .go(new CircularAnim.OnAnimationEndListener()
130 | {
131 | @Override
132 | public void onAnimationEnd()
133 | {
134 | startActivity(new Intent(WelcomeActivity.this, MainActivity.class));
135 | finish();
136 | }
137 | });
138 | }
139 | }, 1000);
140 | }
141 | else
142 | {
143 | Toast.makeText(getApplicationContext(), "Your email is not verified, we have sent you a new one.", Toast.LENGTH_LONG).show();
144 | FirebaseAuth.getInstance().signOut();
145 |
146 | loginButton.setProgress(-1);
147 | loginButton.setClickable(true);
148 | }
149 | }
150 | else
151 | {
152 | Log.d(TAG, "uploadToken failed: " + task.getException().getMessage());
153 | }
154 | }
155 | });
156 | }
157 | else
158 | {
159 | Toast.makeText(getApplicationContext(), task.getException().getMessage(), Toast.LENGTH_LONG).show();
160 |
161 | Log.d(TAG, "signIn failed: " + task.getException().getMessage());
162 |
163 | loginButton.setProgress(-1);
164 | loginButton.setClickable(true);
165 | }
166 | }
167 | });
168 | }
169 | }
170 | });
171 |
172 | // Will handle "enter key" login
173 |
174 | loginPassword.setOnKeyListener(new View.OnKeyListener()
175 | {
176 | public boolean onKey(View v, int keyCode, KeyEvent event)
177 | {
178 | if((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER))
179 | {
180 | loginButton.performClick();
181 | return true;
182 | }
183 | return false;
184 | }
185 | });
186 |
187 | // Setting up register button
188 |
189 | final ActionProcessButton registerButton = findViewById(R.id.register_button);
190 | registerButton.setProgress(0);
191 | registerButton.setMode(ActionProcessButton.Mode.ENDLESS);
192 | registerButton.setOnClickListener(new View.OnClickListener()
193 | {
194 | @Override
195 | public void onClick(View view)
196 | {
197 | registerButton.setClickable(false);
198 |
199 | loginButton.setClickable(false);
200 |
201 | registerName.clearFocus();
202 | registerEmail.clearFocus();
203 | registerPassword.clearFocus();
204 |
205 | // Hiding soft keyboard
206 |
207 | InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
208 | imm.hideSoftInputFromWindow(registerButton.getWindowToken(), 0);
209 |
210 | if(registerEmail.getText().toString().length() == 0 || registerPassword.getText().toString().length() == 0)
211 | {
212 | Toast.makeText(getApplicationContext(), "Fields cannot be empty.", Toast.LENGTH_SHORT).show();
213 |
214 | registerButton.setProgress(-1);
215 | registerButton.setClickable(true);
216 |
217 | loginButton.setClickable(true);
218 | }
219 | else
220 | {
221 | registerButton.setProgress(1);
222 |
223 | // Registering user with data he gave us
224 |
225 | FirebaseAuth.getInstance().createUserWithEmailAndPassword(registerEmail.getText().toString(), registerPassword.getText().toString()).addOnCompleteListener(new OnCompleteListener()
226 | {
227 | @Override
228 | public void onComplete(@NonNull Task task)
229 | {
230 | if(task.isSuccessful())
231 | {
232 | FirebaseUser firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
233 |
234 | if(firebaseUser != null)
235 | {
236 | String userid = firebaseUser.getUid();
237 |
238 | // "Packing" user data
239 |
240 | Map map = new HashMap<>();
241 | map.put("token", FirebaseInstanceId.getInstance().getToken());
242 | map.put("name", registerName.getText().toString());
243 | map.put("email", registerEmail.getText().toString());
244 | map.put("status", "Welcome to my Profile!");
245 | map.put("image", "default");
246 | map.put("cover", "default");
247 | map.put("date", ServerValue.TIMESTAMP);
248 |
249 | // Uploading user data
250 |
251 | FirebaseDatabase.getInstance().getReference().child("Users").child(userid).setValue(map).addOnCompleteListener(new OnCompleteListener()
252 | {
253 | @Override
254 | public void onComplete(@NonNull Task task)
255 | {
256 | if(task.isSuccessful())
257 | {
258 | registerButton.setProgress(100);
259 |
260 | FirebaseAuth.getInstance().getCurrentUser().sendEmailVerification();
261 | Toast.makeText(getApplicationContext(), "We have sent you a verification email to activate your account.", Toast.LENGTH_LONG).show();
262 | FirebaseAuth.getInstance().signOut();
263 |
264 | loginButton.setClickable(true);
265 | }
266 | else
267 | {
268 | Log.d(TAG, "registerData failed: " + task.getException().getMessage());
269 | }
270 | }
271 | });
272 | }
273 | }
274 | else
275 | {
276 | Toast.makeText(getApplicationContext(), task.getException().getMessage(), Toast.LENGTH_LONG).show();
277 |
278 | Log.d(TAG, "createUser failed: " + task.getException().getMessage());
279 |
280 | registerButton.setProgress(-1);
281 | registerButton.setClickable(true);
282 |
283 | loginButton.setClickable(true);
284 | }
285 | }
286 | });
287 | }
288 | }
289 | });
290 |
291 | // Will handle "enter key" register
292 |
293 | registerPassword.setOnKeyListener(new View.OnKeyListener()
294 | {
295 | public boolean onKey(View v, int keyCode, KeyEvent event)
296 | {
297 | if((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER))
298 | {
299 | registerButton.performClick();
300 | return true;
301 | }
302 | return false;
303 | }
304 | });
305 |
306 | // Will handle Terms and Condition text click
307 |
308 | final TextView registerTerms = findViewById(R.id.register_terms);
309 | registerTerms.setOnClickListener(new View.OnClickListener()
310 | {
311 | @Override
312 | public void onClick(View view)
313 | {
314 | startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/h01d/ChatApp/blob/master/TERMS_AND_CONDITIONS.md")));
315 | }
316 | });
317 | }
318 |
319 | @Override
320 | public void onBackPressed()
321 | {
322 | SlidingUpPanelLayout slidingUpPanelLayout = findViewById(R.id.welcome_sliding);
323 |
324 | if(slidingUpPanelLayout.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED)
325 | {
326 | slidingUpPanelLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
327 | }
328 | else
329 | {
330 | super.onBackPressed();
331 | }
332 | }
333 | }
334 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/h01d/chatapp/adapters/MessageAdapter.java:
--------------------------------------------------------------------------------
1 | package com.github.h01d.chatapp.adapters;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 |
8 | import com.github.h01d.chatapp.R;
9 | import com.github.h01d.chatapp.models.Message;
10 | import com.github.h01d.chatapp.holders.MessageHolder;
11 | import com.google.firebase.auth.FirebaseAuth;
12 |
13 | import java.util.List;
14 |
15 | /**
16 | * This is a part of ChatApp Project (https://github.com/h01d/ChatApp)
17 | * Licensed under Apache License 2.0
18 | *
19 | * @author Raf (https://github.com/h01d)
20 | * @version 1.1
21 | * @since 27/02/2018
22 | */
23 |
24 | public class MessageAdapter extends RecyclerView.Adapter
25 | {
26 | private List messagesList;
27 |
28 | public MessageAdapter(List messagesList)
29 | {
30 | this.messagesList = messagesList;
31 | }
32 |
33 | @Override
34 | public MessageHolder onCreateViewHolder(ViewGroup parent, int viewType)
35 | {
36 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.message, parent, false);
37 |
38 | return new MessageHolder(view, view.getContext());
39 | }
40 |
41 | @Override
42 | public void onBindViewHolder(final MessageHolder holder, int position)
43 | {
44 | final String currentUserId = FirebaseAuth.getInstance().getCurrentUser().getUid();
45 |
46 | Message c = messagesList.get(position);
47 |
48 | if(messagesList.size() - 1 == position)
49 | {
50 | holder.setLastMessage(currentUserId, c.getFrom(), c.getTo());
51 | }
52 | else
53 | {
54 | holder.hideBottom();
55 | }
56 |
57 | if(c.getFrom().equals(currentUserId))
58 | {
59 | holder.setRightMessage(c.getFrom(), c.getMessage(), c.getTimestamp(), c.getType());
60 | }
61 | else
62 | {
63 | holder.setLeftMessage(c.getFrom(), c.getMessage(), c.getTimestamp(), c.getType());
64 | }
65 | }
66 |
67 | @Override
68 | public int getItemCount()
69 | {
70 | return messagesList.size();
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/h01d/chatapp/fragments/ChatFragment.java:
--------------------------------------------------------------------------------
1 | package com.github.h01d.chatapp.fragments;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.annotation.NonNull;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v7.widget.DividerItemDecoration;
8 | import android.support.v7.widget.LinearLayoutManager;
9 | import android.support.v7.widget.RecyclerView;
10 | import android.view.LayoutInflater;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 | import android.widget.TextView;
14 |
15 | import com.firebase.ui.database.FirebaseRecyclerAdapter;
16 | import com.firebase.ui.database.FirebaseRecyclerOptions;
17 | import com.github.h01d.chatapp.R;
18 | import com.github.h01d.chatapp.activities.ChatActivity;
19 | import com.github.h01d.chatapp.holders.ChatHolder;
20 | import com.github.h01d.chatapp.models.Chat;
21 | import com.google.firebase.auth.FirebaseAuth;
22 | import com.google.firebase.database.DatabaseReference;
23 | import com.google.firebase.database.FirebaseDatabase;
24 |
25 | /**
26 | * This is a part of ChatApp Project (https://github.com/h01d/ChatApp)
27 | * Licensed under Apache License 2.0
28 | *
29 | * @author Raf (https://github.com/h01d)
30 | * @version 1.1
31 | * @since 27/02/2018
32 | */
33 |
34 | public class ChatFragment extends Fragment
35 | {
36 | private FirebaseRecyclerAdapter adapter;
37 |
38 | public ChatFragment()
39 | {
40 |
41 | }
42 |
43 | @Override
44 | public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
45 | {
46 | final View view = inflater.inflate(R.layout.fragment_chat, container, false);
47 |
48 | String currentUserId = FirebaseAuth.getInstance().getCurrentUser().getUid();
49 |
50 | // Initialize Chat Database
51 |
52 | DatabaseReference chatDatabase = FirebaseDatabase.getInstance().getReference().child("Chat").child(currentUserId);
53 | chatDatabase.keepSynced(true); // For offline use
54 |
55 | // RecyclerView related
56 |
57 | LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
58 | linearLayoutManager.setReverseLayout(true);
59 | linearLayoutManager.setStackFromEnd(true);
60 |
61 | RecyclerView recyclerView = view.findViewById(R.id.chat_recycler);
62 | recyclerView.setHasFixedSize(true);
63 | recyclerView.setLayoutManager(linearLayoutManager);
64 |
65 | DividerItemDecoration mDividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), linearLayoutManager.getOrientation());
66 | recyclerView.addItemDecoration(mDividerItemDecoration);
67 |
68 | // Initializing adapter
69 |
70 | FirebaseRecyclerOptions options = new FirebaseRecyclerOptions.Builder().setQuery(chatDatabase.orderByChild("timestamp"), Chat.class).build();
71 |
72 | adapter = new FirebaseRecyclerAdapter(options)
73 | {
74 | @Override
75 | public ChatHolder onCreateViewHolder(ViewGroup parent, int viewType)
76 | {
77 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.user, parent, false);
78 |
79 | return new ChatHolder(getActivity(), view, getContext());
80 | }
81 |
82 | @Override
83 | protected void onBindViewHolder(final ChatHolder holder, int position, final Chat model)
84 | {
85 | final String userid = getRef(position).getKey();
86 |
87 | holder.setHolder(userid, model.getMessage(), model.getTimestamp(), model.getSeen());
88 | holder.getView().setOnClickListener(new View.OnClickListener()
89 | {
90 | @Override
91 | public void onClick(View view)
92 | {
93 | Intent chatIntent = new Intent(getContext(), ChatActivity.class);
94 | chatIntent.putExtra("userid", userid);
95 | startActivity(chatIntent);
96 | }
97 | });
98 | }
99 |
100 | @Override
101 | public void onDataChanged()
102 | {
103 | super.onDataChanged();
104 |
105 | TextView text = view.findViewById(R.id.f_chat_text);
106 |
107 | if(adapter.getItemCount() == 0)
108 | {
109 | text.setVisibility(View.VISIBLE);
110 | }
111 | else
112 | {
113 | text.setVisibility(View.GONE);
114 | }
115 | }
116 | };
117 |
118 | recyclerView.setAdapter(adapter);
119 | return view;
120 | }
121 |
122 | @Override
123 | public void onStart()
124 | {
125 | super.onStart();
126 |
127 | adapter.startListening();
128 | adapter.notifyDataSetChanged();
129 | }
130 |
131 | @Override
132 | public void onStop()
133 | {
134 | super.onStop();
135 |
136 | adapter.stopListening();
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/h01d/chatapp/fragments/FriendsFragment.java:
--------------------------------------------------------------------------------
1 | package com.github.h01d.chatapp.fragments;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.annotation.NonNull;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v7.widget.DividerItemDecoration;
8 | import android.support.v7.widget.LinearLayoutManager;
9 | import android.support.v7.widget.RecyclerView;
10 | import android.view.LayoutInflater;
11 | import android.view.Menu;
12 | import android.view.MenuItem;
13 | import android.view.View;
14 | import android.view.ViewGroup;
15 | import android.widget.PopupMenu;
16 | import android.widget.TextView;
17 |
18 | import com.firebase.ui.database.FirebaseRecyclerAdapter;
19 | import com.firebase.ui.database.FirebaseRecyclerOptions;
20 | import com.github.h01d.chatapp.R;
21 | import com.github.h01d.chatapp.activities.ChatActivity;
22 | import com.github.h01d.chatapp.activities.ProfileActivity;
23 | import com.github.h01d.chatapp.holders.FriendHolder;
24 | import com.github.h01d.chatapp.models.Friend;
25 | import com.google.firebase.auth.FirebaseAuth;
26 | import com.google.firebase.database.DatabaseReference;
27 | import com.google.firebase.database.FirebaseDatabase;
28 |
29 | /**
30 | * This is a part of ChatApp Project (https://github.com/h01d/ChatApp)
31 | * Licensed under Apache License 2.0
32 | *
33 | * @author Raf (https://github.com/h01d)
34 | * @version 1.1
35 | * @since 27/02/2018
36 | */
37 |
38 | public class FriendsFragment extends Fragment
39 | {
40 | private FirebaseRecyclerAdapter adapter;
41 |
42 | public FriendsFragment()
43 | {
44 |
45 | }
46 |
47 | @Override
48 | public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
49 | {
50 | final View view = inflater.inflate(R.layout.fragment_friends, container, false);
51 |
52 | String currentUserId = FirebaseAuth.getInstance().getCurrentUser().getUid();
53 |
54 | // Initializing Friends database
55 |
56 | DatabaseReference friendsDatabase = FirebaseDatabase.getInstance().getReference().child("Friends").child(currentUserId);
57 | friendsDatabase.keepSynced(true); // For offline use
58 |
59 | // RecyclerView related
60 |
61 | LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
62 | linearLayoutManager.setReverseLayout(true);
63 | linearLayoutManager.setStackFromEnd(true);
64 |
65 | final RecyclerView recyclerView = view.findViewById(R.id.friends_recycler);
66 | recyclerView.setHasFixedSize(true);
67 | recyclerView.setLayoutManager(linearLayoutManager);
68 |
69 | DividerItemDecoration mDividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), linearLayoutManager.getOrientation());
70 | recyclerView.addItemDecoration(mDividerItemDecoration);
71 |
72 | // Initializing adapter
73 |
74 | FirebaseRecyclerOptions options = new FirebaseRecyclerOptions.Builder().setQuery(friendsDatabase.orderByChild("date"), Friend.class).build();
75 |
76 | adapter = new FirebaseRecyclerAdapter(options)
77 | {
78 | @Override
79 | protected void onBindViewHolder(final FriendHolder holder, int position, final Friend model)
80 | {
81 | final String userid = getRef(position).getKey();
82 |
83 | holder.setHolder(userid, model.getDate());
84 | holder.getView().setOnClickListener(new View.OnClickListener()
85 | {
86 | @Override
87 | public void onClick(View view)
88 | {
89 | PopupMenu popup = new PopupMenu(getContext(), view);
90 |
91 | popup.getMenu().add(Menu.NONE, 1, 1, "View Profile");
92 | popup.getMenu().add(Menu.NONE, 2, 2, "Send Message");
93 |
94 | popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener()
95 | {
96 | @Override
97 | public boolean onMenuItemClick(MenuItem menuItem)
98 | {
99 | switch(menuItem.getItemId())
100 | {
101 | case 1:
102 | Intent userProfileIntent = new Intent(getContext(), ProfileActivity.class);
103 | userProfileIntent.putExtra("userid", userid);
104 | startActivity(userProfileIntent);
105 | return true;
106 | case 2:
107 | Intent sendMessageIntent = new Intent(getContext(), ChatActivity.class);
108 | sendMessageIntent.putExtra("userid", userid);
109 | startActivity(sendMessageIntent);
110 | return true;
111 | default:
112 | return false;
113 | }
114 | }
115 | });
116 | popup.show();
117 | }
118 | });
119 | }
120 |
121 | @Override
122 | public FriendHolder onCreateViewHolder(ViewGroup parent, int viewType)
123 | {
124 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.user, parent, false);
125 |
126 | return new FriendHolder(getActivity(), view, getContext());
127 | }
128 |
129 | @Override
130 | public void onDataChanged()
131 | {
132 | super.onDataChanged();
133 |
134 | TextView text = view.findViewById(R.id.f_friends_text);
135 |
136 | if(adapter.getItemCount() == 0)
137 | {
138 | text.setVisibility(View.VISIBLE);
139 | }
140 | else
141 | {
142 | text.setVisibility(View.GONE);
143 | }
144 |
145 | recyclerView.scrollToPosition(adapter.getItemCount() - 1);
146 | }
147 | };
148 |
149 | recyclerView.setAdapter(adapter);
150 | return view;
151 | }
152 |
153 | public void onStart()
154 | {
155 | super.onStart();
156 |
157 | adapter.startListening();
158 | adapter.notifyDataSetChanged();
159 | }
160 |
161 | @Override
162 | public void onStop()
163 | {
164 | super.onStop();
165 |
166 | adapter.stopListening();
167 | }
168 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/github/h01d/chatapp/fragments/RequestsFragment.java:
--------------------------------------------------------------------------------
1 | package com.github.h01d.chatapp.fragments;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.annotation.NonNull;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v7.widget.DividerItemDecoration;
8 | import android.support.v7.widget.LinearLayoutManager;
9 | import android.support.v7.widget.RecyclerView;
10 | import android.util.Log;
11 | import android.view.LayoutInflater;
12 | import android.view.Menu;
13 | import android.view.MenuItem;
14 | import android.view.View;
15 | import android.view.ViewGroup;
16 | import android.widget.PopupMenu;
17 | import android.widget.TextView;
18 | import android.widget.Toast;
19 |
20 | import com.firebase.ui.database.FirebaseRecyclerAdapter;
21 | import com.firebase.ui.database.FirebaseRecyclerOptions;
22 | import com.github.h01d.chatapp.R;
23 | import com.github.h01d.chatapp.activities.ProfileActivity;
24 | import com.github.h01d.chatapp.holders.RequestHolder;
25 | import com.github.h01d.chatapp.models.Request;
26 | import com.google.firebase.auth.FirebaseAuth;
27 | import com.google.firebase.database.DatabaseError;
28 | import com.google.firebase.database.DatabaseReference;
29 | import com.google.firebase.database.FirebaseDatabase;
30 | import com.google.firebase.database.ServerValue;
31 |
32 | import java.util.HashMap;
33 | import java.util.Map;
34 |
35 | /**
36 | * This is a part of ChatApp Project (https://github.com/h01d/ChatApp)
37 | * Licensed under Apache License 2.0
38 | *
39 | * @author Raf (https://github.com/h01d)
40 | * @version 1.1
41 | * @since 27/02/2018
42 | */
43 |
44 | public class RequestsFragment extends Fragment
45 | {
46 | private final String TAG = "CA/RequestsFragment";
47 |
48 | private FirebaseRecyclerAdapter adapter;
49 |
50 | public RequestsFragment()
51 | {
52 |
53 | }
54 |
55 | @Override
56 | public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
57 | {
58 | final View view = inflater.inflate(R.layout.fragment_request, container, false);
59 |
60 | final String currentUserId = FirebaseAuth.getInstance().getCurrentUser().getUid();
61 |
62 | // Initializing Request database
63 |
64 | DatabaseReference requestsDatabase = FirebaseDatabase.getInstance().getReference().child("Requests").child(currentUserId);
65 | requestsDatabase.keepSynced(true); // For offline use
66 |
67 | // RecyclerView related
68 |
69 | LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
70 |
71 | RecyclerView recyclerView = view.findViewById(R.id.f_request_recycler);
72 | recyclerView.setHasFixedSize(true);
73 | recyclerView.setLayoutManager(linearLayoutManager);
74 |
75 | DividerItemDecoration mDividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), linearLayoutManager.getOrientation());
76 | recyclerView.addItemDecoration(mDividerItemDecoration);
77 |
78 | // Initializing adapter
79 |
80 | FirebaseRecyclerOptions options = new FirebaseRecyclerOptions.Builder().setQuery(requestsDatabase.orderByChild("type"), Request.class).build();
81 |
82 | adapter = new FirebaseRecyclerAdapter(options)
83 | {
84 | @Override
85 | protected void onBindViewHolder(final RequestHolder holder, int position, final Request model)
86 | {
87 | if(model.getType().equals("sent"))
88 | {
89 | holder.getView().setVisibility(View.GONE);
90 | }
91 | else
92 | {
93 | final String userid = getRef(position).getKey();
94 |
95 | holder.setHolder(userid);
96 | holder.getView().setOnClickListener(new View.OnClickListener()
97 | {
98 | @Override
99 | public void onClick(View view)
100 | {
101 | PopupMenu popup = new PopupMenu(getContext(), view);
102 |
103 | popup.getMenu().add(Menu.NONE, 1, 1, "View Profile");
104 | popup.getMenu().add(Menu.NONE, 2, 2, "Accept Request");
105 |
106 | popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener()
107 | {
108 | @Override
109 | public boolean onMenuItemClick(MenuItem menuItem)
110 | {
111 | switch(menuItem.getItemId())
112 | {
113 | case 1:
114 | Intent userProfileIntent = new Intent(getContext(), ProfileActivity.class);
115 | userProfileIntent.putExtra("userid", userid);
116 | startActivity(userProfileIntent);
117 | return true;
118 | case 2:
119 | // Pushing notification to get keyId
120 |
121 | DatabaseReference acceptNotificationRef = FirebaseDatabase.getInstance().getReference().child("Notifications").child(userid).push();
122 | String acceptNotificationId = acceptNotificationRef.getKey();
123 |
124 | // "Packing" request
125 |
126 | HashMap acceptNotificationData = new HashMap<>();
127 | acceptNotificationData.put("from", currentUserId);
128 | acceptNotificationData.put("type", "accept");
129 |
130 | // "Packing" data
131 |
132 | Map map = new HashMap<>();
133 | map.put("Friends/" + userid + "/" + currentUserId + "/date", ServerValue.TIMESTAMP);
134 | map.put("Friends/" + currentUserId + "/" + userid + "/date", ServerValue.TIMESTAMP);
135 |
136 | map.put("Requests/" + userid + "/" + currentUserId, null);
137 | map.put("Requests/" + currentUserId + "/" + userid, null);
138 |
139 | map.put("Notifications/" + userid + "/" + acceptNotificationId, acceptNotificationData);
140 |
141 | // Updating data
142 |
143 | FirebaseDatabase.getInstance().getReference().updateChildren(map, new DatabaseReference.CompletionListener()
144 | {
145 | @Override
146 | public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference)
147 | {
148 | if(databaseError == null)
149 | {
150 | Toast.makeText(getContext(), "You are now friends!", Toast.LENGTH_SHORT).show();
151 | }
152 | else
153 | {
154 | Log.d(TAG, "acceptRequest failed: " + databaseError.getMessage());
155 | }
156 | }
157 | });
158 | return true;
159 | default:
160 | return false;
161 | }
162 | }
163 | });
164 | popup.show();
165 | }
166 | });
167 | }
168 | }
169 |
170 | @Override
171 | public RequestHolder onCreateViewHolder(ViewGroup parent, int viewType)
172 | {
173 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.user, parent, false);
174 |
175 | return new RequestHolder(getActivity(), view, getContext());
176 | }
177 |
178 | @Override
179 | public void onDataChanged()
180 | {
181 | super.onDataChanged();
182 |
183 | int counter = 0;
184 |
185 | for(int i = 0; i < adapter.getItemCount(); i++)
186 | {
187 | Request tmp = (Request) adapter.getItem(i);
188 |
189 | if(tmp != null && tmp.getType().equals("received"))
190 | {
191 | counter++;
192 | }
193 | }
194 |
195 | TextView text = view.findViewById(R.id.f_request_text);
196 |
197 | if(counter == 0)
198 | {
199 | text.setVisibility(View.VISIBLE);
200 | }
201 | else
202 | {
203 | text.setVisibility(View.GONE);
204 | }
205 | }
206 | };
207 |
208 | recyclerView.setAdapter(adapter);
209 | return view;
210 | }
211 |
212 | public void onStart()
213 | {
214 | super.onStart();
215 |
216 | adapter.startListening();
217 | adapter.notifyDataSetChanged();
218 | }
219 |
220 | @Override
221 | public void onStop()
222 | {
223 | super.onStop();
224 |
225 | adapter.stopListening();
226 | }
227 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/github/h01d/chatapp/holders/ChatHolder.java:
--------------------------------------------------------------------------------
1 | package com.github.h01d.chatapp.holders;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.graphics.Typeface;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.util.Log;
8 | import android.util.TypedValue;
9 | import android.view.View;
10 | import android.widget.ImageView;
11 | import android.widget.TextView;
12 |
13 | import com.github.h01d.chatapp.R;
14 | import com.google.firebase.database.DataSnapshot;
15 | import com.google.firebase.database.DatabaseError;
16 | import com.google.firebase.database.DatabaseReference;
17 | import com.google.firebase.database.FirebaseDatabase;
18 | import com.google.firebase.database.ValueEventListener;
19 | import com.squareup.picasso.Callback;
20 | import com.squareup.picasso.NetworkPolicy;
21 | import com.squareup.picasso.Picasso;
22 |
23 | import java.text.SimpleDateFormat;
24 | import java.util.Locale;
25 | import java.util.Timer;
26 | import java.util.TimerTask;
27 |
28 | import de.hdodenhof.circleimageview.CircleImageView;
29 |
30 | /**
31 | * This is a part of ChatApp Project (https://github.com/h01d/ChatApp)
32 | * Licensed under Apache License 2.0
33 | *
34 | * @author Raf (https://github.com/h01d)
35 | * @version 1.1
36 | * @since 27/02/2018
37 | */
38 |
39 | public class ChatHolder extends RecyclerView.ViewHolder
40 | {
41 | private final String TAG = "CA/ChatHolder";
42 |
43 | private Activity activity;
44 | private View view;
45 | private Context context;
46 |
47 | // Will handle user data
48 |
49 | private DatabaseReference userDatabase;
50 | private ValueEventListener userListener;
51 |
52 | public ChatHolder(Activity activity, View view, Context context)
53 | {
54 | super(view);
55 |
56 | this.activity = activity;
57 | this.view = view;
58 | this.context = context;
59 | }
60 |
61 | public View getView()
62 | {
63 | return view;
64 | }
65 |
66 |
67 | public void setHolder(String userid, String message, long timestamp, long seen)
68 | {
69 | final TextView userName = view.findViewById(R.id.user_name);
70 | final TextView userStatus = view.findViewById(R.id.user_status);
71 | final TextView userTime = view.findViewById(R.id.user_timestamp);
72 | final CircleImageView userImage = view.findViewById(R.id.user_image);
73 | final ImageView userOnline = view.findViewById(R.id.user_online);
74 |
75 | userStatus.setText(message);
76 |
77 | userTime.setVisibility(View.VISIBLE);
78 | userTime.setText(new SimpleDateFormat("MMM d, HH:mm", Locale.getDefault()).format(timestamp));
79 |
80 | if(seen == 0L)
81 | {
82 | userStatus.setTypeface(null, Typeface.BOLD);
83 | userTime.setTypeface(null, Typeface.BOLD);
84 | }
85 | else
86 | {
87 | userStatus.setTypeface(null, Typeface.NORMAL);
88 | userTime.setTypeface(null, Typeface.NORMAL);
89 | }
90 |
91 | if(userDatabase != null && userListener != null)
92 | {
93 | userDatabase.removeEventListener(userListener);
94 | }
95 |
96 | // Initialize/Update user data
97 |
98 | userDatabase = FirebaseDatabase.getInstance().getReference().child("Users").child(userid);
99 | userListener = new ValueEventListener()
100 | {
101 | Timer timer; // Will be used to avoid flickering online status when changing activity
102 |
103 | @Override
104 | public void onDataChange(DataSnapshot dataSnapshot)
105 | {
106 | try
107 | {
108 | final String name = dataSnapshot.child("name").getValue().toString();
109 | final String image = dataSnapshot.child("image").getValue().toString();
110 |
111 | if(dataSnapshot.hasChild("online"))
112 | {
113 | String online = dataSnapshot.child("online").getValue().toString();
114 |
115 | if(online.equals("true"))
116 | {
117 | if(timer != null)
118 | {
119 | timer.cancel();
120 | timer = null;
121 | }
122 |
123 | userOnline.setVisibility(View.VISIBLE);
124 | }
125 | else
126 | {
127 | if(userName.getText().toString().equals(""))
128 | {
129 | userOnline.setVisibility(View.INVISIBLE);
130 | }
131 | else
132 | {
133 | timer = new Timer();
134 | timer.schedule(new TimerTask()
135 | {
136 | @Override
137 | public void run()
138 | {
139 | activity.runOnUiThread(new Runnable()
140 | {
141 | @Override
142 | public void run()
143 | {
144 | userOnline.setVisibility(View.INVISIBLE);
145 | }
146 | });
147 | }
148 | }, 2000);
149 | }
150 | }
151 | }
152 |
153 | userName.setText(name);
154 |
155 | if(!image.equals("default"))
156 | {
157 | Picasso.with(context)
158 | .load(image)
159 | .networkPolicy(NetworkPolicy.OFFLINE)
160 | .resize((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics()), (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics()))
161 | .centerCrop()
162 | .placeholder(R.drawable.user)
163 | .into(userImage, new Callback()
164 | {
165 | @Override
166 | public void onSuccess()
167 | {
168 |
169 | }
170 |
171 | @Override
172 | public void onError()
173 | {
174 | Picasso.with(context)
175 | .load(image)
176 | .resize((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics()), (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics()))
177 | .centerCrop()
178 | .placeholder(R.drawable.user)
179 | .error(R.drawable.user)
180 | .into(userImage);
181 | }
182 | });
183 | }
184 | else
185 | {
186 | userImage.setImageResource(R.drawable.user);
187 | }
188 | }
189 | catch(Exception e)
190 | {
191 | Log.d(TAG, "userListener exception: " + e.getMessage());
192 | e.printStackTrace();
193 | }
194 | }
195 |
196 | @Override
197 | public void onCancelled(DatabaseError databaseError)
198 | {
199 | Log.d(TAG, "userListener failed: " + databaseError.getMessage());
200 | }
201 | };
202 | userDatabase.addValueEventListener(userListener);
203 | }
204 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/github/h01d/chatapp/holders/FriendHolder.java:
--------------------------------------------------------------------------------
1 | package com.github.h01d.chatapp.holders;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.util.Log;
7 | import android.util.TypedValue;
8 | import android.view.View;
9 | import android.widget.ImageView;
10 | import android.widget.TextView;
11 |
12 | import com.github.h01d.chatapp.R;
13 | import com.google.firebase.database.DataSnapshot;
14 | import com.google.firebase.database.DatabaseError;
15 | import com.google.firebase.database.DatabaseReference;
16 | import com.google.firebase.database.FirebaseDatabase;
17 | import com.google.firebase.database.ValueEventListener;
18 | import com.squareup.picasso.Callback;
19 | import com.squareup.picasso.NetworkPolicy;
20 | import com.squareup.picasso.Picasso;
21 |
22 | import java.text.SimpleDateFormat;
23 | import java.util.Locale;
24 | import java.util.Timer;
25 | import java.util.TimerTask;
26 |
27 | import de.hdodenhof.circleimageview.CircleImageView;
28 |
29 | /**
30 | * This is a part of ChatApp Project (https://github.com/h01d/ChatApp)
31 | * Licensed under Apache License 2.0
32 | *
33 | * @author Raf (https://github.com/h01d)
34 | * @version 1.1
35 | * @since 27/02/2018
36 | */
37 |
38 | public class FriendHolder extends RecyclerView.ViewHolder
39 | {
40 | private final String TAG = "CA/FriendHolder";
41 |
42 | private Activity activity;
43 | private View view;
44 | private Context context;
45 |
46 | // Will handle user data
47 |
48 | private DatabaseReference userDatabase;
49 | private ValueEventListener userListener;
50 |
51 | public FriendHolder(Activity activity, View view, Context context)
52 | {
53 | super(view);
54 |
55 | this.activity = activity;
56 | this.view = view;
57 | this.context = context;
58 | }
59 |
60 | public View getView()
61 | {
62 | return view;
63 | }
64 |
65 | public void setHolder(String userid, long date)
66 | {
67 | final TextView userName = view.findViewById(R.id.user_name);
68 | final TextView userStatus = view.findViewById(R.id.user_status);
69 | final CircleImageView userImage = view.findViewById(R.id.user_image);
70 | final ImageView userOnline = view.findViewById(R.id.user_online);
71 |
72 | userStatus.setText("Friends Since: " + new SimpleDateFormat("MMM d, yyyy", Locale.getDefault()).format(date));
73 |
74 | if(userDatabase != null & userListener != null)
75 | {
76 | userDatabase.removeEventListener(userListener);
77 | }
78 |
79 | // Initialize/Update user data
80 |
81 | userDatabase = FirebaseDatabase.getInstance().getReference().child("Users").child(userid);
82 | userListener = new ValueEventListener()
83 | {
84 | Timer timer; // Will be used to avoid flickering online status when changing activity
85 |
86 | @Override
87 | public void onDataChange(DataSnapshot dataSnapshot)
88 | {
89 | try
90 | {
91 | final String name = dataSnapshot.child("name").getValue().toString();
92 | final String image = dataSnapshot.child("image").getValue().toString();
93 |
94 | if(dataSnapshot.hasChild("online"))
95 | {
96 | String online = dataSnapshot.child("online").getValue().toString();
97 |
98 | if(online.equals("true"))
99 | {
100 | if(timer != null)
101 | {
102 | timer.cancel();
103 | timer = null;
104 | }
105 |
106 | userOnline.setVisibility(View.VISIBLE);
107 | }
108 | else
109 | {
110 | if(userName.getText().toString().equals(""))
111 | {
112 | userOnline.setVisibility(View.INVISIBLE);
113 | }
114 | else
115 | {
116 | timer = new Timer();
117 | timer.schedule(new TimerTask()
118 | {
119 | @Override
120 | public void run()
121 | {
122 | activity.runOnUiThread(new Runnable()
123 | {
124 | @Override
125 | public void run()
126 | {
127 | userOnline.setVisibility(View.INVISIBLE);
128 | }
129 | });
130 | }
131 | }, 2000);
132 | }
133 | }
134 | }
135 |
136 | userName.setText(name);
137 |
138 | if(!image.equals("default"))
139 | {
140 | Picasso.with(context)
141 | .load(image)
142 | .networkPolicy(NetworkPolicy.OFFLINE)
143 | .resize((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics()), (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics()))
144 | .centerCrop()
145 | .placeholder(R.drawable.user)
146 | .into(userImage, new Callback()
147 | {
148 | @Override
149 | public void onSuccess()
150 | {
151 |
152 | }
153 |
154 | @Override
155 | public void onError()
156 | {
157 | Picasso.with(context)
158 | .load(image)
159 | .resize((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics()), (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics()))
160 | .centerCrop()
161 | .placeholder(R.drawable.user)
162 | .error(R.drawable.user)
163 | .into(userImage);
164 | }
165 | });
166 | }
167 | else
168 | {
169 | userImage.setImageResource(R.drawable.user);
170 | }
171 | }
172 | catch(Exception e)
173 | {
174 | Log.d(TAG, "userListener exception: " + e.getMessage());
175 | e.printStackTrace();
176 | }
177 | }
178 |
179 | @Override
180 | public void onCancelled(DatabaseError databaseError)
181 | {
182 | Log.d(TAG, "userListener failed: " + databaseError.getMessage());
183 | }
184 | };
185 | userDatabase.addValueEventListener(userListener);
186 | }
187 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/github/h01d/chatapp/holders/RequestHolder.java:
--------------------------------------------------------------------------------
1 | package com.github.h01d.chatapp.holders;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.util.Log;
7 | import android.util.TypedValue;
8 | import android.view.View;
9 | import android.widget.ImageView;
10 | import android.widget.TextView;
11 |
12 | import com.github.h01d.chatapp.R;
13 | import com.google.firebase.database.DataSnapshot;
14 | import com.google.firebase.database.DatabaseError;
15 | import com.google.firebase.database.DatabaseReference;
16 | import com.google.firebase.database.FirebaseDatabase;
17 | import com.google.firebase.database.ValueEventListener;
18 | import com.squareup.picasso.Callback;
19 | import com.squareup.picasso.NetworkPolicy;
20 | import com.squareup.picasso.Picasso;
21 |
22 | import java.util.Timer;
23 | import java.util.TimerTask;
24 |
25 | import de.hdodenhof.circleimageview.CircleImageView;
26 |
27 | /**
28 | * This is a part of ChatApp Project (https://github.com/h01d/ChatApp)
29 | * Licensed under Apache License 2.0
30 | *
31 | * @author Raf (https://github.com/h01d)
32 | * @version 1.1
33 | * @since 27/02/2018
34 | */
35 |
36 | public class RequestHolder extends RecyclerView.ViewHolder
37 | {
38 | private final String TAG = "CA/RequestHolder";
39 |
40 | private Activity activity;
41 | private View view;
42 | private Context context;
43 |
44 | // Will handle user data
45 |
46 | private DatabaseReference userDatabase;
47 | private ValueEventListener userListener;
48 |
49 | public RequestHolder(Activity activity, View view, Context context)
50 | {
51 | super(view);
52 |
53 | this.activity = activity;
54 | this.view = view;
55 | this.context = context;
56 | }
57 |
58 | public View getView()
59 | {
60 | return view;
61 | }
62 |
63 | public void setHolder(String userid)
64 | {
65 | final TextView userName = view.findViewById(R.id.user_name);
66 | final TextView userStatus = view.findViewById(R.id.user_status);
67 | final CircleImageView userImage = view.findViewById(R.id.user_image);
68 | final ImageView userOnline = view.findViewById(R.id.user_online);
69 |
70 | userStatus.setText("Wants to be your Friend!");
71 |
72 | if(userDatabase != null & userListener != null)
73 | {
74 | userDatabase.removeEventListener(userListener);
75 | }
76 |
77 | // Initilize/Update user data
78 |
79 | userDatabase = FirebaseDatabase.getInstance().getReference().child("Users").child(userid);
80 | userListener = new ValueEventListener()
81 | {
82 | Timer timer; // Will be used to avoid flickering online status when changing activity
83 |
84 | @Override
85 | public void onDataChange(DataSnapshot dataSnapshot)
86 | {
87 | try
88 | {
89 | final String name = dataSnapshot.child("name").getValue().toString();
90 | final String image = dataSnapshot.child("image").getValue().toString();
91 |
92 | if(dataSnapshot.hasChild("online"))
93 | {
94 | String online = dataSnapshot.child("online").getValue().toString();
95 |
96 | if(online.equals("true"))
97 | {
98 | if(timer != null)
99 | {
100 | timer.cancel();
101 | timer = null;
102 | }
103 |
104 | userOnline.setVisibility(View.VISIBLE);
105 | }
106 | else
107 | {
108 | if(userName.getText().toString().equals(""))
109 | {
110 | userOnline.setVisibility(View.INVISIBLE);
111 | }
112 | else
113 | {
114 | timer = new Timer();
115 | timer.schedule(new TimerTask()
116 | {
117 | @Override
118 | public void run()
119 | {
120 | activity.runOnUiThread(new Runnable()
121 | {
122 | @Override
123 | public void run()
124 | {
125 | userOnline.setVisibility(View.INVISIBLE);
126 | }
127 | });
128 | }
129 | }, 2000);
130 | }
131 | }
132 | }
133 |
134 | userName.setText(name);
135 |
136 | if(!image.equals("default"))
137 | {
138 | Picasso.with(context)
139 | .load(image)
140 | .resize((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics()), (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics()))
141 | .centerCrop()
142 | .networkPolicy(NetworkPolicy.OFFLINE)
143 | .placeholder(R.drawable.user)
144 | .into(userImage, new Callback()
145 | {
146 | @Override
147 | public void onSuccess()
148 | {
149 |
150 | }
151 |
152 | @Override
153 | public void onError()
154 | {
155 | Picasso.with(context)
156 | .load(image)
157 | .resize((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics()), (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics()))
158 | .centerCrop()
159 | .placeholder(R.drawable.user)
160 | .error(R.drawable.user)
161 | .into(userImage);
162 | }
163 | });
164 | }
165 | else
166 | {
167 | userImage.setImageResource(R.drawable.user);
168 | }
169 | }
170 | catch(Exception e)
171 | {
172 | Log.d(TAG, "userListener exception: " + e.getMessage());
173 | e.printStackTrace();
174 | }
175 | }
176 |
177 | @Override
178 | public void onCancelled(DatabaseError databaseError)
179 | {
180 | Log.d(TAG, "userListener failed: " + databaseError.getMessage());
181 | }
182 | };
183 | userDatabase.addValueEventListener(userListener);
184 | }
185 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/github/h01d/chatapp/holders/UserHolder.java:
--------------------------------------------------------------------------------
1 | package com.github.h01d.chatapp.holders;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.util.Log;
7 | import android.util.TypedValue;
8 | import android.view.View;
9 | import android.widget.ImageView;
10 | import android.widget.TextView;
11 |
12 | import com.github.h01d.chatapp.R;
13 | import com.google.firebase.database.DataSnapshot;
14 | import com.google.firebase.database.DatabaseError;
15 | import com.google.firebase.database.DatabaseReference;
16 | import com.google.firebase.database.FirebaseDatabase;
17 | import com.google.firebase.database.ValueEventListener;
18 | import com.squareup.picasso.Callback;
19 | import com.squareup.picasso.NetworkPolicy;
20 | import com.squareup.picasso.Picasso;
21 |
22 | import java.util.Timer;
23 | import java.util.TimerTask;
24 |
25 | import de.hdodenhof.circleimageview.CircleImageView;
26 |
27 | /**
28 | * This is a part of ChatApp Project (https://github.com/h01d/ChatApp)
29 | * Licensed under Apache License 2.0
30 | *
31 | * @author Raf (https://github.com/h01d)
32 | * @version 1.1
33 | * @since 27/02/2018
34 | */
35 |
36 | public class UserHolder extends RecyclerView.ViewHolder
37 | {
38 | private final String TAG = "CA/UserHolder";
39 |
40 | private Activity activity;
41 | private View view;
42 | private Context context;
43 |
44 | // Will handle user data
45 |
46 | private DatabaseReference userDatabase;
47 | private ValueEventListener userListener;
48 |
49 | public UserHolder(Activity activity, View view, Context context)
50 | {
51 | super(view);
52 |
53 | this.activity = activity;
54 | this.view = view;
55 | this.context = context;
56 | }
57 |
58 | public View getView()
59 | {
60 | return view;
61 | }
62 |
63 | public void setHolder(String userid)
64 | {
65 | final TextView userName = view.findViewById(R.id.user_name);
66 | final TextView userStatus = view.findViewById(R.id.user_status);
67 | final CircleImageView userImage = view.findViewById(R.id.user_image);
68 | final ImageView userOnline = view.findViewById(R.id.user_online);
69 |
70 | if(userDatabase != null & userListener != null)
71 | {
72 | userDatabase.removeEventListener(userListener);
73 | }
74 |
75 | // Initialize/Upadte user data
76 |
77 | userDatabase = FirebaseDatabase.getInstance().getReference().child("Users").child(userid);
78 | userListener = new ValueEventListener()
79 | {
80 | Timer timer; // Will be used to avoid flickering online status when changing activity
81 |
82 | @Override
83 | public void onDataChange(DataSnapshot dataSnapshot)
84 | {
85 | try
86 | {
87 | final String name = dataSnapshot.child("name").getValue().toString();
88 | final String status = dataSnapshot.child("status").getValue().toString();
89 | final String image = dataSnapshot.child("image").getValue().toString();
90 |
91 | if(dataSnapshot.hasChild("online"))
92 | {
93 | String online = dataSnapshot.child("online").getValue().toString();
94 |
95 | if(online.equals("true"))
96 | {
97 | if(timer != null)
98 | {
99 | timer.cancel();
100 | timer = null;
101 | }
102 |
103 | userOnline.setVisibility(View.VISIBLE);
104 | }
105 | else
106 | {
107 | if(userName.getText().toString().equals(""))
108 | {
109 | userOnline.setVisibility(View.INVISIBLE);
110 | }
111 | else
112 | {
113 | timer = new Timer();
114 | timer.schedule(new TimerTask()
115 | {
116 | @Override
117 | public void run()
118 | {
119 | activity.runOnUiThread(new Runnable()
120 | {
121 | @Override
122 | public void run()
123 | {
124 | userOnline.setVisibility(View.INVISIBLE);
125 | }
126 | });
127 | }
128 | }, 2000);
129 | }
130 | }
131 | }
132 |
133 | userName.setText(name);
134 | userStatus.setText(status);
135 |
136 | if(!image.equals("default"))
137 | {
138 | Picasso.with(context)
139 | .load(image)
140 | .resize((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics()), (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics()))
141 | .centerCrop()
142 | .networkPolicy(NetworkPolicy.OFFLINE)
143 | .placeholder(R.drawable.user)
144 | .into(userImage, new Callback()
145 | {
146 | @Override
147 | public void onSuccess()
148 | {
149 |
150 | }
151 |
152 | @Override
153 | public void onError()
154 | {
155 | Picasso.with(context)
156 | .load(image)
157 | .resize((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics()), (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics()))
158 | .centerCrop()
159 | .placeholder(R.drawable.user)
160 | .error(R.drawable.user)
161 | .into(userImage);
162 | }
163 | });
164 | }
165 | else
166 | {
167 | userImage.setImageResource(R.drawable.user);
168 | }
169 | }
170 | catch(Exception e)
171 | {
172 | Log.d(TAG, "userListener exception: " + e.getMessage());
173 | e.printStackTrace();
174 | }
175 | }
176 |
177 | @Override
178 | public void onCancelled(DatabaseError databaseError)
179 | {
180 | Log.d(TAG, "userListener failed: " + databaseError.getMessage());
181 | }
182 | };
183 | userDatabase.addValueEventListener(userListener);
184 | }
185 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/github/h01d/chatapp/models/Chat.java:
--------------------------------------------------------------------------------
1 | package com.github.h01d.chatapp.models;
2 |
3 | /**
4 | * This is a part of ChatApp Project (https://github.com/h01d/ChatApp)
5 | * Licensed under Apache License 2.0
6 | *
7 | * @author Raf (https://github.com/h01d)
8 | * @version 1.1
9 | * @since 27/02/2018
10 | */
11 |
12 | public class Chat
13 | {
14 | private String message;
15 | private int typing;
16 | private long timestamp, seen;
17 |
18 | public Chat()
19 | {
20 |
21 | }
22 |
23 | public Chat(String message, int typing, long timestamp, long seen)
24 | {
25 | this.message = message;
26 | this.typing = typing;
27 | this.timestamp = timestamp;
28 | this.seen = seen;
29 | }
30 |
31 | public String getMessage()
32 | {
33 | return message;
34 | }
35 |
36 | public void setMessage(String message)
37 | {
38 | this.message = message;
39 | }
40 |
41 | public int getTyping()
42 | {
43 | return typing;
44 | }
45 |
46 | public void setTyping(int typing)
47 | {
48 | this.typing = typing;
49 | }
50 |
51 | public long getTimestamp()
52 | {
53 | return timestamp;
54 | }
55 |
56 | public void setTimestamp(long timestamp)
57 | {
58 | this.timestamp = timestamp;
59 | }
60 |
61 | public long getSeen()
62 | {
63 | return seen;
64 | }
65 |
66 | public void setSeen(long seen)
67 | {
68 | this.seen = seen;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/h01d/chatapp/models/Friend.java:
--------------------------------------------------------------------------------
1 | package com.github.h01d.chatapp.models;
2 |
3 | /**
4 | * This is a part of ChatApp Project (https://github.com/h01d/ChatApp)
5 | * Licensed under Apache License 2.0
6 | *
7 | * @author Raf (https://github.com/h01d)
8 | * @version 1.1
9 | * @since 27/02/2018
10 | */
11 |
12 | public class Friend
13 | {
14 | private long date;
15 |
16 | public Friend()
17 | {
18 |
19 | }
20 |
21 | public Friend(long date)
22 | {
23 | this.date = date;
24 | }
25 |
26 | public long getDate()
27 | {
28 | return date;
29 | }
30 |
31 | public void setDate(long date)
32 | {
33 | this.date = date;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/h01d/chatapp/models/Message.java:
--------------------------------------------------------------------------------
1 | package com.github.h01d.chatapp.models;
2 |
3 | /**
4 | * This is a part of ChatApp Project (https://github.com/h01d/ChatApp)
5 | * Licensed under Apache License 2.0
6 | *
7 | * @author Raf (https://github.com/h01d)
8 | * @version 1.1
9 | * @since 27/02/2018
10 | */
11 |
12 | public class Message
13 | {
14 | private String message, type, from, to;
15 | private long timestamp;
16 |
17 | public Message()
18 | {
19 |
20 | }
21 |
22 | public Message(String message, String type, String from, String to, long timestamp)
23 | {
24 | this.message = message;
25 | this.type = type;
26 | this.from = from;
27 | this.to = to;
28 | this.timestamp = timestamp;
29 | }
30 |
31 | public String getMessage()
32 | {
33 | return message;
34 | }
35 |
36 | public void setMessage(String message)
37 | {
38 | this.message = message;
39 | }
40 |
41 | public String getType()
42 | {
43 | return type;
44 | }
45 |
46 | public void setType(String type)
47 | {
48 | this.type = type;
49 | }
50 |
51 | public String getFrom()
52 | {
53 | return from;
54 | }
55 |
56 | public void setFrom(String from)
57 | {
58 | this.from = from;
59 | }
60 |
61 | public String getTo()
62 | {
63 | return to;
64 | }
65 |
66 | public void setTo(String to)
67 | {
68 | this.to = to;
69 | }
70 |
71 | public long getTimestamp()
72 | {
73 | return timestamp;
74 | }
75 |
76 | public void setTimestamp(long timestamp)
77 | {
78 | this.timestamp = timestamp;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/h01d/chatapp/models/Request.java:
--------------------------------------------------------------------------------
1 | package com.github.h01d.chatapp.models;
2 |
3 | /**
4 | * This is a part of ChatApp Project (https://github.com/h01d/ChatApp)
5 | * Licensed under Apache License 2.0
6 | *
7 | * @author Raf (https://github.com/h01d)
8 | * @version 1.1
9 | * @since 27/02/2018
10 | */
11 |
12 | public class Request
13 | {
14 | private String type;
15 |
16 | public Request()
17 | {
18 |
19 | }
20 |
21 | public Request(String type)
22 | {
23 | this.type = type;
24 | }
25 |
26 | public String getType()
27 | {
28 | return type;
29 | }
30 |
31 | public void setType(String type)
32 | {
33 | this.type = type;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/h01d/chatapp/models/User.java:
--------------------------------------------------------------------------------
1 | package com.github.h01d.chatapp.models;
2 |
3 | /**
4 | * This is a part of ChatApp Project (https://github.com/h01d/ChatApp)
5 | * Licensed under Apache License 2.0
6 | *
7 | * @author Raf (https://github.com/h01d)
8 | * @version 1.1
9 | * @since 27/02/2018
10 | */
11 |
12 | public class User
13 | {
14 | private String token, name, email, status, image, cover;
15 | private long date;
16 |
17 | public User()
18 | {
19 |
20 | }
21 |
22 | public User(String token, String name, String email, String status, String image, String cover, long date)
23 | {
24 | this.token = token;
25 | this.name = name;
26 | this.email = email;
27 | this.status = status;
28 | this.image = image;
29 | this.cover = cover;
30 | this.date = date;
31 | }
32 |
33 | public String getToken()
34 | {
35 | return token;
36 | }
37 |
38 | public void setToken(String token)
39 | {
40 | this.token = token;
41 | }
42 |
43 | public String getName()
44 | {
45 | return name;
46 | }
47 |
48 | public void setName(String name)
49 | {
50 | this.name = name;
51 | }
52 |
53 | public String getEmail()
54 | {
55 | return email;
56 | }
57 |
58 | public void setEmail(String email)
59 | {
60 | this.email = email;
61 | }
62 |
63 | public String getStatus()
64 | {
65 | return status;
66 | }
67 |
68 | public void setStatus(String status)
69 | {
70 | this.status = status;
71 | }
72 |
73 | public String getImage()
74 | {
75 | return image;
76 | }
77 |
78 | public void setImage(String image)
79 | {
80 | this.image = image;
81 | }
82 |
83 | public String getCover()
84 | {
85 | return cover;
86 | }
87 |
88 | public void setCover(String cover)
89 | {
90 | this.cover = cover;
91 | }
92 |
93 | public long getDate()
94 | {
95 | return date;
96 | }
97 |
98 | public void setDate(long date)
99 | {
100 | this.date = date;
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/h01d/chatapp/utils/Capabilities.java:
--------------------------------------------------------------------------------
1 | package com.github.h01d.chatapp.utils;
2 |
3 | import android.app.Application;
4 | import android.util.Log;
5 |
6 | import com.google.firebase.auth.FirebaseAuth;
7 | import com.google.firebase.database.DataSnapshot;
8 | import com.google.firebase.database.DatabaseError;
9 | import com.google.firebase.database.DatabaseReference;
10 | import com.google.firebase.database.FirebaseDatabase;
11 | import com.google.firebase.database.ServerValue;
12 | import com.google.firebase.database.ValueEventListener;
13 | import com.squareup.picasso.OkHttpDownloader;
14 | import com.squareup.picasso.Picasso;
15 |
16 | /**
17 | * This is a part of ChatApp Project (https://github.com/h01d/ChatApp)
18 | * Licensed under Apache License 2.0
19 | *
20 | * @author Raf (https://github.com/h01d)
21 | * @version 1.1
22 | * @since 27/02/2018
23 | */
24 |
25 | public class Capabilities extends Application
26 | {
27 | private final String TAG = "CA/Capabilities";
28 |
29 | @Override
30 | public void onCreate()
31 | {
32 | super.onCreate();
33 |
34 | // For offline use
35 |
36 | FirebaseDatabase.getInstance().setPersistenceEnabled(true);
37 |
38 | Picasso.Builder builder = new Picasso.Builder(this);
39 | builder.downloader(new OkHttpDownloader(this, Integer.MAX_VALUE));
40 |
41 | Picasso build = builder.build();
42 | build.setLoggingEnabled(true);
43 | Picasso.setSingletonInstance(build);
44 |
45 | // If user disconnect
46 |
47 | if(FirebaseAuth.getInstance().getCurrentUser() != null)
48 | {
49 | final DatabaseReference userDatabase = FirebaseDatabase.getInstance().getReference().child("Users").child(FirebaseAuth.getInstance().getCurrentUser().getUid());
50 | userDatabase.addValueEventListener(new ValueEventListener()
51 | {
52 | @Override
53 | public void onDataChange(DataSnapshot dataSnapshot)
54 | {
55 | if(dataSnapshot != null)
56 | {
57 | userDatabase.child("online").onDisconnect().setValue(ServerValue.TIMESTAMP);
58 | }
59 | }
60 |
61 | @Override
62 | public void onCancelled(DatabaseError databaseError)
63 | {
64 | Log.d(TAG, "usersDatabase failed: " + databaseError.getMessage());
65 | }
66 | });
67 | }
68 | }
69 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/github/h01d/chatapp/utils/FirebaseMessagingService.java:
--------------------------------------------------------------------------------
1 | package com.github.h01d.chatapp.utils;
2 |
3 | import android.app.Notification;
4 | import android.app.NotificationChannel;
5 | import android.app.NotificationManager;
6 | import android.app.PendingIntent;
7 | import android.content.Intent;
8 | import android.graphics.BitmapFactory;
9 | import android.os.Build;
10 | import android.support.v4.app.NotificationCompat;
11 |
12 | import com.github.h01d.chatapp.R;
13 | import com.github.h01d.chatapp.activities.ChatActivity;
14 | import com.google.firebase.messaging.RemoteMessage;
15 |
16 | /**
17 | * This is a part of ChatApp Project (https://github.com/h01d/ChatApp)
18 | * Licensed under Apache License 2.0
19 | *
20 | * @author Raf (https://github.com/h01d)
21 | * @version 1.1
22 | * @since 27/02/2018
23 | */
24 |
25 | public class FirebaseMessagingService extends com.google.firebase.messaging.FirebaseMessagingService
26 | {
27 | @Override
28 | public void onMessageReceived(RemoteMessage remoteMessage)
29 | {
30 | super.onMessageReceived(remoteMessage);
31 |
32 | // Notification data
33 |
34 | NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
35 |
36 | if(Build.VERSION.SDK_INT >= 26)
37 | {
38 | // API 26+ is required to provide a channel Id
39 |
40 | NotificationChannel notificationChannel = new NotificationChannel(getString(R.string.default_notification_channel_id), "My Notifications", NotificationManager.IMPORTANCE_HIGH);
41 |
42 | notificationChannel.setDescription("Channel description");
43 | notificationChannel.enableLights(true);
44 | notificationChannel.setLightColor(Notification.DEFAULT_LIGHTS);
45 | notificationChannel.setVibrationPattern(new long[]{0, 100, 100, 100, 100, 100});
46 | notificationChannel.enableVibration(true);
47 | notificationManager.createNotificationChannel(notificationChannel);
48 | }
49 |
50 | String notificationTitle = remoteMessage.getData().get("title");
51 | String notificationMessage = remoteMessage.getData().get("body");
52 | String notificationAction = remoteMessage.getData().get("click_action");
53 | String notificationFrom = remoteMessage.getData().get("from_user_id");
54 |
55 | if(notificationTitle.equals("You have a new Message"))
56 | {
57 | // If it's a message notification
58 | // Checking if ChatActivity is not open or if its, it should have a different userId from current
59 |
60 | if(!ChatActivity.running || ChatActivity.running && !ChatActivity.otherUserId.equals(notificationFrom))
61 | {
62 | // Creating the notification
63 |
64 | NotificationCompat.Builder notification = new NotificationCompat.Builder(this, getString(R.string.default_notification_channel_id))
65 | .setContentTitle(notificationTitle)
66 | .setContentText(notificationMessage)
67 | .setSmallIcon(R.drawable.logo)
68 | .setLargeIcon(BitmapFactory.decodeResource(getApplicationContext().getResources(), R.mipmap.ic_launcher_round))
69 | .setAutoCancel(true)
70 | .setDefaults(Notification.DEFAULT_LIGHTS | Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE);
71 |
72 | Intent intent = new Intent(notificationAction);
73 | intent.putExtra("userid", notificationFrom);
74 |
75 | // Extract a unique notification from sender userId so we can have only 1 notification per user
76 |
77 | int notificationId = Integer.parseInt(notificationFrom.replaceAll("[^0-9]", ""));
78 |
79 | PendingIntent pendingIntent = PendingIntent.getActivity(this, notificationId % 65535, intent, PendingIntent.FLAG_ONE_SHOT);
80 |
81 | notification.setContentIntent(pendingIntent);
82 |
83 | // Pushing notification to device
84 |
85 | notificationManager.notify(notificationId % 65535, notification.build());
86 | }
87 | }
88 | else if(notificationTitle.equals("You have a Friend Request"))
89 | {
90 | // If it's friend request notification
91 |
92 | // Creating the notification
93 |
94 | NotificationCompat.Builder notification = new NotificationCompat.Builder(this, getString(R.string.default_notification_channel_id))
95 | .setContentTitle(notificationTitle)
96 | .setContentText(notificationMessage)
97 | .setSmallIcon(R.drawable.ic_person_add_white_24dp)
98 | .setLargeIcon(BitmapFactory.decodeResource(getApplicationContext().getResources(), R.mipmap.ic_launcher_round))
99 | .setAutoCancel(true)
100 | .setDefaults(Notification.DEFAULT_LIGHTS | Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE);
101 |
102 | Intent intent = new Intent(notificationAction);
103 | intent.putExtra("userid", notificationFrom);
104 |
105 | // Extract a unique notification from sender userId so we can have only 1 notification per user
106 |
107 | int notificationId = Integer.parseInt(notificationFrom.replaceAll("[^0-9]", ""));
108 |
109 | // Adding +1 to notification Id se we can have a Friend Request and a Message Notification at the same time
110 |
111 | PendingIntent pendingIntent = PendingIntent.getActivity(this, notificationId + 1 % 65535, intent, PendingIntent.FLAG_ONE_SHOT);
112 |
113 | notification.setContentIntent(pendingIntent);
114 |
115 | // Pushing notification to device
116 |
117 | notificationManager.notify(notificationId + 1 % 65535, notification.build());
118 | }
119 | else if(notificationTitle.equals("You have a new friend"))
120 | {
121 | // If it's a new friend
122 |
123 | // Creating the notification
124 |
125 | NotificationCompat.Builder notification = new NotificationCompat.Builder(this, getString(R.string.default_notification_channel_id))
126 | .setContentTitle(notificationTitle)
127 | .setContentText(notificationMessage)
128 | .setSmallIcon(R.drawable.ic_person_add_white_24dp)
129 | .setLargeIcon(BitmapFactory.decodeResource(getApplicationContext().getResources(), R.mipmap.ic_launcher_round))
130 | .setAutoCancel(true)
131 | .setDefaults(Notification.DEFAULT_LIGHTS | Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE);
132 |
133 | Intent intent = new Intent(notificationAction);
134 | intent.putExtra("userid", notificationFrom);
135 |
136 | // Extract a unique notification from sender userId so we can have only 1 notification per user
137 |
138 | int notificationId = Integer.parseInt(notificationFrom.replaceAll("[^0-9]", ""));
139 |
140 | // Adding +2 to notification Id se we can have a all notifications at the same time
141 |
142 | PendingIntent pendingIntent = PendingIntent.getActivity(this, notificationId + 2 % 65535, intent, PendingIntent.FLAG_ONE_SHOT);
143 |
144 | notification.setContentIntent(pendingIntent);
145 |
146 | // Pushing notification to device
147 |
148 | notificationManager.notify(notificationId + 2 % 65535, notification.build());
149 | }
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/h01d/chatapp/utils/TouchImageView.java:
--------------------------------------------------------------------------------
1 | package com.github.h01d.chatapp.utils;
2 |
3 | /**
4 | * This is a part of ChatApp Project (https://github.com/h01d/ChatApp)
5 | * Licensed under Apache License 2.0
6 | *
7 | * @author Raf (https://github.com/h01d)
8 | * @version 1.1
9 | * @since 27/02/2018
10 | */
11 |
12 | import android.content.Context;
13 | import android.graphics.Matrix;
14 | import android.graphics.PointF;
15 | import android.graphics.drawable.Drawable;
16 | import android.util.AttributeSet;
17 | import android.view.MotionEvent;
18 | import android.view.ScaleGestureDetector;
19 | import android.view.View;
20 |
21 | public class TouchImageView extends android.support.v7.widget.AppCompatImageView
22 | {
23 | Matrix matrix;
24 |
25 | static final int NONE = 0;
26 | static final int DRAG = 1;
27 | static final int ZOOM = 2;
28 | int mode = NONE;
29 |
30 | PointF last = new PointF();
31 | PointF start = new PointF();
32 |
33 | float minScale = 1f;
34 | float maxScale = 3f;
35 | float[] m;
36 |
37 | int viewWidth, viewHeight;
38 | static final int CLICK = 3;
39 | float saveScale = 1f;
40 | protected float origWidth, origHeight;
41 | int oldMeasuredWidth, oldMeasuredHeight;
42 |
43 | ScaleGestureDetector mScaleDetector;
44 |
45 | Context context;
46 |
47 | public TouchImageView(Context context)
48 | {
49 | super(context);
50 | sharedConstructing(context);
51 | }
52 |
53 | public TouchImageView(Context context, AttributeSet attrs)
54 | {
55 | super(context, attrs);
56 | sharedConstructing(context);
57 | }
58 |
59 | private void stopInterceptEvent()
60 | {
61 | getParent().requestDisallowInterceptTouchEvent(true);
62 | }
63 |
64 | private void startInterceptEvent()
65 | {
66 | getParent().requestDisallowInterceptTouchEvent(false);
67 | }
68 |
69 | private void sharedConstructing(Context context)
70 | {
71 | super.setClickable(true);
72 |
73 | this.context = context;
74 | mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
75 | matrix = new Matrix();
76 | m = new float[9];
77 |
78 | setImageMatrix(matrix);
79 | setScaleType(ScaleType.MATRIX);
80 |
81 | setOnTouchListener(new OnTouchListener()
82 | {
83 |
84 | @Override
85 | public boolean onTouch(View v, MotionEvent event)
86 | {
87 | mScaleDetector.onTouchEvent(event);
88 | PointF curr = new PointF(event.getX(), event.getY());
89 |
90 | switch(event.getAction())
91 | {
92 | case MotionEvent.ACTION_DOWN:
93 | last.set(curr);
94 | start.set(last);
95 | mode = DRAG;
96 |
97 | stopInterceptEvent();
98 | break;
99 |
100 | case MotionEvent.ACTION_MOVE:
101 | if(mode == DRAG)
102 | {
103 | float deltaX = curr.x - last.x;
104 | float deltaY = curr.y - last.y;
105 | float fixTransX = getFixDragTrans(deltaX, viewWidth, origWidth * saveScale);
106 | float fixTransY = getFixDragTrans(deltaY, viewHeight, origHeight * saveScale);
107 |
108 | matrix.postTranslate(fixTransX, fixTransY);
109 | fixTrans();
110 | last.set(curr.x, curr.y);
111 |
112 | float transX = m[Matrix.MTRANS_X];
113 |
114 | if((int) (getFixTrans(transX, viewWidth, origWidth * saveScale) + fixTransX) == 0)
115 | {
116 | startInterceptEvent();
117 | }
118 | else
119 | {
120 | stopInterceptEvent();
121 | }
122 | }
123 | break;
124 |
125 | case MotionEvent.ACTION_UP:
126 | mode = NONE;
127 | int xDiff = (int) Math.abs(curr.x - start.x);
128 | int yDiff = (int) Math.abs(curr.y - start.y);
129 |
130 | if(xDiff < CLICK && yDiff < CLICK)
131 | {
132 | performClick();
133 | }
134 |
135 | startInterceptEvent();
136 | break;
137 |
138 | case MotionEvent.ACTION_POINTER_UP:
139 | mode = NONE;
140 | break;
141 | }
142 |
143 | setImageMatrix(matrix);
144 | invalidate();
145 | return true;
146 | }
147 |
148 | });
149 | }
150 |
151 | public void setMaxZoom(float x)
152 | {
153 | maxScale = x;
154 | }
155 |
156 | private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener
157 | {
158 | @Override
159 | public boolean onScaleBegin(ScaleGestureDetector detector)
160 | {
161 | mode = ZOOM;
162 | return true;
163 | }
164 |
165 | @Override
166 | public boolean onScale(ScaleGestureDetector detector)
167 | {
168 | float mScaleFactor = detector.getScaleFactor();
169 | float origScale = saveScale;
170 |
171 | saveScale *= mScaleFactor;
172 |
173 | if(saveScale > maxScale)
174 | {
175 | saveScale = maxScale;
176 | mScaleFactor = maxScale / origScale;
177 | }
178 | else if(saveScale < minScale)
179 | {
180 | saveScale = minScale;
181 | mScaleFactor = minScale / origScale;
182 | }
183 |
184 | if(origWidth * saveScale <= viewWidth || origHeight * saveScale <= viewHeight)
185 | {
186 | matrix.postScale(mScaleFactor, mScaleFactor, viewWidth / 2, viewHeight / 2);
187 | }
188 | else
189 | {
190 | matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY());
191 | }
192 |
193 | fixTrans();
194 |
195 | return true;
196 | }
197 | }
198 |
199 | void fixTrans()
200 | {
201 | matrix.getValues(m);
202 |
203 | float transX = m[Matrix.MTRANS_X];
204 | float transY = m[Matrix.MTRANS_Y];
205 |
206 | float fixTransX = getFixTrans(transX, viewWidth, origWidth * saveScale);
207 | float fixTransY = getFixTrans(transY, viewHeight, origHeight * saveScale);
208 |
209 | if(fixTransX != 0 || fixTransY != 0)
210 | {
211 | matrix.postTranslate(fixTransX, fixTransY);
212 | }
213 | }
214 |
215 | float getFixTrans(float trans, float viewSize, float contentSize)
216 | {
217 | float minTrans, maxTrans;
218 |
219 | if(contentSize <= viewSize)
220 | {
221 | minTrans = 0;
222 | maxTrans = viewSize - contentSize;
223 | }
224 | else
225 | {
226 | minTrans = viewSize - contentSize;
227 | maxTrans = 0;
228 | }
229 |
230 | if(trans < minTrans)
231 | {
232 | return -trans + minTrans;
233 | }
234 |
235 | if(trans > maxTrans)
236 | {
237 | return -trans + maxTrans;
238 | }
239 |
240 | return 0;
241 | }
242 |
243 | float getFixDragTrans(float delta, float viewSize, float contentSize)
244 | {
245 | if(contentSize <= viewSize)
246 | {
247 | return 0;
248 | }
249 |
250 | return delta;
251 | }
252 |
253 | @Override
254 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
255 | {
256 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
257 | viewWidth = MeasureSpec.getSize(widthMeasureSpec);
258 | viewHeight = MeasureSpec.getSize(heightMeasureSpec);
259 |
260 | if(oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight || viewWidth == 0 || viewHeight == 0)
261 | {
262 | return;
263 | }
264 |
265 | oldMeasuredHeight = viewHeight;
266 | oldMeasuredWidth = viewWidth;
267 |
268 | if(saveScale == 1)
269 | {
270 | float scale;
271 |
272 | Drawable drawable = getDrawable();
273 |
274 | if(drawable == null || drawable.getIntrinsicWidth() == 0 || drawable.getIntrinsicHeight() == 0)
275 | {
276 | return;
277 | }
278 |
279 | int bmWidth = drawable.getIntrinsicWidth();
280 | int bmHeight = drawable.getIntrinsicHeight();
281 |
282 | float scaleX = (float) viewWidth / (float) bmWidth;
283 | float scaleY = (float) viewHeight / (float) bmHeight;
284 |
285 | scale = Math.min(scaleX, scaleY);
286 | matrix.setScale(scale, scale);
287 |
288 | float redundantYSpace = (float) viewHeight - (scale * (float) bmHeight);
289 | float redundantXSpace = (float) viewWidth - (scale * (float) bmWidth);
290 |
291 | redundantYSpace /= (float) 2;
292 | redundantXSpace /= (float) 2;
293 |
294 | matrix.postTranslate(redundantXSpace, redundantYSpace);
295 |
296 | origWidth = viewWidth - 2 * redundantXSpace;
297 | origHeight = viewHeight - 2 * redundantYSpace;
298 |
299 | setImageMatrix(matrix);
300 | }
301 |
302 | fixTrans();
303 | }
304 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/circle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
14 |
15 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/corner.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
14 |
17 |
20 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_add_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_block_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_cancel_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_edit_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_email_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_filter_hdr_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_group_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_image_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_image_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_lock_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_message_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_person_add_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_person_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_person_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_remove_circle_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_send_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamraf/ChatApp/6d10109408041905ef344582b7894e8a509e33f7/app/src/main/res/drawable/logo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/logo_cover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamraf/ChatApp/6d10109408041905ef344582b7894e8a509e33f7/app/src/main/res/drawable/logo_cover.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/logo_shadow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamraf/ChatApp/6d10109408041905ef344582b7894e8a509e33f7/app/src/main/res/drawable/logo_shadow.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/message_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamraf/ChatApp/6d10109408041905ef344582b7894e8a509e33f7/app/src/main/res/drawable/user.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_chat.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
20 |
21 |
26 |
27 |
28 |
29 |
38 |
39 |
46 |
47 |
59 |
60 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_full_screen.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
15 |
16 |
21 |
22 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
19 |
20 |
24 |
25 |
26 |
27 |
57 |
58 |
59 |
60 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_profile.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
18 |
19 |
26 |
27 |
34 |
35 |
36 |
37 |
48 |
49 |
55 |
56 |
68 |
69 |
81 |
82 |
83 |
84 |
91 |
92 |
105 |
106 |
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_users.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
18 |
19 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/app_bar.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/chat_bar.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
17 |
18 |
26 |
27 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_chat.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
17 |
18 |
22 |
23 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_friends.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
17 |
18 |
22 |
23 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_request.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
17 |
18 |
22 |
23 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/message.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
18 |
19 |
23 |
24 |
32 |
33 |
49 |
50 |
59 |
60 |
63 |
64 |
70 |
71 |
78 |
79 |
80 |
88 |
89 |
90 |
91 |
92 |
96 |
97 |
107 |
108 |
125 |
126 |
134 |
135 |
138 |
139 |
145 |
146 |
153 |
154 |
155 |
163 |
164 |
165 |
166 |
167 |
173 |
174 |
184 |
185 |
196 |
197 |
198 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/status_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
17 |
18 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/user.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
18 |
19 |
23 |
24 |
30 |
31 |
41 |
42 |
43 |
44 |
59 |
60 |
72 |
73 |
83 |
84 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/main_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
--------------------------------------------------------------------------------
/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.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamraf/ChatApp/6d10109408041905ef344582b7894e8a509e33f7/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamraf/ChatApp/6d10109408041905ef344582b7894e8a509e33f7/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamraf/ChatApp/6d10109408041905ef344582b7894e8a509e33f7/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamraf/ChatApp/6d10109408041905ef344582b7894e8a509e33f7/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamraf/ChatApp/6d10109408041905ef344582b7894e8a509e33f7/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamraf/ChatApp/6d10109408041905ef344582b7894e8a509e33f7/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamraf/ChatApp/6d10109408041905ef344582b7894e8a509e33f7/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamraf/ChatApp/6d10109408041905ef344582b7894e8a509e33f7/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamraf/ChatApp/6d10109408041905ef344582b7894e8a509e33f7/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamraf/ChatApp/6d10109408041905ef344582b7894e8a509e33f7/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamraf/ChatApp/6d10109408041905ef344582b7894e8a509e33f7/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamraf/ChatApp/6d10109408041905ef344582b7894e8a509e33f7/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamraf/ChatApp/6d10109408041905ef344582b7894e8a509e33f7/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamraf/ChatApp/6d10109408041905ef344582b7894e8a509e33f7/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamraf/ChatApp/6d10109408041905ef344582b7894e8a509e33f7/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 | #ef5350
8 | #b61827
9 |
10 | #66bb6a
11 | #338a3e
12 |
13 | #42a5f5
14 | #0077c2
15 |
16 | #7e57c2
17 | #4d2c91
18 |
19 | #ec407a
20 | #b4004e
21 |
22 | #bdbdbd
23 | #8d8d8d
24 |
25 | #ffffff
26 | #b3000000
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #42A5F5
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ChatApp
3 |
4 | default
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
17 |
18 |
23 |
24 |
29 |
30 |
35 |
36 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/test/java/com/github/h01d/chatapp/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.github.h01d.chatapp;
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 | {
14 | @Test
15 | public void addition_isCorrect() throws Exception
16 | {
17 | assertEquals(4, 2 + 2);
18 | }
19 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | /**
2 | * This is a part of ChatApp Project (https://github.com/h01d/ChatApp)
3 | * Licensed under Apache License 2.0
4 | *
5 | * @author Raf (https://github.com/h01d)
6 | * @version 1.1
7 | * @since 27/02/2018
8 | */
9 |
10 | buildscript {
11 |
12 | repositories {
13 | google()
14 | jcenter()
15 | }
16 | dependencies {
17 | classpath 'com.android.tools.build:gradle:3.0.1'
18 | classpath 'com.google.gms:google-services:3.1.2'
19 | }
20 | }
21 |
22 | allprojects {
23 | repositories {
24 | google()
25 | jcenter()
26 | maven { url "https://jitpack.io" }
27 | }
28 | }
29 |
30 | task clean(type: Delete) {
31 | delete rootProject.buildDir
32 | }
33 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamraf/ChatApp/6d10109408041905ef344582b7894e8a509e33f7/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Jan 18 13:03:16 EET 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | /**
4 | * This is a part of ChatApp Project (https://github.com/h01d/ChatApp)
5 | * Licensed under Apache License 2.0
6 | *
7 | * @author Raf (https://github.com/h01d)
8 | * @version 1.1
9 | * @since 27/02/2018
10 | */
11 |
12 | const functions = require('firebase-functions');
13 | const admin = require('firebase-admin');
14 |
15 | admin.initializeApp(functions.config().firebase);
16 |
17 | exports.sendNotification = functions.database.ref('/Notifications/{user_id}/{notification_id}').onWrite(event => {
18 | const user_id = event.params.user_id;
19 | const notification_id = event.params.notification_id;
20 |
21 | if(!event.data.val())
22 | {
23 | return console.log('A Notification has been deleted from the database : ', notification_id);
24 | }
25 |
26 | const fromUser = admin.database().ref(`/Notifications/${user_id}/${notification_id}`).once('value');
27 |
28 | return fromUser.then(fromUserResult =>
29 | {
30 | const from_user_id = fromUserResult.val().from;
31 | const type = fromUserResult.val().type;
32 |
33 | const userQuery = admin.database().ref(`Users/${from_user_id}/name`).once('value');
34 | const deviceToken = admin.database().ref(`/Users/${user_id}/token`).once('value');
35 |
36 | return Promise.all([userQuery, deviceToken]).then(result =>
37 | {
38 | const userName = result[0].val();
39 | const token_id = result[1].val();
40 |
41 | if(type == "request")
42 | {
43 | const payload =
44 | {
45 | data:
46 | {
47 | title : "You have a Friend Request",
48 | body: `${userName} wants to be your friend!`,
49 | icon: "default",
50 | click_action : "com.github.h01d.chatapp_PROFILE_TARGET_NOTIFICATION",
51 | from_user_id : from_user_id
52 | }
53 | };
54 |
55 | return admin.messaging().sendToDevice(token_id, payload).then(response =>
56 | {
57 | console.log(`${userName} (${from_user_id}) sent friend request to ${user_id}`);
58 | });
59 | }
60 | else if(type == "message")
61 | {
62 | const payload =
63 | {
64 | data:
65 | {
66 | title : "You have a new Message",
67 | body: `${userName} messaged you!`,
68 | icon: "default",
69 | click_action : "com.github.h01d.chatapp_CHAT_TARGET_NOTIFICATION",
70 | from_user_id : from_user_id
71 | }
72 | };
73 |
74 | return admin.messaging().sendToDevice(token_id, payload).then(response =>
75 | {
76 | console.log(`${userName} (${from_user_id}) send a message to ${user_id}`);
77 | });
78 | }
79 | else if(type == "accept")
80 | {
81 | const payload =
82 | {
83 | data:
84 | {
85 | title : "You have a new friend",
86 | body: `${userName} accepted your request!`,
87 | icon: "default",
88 | click_action : "com.github.h01d.chatapp_PROFILE_TARGET_NOTIFICATION",
89 | from_user_id : from_user_id
90 | }
91 | };
92 |
93 | return admin.messaging().sendToDevice(token_id, payload).then(response =>
94 | {
95 | console.log(`${userName} (${user_id}) accepted request by ${from_user_id}`);
96 | });
97 | }
98 | });
99 | });
100 | });
101 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------