├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── MarceFireBaseChat.iml ├── README.md ├── app ├── .gitignore ├── app.iml ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── marceme │ │ └── marcefirebasechat │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── marceme │ │ └── marcefirebasechat │ │ ├── FireChatHelper │ │ ├── ChatHelper.java │ │ └── ExtraIntent.java │ │ ├── adapter │ │ ├── MessageChatAdapter.java │ │ └── UsersChatAdapter.java │ │ ├── login │ │ └── LogInActivity.java │ │ ├── model │ │ ├── ChatMessage.java │ │ └── User.java │ │ ├── register │ │ └── RegisterActivity.java │ │ └── ui │ │ ├── ChatActivity.java │ │ └── MainActivity.java │ └── res │ ├── drawable │ ├── headshot_7.jpg │ ├── ic_send_white_24dp.png │ ├── recipient_rounded_corners.xml │ ├── send_button_corners.xml │ └── sender_rounded_corners.xml │ ├── layout │ ├── activity_chat.xml │ ├── activity_log_in.xml │ ├── activity_main.xml │ ├── activity_register.xml │ ├── layout_recipient_message.xml │ ├── layout_sender_message.xml │ └── user_profile.xml │ ├── menu │ ├── menu_chat.xml │ ├── menu_log_in.xml │ ├── menu_main.xml │ └── menu_register.xml │ ├── mipmap-hdpi │ ├── ic_avatar_blue.png │ ├── ic_avatar_green.png │ ├── ic_avatar_purple.png │ └── ic_launcher.png │ ├── mipmap-mdpi │ ├── ic_avatar_blue.png │ ├── ic_avatar_green.png │ ├── ic_avatar_purple.png │ └── ic_launcher.png │ ├── mipmap-xhdpi │ ├── ic_avatar_blue.png │ ├── ic_avatar_green.png │ ├── ic_avatar_purple.png │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ ├── ic_avatar_blue.png │ ├── ic_avatar_green.png │ ├── ic_avatar_purple.png │ └── ic_launcher.png │ ├── values-v21 │ └── styles.xml │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── images ├── mChatChat.png └── mChatUsers.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | /captures 8 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | 48 | 49 | 50 | 1.8 51 | 52 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /MarceFireBaseChat.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Warning 2 | * This is not a production app. To release your app in production, make sure you test your code and the app. 3 | * Use firebase new version 4 | 5 | # Setting 6 | * Open account in firebase console and create an app 7 | * Add the google-service.json in your project in Android studio. 8 | * Make sure your device or emulator is running the latest google-services (3.0.0) 9 | 10 | # mChat app 11 | Practicing with a chat app using firebase authentication and real-time database: 12 | * Support different users with user credentials (username and password) 13 | * Chat with any user registered in the database. 14 | 15 | #Library Used 16 | * [Butter Knife](http://jakewharton.github.io/butterknife/) - Bind view to class member fields 17 | 18 | # Android Version 19 | * 5.0 Lollipop - 6.0 Marshmallow 20 | 21 | # Screenshot for final app 22 | ![Alt text](/images/mChatUsers.png?raw=true "users") 23 | 24 | ![Alt text](/images/mChatChat.png?raw=true "chat") 25 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | 5 | compileSdkVersion 23 6 | buildToolsVersion "23.0.1" 7 | 8 | defaultConfig { 9 | applicationId "com.marceme.marcefirebasechat" 10 | minSdkVersion 21 11 | targetSdkVersion 23 12 | versionCode 1 13 | versionName "1.0" 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | } 22 | 23 | dependencies { 24 | compile 'com.android.support:recyclerview-v7:23.+' 25 | compile 'de.hdodenhof:circleimageview:2.0.0' 26 | 27 | compile 'com.google.firebase:firebase-database:10.0.1' 28 | compile 'com.google.firebase:firebase-auth:10.0.1' 29 | 30 | compile 'com.jakewharton:butterknife:8.4.0' 31 | annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0' 32 | } 33 | apply plugin: 'com.google.gms.google-services' 34 | apply plugin: 'com.jakewharton.butterknife' 35 | 36 | 37 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\Marcel\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/marceme/marcefirebasechat/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.marceme.marcefirebasechat; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 12 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 31 | 32 | 38 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/java/com/marceme/marcefirebasechat/FireChatHelper/ChatHelper.java: -------------------------------------------------------------------------------- 1 | package com.marceme.marcefirebasechat.FireChatHelper; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.Context; 5 | 6 | import com.marceme.marcefirebasechat.R; 7 | import com.marceme.marcefirebasechat.login.LogInActivity; 8 | 9 | import java.util.Random; 10 | 11 | /** 12 | * Created by Marcel on 12/8/2015. 13 | */ 14 | public class ChatHelper { 15 | 16 | private static Random randomAvatarGenerator = new Random(); 17 | private static final int NUMBER_OF_AVATAR = 3; 18 | 19 | /*Generate an avatar randomly*/ 20 | public static int generateRandomAvatarForUser(){ 21 | return randomAvatarGenerator.nextInt(NUMBER_OF_AVATAR); 22 | } 23 | 24 | /*Get avatar id*/ 25 | 26 | public static int getDrawableAvatarId(int givenRandomAvatarId){ 27 | 28 | switch (givenRandomAvatarId){ 29 | 30 | case 0: 31 | return R.mipmap.ic_avatar_blue; 32 | case 1: 33 | return R.mipmap.ic_avatar_green; 34 | case 2: 35 | return R.mipmap.ic_avatar_purple; 36 | default: 37 | return R.mipmap.ic_avatar_purple; 38 | } 39 | } 40 | 41 | public static AlertDialog buildAlertDialog(String title,String message,boolean isCancelable,Context context){ 42 | 43 | AlertDialog.Builder builder = new AlertDialog.Builder(context); 44 | builder.setMessage(message) 45 | .setTitle(title); 46 | 47 | if(isCancelable){ 48 | builder.setPositiveButton(android.R.string.ok, null); 49 | }else { 50 | builder.setCancelable(false); 51 | } 52 | return builder.create(); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/marceme/marcefirebasechat/FireChatHelper/ExtraIntent.java: -------------------------------------------------------------------------------- 1 | package com.marceme.marcefirebasechat.FireChatHelper; 2 | 3 | /** 4 | * @author Marcelino Yax-marce7j@gmail.com-Android Developer 5 | * Created on 12/26/2016. 6 | */ 7 | 8 | public final class ExtraIntent { 9 | public static final String EXTRA_CHAT_REF = "EXTRA_CHAT_REF"; 10 | public static final String EXTRA_CURRENT_USER_ID = "EXTRA_CURRENT_USER_ID"; 11 | public static final String EXTRA_RECIPIENT_ID = "EXTRA_RECIPIENT_ID"; 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/marceme/marcefirebasechat/adapter/MessageChatAdapter.java: -------------------------------------------------------------------------------- 1 | package com.marceme.marcefirebasechat.adapter; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.TextView; 8 | 9 | import com.marceme.marcefirebasechat.R; 10 | import com.marceme.marcefirebasechat.model.ChatMessage; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * Created by Marcel on 11/7/2015. 16 | */ 17 | public class MessageChatAdapter extends RecyclerView.Adapter{ 18 | 19 | private List mChatList; 20 | public static final int SENDER = 0; 21 | public static final int RECIPIENT = 1; 22 | 23 | public MessageChatAdapter(List listOfFireChats) { 24 | mChatList = listOfFireChats; 25 | } 26 | 27 | @Override 28 | public int getItemViewType(int position) { 29 | if(mChatList.get(position).getRecipientOrSenderStatus()==SENDER){ 30 | return SENDER; 31 | }else { 32 | return RECIPIENT; 33 | } 34 | } 35 | 36 | @Override 37 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { 38 | RecyclerView.ViewHolder viewHolder; 39 | LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext()); 40 | 41 | switch (viewType) { 42 | case SENDER: 43 | View viewSender = inflater.inflate(R.layout.layout_sender_message, viewGroup, false); 44 | viewHolder= new ViewHolderSender(viewSender); 45 | break; 46 | case RECIPIENT: 47 | View viewRecipient = inflater.inflate(R.layout.layout_recipient_message, viewGroup, false); 48 | viewHolder=new ViewHolderRecipient(viewRecipient); 49 | break; 50 | default: 51 | View viewSenderDefault = inflater.inflate(R.layout.layout_sender_message, viewGroup, false); 52 | viewHolder= new ViewHolderSender(viewSenderDefault); 53 | break; 54 | } 55 | return viewHolder; 56 | } 57 | 58 | @Override 59 | public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) { 60 | 61 | switch (viewHolder.getItemViewType()){ 62 | case SENDER: 63 | ViewHolderSender viewHolderSender=(ViewHolderSender)viewHolder; 64 | configureSenderView(viewHolderSender,position); 65 | break; 66 | case RECIPIENT: 67 | ViewHolderRecipient viewHolderRecipient=(ViewHolderRecipient)viewHolder; 68 | configureRecipientView(viewHolderRecipient,position); 69 | break; 70 | } 71 | 72 | 73 | } 74 | 75 | private void configureSenderView(ViewHolderSender viewHolderSender, int position) { 76 | ChatMessage senderFireMessage= mChatList.get(position); 77 | viewHolderSender.getSenderMessageTextView().setText(senderFireMessage.getMessage()); 78 | } 79 | 80 | private void configureRecipientView(ViewHolderRecipient viewHolderRecipient, int position) { 81 | ChatMessage recipientFireMessage = mChatList.get(position); 82 | viewHolderRecipient.getRecipientMessageTextView().setText(recipientFireMessage.getMessage()); 83 | } 84 | 85 | @Override 86 | public int getItemCount() { 87 | return mChatList.size(); 88 | } 89 | 90 | 91 | public void refillAdapter(ChatMessage newFireChatMessage){ 92 | 93 | /*add new message chat to list*/ 94 | mChatList.add(newFireChatMessage); 95 | 96 | /*refresh view*/ 97 | notifyItemInserted(getItemCount()-1); 98 | } 99 | 100 | 101 | public void cleanUp() { 102 | mChatList.clear(); 103 | } 104 | 105 | 106 | /*==============ViewHolder===========*/ 107 | 108 | /*ViewHolder for Sender*/ 109 | 110 | public class ViewHolderSender extends RecyclerView.ViewHolder { 111 | 112 | private TextView mSenderMessageTextView; 113 | 114 | public ViewHolderSender(View itemView) { 115 | super(itemView); 116 | mSenderMessageTextView =(TextView)itemView.findViewById(R.id.text_view_sender_message); 117 | } 118 | 119 | public TextView getSenderMessageTextView() { 120 | return mSenderMessageTextView; 121 | } 122 | 123 | } 124 | 125 | 126 | /*ViewHolder for Recipient*/ 127 | public class ViewHolderRecipient extends RecyclerView.ViewHolder { 128 | 129 | private TextView mRecipientMessageTextView; 130 | 131 | public ViewHolderRecipient(View itemView) { 132 | super(itemView); 133 | mRecipientMessageTextView=(TextView)itemView.findViewById(R.id.text_view_recipient_message); 134 | } 135 | 136 | public TextView getRecipientMessageTextView() { 137 | return mRecipientMessageTextView; 138 | } 139 | 140 | } 141 | } -------------------------------------------------------------------------------- /app/src/main/java/com/marceme/marcefirebasechat/adapter/UsersChatAdapter.java: -------------------------------------------------------------------------------- 1 | package com.marceme.marcefirebasechat.adapter; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.graphics.Color; 6 | import android.graphics.drawable.Drawable; 7 | import android.support.v4.content.ContextCompat; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.ImageView; 13 | import android.widget.TextView; 14 | 15 | import com.marceme.marcefirebasechat.FireChatHelper.ChatHelper; 16 | import com.marceme.marcefirebasechat.FireChatHelper.ExtraIntent; 17 | import com.marceme.marcefirebasechat.R; 18 | import com.marceme.marcefirebasechat.model.User; 19 | import com.marceme.marcefirebasechat.ui.ChatActivity; 20 | 21 | import java.util.List; 22 | 23 | /** 24 | * Created by Marcel on 11/11/2015. 25 | */ 26 | public class UsersChatAdapter extends RecyclerView.Adapter { 27 | 28 | public static final String ONLINE = "online"; 29 | public static final String OFFLINE = "offline"; 30 | private List mUsers; 31 | private Context mContext; 32 | private String mCurrentUserEmail; 33 | private Long mCurrentUserCreatedAt; 34 | private String mCurrentUserId; 35 | 36 | public UsersChatAdapter(Context context, List fireChatUsers) { 37 | mUsers = fireChatUsers; 38 | mContext = context; 39 | } 40 | 41 | @Override 42 | public ViewHolderUsers onCreateViewHolder(ViewGroup parent, int viewType) { 43 | return new ViewHolderUsers(mContext,LayoutInflater.from(parent.getContext()).inflate(R.layout.user_profile, parent, false)); 44 | } 45 | 46 | @Override 47 | public void onBindViewHolder(ViewHolderUsers holder, int position) { 48 | 49 | User fireChatUser = mUsers.get(position); 50 | 51 | // Set avatar 52 | int userAvatarId= ChatHelper.getDrawableAvatarId(fireChatUser.getAvatarId()); 53 | Drawable avatarDrawable = ContextCompat.getDrawable(mContext,userAvatarId); 54 | holder.getUserAvatar().setImageDrawable(avatarDrawable); 55 | 56 | // Set display name 57 | holder.getUserDisplayName().setText(fireChatUser.getDisplayName()); 58 | 59 | // Set presence status 60 | holder.getStatusConnection().setText(fireChatUser.getConnection()); 61 | 62 | // Set presence text color 63 | if(fireChatUser.getConnection().equals(ONLINE)) { 64 | // Green color 65 | holder.getStatusConnection().setTextColor(Color.parseColor("#00FF00")); 66 | }else { 67 | // Red color 68 | holder.getStatusConnection().setTextColor(Color.parseColor("#FF0000")); 69 | } 70 | 71 | } 72 | 73 | @Override 74 | public int getItemCount() { 75 | return mUsers.size(); 76 | } 77 | 78 | public void refill(User users) { 79 | mUsers.add(users); 80 | notifyDataSetChanged(); 81 | } 82 | 83 | public void changeUser(int index, User user) { 84 | mUsers.set(index,user); 85 | notifyDataSetChanged(); 86 | } 87 | 88 | public void setCurrentUserInfo(String userUid, String email, long createdAt) { 89 | mCurrentUserId = userUid; 90 | mCurrentUserEmail = email; 91 | mCurrentUserCreatedAt = createdAt; 92 | } 93 | 94 | public void clear() { 95 | mUsers.clear(); 96 | } 97 | 98 | 99 | /* ViewHolder for RecyclerView */ 100 | public class ViewHolderUsers extends RecyclerView.ViewHolder implements View.OnClickListener{ 101 | 102 | private ImageView mUserAvatar; 103 | private TextView mUserDisplayName; 104 | private TextView mStatusConnection; 105 | private Context mContextViewHolder; 106 | 107 | public ViewHolderUsers(Context context, View itemView) { 108 | super(itemView); 109 | mUserAvatar = (ImageView)itemView.findViewById(R.id.img_avatar); 110 | mUserDisplayName = (TextView)itemView.findViewById(R.id.text_view_display_name); 111 | mStatusConnection = (TextView)itemView.findViewById(R.id.text_view_connection_status); 112 | mContextViewHolder = context; 113 | 114 | itemView.setOnClickListener(this); 115 | } 116 | 117 | public ImageView getUserAvatar() { 118 | return mUserAvatar; 119 | } 120 | 121 | public TextView getUserDisplayName() { 122 | return mUserDisplayName; 123 | } 124 | public TextView getStatusConnection() { 125 | return mStatusConnection; 126 | } 127 | 128 | 129 | @Override 130 | public void onClick(View view) { 131 | 132 | User user = mUsers.get(getLayoutPosition()); 133 | 134 | String chatRef = user.createUniqueChatRef(mCurrentUserCreatedAt,mCurrentUserEmail); 135 | 136 | Intent chatIntent = new Intent(mContextViewHolder, ChatActivity.class); 137 | chatIntent.putExtra(ExtraIntent.EXTRA_CURRENT_USER_ID, mCurrentUserId); 138 | chatIntent.putExtra(ExtraIntent.EXTRA_RECIPIENT_ID, user.getRecipientId()); 139 | chatIntent.putExtra(ExtraIntent.EXTRA_CHAT_REF, chatRef); 140 | 141 | // Start new activity 142 | mContextViewHolder.startActivity(chatIntent); 143 | 144 | } 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /app/src/main/java/com/marceme/marcefirebasechat/login/LogInActivity.java: -------------------------------------------------------------------------------- 1 | package com.marceme.marcefirebasechat.login; 2 | 3 | import android.app.Activity; 4 | import android.app.AlertDialog; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.support.annotation.NonNull; 8 | import android.util.Log; 9 | import android.widget.Button; 10 | import android.widget.EditText; 11 | 12 | import com.google.android.gms.tasks.OnCompleteListener; 13 | import com.google.android.gms.tasks.Task; 14 | import com.google.firebase.auth.AuthResult; 15 | import com.google.firebase.auth.FirebaseAuth; 16 | import com.google.firebase.database.FirebaseDatabase; 17 | import com.marceme.marcefirebasechat.FireChatHelper.ChatHelper; 18 | import com.marceme.marcefirebasechat.R; 19 | import com.marceme.marcefirebasechat.adapter.UsersChatAdapter; 20 | import com.marceme.marcefirebasechat.register.RegisterActivity; 21 | import com.marceme.marcefirebasechat.ui.MainActivity; 22 | 23 | import butterknife.BindView; 24 | import butterknife.ButterKnife; 25 | import butterknife.OnClick; 26 | 27 | public class LogInActivity extends Activity { 28 | 29 | private static final String TAG = LogInActivity.class.getSimpleName(); 30 | @BindView(R.id.edit_text_email_login) EditText mUserEmail; 31 | @BindView(R.id.edit_text_password_log_in) EditText mUserPassWord; 32 | 33 | private FirebaseAuth mAuth; 34 | private AlertDialog dialog; 35 | 36 | @Override 37 | protected void onCreate(Bundle savedInstanceState) { 38 | super.onCreate(savedInstanceState); 39 | setContentView(R.layout.activity_log_in); 40 | 41 | hideActionBar(); 42 | bindButterKnife(); 43 | setAuthInstance(); 44 | } 45 | 46 | private void hideActionBar() { 47 | this.getActionBar().hide(); 48 | } 49 | 50 | private void bindButterKnife() { 51 | ButterKnife.bind(this); 52 | } 53 | 54 | private void setAuthInstance() { 55 | mAuth = FirebaseAuth.getInstance(); 56 | } 57 | 58 | @OnClick(R.id.btn_login) 59 | public void logInClickListener(Button button) { 60 | onLogInUser(); 61 | } 62 | 63 | @OnClick(R.id.btn_register) 64 | public void registerClickListener(Button button) { 65 | goToRegisterActivity(); 66 | } 67 | 68 | private void onLogInUser() { 69 | if(getUserEmail().equals("") || getUserPassword().equals("")){ 70 | showFieldsAreRequired(); 71 | }else { 72 | logIn(getUserEmail(), getUserPassword()); 73 | } 74 | } 75 | 76 | private void showFieldsAreRequired() { 77 | showAlertDialog(getString(R.string.error_incorrect_email_pass),true); 78 | } 79 | 80 | private void logIn(String email, String password) { 81 | 82 | showAlertDialog("Log In...",false); 83 | 84 | mAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener(this, new OnCompleteListener() { 85 | @Override 86 | public void onComplete(@NonNull Task task) { 87 | 88 | dismissAlertDialog(); 89 | 90 | if(task.isSuccessful()){ 91 | setUserOnline(); 92 | goToMainActivity(); 93 | }else { 94 | showAlertDialog(task.getException().getMessage(),true); 95 | } 96 | } 97 | }); 98 | } 99 | 100 | private void setUserOnline() { 101 | if(mAuth.getCurrentUser()!=null ) { 102 | String userId = mAuth.getCurrentUser().getUid(); 103 | FirebaseDatabase.getInstance() 104 | .getReference(). 105 | child("users"). 106 | child(userId). 107 | child("connection"). 108 | setValue(UsersChatAdapter.ONLINE); 109 | } 110 | } 111 | 112 | private void goToMainActivity() { 113 | Intent intent = new Intent(LogInActivity.this, MainActivity.class); 114 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 115 | intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); 116 | startActivity(intent); 117 | } 118 | 119 | private void goToRegisterActivity() { 120 | Intent intent = new Intent(LogInActivity.this, RegisterActivity.class); 121 | startActivity(intent); 122 | } 123 | 124 | private String getUserEmail() { 125 | return mUserEmail.getText().toString().trim(); 126 | } 127 | 128 | private String getUserPassword() { 129 | return mUserPassWord.getText().toString().trim(); 130 | } 131 | 132 | private void showAlertDialog(String message, boolean isCancelable){ 133 | dialog = ChatHelper.buildAlertDialog(getString(R.string.login_error_title), message,isCancelable,LogInActivity.this); 134 | dialog.show(); 135 | } 136 | 137 | private void dismissAlertDialog() { 138 | dialog.dismiss(); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /app/src/main/java/com/marceme/marcefirebasechat/model/ChatMessage.java: -------------------------------------------------------------------------------- 1 | package com.marceme.marcefirebasechat.model; 2 | 3 | import com.google.firebase.database.Exclude; 4 | 5 | /** 6 | * Created by Marcel on 11/7/2015. 7 | */ 8 | public class ChatMessage { 9 | 10 | private String message; 11 | private String sender; 12 | private String recipient; 13 | 14 | private int mRecipientOrSenderStatus; 15 | 16 | public ChatMessage() { 17 | } 18 | 19 | public ChatMessage(String message, String sender, String recipient) { 20 | this.message = message; 21 | this.recipient = recipient; 22 | this.sender = sender; 23 | } 24 | 25 | 26 | public void setRecipientOrSenderStatus(int recipientOrSenderStatus) { 27 | this.mRecipientOrSenderStatus = recipientOrSenderStatus; 28 | } 29 | 30 | 31 | public String getMessage() { 32 | return message; 33 | } 34 | 35 | public String getRecipient(){ 36 | return recipient; 37 | } 38 | 39 | public String getSender(){ 40 | return sender; 41 | } 42 | 43 | @Exclude 44 | public int getRecipientOrSenderStatus() { 45 | return mRecipientOrSenderStatus; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/marceme/marcefirebasechat/model/User.java: -------------------------------------------------------------------------------- 1 | package com.marceme.marcefirebasechat.model; 2 | 3 | import com.google.firebase.database.Exclude; 4 | import com.google.firebase.database.IgnoreExtraProperties; 5 | 6 | /** 7 | * @author Marcelino Yax-marce7j@gmail.com-Android Developer 8 | * Created on 12/23/2016. 9 | */ 10 | 11 | public class User { 12 | 13 | private String displayName; 14 | private String email; 15 | private String connection; 16 | private int avatarId; 17 | private long createdAt; 18 | 19 | private String mRecipientId; 20 | 21 | public User() { 22 | } 23 | 24 | public User(String displayName, String email, String connection, int avatarId, long createdAt) { 25 | this.displayName = displayName; 26 | this.email = email; 27 | this.connection = connection; 28 | this.avatarId = avatarId; 29 | this.createdAt = createdAt; 30 | } 31 | 32 | 33 | public String createUniqueChatRef(long createdAtCurrentUser, String currentUserEmail){ 34 | String uniqueChatRef=""; 35 | if(createdAtCurrentUser > getCreatedAt()){ 36 | uniqueChatRef = cleanEmailAddress(currentUserEmail)+"-"+cleanEmailAddress(getUserEmail()); 37 | }else { 38 | 39 | uniqueChatRef=cleanEmailAddress(getUserEmail())+"-"+cleanEmailAddress(currentUserEmail); 40 | } 41 | return uniqueChatRef; 42 | } 43 | 44 | public long getCreatedAt() { 45 | return createdAt; 46 | } 47 | 48 | private String cleanEmailAddress(String email){ 49 | //replace dot with comma since firebase does not allow dot 50 | return email.replace(".","-"); 51 | } 52 | 53 | private String getUserEmail() { 54 | //Log.e("user email ", userEmail); 55 | return email; 56 | } 57 | 58 | public String getDisplayName() { 59 | return displayName; 60 | } 61 | 62 | public String getEmail() { 63 | return email; 64 | } 65 | 66 | public String getConnection() { 67 | return connection; 68 | } 69 | 70 | public int getAvatarId() { 71 | return avatarId; 72 | } 73 | 74 | @Exclude 75 | public String getRecipientId() { 76 | return mRecipientId; 77 | } 78 | 79 | public void setRecipientId(String recipientId) { 80 | this.mRecipientId = recipientId; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/java/com/marceme/marcefirebasechat/register/RegisterActivity.java: -------------------------------------------------------------------------------- 1 | package com.marceme.marcefirebasechat.register; 2 | 3 | import android.app.Activity; 4 | import android.app.AlertDialog; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.support.annotation.NonNull; 8 | import android.widget.Button; 9 | import android.widget.EditText; 10 | 11 | import com.google.android.gms.tasks.OnCompleteListener; 12 | import com.google.android.gms.tasks.Task; 13 | import com.google.firebase.auth.AuthResult; 14 | import com.google.firebase.auth.FirebaseAuth; 15 | import com.google.firebase.auth.FirebaseUser; 16 | import com.google.firebase.database.DatabaseReference; 17 | import com.google.firebase.database.FirebaseDatabase; 18 | import com.marceme.marcefirebasechat.FireChatHelper.ChatHelper; 19 | import com.marceme.marcefirebasechat.R; 20 | import com.marceme.marcefirebasechat.adapter.UsersChatAdapter; 21 | import com.marceme.marcefirebasechat.model.User; 22 | import com.marceme.marcefirebasechat.ui.MainActivity; 23 | 24 | import java.util.Date; 25 | 26 | import butterknife.BindView; 27 | import butterknife.ButterKnife; 28 | import butterknife.OnClick; 29 | 30 | public class RegisterActivity extends Activity{ 31 | 32 | private static final String TAG = RegisterActivity.class.getSimpleName(); 33 | 34 | @BindView(R.id.edit_text_display_name) EditText mUserFirstNameRegister; 35 | @BindView(R.id.edit_text_email_register) EditText mUserEmailRegister; 36 | @BindView(R.id.edit_text_password_register) EditText mUserPassWordRegister; 37 | 38 | private FirebaseAuth mAuth; 39 | private DatabaseReference mDatabase; 40 | private AlertDialog dialog; 41 | 42 | @Override 43 | protected void onCreate(Bundle savedInstanceState) { 44 | super.onCreate(savedInstanceState); 45 | setContentView(R.layout.activity_register); 46 | 47 | hideActionBar(); 48 | bindButterKnife(); 49 | setAuthInstance(); 50 | setDatabaseInstance(); 51 | } 52 | 53 | private void hideActionBar() { 54 | this.getActionBar().hide(); 55 | } 56 | 57 | private void bindButterKnife() { 58 | ButterKnife.bind(this); 59 | } 60 | 61 | private void setAuthInstance() { 62 | mAuth = FirebaseAuth.getInstance(); 63 | } 64 | 65 | private void setDatabaseInstance() { 66 | mDatabase = FirebaseDatabase.getInstance().getReference(); 67 | } 68 | 69 | @OnClick(R.id.btn_register_user) 70 | public void registerUserClickListener(Button button) { 71 | onRegisterUser(); 72 | } 73 | 74 | @OnClick(R.id.btn_cancel_register) 75 | public void cancelClickListener(Button button) { 76 | finish(); 77 | } 78 | 79 | private void onRegisterUser() { 80 | if(getUserDisplayName().equals("") || getUserEmail().equals("") || getUserPassword().equals("")){ 81 | showFieldsAreRequired(); 82 | }else if(isIncorrectEmail(getUserEmail()) || isIncorrectPassword(getUserPassword())) { 83 | showIncorrectEmailPassword(); 84 | }else { 85 | signUp(getUserEmail(), getUserPassword()); 86 | } 87 | } 88 | 89 | private boolean isIncorrectEmail(String userEmail) { 90 | return !android.util.Patterns.EMAIL_ADDRESS.matcher(userEmail).matches(); 91 | } 92 | 93 | private boolean isIncorrectPassword(String userPassword) { 94 | return !(userPassword.length() >= 6); 95 | } 96 | 97 | private void showIncorrectEmailPassword() { 98 | showAlertDialog(getString(R.string.error_incorrect_email_pass), true); 99 | } 100 | 101 | private void showFieldsAreRequired() { 102 | showAlertDialog(getString(R.string.error_fields_empty), true); 103 | } 104 | 105 | private void showAlertDialog(String message, boolean isCancelable){ 106 | 107 | dialog = ChatHelper.buildAlertDialog(getString(R.string.login_error_title),message,isCancelable,RegisterActivity.this); 108 | dialog.show(); 109 | } 110 | 111 | private String getUserDisplayName() { 112 | return mUserFirstNameRegister.getText().toString().trim(); 113 | } 114 | 115 | private String getUserEmail() { 116 | return mUserEmailRegister.getText().toString().trim(); 117 | } 118 | 119 | private String getUserPassword() { 120 | return mUserPassWordRegister.getText().toString().trim(); 121 | } 122 | 123 | 124 | private void signUp(String email, String password) { 125 | 126 | showAlertDialog("Registering...",true); 127 | mAuth.createUserWithEmailAndPassword(email, password).addOnCompleteListener(this, new OnCompleteListener() { 128 | @Override 129 | public void onComplete(@NonNull Task task) { 130 | 131 | dismissAlertDialog(); 132 | 133 | if(task.isSuccessful()){ 134 | onAuthSuccess(task.getResult().getUser()); 135 | }else { 136 | showAlertDialog(task.getException().getMessage(), true); 137 | } 138 | } 139 | }); 140 | } 141 | 142 | private void dismissAlertDialog() { 143 | dialog.dismiss(); 144 | } 145 | 146 | private void onAuthSuccess(FirebaseUser user) { 147 | createNewUser(user.getUid()); 148 | goToMainActivity(); 149 | } 150 | 151 | private void goToMainActivity() { 152 | Intent intent = new Intent(RegisterActivity.this, MainActivity.class); 153 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 154 | intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); 155 | startActivity(intent); 156 | } 157 | 158 | private void createNewUser(String userId){ 159 | User user = buildNewUser(); 160 | mDatabase.child("users").child(userId).setValue(user); 161 | } 162 | 163 | private User buildNewUser() { 164 | return new User( 165 | getUserDisplayName(), 166 | getUserEmail(), 167 | UsersChatAdapter.ONLINE, 168 | ChatHelper.generateRandomAvatarForUser(), 169 | new Date().getTime() 170 | ); 171 | } 172 | 173 | } 174 | -------------------------------------------------------------------------------- /app/src/main/java/com/marceme/marcefirebasechat/ui/ChatActivity.java: -------------------------------------------------------------------------------- 1 | package com.marceme.marcefirebasechat.ui; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.support.v7.widget.LinearLayoutManager; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.view.View; 8 | import android.widget.EditText; 9 | 10 | import com.google.firebase.database.ChildEventListener; 11 | import com.google.firebase.database.DataSnapshot; 12 | import com.google.firebase.database.DatabaseError; 13 | import com.google.firebase.database.DatabaseReference; 14 | import com.google.firebase.database.FirebaseDatabase; 15 | import com.marceme.marcefirebasechat.FireChatHelper.ExtraIntent; 16 | import com.marceme.marcefirebasechat.R; 17 | import com.marceme.marcefirebasechat.adapter.MessageChatAdapter; 18 | import com.marceme.marcefirebasechat.model.ChatMessage; 19 | 20 | import java.util.ArrayList; 21 | 22 | import butterknife.BindView; 23 | import butterknife.ButterKnife; 24 | import butterknife.OnClick; 25 | 26 | public class ChatActivity extends Activity { 27 | 28 | private static final String TAG = ChatActivity.class.getSimpleName(); 29 | 30 | @BindView(R.id.recycler_view_chat) RecyclerView mChatRecyclerView; 31 | @BindView(R.id.edit_text_message) EditText mUserMessageChatText; 32 | 33 | 34 | private String mRecipientId; 35 | private String mCurrentUserId; 36 | private MessageChatAdapter messageChatAdapter; 37 | private DatabaseReference messageChatDatabase; 38 | private ChildEventListener messageChatListener; 39 | 40 | 41 | @Override 42 | protected void onCreate(Bundle savedInstanceState) { 43 | super.onCreate(savedInstanceState); 44 | setContentView(R.layout.activity_chat); 45 | 46 | bindButterKnife(); 47 | setDatabaseInstance(); 48 | setUsersId(); 49 | setChatRecyclerView(); 50 | } 51 | 52 | private void bindButterKnife() { 53 | ButterKnife.bind(this); 54 | } 55 | private void setDatabaseInstance() { 56 | String chatRef = getIntent().getStringExtra(ExtraIntent.EXTRA_CHAT_REF); 57 | messageChatDatabase = FirebaseDatabase.getInstance().getReference().child(chatRef); 58 | } 59 | 60 | private void setUsersId() { 61 | mRecipientId = getIntent().getStringExtra(ExtraIntent.EXTRA_RECIPIENT_ID); 62 | mCurrentUserId = getIntent().getStringExtra(ExtraIntent.EXTRA_CURRENT_USER_ID); 63 | } 64 | 65 | private void setChatRecyclerView() { 66 | mChatRecyclerView.setLayoutManager(new LinearLayoutManager(this)); 67 | mChatRecyclerView.setHasFixedSize(true); 68 | messageChatAdapter = new MessageChatAdapter(new ArrayList()); 69 | mChatRecyclerView.setAdapter(messageChatAdapter); 70 | } 71 | 72 | @Override 73 | protected void onStart() { 74 | super.onStart(); 75 | 76 | messageChatListener = messageChatDatabase.limitToFirst(20).addChildEventListener(new ChildEventListener() { 77 | @Override 78 | public void onChildAdded(DataSnapshot dataSnapshot, String previousChildKey) { 79 | 80 | if(dataSnapshot.exists()){ 81 | ChatMessage newMessage = dataSnapshot.getValue(ChatMessage.class); 82 | if(newMessage.getSender().equals(mCurrentUserId)){ 83 | newMessage.setRecipientOrSenderStatus(MessageChatAdapter.SENDER); 84 | }else{ 85 | newMessage.setRecipientOrSenderStatus(MessageChatAdapter.RECIPIENT); 86 | } 87 | messageChatAdapter.refillAdapter(newMessage); 88 | mChatRecyclerView.scrollToPosition(messageChatAdapter.getItemCount()-1); 89 | } 90 | 91 | } 92 | 93 | @Override 94 | public void onChildChanged(DataSnapshot dataSnapshot, String s) { 95 | 96 | } 97 | 98 | @Override 99 | public void onChildRemoved(DataSnapshot dataSnapshot) { 100 | 101 | } 102 | 103 | @Override 104 | public void onChildMoved(DataSnapshot dataSnapshot, String s) { 105 | 106 | } 107 | 108 | @Override 109 | public void onCancelled(DatabaseError databaseError) { 110 | 111 | } 112 | }); 113 | 114 | } 115 | 116 | 117 | @Override 118 | protected void onStop() { 119 | super.onStop(); 120 | 121 | if(messageChatListener != null) { 122 | messageChatDatabase.removeEventListener(messageChatListener); 123 | } 124 | messageChatAdapter.cleanUp(); 125 | 126 | } 127 | 128 | @OnClick(R.id.btn_send_message) 129 | public void btnSendMsgListener(View sendButton){ 130 | 131 | String senderMessage = mUserMessageChatText.getText().toString().trim(); 132 | 133 | if(!senderMessage.isEmpty()){ 134 | 135 | ChatMessage newMessage = new ChatMessage(senderMessage,mCurrentUserId,mRecipientId); 136 | messageChatDatabase.push().setValue(newMessage); 137 | 138 | mUserMessageChatText.setText(""); 139 | } 140 | } 141 | 142 | 143 | } 144 | -------------------------------------------------------------------------------- /app/src/main/java/com/marceme/marcefirebasechat/ui/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.marceme.marcefirebasechat.ui; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.support.annotation.NonNull; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.Menu; 10 | import android.view.MenuItem; 11 | import android.view.View; 12 | import android.widget.ProgressBar; 13 | 14 | import com.google.firebase.auth.FirebaseAuth; 15 | import com.google.firebase.auth.FirebaseUser; 16 | import com.google.firebase.database.ChildEventListener; 17 | import com.google.firebase.database.DataSnapshot; 18 | import com.google.firebase.database.DatabaseError; 19 | import com.google.firebase.database.DatabaseReference; 20 | import com.google.firebase.database.FirebaseDatabase; 21 | import com.marceme.marcefirebasechat.R; 22 | import com.marceme.marcefirebasechat.adapter.UsersChatAdapter; 23 | import com.marceme.marcefirebasechat.login.LogInActivity; 24 | import com.marceme.marcefirebasechat.model.User; 25 | 26 | import java.util.ArrayList; 27 | import java.util.List; 28 | 29 | import butterknife.BindView; 30 | import butterknife.ButterKnife; 31 | 32 | 33 | /* 34 | * CAUTION: This app is still far away from a production app 35 | * Note: (1) Still fixing some code, and functionality and 36 | * I don't use FirebaseUI, but recommend you to use it. 37 | * */ 38 | 39 | public class MainActivity extends Activity { 40 | 41 | 42 | private static String TAG = MainActivity.class.getSimpleName(); 43 | 44 | @BindView(R.id.progress_bar_users) ProgressBar mProgressBarForUsers; 45 | @BindView(R.id.recycler_view_users) RecyclerView mUsersRecyclerView; 46 | 47 | private String mCurrentUserUid; 48 | private List mUsersKeyList; 49 | 50 | private FirebaseAuth mAuth; 51 | private FirebaseAuth.AuthStateListener mAuthListener; 52 | private DatabaseReference mUserRefDatabase; 53 | private ChildEventListener mChildEventListener; 54 | private UsersChatAdapter mUsersChatAdapter; 55 | 56 | @Override 57 | protected void onCreate(Bundle savedInstanceState) { 58 | super.onCreate(savedInstanceState); 59 | setContentView(R.layout.activity_main); 60 | 61 | bindButterKnife(); 62 | setAuthInstance(); 63 | setUsersDatabase(); 64 | setUserRecyclerView(); 65 | setUsersKeyList(); 66 | setAuthListener(); 67 | } 68 | 69 | private void bindButterKnife() { 70 | ButterKnife.bind(this); 71 | } 72 | 73 | private void setAuthInstance() { 74 | mAuth = FirebaseAuth.getInstance(); 75 | } 76 | 77 | private void setUsersDatabase() { 78 | mUserRefDatabase = FirebaseDatabase.getInstance().getReference().child("users"); 79 | } 80 | private void setUserRecyclerView() { 81 | mUsersChatAdapter = new UsersChatAdapter(this, new ArrayList()); 82 | mUsersRecyclerView.setLayoutManager(new LinearLayoutManager(this)); 83 | mUsersRecyclerView.setHasFixedSize(true); 84 | mUsersRecyclerView.setAdapter(mUsersChatAdapter); 85 | } 86 | 87 | private void setUsersKeyList() { 88 | mUsersKeyList = new ArrayList(); 89 | } 90 | 91 | private void setAuthListener() { 92 | mAuthListener = new FirebaseAuth.AuthStateListener() { 93 | @Override 94 | public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { 95 | 96 | hideProgressBarForUsers(); 97 | FirebaseUser user = firebaseAuth.getCurrentUser(); 98 | 99 | if (user != null) { 100 | setUserData(user); 101 | queryAllUsers(); 102 | } else { 103 | // User is signed out 104 | goToLogin(); 105 | } 106 | } 107 | }; 108 | } 109 | 110 | private void setUserData(FirebaseUser user) { 111 | mCurrentUserUid = user.getUid(); 112 | } 113 | 114 | private void queryAllUsers() { 115 | mChildEventListener = getChildEventListener(); 116 | mUserRefDatabase.limitToFirst(50).addChildEventListener(mChildEventListener); 117 | } 118 | 119 | private void goToLogin() { 120 | Intent intent = new Intent(this, LogInActivity.class); 121 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // LoginActivity is a New Task 122 | intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); // The old task when coming back to this activity should be cleared so we cannot come back to it. 123 | startActivity(intent); 124 | } 125 | 126 | @Override 127 | public void onStart() { 128 | super.onStart(); 129 | showProgressBarForUsers(); 130 | mAuth.addAuthStateListener(mAuthListener); 131 | } 132 | 133 | @Override 134 | public void onStop() { 135 | super.onStop(); 136 | 137 | clearCurrentUsers(); 138 | 139 | if (mChildEventListener != null) { 140 | mUserRefDatabase.removeEventListener(mChildEventListener); 141 | } 142 | 143 | if (mAuthListener != null) { 144 | mAuth.removeAuthStateListener(mAuthListener); 145 | } 146 | 147 | } 148 | 149 | private void clearCurrentUsers() { 150 | mUsersChatAdapter.clear(); 151 | mUsersKeyList.clear(); 152 | } 153 | 154 | private void logout() { 155 | showProgressBarForUsers(); 156 | setUserOffline(); 157 | mAuth.signOut(); 158 | } 159 | 160 | private void setUserOffline() { 161 | if(mAuth.getCurrentUser()!=null ) { 162 | String userId = mAuth.getCurrentUser().getUid(); 163 | mUserRefDatabase.child(userId).child("connection").setValue(UsersChatAdapter.OFFLINE); 164 | } 165 | } 166 | 167 | @Override 168 | public boolean onCreateOptionsMenu(Menu menu) { 169 | // Inflate the menu; this adds items to the action bar if it is present. 170 | getMenuInflater().inflate(R.menu.menu_main, menu); 171 | return true; 172 | } 173 | 174 | @Override 175 | public boolean onOptionsItemSelected(MenuItem item) { 176 | if(item.getItemId()==R.id.action_logout){ 177 | logout(); 178 | return true; 179 | } 180 | 181 | return super.onOptionsItemSelected(item); 182 | } 183 | 184 | private void showProgressBarForUsers(){ 185 | mProgressBarForUsers.setVisibility(View.VISIBLE); 186 | } 187 | 188 | private void hideProgressBarForUsers(){ 189 | if(mProgressBarForUsers.getVisibility()==View.VISIBLE) { 190 | mProgressBarForUsers.setVisibility(View.GONE); 191 | } 192 | } 193 | 194 | private ChildEventListener getChildEventListener() { 195 | return new ChildEventListener() { 196 | @Override 197 | public void onChildAdded(DataSnapshot dataSnapshot, String s) { 198 | 199 | if(dataSnapshot.exists()){ 200 | 201 | String userUid = dataSnapshot.getKey(); 202 | 203 | if(dataSnapshot.getKey().equals(mCurrentUserUid)){ 204 | User currentUser = dataSnapshot.getValue(User.class); 205 | mUsersChatAdapter.setCurrentUserInfo(userUid, currentUser.getEmail(), currentUser.getCreatedAt()); 206 | }else { 207 | User recipient = dataSnapshot.getValue(User.class); 208 | recipient.setRecipientId(userUid); 209 | mUsersKeyList.add(userUid); 210 | mUsersChatAdapter.refill(recipient); 211 | } 212 | } 213 | 214 | } 215 | 216 | @Override 217 | public void onChildChanged(DataSnapshot dataSnapshot, String s) { 218 | if(dataSnapshot.exists()) { 219 | String userUid = dataSnapshot.getKey(); 220 | if(!userUid.equals(mCurrentUserUid)) { 221 | 222 | User user = dataSnapshot.getValue(User.class); 223 | 224 | int index = mUsersKeyList.indexOf(userUid); 225 | if(index > -1) { 226 | mUsersChatAdapter.changeUser(index, user); 227 | } 228 | } 229 | 230 | } 231 | } 232 | 233 | @Override 234 | public void onChildRemoved(DataSnapshot dataSnapshot) { 235 | 236 | } 237 | 238 | @Override 239 | public void onChildMoved(DataSnapshot dataSnapshot, String s) { 240 | 241 | } 242 | 243 | @Override 244 | public void onCancelled(DatabaseError databaseError) { 245 | 246 | } 247 | }; 248 | } 249 | 250 | } 251 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/headshot_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marceand/MChat/8c2b18a16af91480931ccba18fe81b01de812ad5/app/src/main/res/drawable/headshot_7.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_send_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marceand/MChat/8c2b18a16af91480931ccba18fe81b01de812ad5/app/src/main/res/drawable/ic_send_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/recipient_rounded_corners.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 22 | 23 | 24 | 25 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/send_button_corners.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/sender_rounded_corners.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 22 | 23 | 24 | 25 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_chat.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 16 | 23 | 33 | 34 | 45 |