Jan
Jan

Reputation: 11

why isn't my program displaying february 2016 and following months correctly?

I am trying to create a simple calendar for android. It is supposed to show one month at a time and list associated events according to a selected day. I am stuck now on the implementation of the calendar UI since it doesn't list february 2016 and following months correctly.

instead of 29 days it lists 28 and also the listing of february starts on sunday instead of monday. can someone please take a look at my program and help me?

I suspect the error in the following lines:

// init temporary calendar to monday, first day of displayed month
Calendar calx= getCalendar(year, month, 1);
// get WEEK_OF_YEAR of first Day of Month
int firstWeek = calx.get(Calendar.WEEK_OF_YEAR);
// Set DAY_OF_WEEK to Monday
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
// Set WEEK_OF_YEAR to first week the month is part of
cal.set(Calendar.WEEK_OF_YEAR, firstWeek);

I hope not to offend anyone by posting my complete program, but i am really unsure where the bug is crawling........

drawable/circle_today.xml:

<?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android">
        <solid android:color="#ffff00" />
        <corners
            android:topLeftRadius="30dp"
            android:topRightRadius="30dp"
            android:bottomLeftRadius="30dp"
            android:bottomRightRadius="30dp"
            />
    </shape>

drawable/circle_selected.xml:

<?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android">
        <solid android:color="#00ff00" />
        <corners
            android:topLeftRadius="30dp"
            android:topRightRadius="30dp"
            android:bottomLeftRadius="30dp"
            android:bottomRightRadius="30dp"
            />
    </shape>

layout/activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <TableLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:id="@+id/tableLayout"></TableLayout>

    <ListView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/listView"
        android:layout_below="@+id/tableLayout"
        android:layout_centerHorizontal="true" />

</RelativeLayout>

MainActivity.java:

import android.content.Intent;
import android.graphics.Color;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.AppCompatActivity;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;

public class MainActivity extends AppCompatActivity {
// TableLayout which holds the calendar matrix
private TableLayout calendarTable;
// list for future use as list of events of selected day
private ListView dayList;
//LIST OF ARRAY STRINGS WHICH WILL SERVE AS LIST ITEMS
ArrayList<String> listItems=new ArrayList<String>();
//DEFINING A STRING ADAPTER WHICH WILL HANDLE THE DATA OF THE LISTVIEW
ArrayAdapter<String> adapter;
// today stays today for the complete lifecycle of MainActivity
private int today;
// thisMonth stays thisMonth for the complete lifecycle of MainActivity
private int thisMonth;
// selectedDay changes onClick
private int selectedDay;
// month changes onClick on day of other month
private int month;
// year changes when other month either is january or december of different year
private int year;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    // get calendar whith parameters of now
    Calendar calendar = getCalendar();
    // initiate global variables
    selectedDay = today = calendar.get(Calendar.DAY_OF_MONTH);
    thisMonth = month = calendar.get(Calendar.MONTH);
    year = calendar.get(Calendar.YEAR);
    // set up TableLayout which holds the calendar matrix
    calendarTable = (TableLayout) findViewById(R.id.tableLayout);
    // set up list for future use as list of events of selected day
    dayList = (ListView) findViewById(R.id.listView);
    adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, listItems);
    dayList.setAdapter(adapter);
    // sanity test
    testCalendar();
    // build calendar table
    updateCalendar();
}

// function to test Calendar behaviour, as expected the output is
// Week: 8 Day: 27 Month: 1
// Week: 8 Day: 28 Month: 1
// Week: 9 Day: 29 Month: 1
// Week: 9 Day: 1 Month: 2
// contrary to UI behaviour which lists 2016-2-1 as sunday and lists only 28 days
private final void testCalendar() {
    Calendar c = getCalendar(2016, 1, 27);
    for (int i = 0; i < 4; i++) {
        System.out.println("Week: " +c.get(Calendar.WEEK_OF_YEAR) + " Day: " +
                c.get(Calendar.DAY_OF_MONTH) + " Month: " + c.get(Calendar.MONTH));
        c.add(Calendar.DAY_OF_MONTH, 1);
    }
}

// function to ensure correct configuration of Calendar
private final Calendar getCalendar() {
    Calendar gc = new GregorianCalendar();
    gc.setFirstDayOfWeek(Calendar.MONDAY);
    gc.setMinimalDaysInFirstWeek(4);
    return gc;
}

// function to ensure correct configuration of Calendar
private final Calendar getCalendar(int year, int month, int day) {
    Calendar gc = new GregorianCalendar(year, month, day);
    gc.setFirstDayOfWeek(Calendar.MONDAY);
    gc.setMinimalDaysInFirstWeek(4);
    return gc;
}

private void updateCalendar() {
    // reset table
    calendarTable.removeAllViews();
    // init calendar used by this function
    Calendar cal = getCalendar();
    // init temporary calendar to monday, first day of displayed month
    Calendar calx= getCalendar(year, month, 1);
    // get WEEK_OF_YEAR of first Day of Month
    int firstWeek = calx.get(Calendar.WEEK_OF_YEAR);
    // Set DAY_OF_WEEK to Monday
    cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
    // Set WEEK_OF_YEAR to first week the month is part of
    cal.set(Calendar.WEEK_OF_YEAR, firstWeek);
    // init reusable vars
    TableRow row = null;
    TextView tv = null;
    int paddingNormal = 35;
    //outer loop, rows
    for (int i = 0; i < 7; i++) {
        // init row
        row = new TableRow(this);
        // stretch row
        // code to stretch row width to parent view, took no effect
        /*row.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT,
                TableRow.LayoutParams.WRAP_CONTENT));*/
        // inner loop, fields
        for (int j = 0; j < 8; j++) {
            // init
            tv = new TextView(this);
            // center day labels
            tv.setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL);
            // code to stretch row width to parent view, took no effect
            /*tv.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT,
                    TableRow.LayoutParams.WRAP_CONTENT));*/
            // first row, headers
            if (i == 0) {
                tv.setPadding(paddingNormal, paddingNormal, paddingNormal, paddingNormal);
                tv.setBackgroundColor(Color.rgb(213, 213, 213));
                switch (j) {
                    case 0:
                        break;
                    case 1:
                        tv.setText("MO");
                        break;
                    case 2:
                        tv.setText("DI");
                        break;
                    case 3:
                        tv.setText("MI");
                        break;
                    case 4:
                        tv.setText("DO");
                        break;
                    case 5:
                        tv.setText("FR");
                        break;
                    case 6:
                        tv.setText("SA");
                        break;
                    case 7:
                        tv.setText("SO");
                        break;
                }
            }
            else if (j == 0) {
                // week no
                tv.setPadding(paddingNormal, paddingNormal, paddingNormal, paddingNormal);
                tv.setBackgroundColor(Color.rgb(213, 213, 213));
                tv.setText(""+cal.get(Calendar.WEEK_OF_YEAR));
            } else {
                // days
                tv.setPadding(paddingNormal, paddingNormal, paddingNormal, paddingNormal);
                tv.setText("" + cal.get(Calendar.DAY_OF_MONTH));
                // mark days of different month
                if ((cal.get(Calendar.MONTH) != month)) {
                    tv.setTextColor(Color.rgb(213, 213, 213));
                    // switch to previous or next month
                    tv.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            // set selectedDay of different month
                            selectedDay = Integer.parseInt(((TextView) v).getText() + "");
                            // if selectedDay is bigger 15 it is part of previous month
                            if (selectedDay > 15) {
                                // if month is january
                                if (month == Calendar.JANUARY) {
                                    // month is reset to december
                                    month = Calendar.DECEMBER;
                                    // and year decremented to previous year
                                    year = year - 1;
                                } else {
                                    // else month is decremented
                                    month = month - 1;
                                }
                                // else selectedDay is part of next month
                            } else {
                                // if month is december
                                if (month == Calendar.DECEMBER) {
                                    // month is reset to january
                                    month = Calendar.JANUARY;
                                    // and year is incremented
                                    year = year + 1;
                                } else {
                                    // else only month is incremented
                                    month = month + 1;
                                }
                            }
                            // updateCalendar to display different month
                            updateCalendar();
                        }
                    });
                } else {
                    // mark today with yellow circle
                    if ((cal.get(Calendar.DAY_OF_MONTH) == today) && month == thisMonth) {
                        tv.setBackgroundResource(R.drawable.circle_today);
                    }
                    // mark selected day with green circle
                    if ((cal.get(Calendar.DAY_OF_MONTH) == selectedDay)) {
                        tv.setBackgroundResource(R.drawable.circle_selected);
                    }
                    // setOnclickListener to updateCalendar and display the new selection and dayList
                    tv.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            // set selectedDay before rebuilding table
                            selectedDay = Integer.parseInt(((TextView) v).getText() + "");
                            // rebuild table
                            updateCalendar();
                        }
                    });
                }
                // increment calendar DAY_OF_MONTH field by 1
                cal.add(Calendar.DAY_OF_MONTH, 1);
            }
            // add TextView to row
            row.addView(tv);
        }
        // add row to TableLayout
        calendarTable.addView(row);
    }
    // Set ActionBar Title to "*month* *year*"
    String title ="";
    switch(month)
    {
        case Calendar.JANUARY:
            title = "Jänner " + year;
            break;
        case Calendar.FEBRUARY:
            title = "Februar " + year;
            break;
        case Calendar.MARCH:
            title = "März " + year;
            break;
        case Calendar.APRIL:
            title = "April " + year;
            break;
        case Calendar.MAY:
            title = "Mai " + year;
            break;
        case Calendar.JUNE:
            title = "Juni " + year;
            break;
        case Calendar.JULY:
            title = "Juli " + year;
            break;
        case Calendar.AUGUST:
            title = "August " + year;
            break;
        case Calendar.SEPTEMBER:
            title = "September " + year;
            break;
        case Calendar.OCTOBER:
            title = "Oktober " + year;
            break;
        case Calendar.NOVEMBER:
            title = "November " + year;
            break;
        case Calendar.DECEMBER:
            title = "Dezember " + year;
            break;
    }
    setTitle(title);
    // list events of selected day
    updateDayList();
}

private void updateDayList() {
    // TODO implement...
    adapter.clear();
    adapter.add(selectedDay + "/" + month + "/" + year);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }
    return super.onOptionsItemSelected(item);
}

Upvotes: 1

Views: 93

Answers (2)

Jan
Jan

Reputation: 11

Do not use old Java time classes, use Joda Time or the new Java time classes introduced in JDK 1.8 .

Upvotes: 0

Andreas
Andreas

Reputation: 159135

Remember that DAY_OF_WEEK uses 0=Sunday, 1=Monday, ... and so on. Don't know if locale makes a difference, but in US the week starts on Sunday.

Feb 1, 2015 is a Sunday. WEEK_OF_YEAR is 6.
Setting DAY_OF_WEEK to 1=Monday will get you Monday, Feb 2, 2015.
I don't think that is what you were after.

Upvotes: 1

Related Questions