How to Create Android Custom Calendar View with Events

In this tutorial, we are going to learn how to create android custom calendar view with events stored in local SQLite database. If you have used the default android calendar view widget, you will understand that you cannot do much with it.

In other to create a flexible android custom calendar view in your application, you need to create a custom view. In android, there are many View widgets that are provided to us to use freely. But when you cannot find a default view widget that can do what you need then there are many options available to you.

  • You can create a custom calender view by extending the default calendar Veiw that android has provided.
  • You can create your own entire custom calendar view by extending the android View. In this case you will need to override the View.onDraw() method and probably the View.onMeasure() method. You can also decide to override other on… methods for event listener.
  • Create a compound component view by wrapping different other view widgets as a single component which can be reuse.

In this example, we are going to use the third option by create a compound component View that will represent our android custom calendar.

If you are interested in learning how to create a custom view by overriding the View onDraw() and onMeasure() methods, I will suggest you read my post on How to Create a Custom Piano App in Android.

Also, the events for this android application will be store in a local SQLite database but if you want to use your default android Calendar events then you should check my alternative post on using android default calendar events and calendar provider API.

What we are going to do is to use TextView, ImageView and GridView to draw a calendar view. The View widgets will be wrapped in a Linearlayout that is we are going to create a custom calendar view by extending the default android Linearlayout.

In other to get a visual understanding of what we are going to create in this android tutorial, I have add below some screen shots from the application.

 

SOME SCREENSHOT FROM THE APPLICATION

android custom calendar event

 

CREATE NEW ANDROID PROJECT

Lets start to soil our hands in code. Start up your IDE. For this tutorial, I am using the following tools and environment, feel free to use what works for you.

Windows 10

Android Studio

Sony Xperia ZL

Min SDK 14

Target SDK 24

To create a new android application project, follow the steps as stipulated below.

Go to File menu

Click on New menu

Click on Android Application

Enter Project name: AndroidCustomCalendar

Package: com.inducesmile.androidcustomcalendar

Select Empty Activity

Name your activity: MainActivity

Keep other default selections

Continue to click on next button until Finish button is active, then click on Finish Button.

Now that we have created our android project, we are going to add some library dependencies to our app level build.gradle. Since we are going to store our events in a database, we are going to use a database helper library and also Joda-time for date manipulation.

Open you app level build.gradle file and add the code below.

apply plugin: 'com.android.application'
apply plugin: 'com.android.application'
android {
    compileSdkVersion 24
    buildToolsVersion "24.0.1"
    defaultConfig {
        applicationId "com.inducesmile.androidcustomcalendar"
        minSdkVersion 14
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:24.2.1'
    testCompile 'junit:junit:4.12'
    compile 'com.readystatesoftware.sqliteasset:sqliteassethelper:+'
    compile 'joda-time:joda-time:2.9.4'
}

 

STRINGS.XML

We are going to update our project strings.xml file located in the values folder inside the res folder. Open the file and add the code below to it.

<resources>
    <string name="app_name">Android Custom Calendar</string>
    <string name="current_date">June, 2016</string>
    <string name="add_event">ADD CALENDAR EVENT</string>
    <string name="sun">SUN</string>
    <string name="mon">MON</string>
    <string name="tue">TUE</string>
    <string name="wed">WED</string>
    <string name="thu">THU</string>
    <string name="fri">FRI</string>
    <string name="sat">SAT</string>
    <string name="last_date">30</string>
</resources>

 

COLORS.XML

Open the colors.xml file in the same location as the strings.xml file and add the code below to the file.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>
    <color name="colorWhite">#ffffff</color>
    <color name="colorBlack">#000000</color>
</resources>

 

Create calendar_layout.xml

In your project layout folder under the res folder, we are going to create a layout file for our custom calendar application. The layout file will use a LinearLayout as it root ViewGroup and will contain TextView, ImageView and GridView.

The GridView will have 7 columns that will represent the seven days in a calendar week. Right click on the layout folder and select New and XML layout file, name the layout file calendar_layout.xml.

Open the layout file and add the code below to it.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_custom_calendar"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingTop="8dp"
        android:paddingBottom="8dp"
        android:background="@color/colorAccent"
        android:orientation="horizontal">
        <ImageView
            android:id="@+id/previous_month"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_gravity="left"
            android:contentDescription="@string/app_name"
            android:src="@drawable/left_arrow"
            android:layout_weight="1"/>
        <TextView
            android:id="@+id/display_current_date"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:textColor="@color/colorPrimaryDark"
            android:text="@string/current_date"
            android:layout_marginTop="4dp"
            android:textStyle="bold"
            android:layout_weight="3"/>
        <ImageView
            android:id="@+id/next_month"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_gravity="left"
            android:contentDescription="@string/app_name"
            android:src="@drawable/right_arrow"
            android:layout_weight="1"/>
    </LinearLayout>
    <Button
        android:id="@+id/add_calendar_event"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textStyle="bold"
        android:textSize="12sp"
        android:text="@string/add_event"
        android:gravity="center"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorPrimaryDark"
        android:paddingBottom="4dp"
        android:paddingTop="4dp"
        android:orientation="horizontal">
        <TextView
            android:id="@+id/sun"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:textColor="@color/colorWhite"
            android:text="@string/sun"
            android:layout_marginTop="4dp"
            android:textStyle="bold"
            android:layout_weight="1"/>
        <TextView
            android:id="@+id/mon"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:textColor="@color/colorWhite"
            android:text="@string/mon"
            android:layout_marginTop="4dp"
            android:textStyle="bold"
            android:layout_weight="1"/>
        <TextView
            android:id="@+id/tue"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:textColor="@color/colorWhite"
            android:text="@string/tue"
            android:layout_marginTop="4dp"
            android:textStyle="bold"
            android:layout_weight="1"/>
        <TextView
            android:id="@+id/wed"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:textColor="@color/colorWhite"
            android:text="@string/wed"
            android:layout_marginTop="4dp"
            android:textStyle="bold"
            android:layout_weight="1"/>
        <TextView
            android:id="@+id/thu"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:textColor="@color/colorWhite"
            android:text="@string/thu"
            android:layout_marginTop="4dp"
            android:textStyle="bold"
            android:layout_weight="1"/>
        <TextView
            android:id="@+id/fri"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:textColor="@color/colorWhite"
            android:text="@string/fri"
            android:layout_marginTop="4dp"
            android:textStyle="bold"
            android:layout_weight="1"/>
        <TextView
            android:id="@+id/sat"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:textColor="@color/colorWhite"
            android:text="@string/sat"
            android:layout_marginTop="4dp"
            android:textStyle="bold"
            android:layout_weight="1"/>
    </LinearLayout>
    <GridView
        android:id="@+id/calendar_grid"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:numColumns="7"/>
</LinearLayout>

 

Create CalendarCustomView.java as a Compound Component

We are going to start with creating our custom calendar view. First, create a new java file in your project package folder and name it CalendarCustomView.java.

Open the file in your IDE, let the class extends from LinearLayout and it will override the parent constructor.

This class is going to use the LayoutInflater class to inflate the layout file we have created above. Once the layout has been inflated, we can get access to the instances of the view widgets used in the layout file.

The ImageView widgets that represents the previous and next month in the calendar interface are wire with click events which will help us to navigate through the calendar application.

Also, in other to get the actual date in a cell in the calendar, the GridView object will make use of an adapter which will bind the GridView interface with the calender day data source.

Finally, we will use a Calendar instance to calculate the data to be shown on the calendar as it is used.

Open this file and add the code below to it.

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.inducesmile.androidcustomcalendar.database.DatabaseQuery;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
public class CalendarCustomView extends LinearLayout{
    private static final String TAG = CalendarCustomView.class.getSimpleName();
    private ImageView previousButton, nextButton;
    private TextView currentDate;
    private GridView calendarGridView;
    private Button addEventButton;
    private static final int MAX_CALENDAR_COLUMN = 42;
    private int month, year;
    private SimpleDateFormat formatter = new SimpleDateFormat("MMMM yyyy", Locale.ENGLISH);
    private Calendar cal = Calendar.getInstance(Locale.ENGLISH);
    private Context context;
    private GridAdapter mAdapter;
    private DatabaseQuery mQuery;
    public CalendarCustomView(Context context) {
        super(context);
    }
    public CalendarCustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        initializeUILayout();
        setUpCalendarAdapter();
        setPreviousButtonClickEvent();
        setNextButtonClickEvent();
        setGridCellClickEvents();
        Log.d(TAG, "I need to call this method");
    }
    public CalendarCustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    private void initializeUILayout(){
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
        View view = inflater.inflate(R.layout.calendar_layout, this);
        previousButton = (ImageView)view.findViewById(R.id.previous_month);
        nextButton = (ImageView)view.findViewById(R.id.next_month);
        currentDate = (TextView)view.findViewById(R.id.display_current_date);
        addEventButton = (Button)view.findViewById(R.id.add_calendar_event);
        calendarGridView = (GridView)view.findViewById(R.id.calendar_grid);
    }
    private void setPreviousButtonClickEvent(){
        previousButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                cal.add(Calendar.MONTH, -1);
                setUpCalendarAdapter();
            }
        });
    }
    private void setNextButtonClickEvent(){
        nextButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                cal.add(Calendar.MONTH, 1);
                setUpCalendarAdapter();
            }
        });
    }
    private void setGridCellClickEvents(){
        calendarGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Toast.makeText(context, "Clicked " + position, Toast.LENGTH_LONG).show();
            }
        });
    }
    private void setUpCalendarAdapter(){
        List<Date> dayValueInCells = new ArrayList<Date>();
        mQuery = new DatabaseQuery(context);
        List<EventObjects> mEvents = mQuery.getAllFutureEvents();
        Calendar mCal = (Calendar)cal.clone();
        mCal.set(Calendar.DAY_OF_MONTH, 1);
        int firstDayOfTheMonth = mCal.get(Calendar.DAY_OF_WEEK) - 1;
        mCal.add(Calendar.DAY_OF_MONTH, -firstDayOfTheMonth);
        while(dayValueInCells.size() < MAX_CALENDAR_COLUMN){
            dayValueInCells.add(mCal.getTime());
            mCal.add(Calendar.DAY_OF_MONTH, 1);
        }
        Log.d(TAG, "Number of date " + dayValueInCells.size());
        String sDate = formatter.format(cal.getTime());
        currentDate.setText(sDate);
        mAdapter = new GridAdapter(context, dayValueInCells, cal, mEvents);
        calendarGridView.setAdapter(mAdapter);
    }
}

 

Create GridAdapter.java

In other to bind data to the GridView widget we added in our custom view, we will need to set an adapter to it with will bind to its data source.

In your project folder, create a new java file and name the file GridAdapter.java. The class will extend from default android ArrayAdapter.

The adapter class will also override the getView() method where the view interface will be created and data bind to it. Also the getCount(), getItem() and getPosition() methods are overridden.

The GridAdapter class will inflate a layout file that will represent a single in the GridView layout. Also the data source for the cells are passed as a parameter with stored events in the database.

In other to see where the days in the current month starts and ends, we will use a different color and grey-out other lending or trailing days in the calendar since the number of cells in each view is 42.

Open this file and copy and paste the code below to it.

import android.content.Context;

import android.graphics.Color;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
public class GridAdapter extends ArrayAdapter {
    private static final String TAG = GridAdapter.class.getSimpleName();
    private LayoutInflater mInflater;
    private List<Date> monthlyDates;
    private Calendar currentDate;
    private List<EventObjects> allEvents;
    public GridAdapter(Context context, List<Date> monthlyDates, Calendar currentDate, List<EventObjects> allEvents) {
        super(context, R.layout.single_cell_layout);
        this.monthlyDates = monthlyDates;
        this.currentDate = currentDate;
        this.allEvents = allEvents;
        mInflater = LayoutInflater.from(context);
    }
    @NonNull
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Date mDate = monthlyDates.get(position);
        Calendar dateCal = Calendar.getInstance();
        dateCal.setTime(mDate);
        int dayValue = dateCal.get(Calendar.DAY_OF_MONTH);
        int displayMonth = dateCal.get(Calendar.MONTH) + 1;
        int displayYear = dateCal.get(Calendar.YEAR);
        int currentMonth = currentDate.get(Calendar.MONTH) + 1;
        int currentYear = currentDate.get(Calendar.YEAR);
        View view = convertView;
        if(view == null){
            view = mInflater.inflate(R.layout.single_cell_layout, parent, false);
        }
        if(displayMonth == currentMonth && displayYear == currentYear){
            view.setBackgroundColor(Color.parseColor("#FF5733"));
        }else{
            view.setBackgroundColor(Color.parseColor("#cccccc"));
        }
        //Add day to calendar
        TextView cellNumber = (TextView)view.findViewById(R.id.calendar_date_id);
        cellNumber.setText(String.valueOf(dayValue));
        //Add events to the calendar
        TextView eventIndicator = (TextView)view.findViewById(R.id.event_id);
        Calendar eventCalendar = Calendar.getInstance();
        for(int i = 0; i < allEvents.size(); i++){
            eventCalendar.setTime(allEvents.get(i).getDate());
            if(dayValue == eventCalendar.get(Calendar.DAY_OF_MONTH) && displayMonth == eventCalendar.get(Calendar.MONTH) + 1
                    && displayYear == eventCalendar.get(Calendar.YEAR)){
                eventIndicator.setBackgroundColor(Color.parseColor("#FF4081"));
            }
        }
        return view;
    }
    @Override
    public int getCount() {
        return monthlyDates.size();
    }
    @Nullable
    @Override
    public Object getItem(int position) {
        return monthlyDates.get(position);
    }
    @Override
    public int getPosition(Object item) {
        return monthlyDates.indexOf(item);
    }
}

 

Create single_cell_layout.xml

As stated above, we will feed the GridAdapter with a layout that it will inflate that will represent each cell in the GridView.

Create a new layout file inside your project layout folder and name it single_cell_layout.xml.

The layout will wrap a TextView of current day of the month value and a LinearLayout that wraps a TextView that shows number of events present in a particular day of the month.

Open the layout file and add the code below.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="8dp">
    <TextView
        android:id="@+id/calendar_date_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="16sp"
        android:textStyle="bold"
        android:layout_gravity="center"
        android:text="@string/last_date"/>
    <LinearLayout
        android:id="@+id/event_wrapper"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="4dp"
        android:gravity="right"
        android:orientation="horizontal">
        <TextView
            android:id="@+id/event_id"
            android:layout_width="4dp"
            android:layout_height="4dp"/>
    </LinearLayout>
</LinearLayout>

 

Stored Calendar Events in SQLite Database

We are going to create different classes that will help use to work with sqlite database. We are opening to use an external sqlite manager software to create our database file outside our application.

Once we have created it, we will navigate to our project main file and create a new folder called assets. Inside the assets folder, create any folder named databases and the drop the database file in a zip format inside this folder.

Remember that we have add sqlite helper library when we initially created our project. What this library will do is to copy our database file, unzip it and move it to it normal location so that our application will still have access to it.

To create the database file, run the sqlite query below.

CREATE TABLE "events" ( `_id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, `message` TEXT NOT NULL, `reminder` TEXT NOT NULL, `end` TEXT );

We are going to use the classes below to manage our database.

 

Create Database.java

Create a new java file inside the database package folder. Name the file Database.java. Open the file and paste the code below.

import android.content.Context;
import com.readystatesoftware.sqliteasset.SQLiteAssetHelper;
public class Database extends SQLiteAssetHelper {
    private static final String DATABASE_NAMES = "events";
    private static final int DATABASE_VERSION = 3;
    public Database(Context context) {
        super(context, DATABASE_NAMES, null, DATABASE_VERSION);
    }
}

 

Create DatabaseObject.java

Follow the same process as above and add the code below to this file.

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
public class DatabaseObject {
    private static Database dbHelper;
    private SQLiteDatabase db;
    public DatabaseObject(Context context) {
        dbHelper = new Database(context);
        this.dbHelper.getWritableDatabase();
        this.db = dbHelper.getReadableDatabase();
    }
    public SQLiteDatabase getDbConnection(){
        return this.db;
    }
    public void closeDbConnection(){
        if(this.db != null){
            this.db.close();
        }
    }
}

 

Create DatabaseQuery.java

Follow the same process as above and add the code below to this file.

import android.content.Context;
import android.database.Cursor;
import com.inducesmile.androidcustomcalendar.EventObjects;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
public class DatabaseQuery extends DatabaseObject{
    private static final String TAG = Database.class.getSimpleName();
    public DatabaseQuery(Context context) {
        super(context);
    }
    public List<EventObjects> getAllFutureEvents(){
        Date dateToday = new Date();
        List<EventObjects> events = new ArrayList<>();
        String query = "select * from reminder";
        Cursor cursor = this.getDbConnection().rawQuery(query, null);
        if(cursor.moveToFirst()){
            do{
                int id = cursor.getInt(0);
                String message = cursor.getString(cursor.getColumnIndexOrThrow("message"));
                String startDate = cursor.getString(cursor.getColumnIndexOrThrow("start_date"));
                //convert start date to date object
                Date reminderDate = convertStringToDate(startDate);
                if(reminderDate.after(dateToday) || reminderDate.equals(dateToday)){
                    events.add(new EventObjects(id, message, reminderDate));
                }
            }while (cursor.moveToNext());
        }
        cursor.close();
        return events;
    }
    private Date convertStringToDate(String dateInString){
        DateFormat format = new SimpleDateFormat("d-MM-yyyy", Locale.ENGLISH);
        Date date = null;
        try {
            date = format.parse(dateInString);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }
}

 

Create EventObjects.java

We are going to create an entity bean object that will wrap a single row of the database and store it as an object.

Create a new java file and name it EventObjects.java. Open the file and add the code below.

import java.util.Date;
public class EventObjects {
    private int id;
    private String message;
    private Date date;
    public EventObjects(String message, Date date) {
        this.message = message;
        this.date = date;
    }
    public EventObjects(int id, String message, Date date) {
        this.date = date;
        this.message = message;
        this.id = id;
    }
    public int getId() {
        return id;
    }
    public String getMessage() {
        return message;
    }
    public Date getDate() {
        return date;
    }
}

 

How to use our Android Custom Calendar View

In other to make use of the custom calendar view we create in a layout file, we will open the MainActivity.java file and its corresponding layout file Android Studio created by default when we first created our android project.

You can rename the file and its layout file to  CustomCalendarActivity and activity_custom_calendar.xml.

Open the layout file and add our custom calendar view to it as shown below.

?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_custom_calendar"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.inducesmile.androidcustomcalendar.CustomCalendarActivity">
    <com.inducesmile.androidcustomcalendar.CalendarCustomView
        android:id="@+id/custom_calendar"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </com.inducesmile.androidcustomcalendar.CalendarCustomView>
</LinearLayout>

if you need more attributes in your custom calendar, you can go further to achieve it by defining some style attribute to your custom view. This is not covered in this tutorial but check my custom android piano application example.

For that activity class, add the following code to it.

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
public class CustomCalendarActivity extends AppCompatActivity {
    private static final String TAG = CustomCalendarActivity.class.getSimpleName();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_custom_calendar);
        CalendarCustomView mView = (CalendarCustomView)findViewById(R.id.custom_calendar);
    }
}

This brings us to the end of this tutorial. I hope that you have learn something. Run your app and see for yourself.

You can download the code for this tutorial below. If you are having hard time downloading the tutorial, kindly contact me.

Remember to subscribe with your email address to be among the first to receive my new android blog post once it is published.

70 Comments

    • Inducesmile
        • Inducesmile
    • Inducesmile
    • Inducesmile
    • Inducesmile
  1. Inducesmile
    • Inducesmile
    • Inducesmile
    • Inducesmile
    • Inducesmile

Add a Comment