com.flowzr.budget.holo.activity.RecurActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.flowzr.budget.holo.activity.RecurActivity.java

Source

/*******************************************************************************
 * Copyright (c) 2010 Denis Solonenko.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v2.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     Denis Solonenko - initial API and implementation
 ******************************************************************************/
package com.flowzr.budget.holo.activity;

import java.text.DateFormat;
import java.util.Calendar;

import com.flowzr.budget.holo.R;
import com.flowzr.budget.holo.datetime.DateUtils;
import com.flowzr.budget.holo.utils.LocalizableEnum;
import com.flowzr.budget.holo.utils.PinProtection;
import com.flowzr.budget.holo.utils.RecurUtils;
import com.flowzr.budget.holo.utils.Utils;
import com.flowzr.budget.holo.utils.RecurUtils.DayOfWeek;
import com.flowzr.budget.holo.utils.RecurUtils.EveryXDay;
import com.flowzr.budget.holo.utils.RecurUtils.Layoutable;
import com.flowzr.budget.holo.utils.RecurUtils.Recur;
import com.flowzr.budget.holo.utils.RecurUtils.RecurInterval;
import com.flowzr.budget.holo.utils.RecurUtils.RecurPeriod;
import com.flowzr.budget.holo.utils.RecurUtils.SemiMonthly;
import com.flowzr.budget.holo.utils.RecurUtils.Weekly;

import android.app.Activity;
import android.app.DatePickerDialog;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.support.v4.app.NavUtils;
import android.support.v4.app.TaskStackBuilder;
import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.SpinnerAdapter;
import android.widget.AdapterView.OnItemSelectedListener;

public class RecurActivity extends ActionBarActivity {

    public static final String EXTRA_RECUR = "recur";

    private static final RecurPeriod[] periods = RecurPeriod.values();

    private Spinner sInterval;
    private Spinner sPeriod;
    private LinearLayout layoutInterval;
    private LinearLayout layoutRecur;
    private Button bStartDate;

    private final Calendar startDate = Calendar.getInstance();
    private final Calendar stopsOnDate = Calendar.getInstance();

    private DateFormat df;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Setup ActionBar      
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        setContentView(R.layout.recur);

        df = DateUtils.getLongDateFormat(this);

        stopsOnDate.add(Calendar.YEAR, 1);

        sInterval = (Spinner) findViewById(R.id.intervalSpinner);
        sPeriod = (Spinner) findViewById(R.id.recurSpinner);
        layoutInterval = (LinearLayout) findViewById(R.id.layoutInterval);
        layoutRecur = (LinearLayout) findViewById(R.id.recurInterval);

        bStartDate = (Button) findViewById(R.id.bStartDate);
        bStartDate.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(final View v) {
                final Calendar c = startDate;
                DatePickerDialog d = new DatePickerDialog(RecurActivity.this,
                        new DatePickerDialog.OnDateSetListener() {
                            @Override
                            public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
                                c.set(Calendar.YEAR, year);
                                c.set(Calendar.MONTH, monthOfYear);
                                c.set(Calendar.DAY_OF_MONTH, dayOfMonth);
                                DateUtils.startOfDay(c);
                                editStartDate(c.getTimeInMillis());
                            }
                        }, c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_MONTH));
                d.show();
            }
        });

        addSpinnerItems(sInterval,
                new RecurInterval[] { RecurInterval.NO_RECUR, RecurInterval.WEEKLY, RecurInterval.MONTHLY });
        addSpinnerItems(sPeriod, periods);

        LayoutInflater inflater = getLayoutInflater();
        //addLayouts(inflater, layoutInterval, intervals);
        addLayouts(inflater, layoutRecur, periods);

        Recur recur = RecurUtils.createDefaultRecur();
        Intent intent = getIntent();
        if (intent != null) {
            String extra = intent.getStringExtra(EXTRA_RECUR);
            if (extra != null) {
                recur = RecurUtils.createFromExtraString(extra);
            }
        }
        editRecur(recur);

        sInterval.setOnItemSelectedListener(new OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                RecurInterval interval = getRecurInterval(sInterval.getSelectedItem());
                selectInterval(interval);
            }

            @Override
            public void onNothingSelected(AdapterView<?> arg0) {
            }

        });

        sPeriod.setOnItemSelectedListener(new OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                RecurPeriod period = periods[position];
                selectPeriod(period);
            }

            @Override
            public void onNothingSelected(AdapterView<?> arg0) {
            }

        });

    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.action_done:
            RecurInterval interval = getRecurInterval(sInterval.getSelectedItem());
            RecurPeriod period = periods[sPeriod.getSelectedItemPosition()];
            Recur r = RecurUtils.createRecur(interval);
            r.startDate = startDate.getTimeInMillis();
            r.period = period;
            if (updateInterval(r) && updatePeriod(r)) {
                Intent data = new Intent();
                data.putExtra(EXTRA_RECUR, r.toString());
                setResult(RESULT_OK, data);
                finish();
            }
            return true;
        case R.id.action_cancel:
            setResult(RESULT_CANCELED, null);
            finish();
            return true;
        case android.R.id.home: {
            TaskStackBuilder tsb = TaskStackBuilder.create(this);
            final int intentCount = tsb.getIntentCount();
            if (intentCount > 0) {
                Intent upIntent = tsb.getIntents()[intentCount - 1];
                if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
                    // This activity is not part of the application's task, so create a new task with a synthesized back stack.
                    tsb.startActivities();
                    finish();
                } else {
                    // This activity is part of the application's task, so simply navigate up to the hierarchical parent activity.
                    NavUtils.navigateUpTo(this, upIntent);
                }
            } else {
                onBackPressed();
            }
            return true;
        }
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.ok_cancel, menu);
        return true;
    }

    private static class SpinnerItem {
        public final String title;
        public final String value;

        public SpinnerItem(String title, String value) {
            super();
            this.title = title;
            this.value = value;
        }

        @Override
        public String toString() {
            return title;
        }
    }

    private void addSpinnerItems(Spinner spinner, LocalizableEnum[] a) {
        int length = a.length;
        SpinnerItem[] items = new SpinnerItem[length];
        for (int i = 0; i < length; i++) {
            LocalizableEnum x = a[i];
            String title = getString(x.getTitleId());
            String value = x.name();
            items[i] = new SpinnerItem(title, value);
        }
        ArrayAdapter<SpinnerItem> adapter = new ArrayAdapter<SpinnerItem>(this,
                android.R.layout.simple_spinner_item, items);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinner.setAdapter(adapter);
    }

    protected RecurInterval getRecurInterval(Object item) {
        return RecurInterval.valueOf(((SpinnerItem) item).value);
    }

    protected boolean updateInterval(Recur r) {
        RecurInterval interval = r.interval;
        View v = selectInterval(interval);
        switch (interval) {
        case EVERY_X_DAY:
            return updateEveryXDay(v, r);
        case WEEKLY:
            return updateWeekly(v, r);
        case SEMI_MONTHLY:
            return updateSemiMonthly(v, r);
        }
        return true;
    }

    protected boolean updatePeriod(Recur r) {
        RecurPeriod period = r.period;
        View v = selectPeriod(period);
        switch (period) {
        case EXACTLY_TIMES:
            return updateExactlyTimes(v, r);
        case STOPS_ON_DATE:
            return updateStopsOnDate(v, r);
        }
        return true;
    }

    private void addLayouts(LayoutInflater inflater, LinearLayout layout, Layoutable[] items) {
        for (Layoutable i : items) {
            int layoutId = i.getLayoutId();
            if (layoutId != 0) {
                final View v = inflater.inflate(layoutId, null);
                v.setTag(i);
                v.setVisibility(View.INVISIBLE);
                if (i == RecurPeriod.STOPS_ON_DATE) {
                    Button b = (Button) v.findViewById(R.id.bStopsOnDate);
                    final Calendar c = this.stopsOnDate;
                    editStopsOnDate(v, c.getTimeInMillis());
                    b.setOnClickListener(new OnClickListener() {
                        @Override
                        public void onClick(final View view) {
                            DatePickerDialog d = new DatePickerDialog(RecurActivity.this,
                                    new DatePickerDialog.OnDateSetListener() {
                                        @Override
                                        public void onDateSet(DatePicker view, int year, int monthOfYear,
                                                int dayOfMonth) {
                                            c.set(Calendar.YEAR, year);
                                            c.set(Calendar.MONTH, monthOfYear);
                                            c.set(Calendar.DAY_OF_MONTH, dayOfMonth);
                                            DateUtils.endOfDay(c);
                                            editStopsOnDate(v, c.getTimeInMillis());
                                        }
                                    }, c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_MONTH));
                            d.show();
                        }
                    });
                }
                layout.addView(v, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
            }
        }
    }

    private void editRecur(Recur recur) {
        editStartDate(recur.startDate);
        RecurInterval interval = recur.interval;
        SpinnerAdapter adapter = sInterval.getAdapter();
        int count = adapter.getCount();
        for (int i = 0; i < count; i++) {
            SpinnerItem item = (SpinnerItem) adapter.getItem(i);
            if (interval == RecurInterval.valueOf(item.value)) {
                sInterval.setSelection(i);
                break;
            }
        }
        View v = selectInterval(interval);
        switch (interval) {
        case EVERY_X_DAY:
            editEveryXDay(v, recur);
            break;
        case WEEKLY:
            editWeekly(v, recur);
            break;
        case SEMI_MONTHLY:
            editSemiMonthly(v, recur);
            break;
        }
        RecurPeriod period = recur.period;
        sPeriod.setSelection(period.ordinal());
        v = selectPeriod(period);
        switch (period) {
        case EXACTLY_TIMES:
            editExactlyTimes(v, recur.periodParam);
            break;
        case STOPS_ON_DATE:
            editStopsOnDate(v, recur.periodParam);
            break;
        }
    }

    private void editEveryXDay(View v, Recur recur) {
        EveryXDay x = (EveryXDay) recur;
        EditText t = (EditText) v.findViewById(R.id.edEveryXDays);
        t.setText(String.valueOf(x.days));
    }

    private void editWeekly(View v, Recur recur) {
        return;
    }

    private void editSemiMonthly(View v, Recur recur) {
        SemiMonthly sm = (SemiMonthly) recur;
        EditText t1 = (EditText) v.findViewById(R.id.edFirstDay);
        t1.setText(String.valueOf(sm.firstDay));
        EditText t2 = (EditText) v.findViewById(R.id.edSecondDay);
        t2.setText(String.valueOf(sm.secondDay));
    }

    private boolean updateEveryXDay(View v, Recur r) {
        EveryXDay x = (EveryXDay) r;
        EditText t = (EditText) v.findViewById(R.id.edEveryXDays);
        if (Utils.isEmpty(t)) {
            showError(t, R.string.recur_error_specify_days);
            return false;
        }
        x.days = Integer.parseInt(Utils.text(t));
        return true;
    }

    private void showError(EditText t, int messageId) {
        t.setError(getString(messageId));
    }

    private boolean updateWeekly(View v, Recur r) {
        Weekly w = (Weekly) r;
        int i = startDate.get(Calendar.DAY_OF_WEEK);
        DayOfWeek[] days = DayOfWeek.values();
        for (DayOfWeek d : days) {
            w.unset(d);
        }
        w.set(days[i - 1]);
        return true;
    }

    private boolean updateSemiMonthly(View v, Recur r) {
        SemiMonthly sm = (SemiMonthly) r;
        EditText t1 = (EditText) v.findViewById(R.id.edFirstDay);
        if (Utils.isEmpty(t1)) {
            showError(t1, R.string.recur_error_specify_first_day);
            return false;
        }
        sm.firstDay = Integer.parseInt(Utils.text(t1));
        EditText t2 = (EditText) v.findViewById(R.id.edSecondDay);
        if (Utils.isEmpty(t2)) {
            showError(t2, R.string.recur_error_specify_second_day);
            return false;
        }
        sm.secondDay = Integer.parseInt(Utils.text(t2));
        return true;
    }

    private void editExactlyTimes(View v, long times) {
        EditText e = (EditText) v.findViewById(R.id.edTimes);
        e.setText(times > 0 ? String.valueOf(times) : "1");
    }

    private void editStartDate(long date) {
        Calendar c = startDate;
        c.setTimeInMillis(date);
        bStartDate.setText(df.format(c.getTime()));
    }

    private void editStopsOnDate(View v, long date) {
        Calendar c = stopsOnDate;
        c.setTimeInMillis(date);
        Button b = (Button) v.findViewById(R.id.bStopsOnDate);
        b.setText(df.format(c.getTime()));
    }

    private boolean updateExactlyTimes(View v, Recur r) {
        EditText e = (EditText) v.findViewById(R.id.edTimes);
        if (Utils.isEmpty(e)) {
            showError(e, R.string.recur_error_specify_times);
            return false;
        }
        r.periodParam = Long.parseLong(Utils.text(e));
        return true;
    }

    private boolean updateStopsOnDate(View v, Recur r) {
        r.periodParam = stopsOnDate.getTimeInMillis();
        return true;
    }

    protected View selectInterval(RecurInterval interval) {
        if (interval == RecurInterval.NO_RECUR) {
            sPeriod.setSelection(RecurPeriod.STOPS_ON_DATE.ordinal());
            sPeriod.setEnabled(false);
        } else {
            sPeriod.setEnabled(true);
        }
        return selectInLayout(layoutInterval, interval);
    }

    protected View selectPeriod(RecurPeriod period) {
        return selectInLayout(layoutRecur, period);
    }

    private View selectInLayout(LinearLayout layout, Object tag) {
        View selected = null;
        int count = layout.getChildCount();
        for (int i = 0; i < count; i++) {
            View v = layout.getChildAt(i);
            if (tag == v.getTag()) {
                selected = v;
            } else {
                v.setVisibility(View.GONE);
            }
        }
        if (selected != null) {
            selected.setVisibility(View.VISIBLE);
        }
        return selected;
    }

}