Building a Social Media App (Part 1)

Building a Social Media App (Part 1)

Are you interested in building your own social media app, complete with real-time database functionality? Look no further! In this blog post, I'll walk you through the process of creating a fully functional social media app using Kotlin and Firebase's real-time database. Whether you're a beginner or an experienced developer, I've got you covered - this step-by-step guide will take you from start to finish, providing you with all the code and resources you need to create your own custom social media app. So if you're ready to dive in and start building, tune in to some music and let's get started!🥳

Creating a new project✅

So the very first step is to create a new project in Android Studio.

So I'll be naming the project Social Hive, you can name it anything you want. Also, we'll be using Kotlin in this project.

Create a basic layout for your app✅

Design a simple layout for your activity_main.xml, this will show a Sign-Up interface.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/welcomeTv"
        style="@style/TextAppearance.Material3.HeadlineMedium"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="50dp"
        android:fontFamily="@font/cantata_one"
        android:text="@string/welcome"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/nameLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="32dp"
        android:layout_marginEnd="16dp"
        app:boxCornerRadiusTopEnd="10dp"
        app:boxCornerRadiusTopStart="10dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/welcomeTv">

        <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/nameEt"
            style="@style/ThemeOverlay.Material3.TextInputEditText.OutlinedBox.Dense"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="@string/enter_your_name" />

    </com.google.android.material.textfield.TextInputLayout>

    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/emailLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="12dp"
        android:layout_marginEnd="16dp"
        app:boxCornerRadiusTopEnd="10dp"
        app:boxCornerRadiusTopStart="10dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/nameLayout">

        <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/emailEt"
            style="@style/ThemeOverlay.Material3.TextInputEditText.OutlinedBox.Dense"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="@string/enter_your_email" />
    </com.google.android.material.textfield.TextInputLayout>

    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/passwordLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="12dp"
        android:layout_marginEnd="16dp"
        app:boxCornerRadiusTopEnd="10dp"
        app:boxCornerRadiusTopStart="10dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/emailLayout"
        app:passwordToggleEnabled="true">

        <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/passwordEt"
            style="@style/ThemeOverlay.Material3.TextInputEditText.OutlinedBox.Dense"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="@string/enter_password" />
    </com.google.android.material.textfield.TextInputLayout>

    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/rePasswordLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="12dp"
        android:layout_marginEnd="16dp"
        app:boxCornerRadiusTopEnd="10dp"
        app:boxCornerRadiusTopStart="10dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/passwordLayout"
        app:passwordToggleEnabled="true">

        <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/rePasswordEt"
            style="@style/ThemeOverlay.Material3.TextInputEditText.OutlinedBox.Dense"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="@string/re_enter_your_password" />
    </com.google.android.material.textfield.TextInputLayout>

    <com.google.android.material.button.MaterialButton
        android:id="@+id/createAccBtn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="24dp"
        android:layout_marginEnd="16dp"
        android:paddingTop="15dp"
        android:paddingBottom="15dp"
        android:text="@string/create_account"
        app:cornerRadius="10dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/rePasswordLayout" />

    <LinearLayout
        android:id="@+id/linearLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="24dp"
        android:layout_marginEnd="16dp"
        android:orientation="horizontal"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/createAccBtn">

        <View
            android:id="@+id/view"
            android:layout_width="100dp"
            android:layout_height="1dp"
            android:layout_gravity="center"
            android:layout_marginEnd="-10dp"
            android:layout_weight="1"
            android:background="@android:color/darker_gray" />

        <TextView
            android:id="@+id/textView3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="@string/or_login_using"
            android:textAlignment="center" />

        <View
            android:id="@+id/view2"
            android:layout_width="100dp"
            android:layout_height="1dp"
            android:layout_gravity="center"
            android:layout_marginStart="-10dp"
            android:layout_weight="1"
            android:background="@android:color/darker_gray" />
    </LinearLayout>

    <com.google.android.material.button.MaterialButton
        android:id="@+id/googleBtn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="24dp"
        android:layout_marginEnd="16dp"
        android:paddingTop="10dp"
        android:paddingBottom="10dp"
        android:text="@string/google"
        android:textColor="@color/white"
        app:backgroundTint="@android:color/transparent"
        app:cornerRadius="10dp"
        app:icon="@drawable/google_icon"
        app:iconGravity="textStart"
        app:iconSize="30dp"
        app:iconTint="@null"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/linearLayout"
        app:strokeColor="@android:color/darker_gray"
        app:strokeWidth="1dp" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:orientation="horizontal"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/googleBtn">

        <TextView
            android:id="@+id/textView5"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="@string/already_have_an_account"
            android:textAlignment="textEnd"
            android:textSize="16sp" />

        <TextView
            android:id="@+id/signInTv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="4dp"
            android:layout_weight="1"
            android:text="@string/sign_in"
            android:textColor="#5462BF"
            android:textSize="16sp" />
    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

Enable View Binding✅

Enable view binding by adding the below code to your build.gradle(app) file -

    buildFeatures{
        viewBinding = true
    }

Also, make the necessary changes in the MainActivity.kt file

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
    }
}

Add Firebase to your project✅

  • Go to Tools>Firebase

  • Then navigate to Authentication

  • Click on Authenticate using Google

  • Then, the Firebase assistant will show you some steps. Click on Connect to Firebase.

  • It will redirect you to the Firebase Console.

  • Then click on Add Project

  • Click Continue

  • Continue again, then you'll get to the 3rd step, here you can select your Google account and Create Project.

  • Then it will ask you to Connect your app to Firebase, and click Continue.

  • Now, your project is connected to Firebase.

  • Go back to Android Studio, now you're on the 2nd step click on Add the firebase Authentication SDK to your app.

  • It will prompt you to accept changes, click Accept Changes.

  • It will add all the dependencies required for the authentication and firebase.

  • Now you need to add SHA-1 keys to your app in the Firebase Console.

  • Then go to the gear icon>Project settings scroll down and you will see an option for downloading the google-services.json file. Download that.

  • You need to add this file now in your app. You can search in android studio by Double Shift and search for google-services.json and then replace the contents of the file with the one you downloaded.

  • Go back to your Firebase console>Build>Authentication.

  • Under Sign-in methods, enable email/password.

  • Add new provider>Google, add support email id and enable this.

Yayyyyy! now we are all set for implementing the authentication😄

Adding code for Email Authentication✅

So, I have explained all the code in the comments

package com.example.socialhive

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import com.example.socialhive.databinding.ActivityMainBinding
import com.google.firebase.auth.FirebaseAuth

class MainActivity : AppCompatActivity() {

    // here we'll instantiate all variables
    private lateinit var binding: ActivityMainBinding

    // creating var to initialize Firebase auth
    private lateinit var auth: FirebaseAuth

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // initializing the auth variable
        auth = FirebaseAuth.getInstance()
        // adding on click listener to create account button
        binding.createAccBtn.setOnClickListener {
            // making separate method for creating new account for user
            logInUserWithEmail()
        }

    }

    private fun logInUserWithEmail() {
        // getting the text from all the edit text fields in strings
        val name = binding.nameEt.text.toString()
        val email = binding.emailEt.text.toString()
        val password = binding.passwordEt.text.toString()
        val rePassword = binding.rePasswordEt.text.toString()

        // creating a var which will tell you if all the input fields are valid
        var isValid = false

        if (!isValid) { // checking if all are valid, if not showing the error message

            if (name.isEmpty()) {
                binding.nameEt.error = "Please enter your name"
                binding.nameEt.requestFocus()
            }
            if (email.isEmpty()) {
                binding.emailEt.error = "Please enter your email"
                binding.emailEt.requestFocus()
            }
            if (password.isEmpty()) {
                binding.passwordEt.error = "Please enter your password"
                binding.passwordEt.requestFocus()
            }
            if (name.isEmpty()) {
                binding.rePasswordEt.error = "Please enter your password again"
                binding.rePasswordEt.requestFocus()
            }
            if (password != rePassword) {
                binding.rePasswordEt.error = "Passwords don't match"
                binding.rePasswordEt.requestFocus()
            }
            isValid = true
        }
        if (isValid) { // if isValid true, then creating a new user
            auth.createUserWithEmailAndPassword(email, password).addOnCompleteListener {
                if (it.isSuccessful) {
                    // storing the current user in user var
                    val user = auth.currentUser

                    // now signing in the user
                    auth.signInWithEmailAndPassword(email, password).addOnCompleteListener {
                        if (it.isSuccessful) {
                            // adding intent if user is successfully created then pass the user to HomeActivity
                            val intent = Intent(this, HomeActivity::class.java)
                            // passing user's info through intent, so we can use that later
                            intent.putExtra("email", user?.email)
                            intent.putExtra("name", user?.displayName)
                            intent.putExtra("profile", user?.photoUrl)
                            startActivity(intent)

                        } else {
                            Toast.makeText(
                                this,
                                "Login error : ${it.exception.toString()}",
                                Toast.LENGTH_SHORT
                            )
                                .show()
                        }
                    }
                } else {
                    Toast.makeText(
                        this,
                        "Sign-up error : ${it.exception.toString()}",
                        Toast.LENGTH_SHORT
                    )
                        .show()
                }

            }

        }
    }
}

And yes you need to make a new activity, HomeActivity by right-clicking on app>new>activity>Empty Activity.

After that if you run your app, add all the credentials and then click on Create Account button, it will navigate you to the HomeActivity.

Also, you can see the user's details who logged in to the app in Firebase Console.

Hurrayyyyy! The first milestone is completed🥳

You can add another activity, Login Activity which will log in the users who have already created the account.

Now we will further see how to create a user's new account by Google.

Adding code for Google Authentication✅

Firstly we will create a new variable

// creating var to instantiate google sign in client
private lateinit var googleSignInClient : GoogleSignInClient

Then we will add this code to the onCreate() method -

// initializing the auth variable
auth = FirebaseAuth.getInstance()
// we are creating a variable for Google Sign in options
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
    .requestIdToken(getString(R.string.default_web_client_id)) // -> it may show error on default_web_client_id, it will disappear automatically
    .requestEmail()
    .build()

// initializing google sign in client
googleSignInClient = GoogleSignIn.getClient(this, gso)

// adding on click listener to the google button
binding.googleBtn.setOnClickListener {
    // also creating a separate method for google sign in
    googleSignIn()
}

Then we will create the googleSignIn() method and all other necessary methods outside the onCreate() method

private fun googleSignIn() {
    // creating a signInIntent which we can use later while signingIn
    val signInIntent = googleSignInClient.signInIntent
    launcher.launch(signInIntent)
}

// this will get signed in account from the intent and handle the task in between
private val launcher =
    registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            val task = GoogleSignIn.getSignedInAccountFromIntent(result.data)
            handleResults(task)
        }
    }

// this method will handle the task after the sign in with user is completed
private fun handleResults(task: Task<GoogleSignInAccount>) {
    if (task.isSuccessful) {
        val account: GoogleSignInAccount? = task.result
        if (account!=null){
            updateUI(account)
        }

    } else {
        Toast.makeText(this, task.exception.toString(), Toast.LENGTH_SHORT).show()
    }
}

// this will update the UI according to the tasks
private fun updateUI(account: GoogleSignInAccount) {
    val credential = GoogleAuthProvider.getCredential(account.idToken, null)
    auth.signInWithCredential(credential).addOnCompleteListener {
        if (it.isSuccessful) {
            val intent: Intent = Intent(this, HomeActivity::class.java)
            intent.putExtra("gmail", account.email)
            intent.putExtra("gName", account.displayName)
            intent.putExtra("gProfile", account.photoUrl)
            startActivity(intent)
        } else {
            Toast.makeText(this, it.exception.toString(), Toast.LENGTH_LONG).show()
        }
    }

}

After that, you can make some changes in the HomeActivity.kt

package com.example.socialhive

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.socialhive.databinding.ActivityHomeBinding
import com.google.firebase.auth.FirebaseAuth

class HomeActivity : AppCompatActivity() {
// again instantiate these vars
    private lateinit var auth: FirebaseAuth
    private lateinit var binding: ActivityHomeBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityHomeBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // initializing auth
        auth = FirebaseAuth.getInstance()

        // getting data from the intents passed
        val email = intent.getStringExtra("email")
        val name = intent.getStringExtra("name")
        val profile = intent.getStringExtra("profile")
        val gName = intent.getStringExtra("gName")
        val gmail = intent.getStringExtra("gmail")
        val gProfile = intent.getStringExtra("gProfile")

        // changing the text to show the name of user got from the google account
        binding.textView.text = gName
    }
}

Also, I have added a textview in the activity_home.xml to show the user's name -

<TextView
    android:id="@+id/textView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="TextView"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

So, another milestone is achieved! Congrats, if you have come this far🥳

In the next part of this blog, we will use the Real-Time database to do CRUD operations on the posts.

And if you want the whole code, you can check this code out on my GitHub.