├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── misc.xml ├── modules.xml └── runConfigurations.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── google-services.json ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── dekoservidoni │ │ └── firebasechat │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── dekoservidoni │ │ │ └── firebasechat │ │ │ ├── ActivityCallback.java │ │ │ ├── MainActivity.java │ │ │ ├── adapters │ │ │ └── ChatAdapter.java │ │ │ ├── fragments │ │ │ ├── ChatFragment.java │ │ │ ├── CreateAccountFragment.java │ │ │ └── LoginFragment.java │ │ │ ├── models │ │ │ └── ChatData.java │ │ │ └── utils │ │ │ ├── Constants.java │ │ │ └── Utils.java │ └── res │ │ ├── layout │ │ ├── activity_initial.xml │ │ ├── fragment_chat.xml │ │ ├── fragment_create_account.xml │ │ ├── fragment_login.xml │ │ └── row_chat.xml │ │ ├── menu │ │ └── menu_chat.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── dekoservidoni │ └── firebasechat │ └── ExampleUnitTest.java ├── build.gradle ├── firebase_android_logo.gif ├── firebase_app_structure.png ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.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/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FirebaseChatAndroid 2 | 3 | The complete guide showing how this sample was developed can be found at: 4 | https://medium.com/@dekoservidoni/realtime-chats-with-firebase-in-android-a2a131f94e0c 5 | 6 | ### App Structure 7 | 8 | ![Firebase Structure](firebase_app_structure.png) 9 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'com.google.gms.google-services' 3 | 4 | android { 5 | compileSdkVersion 25 6 | buildToolsVersion "25.0.2" 7 | defaultConfig { 8 | applicationId "com.dekoservidoni.firebasechat" 9 | minSdkVersion 15 10 | targetSdkVersion 25 11 | versionCode 1 12 | versionName "1.0" 13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 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 fileTree(dir: 'libs', include: ['*.jar']) 25 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 26 | exclude group: 'com.android.support', module: 'support-annotations' 27 | }) 28 | compile 'com.google.firebase:firebase-core:9.6.1' 29 | compile 'com.google.firebase:firebase-database:9.6.1' 30 | compile 'com.google.firebase:firebase-auth:9.6.1' 31 | compile 'com.android.support:cardview-v7:25.3.1' 32 | compile 'com.android.support:appcompat-v7:25.3.1' 33 | compile 'com.android.support:design:25.3.1' 34 | testCompile 'junit:junit:4.12' 35 | } 36 | -------------------------------------------------------------------------------- /app/google-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_info": { 3 | "project_number": "335662141076", 4 | "firebase_url": "https://fir-chatandroid-784d5.firebaseio.com", 5 | "project_id": "fir-chatandroid-784d5", 6 | "storage_bucket": "fir-chatandroid-784d5.appspot.com" 7 | }, 8 | "client": [ 9 | { 10 | "client_info": { 11 | "mobilesdk_app_id": "1:335662141076:android:36f658ca8e1f30d0", 12 | "android_client_info": { 13 | "package_name": "com.dekoservidoni.firebasechat" 14 | } 15 | }, 16 | "oauth_client": [ 17 | { 18 | "client_id": "335662141076-9j1jdt53c99uene637q3rguc3b2g1d2q.apps.googleusercontent.com", 19 | "client_type": 3 20 | } 21 | ], 22 | "api_key": [ 23 | { 24 | "current_key": "AIzaSyA4Y4hE80DBjN7bBa4EWxw75Ze9R6vYMfs" 25 | } 26 | ], 27 | "services": { 28 | "analytics_service": { 29 | "status": 1 30 | }, 31 | "appinvite_service": { 32 | "status": 1, 33 | "other_platform_oauth_client": [] 34 | }, 35 | "ads_service": { 36 | "status": 2 37 | } 38 | } 39 | } 40 | ], 41 | "configuration_version": "1" 42 | } -------------------------------------------------------------------------------- /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 /Users/avenuecode/Library/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 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/dekoservidoni/firebasechat/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.dekoservidoni.firebasechat; 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 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.dekoservidoni.firebasechat", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/dekoservidoni/firebasechat/ActivityCallback.java: -------------------------------------------------------------------------------- 1 | package com.dekoservidoni.firebasechat; 2 | 3 | /** 4 | * Class responsible to register all the callbacks necessary 5 | * for the application 6 | */ 7 | public interface ActivityCallback { 8 | void openChat(); 9 | void openCreateAccount(); 10 | void logout(); 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/dekoservidoni/firebasechat/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.dekoservidoni.firebasechat; 2 | 3 | import android.support.v4.app.Fragment; 4 | import android.support.v7.app.AppCompatActivity; 5 | 6 | import android.os.Bundle; 7 | 8 | import com.dekoservidoni.firebasechat.fragments.ChatFragment; 9 | import com.dekoservidoni.firebasechat.fragments.CreateAccountFragment; 10 | import com.dekoservidoni.firebasechat.fragments.LoginFragment; 11 | 12 | /** 13 | * A login screen that offers sign up via username. 14 | */ 15 | public class MainActivity extends AppCompatActivity implements ActivityCallback { 16 | 17 | /// Lifecycle methods 18 | 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | setContentView(R.layout.activity_initial); 23 | 24 | getSupportFragmentManager() 25 | .beginTransaction() 26 | .add(R.id.container, LoginFragment.newInstance()) 27 | .commit(); 28 | } 29 | 30 | /// Callback methods 31 | 32 | @Override 33 | public void openChat() { 34 | replaceFragment(ChatFragment.newInstance()); 35 | } 36 | 37 | @Override 38 | public void openCreateAccount() { 39 | replaceFragment(CreateAccountFragment.newInstance()); 40 | } 41 | 42 | @Override 43 | public void logout() { 44 | replaceFragment(LoginFragment.newInstance()); 45 | } 46 | 47 | /// Private methods 48 | 49 | private void replaceFragment(Fragment fragment) { 50 | getSupportFragmentManager() 51 | .beginTransaction() 52 | .replace(R.id.container, fragment) 53 | .commit(); 54 | } 55 | } 56 | 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/dekoservidoni/firebasechat/adapters/ChatAdapter.java: -------------------------------------------------------------------------------- 1 | package com.dekoservidoni.firebasechat.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 | import android.widget.TextView; 8 | 9 | import com.dekoservidoni.firebasechat.R; 10 | import com.dekoservidoni.firebasechat.models.ChatData; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | /** 16 | * Class responsible to show all the messages 17 | * in the chat 18 | */ 19 | public class ChatAdapter extends RecyclerView.Adapter { 20 | 21 | /** 22 | * ViewHolder to be the item of the list 23 | */ 24 | static final class ChatViewHolder extends RecyclerView.ViewHolder { 25 | 26 | TextView name; 27 | TextView message; 28 | 29 | ChatViewHolder(View view) { 30 | super(view); 31 | 32 | name = (TextView) view.findViewById(R.id.item_username); 33 | message = (TextView) view.findViewById(R.id.item_message); 34 | } 35 | } 36 | 37 | private List mContent = new ArrayList<>(); 38 | 39 | public void clearData() { 40 | mContent.clear(); 41 | } 42 | 43 | public void addData(ChatData data) { 44 | mContent.add(data); 45 | } 46 | 47 | @Override 48 | public int getItemCount() { 49 | return mContent.size(); 50 | } 51 | 52 | @Override 53 | public ChatViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 54 | View root = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_chat, parent, false); 55 | return new ChatViewHolder(root); 56 | } 57 | 58 | @Override 59 | public void onBindViewHolder(ChatViewHolder holder, int position) { 60 | ChatData data = mContent.get(position); 61 | 62 | holder.message.setText(data.getMessage()); 63 | holder.name.setText(data.getName()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/java/com/dekoservidoni/firebasechat/fragments/ChatFragment.java: -------------------------------------------------------------------------------- 1 | package com.dekoservidoni.firebasechat.fragments; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.util.Log; 10 | import android.view.KeyEvent; 11 | import android.view.LayoutInflater; 12 | import android.view.Menu; 13 | import android.view.MenuInflater; 14 | import android.view.MenuItem; 15 | import android.view.View; 16 | import android.view.ViewGroup; 17 | import android.widget.EditText; 18 | import android.widget.TextView; 19 | import android.widget.Toast; 20 | 21 | import com.dekoservidoni.firebasechat.ActivityCallback; 22 | import com.dekoservidoni.firebasechat.R; 23 | import com.dekoservidoni.firebasechat.adapters.ChatAdapter; 24 | import com.dekoservidoni.firebasechat.models.ChatData; 25 | import com.dekoservidoni.firebasechat.utils.Constants; 26 | import com.dekoservidoni.firebasechat.utils.Utils; 27 | import com.google.firebase.auth.FirebaseAuth; 28 | import com.google.firebase.database.DataSnapshot; 29 | import com.google.firebase.database.DatabaseError; 30 | import com.google.firebase.database.DatabaseReference; 31 | import com.google.firebase.database.FirebaseDatabase; 32 | import com.google.firebase.database.ValueEventListener; 33 | 34 | import java.util.Date; 35 | 36 | /** 37 | * Class responsible to be the chat screen of the app 38 | */ 39 | public class ChatFragment extends Fragment { 40 | 41 | /** Activity callback **/ 42 | private ActivityCallback mCallback; 43 | 44 | /** Database instance **/ 45 | private DatabaseReference mReference; 46 | 47 | /** UI Components **/ 48 | private EditText mChatInput; 49 | private ChatAdapter mAdapter; 50 | 51 | /** Class variables **/ 52 | private String mUsername; 53 | private String mUserId; 54 | 55 | /** 56 | * Create a instance of this fragment 57 | * 58 | * @return fragment instance 59 | */ 60 | public static ChatFragment newInstance() { 61 | return new ChatFragment(); 62 | } 63 | 64 | /// Lifecycle methods 65 | 66 | @Override 67 | public void onCreate(@Nullable Bundle savedInstanceState) { 68 | super.onCreate(savedInstanceState); 69 | 70 | setHasOptionsMenu(true); 71 | 72 | mUsername = Utils.getLocalUsername(getContext()); 73 | mUserId = Utils.getLocalUserId(getContext()); 74 | 75 | setupConnection(); 76 | } 77 | 78 | @Nullable 79 | @Override 80 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 81 | View root = inflater.inflate(R.layout.fragment_chat, container, false); 82 | 83 | mChatInput = (EditText) root.findViewById(R.id.chat_input); 84 | mChatInput.setOnEditorActionListener(new TextView.OnEditorActionListener() { 85 | @Override 86 | public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { 87 | 88 | ChatData data = new ChatData(); 89 | data.setMessage(mChatInput.getText().toString()); 90 | data.setId(mUserId); 91 | data.setName(mUsername); 92 | 93 | mReference.child(String.valueOf(new Date().getTime())).setValue(data); 94 | 95 | closeAndClean(); 96 | return true; 97 | } 98 | }); 99 | 100 | RecyclerView chat = (RecyclerView) root.findViewById(R.id.chat_message); 101 | chat.setLayoutManager(new LinearLayoutManager(getContext())); 102 | 103 | mAdapter = new ChatAdapter(); 104 | chat.setAdapter(mAdapter); 105 | 106 | return root; 107 | } 108 | 109 | @Override 110 | public void onAttach(Context context) { 111 | super.onAttach(context); 112 | mCallback = (ActivityCallback) context; 113 | } 114 | 115 | @Override 116 | public void onDetach() { 117 | super.onDetach(); 118 | mCallback = null; 119 | } 120 | 121 | @Override 122 | public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 123 | super.onCreateOptionsMenu(menu, inflater); 124 | inflater.inflate(R.menu.menu_chat, menu); 125 | } 126 | 127 | @Override 128 | public boolean onOptionsItemSelected(MenuItem item) { 129 | 130 | if(item.getItemId() == R.id.action_logout) { 131 | FirebaseAuth.getInstance().signOut(); 132 | mCallback.logout(); 133 | } 134 | 135 | return super.onOptionsItemSelected(item); 136 | } 137 | 138 | /// Private methods 139 | 140 | private void closeAndClean() { 141 | Utils.closeKeyboard(getContext(), mChatInput); 142 | mChatInput.setText(""); 143 | } 144 | 145 | private void setupConnection() { 146 | FirebaseDatabase database = FirebaseDatabase.getInstance(); 147 | mReference = database.getReference(Constants.DATABASE_NAME); 148 | 149 | mReference.addValueEventListener(new ValueEventListener() { 150 | @Override 151 | public void onDataChange(DataSnapshot dataSnapshot) { 152 | Log.d(Constants.LOG_TAG,"SUCCESS!"); 153 | handleReturn(dataSnapshot); 154 | } 155 | 156 | @Override 157 | public void onCancelled(DatabaseError databaseError) { 158 | Log.e(Constants.LOG_TAG,"ERROR: " + databaseError.getMessage()); 159 | Toast.makeText(getContext(), R.string.chat_init_error, Toast.LENGTH_SHORT).show(); 160 | mCallback.logout(); 161 | } 162 | }); 163 | } 164 | 165 | private void handleReturn(DataSnapshot dataSnapshot) { 166 | mAdapter.clearData(); 167 | 168 | for(DataSnapshot item : dataSnapshot.getChildren()) { 169 | ChatData data = item.getValue(ChatData.class); 170 | mAdapter.addData(data); 171 | } 172 | 173 | mAdapter.notifyDataSetChanged(); 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /app/src/main/java/com/dekoservidoni/firebasechat/fragments/CreateAccountFragment.java: -------------------------------------------------------------------------------- 1 | package com.dekoservidoni.firebasechat.fragments; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.annotation.NonNull; 6 | import android.support.annotation.Nullable; 7 | import android.support.v4.app.Fragment; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.Button; 12 | import android.widget.EditText; 13 | import android.widget.Toast; 14 | 15 | import com.dekoservidoni.firebasechat.ActivityCallback; 16 | import com.dekoservidoni.firebasechat.R; 17 | import com.dekoservidoni.firebasechat.utils.Utils; 18 | import com.google.android.gms.tasks.OnCompleteListener; 19 | import com.google.android.gms.tasks.Task; 20 | import com.google.firebase.auth.AuthResult; 21 | import com.google.firebase.auth.FirebaseAuth; 22 | 23 | /** 24 | * Class responsible to be the create account screen of the app 25 | */ 26 | public class CreateAccountFragment extends Fragment { 27 | 28 | /** UI Components **/ 29 | private EditText mUsername; 30 | private EditText mPassword; 31 | private EditText mEmail; 32 | private View mProgressView; 33 | private View mCreateForm; 34 | 35 | /** Activity callback **/ 36 | private ActivityCallback mCallback; 37 | 38 | /** Firebase objects **/ 39 | private FirebaseAuth mAuth; 40 | // private FirebaseAuth.AuthStateListener mAuthListener; 41 | 42 | /** 43 | * Create a instance of this fragment 44 | * 45 | * @return fragment instance 46 | */ 47 | public static CreateAccountFragment newInstance() { 48 | return new CreateAccountFragment(); 49 | } 50 | 51 | /// Lifecycle methods 52 | 53 | @Nullable 54 | @Override 55 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 56 | View root = inflater.inflate(R.layout.fragment_create_account, container, false); 57 | 58 | mUsername = (EditText) root.findViewById(R.id.create_account_username); 59 | mPassword = (EditText) root.findViewById(R.id.create_account_password); 60 | mEmail = (EditText) root.findViewById(R.id.create_account_email); 61 | 62 | mCreateForm = root.findViewById(R.id.create_account_form); 63 | mProgressView = root.findViewById(R.id.create_account_progress); 64 | 65 | Button createButton = (Button) root.findViewById(R.id.create_account_button); 66 | createButton.setOnClickListener(new View.OnClickListener() { 67 | @Override 68 | public void onClick(View view) { 69 | createAccount(); 70 | } 71 | }); 72 | 73 | mAuth = FirebaseAuth.getInstance(); 74 | 75 | return root; 76 | } 77 | 78 | @Override 79 | public void onAttach(Context context) { 80 | super.onAttach(context); 81 | mCallback = (ActivityCallback) context; 82 | } 83 | 84 | @Override 85 | public void onDetach() { 86 | super.onDetach(); 87 | mCallback = null; 88 | } 89 | 90 | /// Private methods 91 | 92 | private void createAccount() { 93 | showProgress(true); 94 | 95 | String email = mEmail.getText().toString(); 96 | String password = mPassword.getText().toString(); 97 | 98 | mAuth.createUserWithEmailAndPassword(email, password).addOnCompleteListener(getActivity(), new OnCompleteListener() { 99 | @Override 100 | public void onComplete(@NonNull Task task) { 101 | 102 | if(!task.isSuccessful()) { 103 | Toast.makeText(getContext(), R.string.error_create_account, Toast.LENGTH_SHORT).show(); 104 | } else { 105 | Utils.saveLocalUser(getContext(), 106 | mUsername.getText().toString(), 107 | mEmail.getText().toString(), 108 | task.getResult().getUser().getUid()); 109 | 110 | mCallback.openChat(); 111 | } 112 | 113 | showProgress(false); 114 | Utils.closeKeyboard(getContext(), mEmail); 115 | } 116 | }); 117 | } 118 | 119 | private void showProgress(boolean show) { 120 | mProgressView.setVisibility(show ? View.VISIBLE : View.GONE); 121 | mCreateForm.setVisibility(show ? View.GONE : View.VISIBLE); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /app/src/main/java/com/dekoservidoni/firebasechat/fragments/LoginFragment.java: -------------------------------------------------------------------------------- 1 | package com.dekoservidoni.firebasechat.fragments; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.annotation.NonNull; 6 | import android.support.annotation.Nullable; 7 | import android.support.v4.app.Fragment; 8 | import android.text.TextUtils; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.AutoCompleteTextView; 13 | import android.widget.Button; 14 | import android.widget.EditText; 15 | import android.widget.Toast; 16 | 17 | import com.dekoservidoni.firebasechat.ActivityCallback; 18 | import com.dekoservidoni.firebasechat.R; 19 | import com.dekoservidoni.firebasechat.utils.Constants; 20 | import com.dekoservidoni.firebasechat.utils.Utils; 21 | import com.google.android.gms.tasks.OnFailureListener; 22 | import com.google.android.gms.tasks.OnSuccessListener; 23 | import com.google.firebase.auth.AuthResult; 24 | import com.google.firebase.auth.FirebaseAuth; 25 | 26 | /** 27 | * Class responsible to be the login screen of the application 28 | */ 29 | public class LoginFragment extends Fragment { 30 | 31 | /** UI Components **/ 32 | private AutoCompleteTextView mEmail; 33 | private EditText mPassword; 34 | private View mProgressView; 35 | private View mLoginFormView; 36 | 37 | /** Activity callback **/ 38 | private ActivityCallback mCallback; 39 | 40 | /** Firebase objects **/ 41 | private FirebaseAuth mAuth; 42 | 43 | /** 44 | * Create a instance of this fragment 45 | * 46 | * @return fragment instance 47 | */ 48 | public static LoginFragment newInstance() { 49 | return new LoginFragment(); 50 | } 51 | 52 | /// Lifecycle methods 53 | 54 | @Nullable 55 | @Override 56 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 57 | View root = inflater.inflate(R.layout.fragment_login, container, false); 58 | 59 | mEmail = (AutoCompleteTextView) root.findViewById(R.id.username); 60 | mPassword = (EditText) root.findViewById(R.id.password); 61 | 62 | final Button signInButton = (Button) root.findViewById(R.id.sign_in_button); 63 | signInButton.setOnClickListener(new View.OnClickListener() { 64 | @Override 65 | public void onClick(View view) { 66 | Utils.closeKeyboard(getContext(), signInButton); 67 | attemptLogin(); 68 | } 69 | }); 70 | 71 | final Button createAccount = (Button) root.findViewById(R.id.create_account_button); 72 | createAccount.setOnClickListener(new View.OnClickListener() { 73 | @Override 74 | public void onClick(View view) { 75 | Utils.closeKeyboard(getContext(), createAccount); 76 | mCallback.openCreateAccount(); 77 | } 78 | }); 79 | 80 | mLoginFormView = root.findViewById(R.id.login_form); 81 | mProgressView = root.findViewById(R.id.login_progress); 82 | 83 | mAuth = FirebaseAuth.getInstance(); 84 | Utils.closeKeyboard(getContext(), mEmail); 85 | 86 | return root; 87 | } 88 | 89 | @Override 90 | public void onAttach(Context context) { 91 | super.onAttach(context); 92 | mCallback = (ActivityCallback) context; 93 | } 94 | 95 | @Override 96 | public void onDetach() { 97 | super.onDetach(); 98 | mCallback = null; 99 | } 100 | 101 | /// Private methods 102 | 103 | private void attemptLogin() { 104 | 105 | // Reset errors. 106 | mEmail.setError(null); 107 | mPassword.setError(null); 108 | 109 | // Store values at the time of the login attempt. 110 | String username = mEmail.getText().toString(); 111 | String password = mPassword.getText().toString(); 112 | 113 | // Check for a valid email address. 114 | if (TextUtils.isEmpty(username)) { 115 | mEmail.setError(getString(R.string.error_empty)); 116 | mEmail.requestFocus(); 117 | return; 118 | } 119 | 120 | if (TextUtils.isEmpty(password)) { 121 | mPassword.setError(getString(R.string.error_password)); 122 | mPassword.requestFocus(); 123 | return; 124 | } 125 | 126 | login(); 127 | } 128 | 129 | private void login() { 130 | showProgress(true); 131 | 132 | String email = mEmail.getText().toString(); 133 | String password = mPassword.getText().toString(); 134 | 135 | mAuth.signInWithEmailAndPassword(email, password).addOnSuccessListener(new OnSuccessListener() { 136 | @Override 137 | public void onSuccess(AuthResult authResult) { 138 | if (mCallback != null) { 139 | Utils.saveLocalUser(getContext(), Constants.DEFAULT_USER, 140 | mEmail.getText().toString(), 141 | authResult.getUser().getUid()); 142 | 143 | mCallback.openChat(); 144 | } 145 | } 146 | }).addOnFailureListener(new OnFailureListener() { 147 | @Override 148 | public void onFailure(@NonNull Exception e) { 149 | showProgress(false); 150 | Toast.makeText(getContext(), e.getLocalizedMessage(), Toast.LENGTH_LONG).show(); 151 | } 152 | }); 153 | } 154 | 155 | private void showProgress(boolean show) { 156 | mProgressView.setVisibility(show ? View.VISIBLE : View.GONE); 157 | mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /app/src/main/java/com/dekoservidoni/firebasechat/models/ChatData.java: -------------------------------------------------------------------------------- 1 | package com.dekoservidoni.firebasechat.models; 2 | 3 | /** 4 | * Class responsible to hold the name and the message to the user 5 | * to send to firebase 6 | */ 7 | public class ChatData { 8 | 9 | private String mName; 10 | private String mId; 11 | private String mMessage; 12 | 13 | public ChatData() { 14 | // empty constructor 15 | } 16 | 17 | public String getName() { 18 | return mName; 19 | } 20 | 21 | public void setName(String name) { 22 | mName = name; 23 | } 24 | 25 | public String getId() { 26 | return mId; 27 | } 28 | 29 | public String getMessage() { 30 | return mMessage; 31 | } 32 | 33 | public void setMessage(String message) { 34 | mMessage = message; 35 | } 36 | 37 | public void setId(String id) { 38 | mId = id; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/dekoservidoni/firebasechat/utils/Constants.java: -------------------------------------------------------------------------------- 1 | package com.dekoservidoni.firebasechat.utils; 2 | 3 | /** 4 | * Interface responsible to hold all the constants 5 | * of the application 6 | */ 7 | public interface Constants { 8 | 9 | String SHARED_PREFERENCES = "APP_PREFS"; 10 | 11 | String PREFERENCES_USER_NAME = "username"; 12 | String PREFERENCES_USER_EMAIL = "email"; 13 | String PREFERENCES_USER_ID = "id"; 14 | 15 | String DATABASE_NAME = "chat"; 16 | 17 | String LOG_TAG = "FirebaseChat"; 18 | 19 | String DEFAULT_USER = "User"; 20 | String DEFAULT_ID = "0000"; 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/dekoservidoni/firebasechat/utils/Utils.java: -------------------------------------------------------------------------------- 1 | package com.dekoservidoni.firebasechat.utils; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | import android.view.View; 6 | import android.view.inputmethod.InputMethodManager; 7 | 8 | import java.text.DateFormat; 9 | import java.util.Date; 10 | 11 | /** 12 | * Class responsible to hold all the utility 13 | * methods of the application 14 | */ 15 | public class Utils { 16 | 17 | public static void closeKeyboard(Context context, View view) { 18 | InputMethodManager manager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); 19 | manager.hideSoftInputFromWindow(view.getWindowToken(), 0); 20 | } 21 | 22 | public static void saveLocalUser(Context context, String username, String email, String id) { 23 | SharedPreferences sharedPreferences = context.getSharedPreferences(Constants.SHARED_PREFERENCES, Context.MODE_PRIVATE); 24 | sharedPreferences.edit() 25 | .putString(Constants.PREFERENCES_USER_NAME,username) 26 | .putString(Constants.PREFERENCES_USER_EMAIL,email) 27 | .putString(Constants.PREFERENCES_USER_ID,id) 28 | .apply(); 29 | 30 | } 31 | 32 | public static String getLocalUsername(Context context) { 33 | SharedPreferences sharedPreferences = context.getSharedPreferences(Constants.SHARED_PREFERENCES, Context.MODE_PRIVATE); 34 | return sharedPreferences.getString(Constants.PREFERENCES_USER_NAME, Constants.DEFAULT_USER); 35 | } 36 | 37 | public static String getLocalUserId(Context context) { 38 | SharedPreferences sharedPreferences = context.getSharedPreferences(Constants.SHARED_PREFERENCES, Context.MODE_PRIVATE); 39 | return sharedPreferences.getString(Constants.PREFERENCES_USER_ID, Constants.DEFAULT_ID); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_initial.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_chat.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | 15 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_create_account.xml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 19 | 20 | 24 | 25 | 30 | 31 | 34 | 35 | 42 | 43 | 44 | 45 | 48 | 49 | 56 | 57 | 58 | 59 | 66 | 67 |