Crime.java
package com.example.aster.criminalintent;
import java.util.Date;
import java.util.UUID;
public class Crime {
private UUID mId;
private String mTitle;
private Date mDate;
private boolean mSolved;
public Crime () {
mId = UUID.randomUUID();
mDate = new Date();
}
public UUID getId () {
return mId;
}
public String getTitle () {
return mTitle;
}
public void setTitle (String title) {
mTitle = title;
}
public Date getDate () {
return mDate;
}
public void setDate (Date date) {
mDate = date;
}
public boolean isSolved () {
return mSolved;
}
public void setSolved (boolean solved) {
mSolved = solved;
}
}
CrimeFragment.java
package com.example.aster.criminalintent;
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.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.EditText;
import java.util.Date;
import java.util.UUID;
import static android.widget.CompoundButton.*;
public class CrimeFragment extends Fragment {
private static final String ARG_CRIME_ID = "crime_id" ;
private static final String DIALOG_DATE = "DialogDate" ;
private static final int REQUEST_DATE = 0 ;
private Crime mCrime;
private EditText mTitleField;
private Button mDateButton;
private CheckBox mSolvedCheckBox;
public static CrimeFragment newInstance (UUID crimeId) {
Bundle args = new Bundle();
args.putSerializable(ARG_CRIME_ID, crimeId);
CrimeFragment fragment = new CrimeFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate (Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
UUID crimeId = (UUID) getArguments().getSerializable(ARG_CRIME_ID);
mCrime = CrimeLab.get(getActivity()).getCrime(crimeId);
}
@Override
public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_crime, container, false );
mTitleField = (EditText) v.findViewById(R.id.crime_title);
mTitleField.setText(mCrime.getTitle());
mTitleField.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged (CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged (CharSequence s, int start, int before, int count) {
mCrime.setTitle(s.toString());
}
@Override
public void afterTextChanged (Editable s) {
}
});
mDateButton = (Button) v.findViewById(R.id.crime_date);
updateDate();
mDateButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick (View v) {
FragmentManager manager = getFragmentManager();
DatePickerFragment dialog = DatePickerFragment
.newInstance(mCrime.getDate());
dialog.setTargetFragment(CrimeFragment.this , REQUEST_DATE);
dialog.show(manager, DIALOG_DATE);
}
});
mSolvedCheckBox = (CheckBox) v.findViewById(R.id.crime_solved);
mSolvedCheckBox.setChecked(mCrime.isSolved());
mSolvedCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged (CompoundButton buttonView, boolean isChecked) {
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();
}
}
private void updateDate () {
mDateButton.setText(mCrime.getDate().toString());
}
}
CrimeLab.java
package com.example.aster.criminalintent;
import android.content.Context;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class CrimeLab {
private static CrimeLab sCrimeLab;
private List<Crime> mCrimes;
public static CrimeLab get (Context context) {
if (sCrimeLab == null ) {
sCrimeLab = new CrimeLab(context);
}
return sCrimeLab;
}
private CrimeLab (Context context) {
mCrimes = new ArrayList<>();
for (int i = 0 ; i < 100 ; i++) {
Crime crime = new Crime();
crime.setTitle("Crime #" + i);
crime.setSolved(i % 2 == 0 );
mCrimes.add(crime);
}
}
public List<Crime> getCrimes () {
return mCrimes;
}
public Crime getCrime (UUID id) {
for (Crime crime : mCrimes) {
if (crime.getId().equals(id)) {
return crime;
}
}
return null ;
}
}
CrimeListActivity.java
package com.example.aster.criminalintent;
import android.support.v4.app.Fragment;
public class CrimeListActivity extends SingleFragmentActivity {
@Override
protected Fragment createFragment () {
return new CrimeListFragment();
}
}
CrimeListFragment.java
package com.example.aster.criminalintent;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.List;
public class CrimeListFragment extends Fragment {
private RecyclerView mCrimeRecyclerView;
private CrimeAdapter mAdapter;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container , Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_crime_list, container , false );
mCrimeRecyclerView = (RecyclerView) view.findViewById(R.id.crime_recycler_view);
mCrimeRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
updateUI();
return view;
}
@Override
public void onResume() {
super .onResume();
updateUI();
}
private void updateUI() {
CrimeLab crimeLab = CrimeLab.get(getActivity());
List<Crime> crimes = crimeLab.getCrimes();
if (mAdapter == null ) {
mAdapter = new CrimeAdapter(crimes);
mCrimeRecyclerView.setAdapter(mAdapter);
} else {
mAdapter.notifyDataSetChanged();
}
}
private class CrimeHolder extends RecyclerView .ViewHolder
implements View .OnClickListener {
private Crime mCrime;
private TextView mTitleTextView;
private TextView mDateTextView;
private ImageView mSolvedImageView;
public CrimeHolder(LayoutInflater inflater, ViewGroup parent) {
super (inflater.inflate(R.layout.list_item_crime, parent, false ));
itemView.setOnClickListener(this );
mTitleTextView = (TextView) itemView.findViewById(R.id.crime_title);
mDateTextView = (TextView) itemView.findViewById(R.id.crime_date);
mSolvedImageView = (ImageView) itemView.findViewById(R.id.crime_solved);
}
public void bind(Crime crime) {
mCrime = crime;
mTitleTextView.setText(mCrime.getTitle());
mDateTextView.setText(mCrime.getDate().toString());
mSolvedImageView.setVisibility(crime.isSolved() ? View.VISIBLE : View.GONE);
}
@Override
public void onClick(View view) {
Intent intent = CrimePagerActivity.newIntent(getActivity(), mCrime.getId());
startActivity(intent);
}
}
private class CrimeAdapter extends RecyclerView .Adapter <CrimeHolder > {
private List<Crime> mCrimes;
public CrimeAdapter(List<Crime> crimes) {
mCrimes = crimes;
}
@Override
public CrimeHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
return new CrimeHolder(layoutInflater, parent);
}
@Override
public void onBindViewHolder(CrimeHolder holder, int position) {
Crime crime = mCrimes.get(position);
holder.bind(crime);
}
@Override
public int getItemCount() {
return mCrimes.size();
}
}
}
package com.example.aster.criminalintent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import java.util.List;
import java.util.UUID;
public class CrimePagerActivity extends AppCompatActivity {
private static final String EXTRA_CRIME_ID =
"com.example.aster.criminalintent.crime_id" ;
private ViewPager mViewPager;
private List<Crime> mCrimes;
public static Intent newIntent (Context packageContext, UUID crimeId) {
Intent intent = new Intent(packageContext, CrimePagerActivity.class);
intent.putExtra(EXTRA_CRIME_ID, crimeId);
return intent;
}
@Override
protected void onCreate (Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout.activity_crime_pager);
UUID crimeId = (UUID) getIntent()
.getSerializableExtra(EXTRA_CRIME_ID);
mViewPager = (ViewPager) findViewById(R.id.crime_view_pager);
mCrimes = CrimeLab.get(this ).getCrimes();
FragmentManager fragmentManager = getSupportFragmentManager();
mViewPager.setAdapter(new FragmentStatePagerAdapter(fragmentManager) {
@Override
public Fragment getItem (int position) {
Crime crime = mCrimes.get(position);
return CrimeFragment.newInstance(crime.getId());
}
@Override
public int getCount () {
return mCrimes.size();
}
});
for (int i = 0 ; i < mCrimes.size(); i++) {
if (mCrimes.get(i).getId().equals(crimeId)) {
mViewPager.setCurrentItem(i);
break ;
}
}
}
}
DatePickerFragment.java
package com.example.aster.criminalintent;
import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.DatePicker;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
public class DatePickerFragment extends DialogFragment {
public static final String EXTRA_DATE =
"com.example.aster.criminalintent.date" ;
private static final String ARG_DATE = "date" ;
private DatePicker mDatePicker;
public static DatePickerFragment newInstance (Date date) {
Bundle args = new Bundle();
args.putSerializable(ARG_DATE, date);
DatePickerFragment fragment = new DatePickerFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public Dialog onCreateDialog (Bundle savedInstanceState) {
Date date = (Date) getArguments().getSerializable(ARG_DATE);
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);
View v = LayoutInflater.from(getActivity())
.inflate(R.layout.dialog_date, null );
mDatePicker = (DatePicker) v.findViewById(R.id.dialog_date_picker);
mDatePicker.init(year, month, day, null );
return new AlertDialog.Builder(getActivity())
.setView(v)
.setTitle(R.string.date_picker_title)
.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick (DialogInterface dialog, int which) {
int year = mDatePicker.getYear();
int month = mDatePicker.getMonth();
int day = mDatePicker.getDayOfMonth();
Date date = new GregorianCalendar(year, month, day).getTime();
sendResult(Activity.RESULT_OK, date);
}
})
.create();
}
private void sendResult (int resultCode, Date date) {
if (getTargetFragment() == null ) {
return ;
}
Intent intent = new Intent();
intent.putExtra(EXTRA_DATE, date);
getTargetFragment()
.onActivityResult(getTargetRequestCode(), resultCode, intent);
}
}
SingleFragmentActivity.java
package com.example.aster.criminalintent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;
public abstract class SingleFragmentActivity extends AppCompatActivity {
protected abstract Fragment createFragment ();
@Override
protected void onCreate (Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment);
FragmentManager fm = getSupportFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.fragment_container);
if (fragment == null ) {
fragment = createFragment();
fm.beginTransaction().add(R.id.fragment_container, fragment).commit();
}
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android ="http://schemas.android.com/apk/res/android"
package ="com.example.aster.criminalintent" >
<application
android:allowBackup ="true"
android:icon ="@mipmap/ic_launcher"
android:label ="@string/app_name"
android:roundIcon ="@mipmap/ic_launcher_round"
android:supportsRtl ="true"
android:theme ="@style/AppTheme" >
<activity android:name =".CrimeListActivity" >
<intent-filter >
<action android:name ="android.intent.action.MAIN" />
<category android:name ="android.intent.category.LAUNCHER" />
</intent-filter >
</activity >
<activity android:name =".CrimePagerActivity" >
</activity >
</application >
</manifest >
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.view.ViewPager
xmlns:android ="http://schemas.android.com/apk/res/android"
android:id ="@+id/crime_view_pager"
android:layout_width ="match_parent"
android:layout_height ="match_parent" >
</android.support.v4.view.ViewPager >
activity_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android ="http://schemas.android.com/apk/res/android"
android:id ="@+id/fragment_container"
android:layout_width ="match_parent"
android:layout_height ="match_parent" />
dialog_date.xml
<?xml version="1.0" encoding="utf-8"?>
<DatePicker
xmlns:android ="http://schemas.android.com/apk/res/android"
android:id ="@+id/dialog_date_picker"
android:layout_width ="wrap_content"
android:layout_height ="wrap_content"
android:calendarViewShown ="false" >
</DatePicker >
fragment_crime.xml
<?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 ="match_parent"
android:layout_margin ="16dp"
android:orientation ="vertical" >
<TextView
style ="?android:listSeparatorTextViewStyle"
android:layout_width ="match_parent"
android:layout_height ="wrap_content"
android:text ="@string/crime_title_label" />
<EditText
android:id ="@+id/crime_title"
android:layout_width ="match_parent"
android:layout_height ="wrap_content"
android:hint ="@string/crime_title_hint" />
<TextView
style ="?android:listSeparatorTextViewStyle"
android:layout_width ="match_parent"
android:layout_height ="wrap_content"
android:text ="@string/crime_details_label" />
<Button
android:id ="@+id/crime_date"
android:layout_width ="match_parent"
android:layout_height ="wrap_content" />
<CheckBox
android:id ="@+id/crime_solved"
android:layout_width ="match_parent"
android:layout_height ="wrap_content"
android:text ="@string/crime_solved_label" />
</LinearLayout >
fragment_crime_list.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView
xmlns:android ="http://schemas.android.com/apk/res/android"
android:id ="@+id/crime_recycler_view"
android:layout_width ="match_parent"
android:layout_height ="match_parent" />
list_item_crime.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android ="http://schemas.android.com/apk/res/android"
xmlns:app ="http://schemas.android.com/apk/res-auto"
xmlns:tools ="http://schemas.android.com/tools"
android:id ="@+id/linearLayout"
android:layout_width ="match_parent"
android:layout_height ="wrap_content"
tools:layout_editor_absoluteY ="81dp" >
<TextView
android:id ="@+id/crime_title"
android:layout_width ="0dp"
android:layout_height ="wrap_content"
android:layout_marginEnd ="8dp"
android:layout_marginStart ="16dp"
android:layout_marginTop ="16dp"
android:text ="Crime Title"
app:layout_constraintEnd_toStartOf ="@+id/crime_solved"
app:layout_constraintStart_toStartOf ="parent"
app:layout_constraintTop_toTopOf ="parent" />
<TextView
android:id ="@+id/crime_date"
android:layout_width ="0dp"
android:layout_height ="wrap_content"
android:layout_marginEnd ="8dp"
android:layout_marginStart ="16dp"
android:layout_marginTop ="8dp"
android:text ="Crime Date"
app:layout_constraintEnd_toStartOf ="@+id/crime_solved"
app:layout_constraintStart_toStartOf ="parent"
app:layout_constraintTop_toBottomOf ="@+id/crime_title" />
<ImageView
android:id ="@+id/crime_solved"
android:layout_width ="wrap_content"
android:layout_height ="wrap_content"
android:layout_marginBottom ="16dp"
android:layout_marginEnd ="16dp"
android:layout_marginTop ="16dp"
app:layout_constraintBottom_toBottomOf ="parent"
app:layout_constraintEnd_toEndOf ="parent"
app:layout_constraintTop_toTopOf ="parent"
app:srcCompat ="@drawable/ic_solved" />
</android.support.constraint.ConstraintLayout >
strings.xml
<resources>
<string name ="app_name" >CriminalIntent</string >
<string name ="crime_title_hint" >Enter a title for the crime.</string >
<string name ="crime_title_label" >Title</string >
<string name ="crime_details_label" >Details</string >
<string name ="crime_solved_label" >Solved</string >
<string name ="date_picker_title" >Date of crime:</string >
</resources>