cz.krtinec.birthday.ui.EditActivity.java Source code

Java tutorial

Introduction

Here is the source code for cz.krtinec.birthday.ui.EditActivity.java

Source

/*
 * This file is part of Birthday Widget.
 *
 * Birthday Widget is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Birthday Widget is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Birthday Widget.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Copyright (c) Lukas Marek, 2011.
 */

package cz.krtinec.birthday.ui;

import android.accounts.Account;
import android.app.*;
import android.content.*;

import android.net.Uri;
import android.os.Bundle;
import android.os.RemoteException;
import android.provider.ContactsContract;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.*;
import cz.krtinec.birthday.Birthday;
import cz.krtinec.birthday.DateFormatter;
import cz.krtinec.birthday.R;
import cz.krtinec.birthday.Utils;
import cz.krtinec.birthday.data.BirthdayProvider;

import cz.krtinec.birthday.dto.ContactInfo;
import cz.krtinec.birthday.dto.DateIntegrity;
import cz.krtinec.birthday.dto.EditableEvent;

import cz.krtinec.birthday.dto.EventType;
import org.joda.time.LocalDate;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Allows edit particular event.
 */
public class EditActivity extends Activity {
    private static final int DIALOG_EDIT_DATE = 12;
    private static final int DIALOG_SAVE_FAILED = 13;
    private static final int DIALOG_SAVING = 14;
    private static final int DIALOG_CHOOSE_ACCOUNT = 15;
    private static EditableEvent eventToEdit = null;
    private static EditAdapter listAdapter;
    private static Map<Account, Long> accountMap;
    private static Account[] accounts;
    private static Button saveButton;
    private static long rawContactId;

    private static SpinnerItem[] SPINNER_ITEMS;
    private static final String EVENTS_LIST = "EVENTS_LIST";
    private static final String EVENTS_BASE = "EVENTS_BASE";
    private static final String EVENTS_DELETED = "EVENTS_DELETED";
    private static final String RAW_CONTACT_ID = "RAW_CONTACT_ID";

    private StockPhotoLoader photoLoader;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.edit);
        SPINNER_ITEMS = new SpinnerItem[] { new SpinnerItem(EventType.BIRTHDAY, this.getString(R.string.birthday)),
                new SpinnerItem(EventType.ANNIVERSARY, this.getString(R.string.anniversary)),
                new SpinnerItem(EventType.OTHER, this.getString(R.string.other)) };
        photoLoader = new StockPhotoLoader(this, R.drawable.icon);

        Intent i = getIntent();
        if (i != null) {
            Uri contact = i.getData();
            Log.i("Birthday", "Going to edit " + contact);
            ContactInfo contactInfo = BirthdayProvider.getInstance().getContact(this, contact);
            TextView nameView = (TextView) findViewById(R.id.name);
            nameView.setText(contactInfo.contactName);
            photoLoader.loadPhoto((ImageView) findViewById(R.id.bicon), contactInfo.contactID);

            //empty intent
            setIntent(null);
            if (!contact.toString().contains("raw_contact")) {
                Log.d("Birthday", "Must choose raw contact.");
                Map<Account, Long> rawIds = BirthdayProvider.getInstance().getRawContactIds(this,
                        Long.parseLong(contact.getLastPathSegment()));
                Log.i("Birthday", rawIds.toString());
                accountMap = rawIds;
                showDialog(DIALOG_CHOOSE_ACCOUNT);
            } else {
                Log.d("Birthday", "Get raw contact id for: " + contact);
                rawContactId = Long.parseLong(contact.getLastPathSegment());
                onRawContactIdSelected(rawContactId);
            }
        } else {
            onRawContactIdSelected(rawContactId);
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        photoLoader.resume();
    }

    @Override
    protected void onStop() {
        super.onStop();
        photoLoader.stop();
    }

    @Override
    protected void onPause() {
        super.onPause();
        photoLoader.pause();
    }

    @Override
    public void onSaveInstanceState(Bundle instanceState) {
        super.onSaveInstanceState(instanceState);
        instanceState.putParcelableArrayList(EVENTS_LIST, (ArrayList<EditableEvent>) listAdapter.list);
        instanceState.putParcelableArrayList(EVENTS_BASE, (ArrayList<EditableEvent>) listAdapter.base);
        instanceState.putParcelableArrayList(EVENTS_DELETED, (ArrayList<EditableEvent>) listAdapter.deleted);
        instanceState.putLong(RAW_CONTACT_ID, listAdapter.rawContactId);
    }

    @Override
    public void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        if (savedInstanceState != null && savedInstanceState.containsKey(EVENTS_LIST)) {
            EditAdapter adapter = new EditAdapter(this,
                    (ArrayList) savedInstanceState.getParcelableArrayList(EVENTS_LIST),
                    (ArrayList) savedInstanceState.getParcelableArrayList(EVENTS_BASE),
                    (ArrayList) savedInstanceState.getParcelableArrayList(EVENTS_DELETED),
                    savedInstanceState.getLong(RAW_CONTACT_ID));
            listAdapter = adapter;
            ListView listView = (ListView) findViewById(R.id.list);
            Log.d("Birthday", "Adapter: " + listView.getAdapter());
            listView.setAdapter(listAdapter);
        }
    }

    private void onRawContactIdSelected(long rawContactId) {
        ListView listView = (ListView) findViewById(R.id.list);
        List<EditableEvent> listOfEvents = BirthdayProvider.getInstance().getEvents(this, rawContactId);

        listAdapter = new EditAdapter(this, listOfEvents, rawContactId);
        listView.setAdapter(listAdapter);
        ImageView b = (ImageView) findViewById(R.id.edit_button_add);
        b.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                listAdapter.addRow();
                //disable save button
                if (saveButton != null) {
                    saveButton.setEnabled(false);
                }
            }
        });

        final Context context = this;
        saveButton = (Button) findViewById(R.id.btn_done);
        Button cancelButton = (Button) findViewById(R.id.btn_discard);

        cancelButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent i = new Intent(getBaseContext(), Birthday.class);
                startActivity(i);
            }
        });

        saveButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try {
                    showDialog(DIALOG_SAVING);
                    BirthdayProvider.getInstance().performUpdate(context, listAdapter.buildDiff());
                    //Reload widget...
                    Utils.startWidgetUpdateAlarm(getBaseContext());
                    removeDialog(DIALOG_SAVING);
                    Intent i = new Intent(getBaseContext(), Birthday.class);
                    startActivity(i);
                } catch (RemoteException e) {
                    Log.i("Birthday", "Save failed!", e);
                    showDialog(DIALOG_SAVE_FAILED);
                } catch (OperationApplicationException e) {
                    Log.i("Birthday", "Save failed!", e);
                    showDialog(DIALOG_SAVE_FAILED);
                }
            }
        });
    }

    @Override
    protected Dialog onCreateDialog(int id) {
        switch (id) {
        case (DIALOG_EDIT_DATE): {
            return createEditDialog(this);
        }
        case (DIALOG_SAVE_FAILED): {
            return new AlertDialog.Builder(this).setTitle(R.string.error).setMessage(R.string.save_error)
                    .setPositiveButton(R.string.ok, null).create();
        }
        case (DIALOG_SAVING): {
            return new ProgressDialog.Builder(this).setTitle(R.string.save).setMessage(R.string.wait_dialog)
                    .create();
        }
        case (DIALOG_CHOOSE_ACCOUNT): {
            accounts = accountMap.keySet().toArray(new Account[accountMap.keySet().size()]);
            return new AlertDialog.Builder(this).setTitle(R.string.choose_account)
                    .setAdapter(new AccountAdapter<Account>(this, R.layout.simple_list_item_2, accounts),
                            new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialogInterface, int i) {
                                    Log.d("Birthday", "Selected " + accounts[i] + " account");
                                    onRawContactIdSelected(accountMap.get(accounts[i]));
                                }
                            })
                    .create();
        }
        }
        return null;
    }

    @Override
    protected void onPrepareDialog(int id, Dialog dialog) {
        switch (id) {
        case (DIALOG_EDIT_DATE): {
            DatePickerDialog datePicker = (DatePickerDialog) dialog;
            if (eventToEdit != null && eventToEdit.eventDate != null) {
                datePicker.updateDate(eventToEdit.eventDate.getYear(), eventToEdit.eventDate.getMonthOfYear() - 1,
                        eventToEdit.eventDate.getDayOfMonth());
            } else {
                datePicker.updateDate(2011, 0, 1);
            }
            break;
        }
        case (DIALOG_CHOOSE_ACCOUNT): {
            ((AlertDialog) dialog).getListView()
                    .setAdapter(new AccountAdapter<Account>(this, android.R.layout.two_line_list_item, accounts));
            break;
        }
        }
    }

    private Dialog createEditDialog(final Context ctx) {

        DatePickerDialog datePicker = new DatePickerDialog(ctx, new DatePickerDialog.OnDateSetListener() {
            @Override
            public void onDateSet(DatePicker datePicker, int year, int month, int day) {
                eventToEdit.eventDate = new LocalDate(year, month + 1, day);
                eventToEdit.integrity = DateIntegrity.FULL;
                listAdapter.notifyDataSetChanged();
                //enable save button
                if (saveButton != null) {
                    saveButton.setEnabled(true);
                }

            }
        }, 2011, 0, 1);
        try {
            if (eventToEdit != null && eventToEdit.eventDate != null) {
                datePicker.updateDate(eventToEdit.eventDate.getYear(), eventToEdit.eventDate.getMonthOfYear() - 1,
                        eventToEdit.eventDate.getDayOfMonth());
            }
        } catch (IllegalArgumentException e) {
            //tried to set some weird date - ignore
        }

        return datePicker;
    }

    static class SpinnerItem {
        String label;
        EventType eventType;

        SpinnerItem(EventType eventType, String label) {
            this.eventType = eventType;
            this.label = label;
        }

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

        @Override
        public boolean equals(Object o) {
            if (this == o)
                return true;
            if (o == null || getClass() != o.getClass())
                return false;

            SpinnerItem that = (SpinnerItem) o;

            if (eventType != that.eventType)
                return false;

            return true;
        }

        @Override
        public int hashCode() {
            return eventType.hashCode();
        }
    }

    class EditAdapter extends BaseAdapter {
        private List<EditableEvent> list;
        private Context ctx;
        private List<EditableEvent> base;
        private List<EditableEvent> deleted;
        private Long rawContactId;

        public EditAdapter(Context ctx, List<EditableEvent> list, Long rawContactId) {
            this.ctx = ctx;
            this.list = list;
            this.deleted = new ArrayList<EditableEvent>(1);
            this.base = new ArrayList<EditableEvent>();
            for (EditableEvent e : list) {
                this.base.add(e.clone());
            }
            this.rawContactId = rawContactId;
        }

        private EditAdapter(Context ctx, List<EditableEvent> list, List<EditableEvent> base,
                List<EditableEvent> deleted, Long rawContactId) {
            this.ctx = ctx;
            this.list = list;
            this.base = base;
            this.deleted = deleted;
            this.rawContactId = rawContactId;
        }

        @Override
        public int getCount() {
            return list.size();
        }

        @Override
        public Object getItem(int i) {
            return list.get(i);
        }

        @Override
        public long getItemId(int i) {
            return list.get(i).eventId;
        }

        @Override
        public View getView(int i, View convertView, ViewGroup viewGroup) {
            View v;
            if (convertView == null) {
                LayoutInflater vi = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                v = vi.inflate(R.layout.edit_row, null);
            } else {
                v = convertView;
            }
            EditableEvent evt = list.get(i);
            fillEditRow(v, evt);

            return v;
        }

        private void fillEditRow(View v, final EditableEvent evt) {
            if (evt.eventDate != null) {
                ((Button) v.findViewById(R.id.edit_display_date))
                        .setText(DateFormatter.getInstance(ctx).formatEdit(evt.eventDate));
            } else {
                ((Button) v.findViewById(R.id.edit_display_date)).setText("Click to set");
            }

            Spinner s = (Spinner) v.findViewById(R.id.edit_type_button);
            ArrayAdapter<SpinnerItem> adapter = new ArrayAdapter<SpinnerItem>(ctx,
                    android.R.layout.simple_spinner_item, SPINNER_ITEMS);
            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
            s.setAdapter(adapter);
            s.setSelection(adapter.getPosition(getSpinnerType(evt.type)));
            s.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
                @Override
                public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
                    SpinnerItem si = (SpinnerItem) adapterView.getItemAtPosition(i);
                    Log.d("Birthday", "Selected item: " + si);
                    evt.type = si.eventType;
                }

                @Override
                public void onNothingSelected(AdapterView<?> adapterView) {
                    //do nothing
                }
            });

            v.findViewById(R.id.edit_remove_button).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    list.remove(evt);
                    deleted.add(evt);
                    notifyDataSetChanged();
                }
            });

            v.findViewById(R.id.edit_display_date).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    eventToEdit = evt;
                    showDialog(DIALOG_EDIT_DATE);
                }
            });

        }

        public void addRow() {
            this.list.add(new EditableEvent(rawContactId));
            this.notifyDataSetChanged();
        }

        /**
         * Returns diff to update to database.
         * @return
         */
        public ArrayList<ContentProviderOperation> buildDiff() {
            ArrayList<ContentProviderOperation> diff = new ArrayList<ContentProviderOperation>();
            for (EditableEvent e : list) {

                //update
                if (containsId(base, e.eventId)) {
                    diff.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
                            .withSelection(ContactsContract.Data._ID + " = ?",
                                    new String[] { String.valueOf(e.eventId) })
                            .withValue(ContactsContract.CommonDataKinds.Event.START_DATE, e.eventDate.toString())
                            .withValue(ContactsContract.CommonDataKinds.Event.TYPE, e.type.getCode()).build());
                } else {
                    diff.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                            .withValue(ContactsContract.Data.RAW_CONTACT_ID, String.valueOf(e.rawContactId))
                            .withValue(ContactsContract.CommonDataKinds.Event.START_DATE, e.eventDate.toString())
                            .withValue(ContactsContract.CommonDataKinds.Event.TYPE,
                                    e.type == null ? EventType.BIRTHDAY.getCode() : e.type.getCode())
                            .withValue(ContactsContract.Data.MIMETYPE,
                                    ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE)
                            .build());
                }

            }
            for (EditableEvent e : deleted) {
                diff.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI).withSelection(
                        ContactsContract.Data._ID + " = ?", new String[] { String.valueOf(e.eventId) }).build());
            }

            return diff;
        }

        private boolean containsId(List<EditableEvent> l, Long id) {
            for (EditableEvent e : l) {
                if (e.eventId.equals(id)) {
                    return true;
                }
            }
            return false;
        }
    }

    private static SpinnerItem getSpinnerType(EventType eventType) {
        for (SpinnerItem i : SPINNER_ITEMS) {
            if (i.eventType.equals(eventType)) {
                return i;
            }
        }
        return null;
    }

    static class AccountAdapter<T> extends ArrayAdapter<T> {
        public AccountAdapter(Context context, int textViewResourceId, T[] objects) {
            super(context, textViewResourceId, objects); //To change body of overridden methods use File | Settings | File Templates.
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            Account account = (Account) getItem(position);
            View v;
            if (convertView == null) {
                LayoutInflater vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                v = vi.inflate(R.layout.simple_list_item_2, null);
            } else {
                v = convertView;
            }

            ((TextView) v.findViewById(android.R.id.text1)).setText(account.name);
            ((TextView) v.findViewById(android.R.id.text2)).setText(account.type);

            return v;
        }
    }
}