Challange


#1

Hey there,

I am currently working on the challnge of chapter 12, but the TimePicker doesn’t work like I want it to do.
It was pretty easy to implement another button in CrimeFragment.java that displays a TimePicker dialog after a click on it. The Button also displays
the time correctly. But when I change the time with the TimePicker it doesn’t update the time on the button and in the list.


#2

Here is my code, earlier today I had no internet connection on my laptop. I have worked a litte on it, and now at least the hour updates. But there is still a problem with the minutes?!

My TimePickerFragment.java:

[code]package com.jensjensen.android.criminalintent;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.view.View;
import android.widget.TimePicker;
import android.widget.TimePicker.OnTimeChangedListener;

public class TimePickerFragment extends DialogFragment {
public static final String EXTRA_TIME =
“com.jensjensen.android.criminalintent.time”;

private Date mTime;

public static TimePickerFragment newInstance(Date date) {
	Bundle args = new Bundle();
	args.putSerializable(EXTRA_TIME, date);
	
	TimePickerFragment fragment = new TimePickerFragment();
	fragment.setArguments(args);
	
	return fragment;
}

private void sendResult(int resultCode) {
	if (getTargetFragment() == null)
		return;
	
	Intent i = new Intent();
	i.putExtra(EXTRA_TIME, mTime);
	
	getTargetFragment()
		.onActivityResult(getTargetRequestCode(), resultCode, i);
}

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
	mTime = (Date) getArguments().getSerializable(EXTRA_TIME);
	
	Calendar calendar = Calendar.getInstance();
	calendar.setTime(mTime);
	int hourOfDay = calendar.get(Calendar.HOUR_OF_DAY);
	int minute = calendar.get(Calendar.MINUTE);
	
	View v = getActivity().getLayoutInflater()
		.inflate(R.layout.dialog_time, null);
	
	TimePicker timePicker = (TimePicker) v.findViewById(R.id.dialog_time_timePicker);
	timePicker.setIs24HourView(true);
	timePicker.setCurrentHour(hourOfDay);
	timePicker.setCurrentMinute(minute);
	timePicker.setOnTimeChangedListener(new OnTimeChangedListener() {
		public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
			// Translate year / month / date into a Date object, using a calendar
			mTime = new GregorianCalendar(0, 0, 0, hourOfDay, minute).getTime();
			
			getArguments().putSerializable(EXTRA_TIME, mTime);
		}
	});
	
	return new AlertDialog.Builder(getActivity())
	.setView(v)
	.setTitle(R.string.time_picker_title)
	.setPositiveButton(
			android.R.string.ok, 
			new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int which) {
					sendResult(Activity.RESULT_OK);
				}
			})
	.create();

}
}

[/code]

and CrimeFragment.java:

[code]package com.jensjensen.android.criminalintent;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.text.Editable;
import android.text.TextWatcher;
import android.text.format.DateFormat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;

public class CrimeFragment extends Fragment {
public static final String EXTRA_CRIME_ID =
“com.jensjensen.android.criminalintent.crime_id”;

private static final String DIALOG_DATE = "date";
private static final String DIALOG_TIME = "time";
private static final int REQUEST_DATE = 0; 
private static final int REQUEST_TIME = 1;

private Crime mCrime;
private EditText mTitleField;
private Button mDateButton;
private Button mTimeButton;
private CheckBox mSolvedCheckBox;

@Override
public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	UUID crimeId = (UUID) getArguments().getSerializable(EXTRA_CRIME_ID);
	
	mCrime = CrimeLab.get(getActivity()).getCrime(crimeId);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent,
		Bundle savedInstanceState) {
	View v = inflater.inflate(R.layout.fragment_crime, parent, false);

	mTitleField = (EditText) v.findViewById(R.id.crime_title);
	mTitleField.setText(mCrime.getTitle());
	mTitleField.addTextChangedListener(new TextWatcher() {
		public void onTextChanged(CharSequence c, int start, int before,
				int count) {
			mCrime.setTitle(c.toString());
		}

		public void beforeTextChanged(CharSequence c, int start, int count,
				int after) {
			// erstmal leer
		}

		public void afterTextChanged(Editable c) {
			// hier auch leer
		}
	});
	
	mDateButton = (Button) v.findViewById(R.id.crime_date);
	updateDate();
	mDateButton.setOnClickListener(new View.OnClickListener() {
		
		@Override
		public void onClick(View v) {
			FragmentManager fm = getActivity()
				.getSupportFragmentManager();
			DatePickerFragment dialog = DatePickerFragment
					.newInstance(mCrime.getDate());
			dialog.setTargetFragment(CrimeFragment.this, REQUEST_DATE);
			dialog.show(fm, DIALOG_DATE);
		}
	});
	
	mTimeButton = (Button) v.findViewById(R.id.crime_time);
	updateTime();
	mTimeButton.setOnClickListener(new View.OnClickListener() {
		
		@Override
		public void onClick(View v) {
			FragmentManager fm = getActivity()
				.getSupportFragmentManager();
			TimePickerFragment dialog = TimePickerFragment
					.newInstance(mCrime.getDate());
			dialog.setTargetFragment(CrimeFragment.this, REQUEST_TIME);
					dialog.show(fm, DIALOG_TIME);
		}
	});
	
	mSolvedCheckBox = (CheckBox) v.findViewById(R.id.crime_solved);
	mSolvedCheckBox.setChecked(mCrime.isSolved());
	mSolvedCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
		
		@Override
		public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
			// Set crimes solved property	
			mCrime.setSolved(isChecked);
		}
	});

	return v;
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
	if (resultCode != Activity.RESULT_OK) return;
	if (requestCode == REQUEST_DATE) {
		Date date = (Date) data
				.getSerializableExtra(DatePickerFragment.EXTRA_DATE);
		mCrime.setDate(date);
		updateDate();
	} else if (requestCode == REQUEST_TIME) {
		Date date = (Date) data
				.getSerializableExtra(TimePickerFragment.EXTRA_TIME);
		mCrime.setDate(date);
		updateTime();
	}
}

public void updateDate() {
	Date date = mCrime.getDate();
	SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy");
	mDateButton.setText(sdf.format(date).toString());
}

public void updateTime() {
	Date date = mCrime.getDate();
	SimpleDateFormat sdf = new SimpleDateFormat("HH:MM");
	mTimeButton.setText(sdf.format(date).toString());
}

public static CrimeFragment newInstance(UUID crimeId) {
	Bundle args = new Bundle();
	args.putSerializable(EXTRA_CRIME_ID, crimeId);
	
	CrimeFragment fragment = new CrimeFragment();
	fragment.setArguments(args);
	
	return fragment;
}

}
[/code]


#3

Heres my solution to adding the time picker:

TimePickerFragment.java

-                DatePickerFragment dialog = DatePickerFragment.newInstance(mCrime.getDate());
+                TimePickerFragment dialog = TimePickerFragment.newInstance(mCrime.getDate());

TimePickerFragment.java

public class TimePickerFragment extends DialogFragment {

    public static final String EXTRA_DATE = "com.bignerdranch.android.criminalintent.date";

    private Date mDate;

    public static TimePickerFragment newInstance(Date date) {
        Bundle args = new Bundle();
        args.putSerializable(EXTRA_DATE, date);

        TimePickerFragment fragment = new TimePickerFragment();
        fragment.setArguments(args);

        return fragment;
    }

    private void sendResult(int resultCode) {
        if (getTargetFragment() == null)
            return;

        Intent i = new Intent();
        i.putExtra(EXTRA_DATE, mDate);

        getTargetFragment().onActivityResult(getTargetRequestCode(), resultCode, i);
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        mDate = (Date) getArguments().getSerializable(EXTRA_DATE);

        // Create a Calendar to get the year, month, and day
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(mDate);
        int hour = calendar.get(Calendar.HOUR);
        int minute = calendar.get(Calendar.MINUTE);

        View v = getActivity().getLayoutInflater().inflate(R.layout.dialog_time, null);

        TimePicker timePicker = (TimePicker) v.findViewById(R.id.dialog_time_timePicker);
        timePicker.setCurrentHour(hour);
        timePicker.setCurrentMinute(minute);
        timePicker.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener() {

            public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
                mDate.setHours(hourOfDay);
                mDate.setMinutes(minute);
                // Update argument to preserve selected value on rotation
                getArguments().putSerializable(EXTRA_DATE, mDate);
            }
        });


        return new AlertDialog.Builder(getActivity())
                .setView(v)
                .setTitle(R.string.date_picker_title)
                .setPositiveButton(
                        android.R.string.ok,
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {
                                sendResult(Activity.RESULT_OK);
                            }
                        })
                .create();
    }
}

dialog_time.xml

<?xml version="1.0" encoding="utf-8"?>

<TimePicker xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/dialog_time_timePicker"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">

</TimePicker>

#4

Thats nearly the same like my solution.
In the meantime I found my mistake. The only problem was, that the minutes on my timebutton were not updatet correctly. That came because I used “HH:MM” instead of “HH:mm” in my updateTime();

Thanks paddy.


#5

Hi I finally got the time to display, but when I make a change and press “OK” button the program abends. Any suggestions?


#6

I finally got this figured out. Now I’m having an issue where after I change the time, the date becomes corrupt (part of the year missing. After I press the date button, the program errors off.


#7

I just figured it out by looking at the second listing of TimePickerFragment. Now I feel I can finally move forward:)


#8

Thanks this helped me, it’s quite a tricky challenge. :geek: