diff --git a/app/build.gradle b/app/build.gradle index 175b137..8c271bd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -23,4 +23,7 @@ dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.1.1' + compile 'com.github.bumptech.glide:glide:3.6.1' + compile 'io.realm:realm-android:0.87.1' + compile 'com.android.support:recyclerview-v7:23.1.1' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b2fdab1..2babb4a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ package="slidenerd.vivz.bucketdrops"> mResults; + View mEmptyView; + AdapterDrops mAdapter; + private View.OnClickListener mBtnAddListener = new View.OnClickListener() { + + @Override + public void onClick(View v) { + showDialogAdd(); + } + }; + private AddListener mAddListener = new AddListener() { + @Override + public void add() { + showDialogAdd(); + } + }; + + private RealmChangeListener mChangeListener = new RealmChangeListener() { + @Override + public void onChange() { + mAdapter.update(mResults); + } + }; + + private MarkListener mMarkListener = new MarkListener() { + @Override + public void onMark(int position) { + showDialogMark(position); + } + }; + + private CompleteListener mCompleteListener = new CompleteListener() { + @Override + public void onComplete(int position) { + mAdapter.markComplete(position); + } + }; + private ResetListener mResetListener = new ResetListener() { + @Override + public void onReset() { + AppBucketDrops.save(ActivityMain.this, Filter.NONE); + loadResults(Filter.NONE); + } + }; + + private void showDialogAdd() { + DialogAdd dialog = new DialogAdd(); + dialog.show(getSupportFragmentManager(), "Add"); + } + + private void showDialogMark(int position) { + DialogMark dialog = new DialogMark(); + Bundle bundle = new Bundle(); + bundle.putInt("POSITION", position); + dialog.setArguments(bundle); + dialog.setCompleteListener(mCompleteListener); + dialog.show(getSupportFragmentManager(), "Mark"); + } + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); + mRealm = Realm.getDefaultInstance(); + mToolbar = (Toolbar) findViewById(R.id.toolbar); + setSupportActionBar(mToolbar); + mBtnAdd = (Button) findViewById(R.id.btn_add); + mBtnAdd.setOnClickListener(mBtnAddListener); + + int filterOption = AppBucketDrops.load(this); + loadResults(filterOption); + mEmptyView = findViewById(R.id.empty_drops); + mRecycler = (BucketRecyclerView) findViewById(R.id.rv_drops); + mRecycler.addItemDecoration(new Divider(this, LinearLayoutManager.VERTICAL)); + mRecycler.setItemAnimator(new DefaultItemAnimator()); + mRecycler.hideIfEmpty(mToolbar); + mRecycler.showIfEmpty(mEmptyView); + mAdapter = new AdapterDrops(this, mRealm, mResults, mAddListener, mMarkListener, mResetListener); + mAdapter.setHasStableIds(true); + mRecycler.setAdapter(mAdapter); + SimpleTouchCallback callback = new SimpleTouchCallback(mAdapter); + ItemTouchHelper helper = new ItemTouchHelper(callback); + helper.attachToRecyclerView(mRecycler); + initBackgroundImage(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_main, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int id = item.getItemId(); + boolean handled = true; + int filterOption = Filter.NONE; + switch (id) { + case R.id.action_add: + showDialogAdd(); + break; + case R.id.action_sort_none: + filterOption = Filter.NONE; + break; + case R.id.action_sort_ascending_date: + filterOption = Filter.LEAST_TIME_LEFT; + break; + case R.id.action_sort_descending_date: + filterOption = Filter.MOST_TIME_LEFT; + break; + case R.id.action_show_complete: + filterOption = Filter.COMPLETE; + break; + case R.id.action_show_incomplete: + filterOption = Filter.INCOMPLETE; + break; + default: + handled = false; + break; + } + loadResults(filterOption); + AppBucketDrops.save(this, filterOption); + return handled; + } + + private void loadResults(int filterOption) { + switch (filterOption) { + case Filter.NONE: + mResults = mRealm.where(Drop.class).findAllAsync(); + break; + case Filter.LEAST_TIME_LEFT: + mResults = mRealm.where(Drop.class).findAllSortedAsync("when"); + break; + case Filter.MOST_TIME_LEFT: + mResults = mRealm.where(Drop.class).findAllSortedAsync("when", Sort.DESCENDING); + break; + case Filter.COMPLETE: + mResults = mRealm.where(Drop.class).equalTo("completed", true).findAllAsync(); + break; + case Filter.INCOMPLETE: + mResults = mRealm.where(Drop.class).equalTo("completed", false).findAllAsync(); + break; + } + mResults.addChangeListener(mChangeListener); + } + + + @Override + protected void onStart() { + super.onStart(); + mResults.addChangeListener(mChangeListener); + } + + @Override + protected void onStop() { + super.onStop(); + mResults.removeChangeListener(mChangeListener); + } + + private void initBackgroundImage() { + ImageView background = (ImageView) findViewById(R.id.iv_background); + Glide.with(this) + .load(R.drawable.background) + .centerCrop() + .into(background); } + } diff --git a/app/src/main/java/slidenerd/vivz/bucketdrops/AppBucketDrops.java b/app/src/main/java/slidenerd/vivz/bucketdrops/AppBucketDrops.java new file mode 100644 index 0000000..a13a94b --- /dev/null +++ b/app/src/main/java/slidenerd/vivz/bucketdrops/AppBucketDrops.java @@ -0,0 +1,39 @@ +package slidenerd.vivz.bucketdrops; + +import android.app.Application; +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; + +import io.realm.Realm; +import io.realm.RealmConfiguration; +import slidenerd.vivz.bucketdrops.adapters.Filter; + +/** + * Created by vivz on 30/12/15. + * TODO change to custom fonts wherever appropriate + */ +public class AppBucketDrops extends Application { + public static final String TAG = "VIVZ"; + + @Override + public void onCreate() { + super.onCreate(); + RealmConfiguration configuration = new RealmConfiguration.Builder(this).build(); + Realm.setDefaultConfiguration(configuration); + } + + public static void save(Context context, int filterOption) { + + SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context); + SharedPreferences.Editor editor = pref.edit(); + editor.putInt("filter", filterOption); + editor.apply(); + } + + public static int load(Context context) { + SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context); + int filterOption = pref.getInt("filter", Filter.NONE); + return filterOption; + } +} diff --git a/app/src/main/java/slidenerd/vivz/bucketdrops/DialogAdd.java b/app/src/main/java/slidenerd/vivz/bucketdrops/DialogAdd.java new file mode 100644 index 0000000..a4e3063 --- /dev/null +++ b/app/src/main/java/slidenerd/vivz/bucketdrops/DialogAdd.java @@ -0,0 +1,92 @@ +package slidenerd.vivz.bucketdrops; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.DialogFragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.DatePicker; +import android.widget.EditText; +import android.widget.ImageButton; + +import java.util.Calendar; + +import io.realm.Realm; +import slidenerd.vivz.bucketdrops.beans.Drop; + +/** + * Created by vivz on 28/12/15. + * TODO make it full screen + custom fonts + * TODO add custom date picker + */ +public class DialogAdd extends DialogFragment { + + private ImageButton mBtnClose; + private EditText mInputWhat; + private DatePicker mInputWhen; + private Button mBtnAdd; + + private View.OnClickListener mBtnClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + int id = v.getId(); + switch (id) { + case R.id.btn_add_it: + addAction(); + break; + } + dismiss(); + } + }; + + private void addAction() { + //get the value of the 'goal' or 'to-do' + //get the time when it was added + String what = mInputWhat.getText().toString(); + String date = mInputWhen.getDayOfMonth() + "/" + mInputWhen.getMonth() + "/" + mInputWhen.getYear(); + Calendar calendar = Calendar.getInstance(); + calendar.set(Calendar.DAY_OF_MONTH, mInputWhen.getDayOfMonth()); + calendar.set(Calendar.MONTH, mInputWhen.getMonth()); + calendar.set(Calendar.YEAR, mInputWhen.getYear()); + calendar.set(Calendar.HOUR, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + long now = System.currentTimeMillis(); + Realm realm = Realm.getDefaultInstance(); + Drop drop = new Drop(what, now, calendar.getTimeInMillis(), false); + realm.beginTransaction(); + realm.copyToRealm(drop); + realm.commitTransaction(); + realm.close(); + + } + + public DialogAdd() { + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setStyle(DialogFragment.STYLE_NORMAL, R.style.DialogTheme); + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.dialog_add, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + mBtnClose = (ImageButton) view.findViewById(R.id.btn_close); + mInputWhat = (EditText) view.findViewById(R.id.et_drop); + mInputWhen = (DatePicker) view.findViewById(R.id.bpv_date); + mBtnAdd = (Button) view.findViewById(R.id.btn_add_it); + + mBtnClose.setOnClickListener(mBtnClickListener); + mBtnAdd.setOnClickListener(mBtnClickListener); + } +} diff --git a/app/src/main/java/slidenerd/vivz/bucketdrops/DialogMark.java b/app/src/main/java/slidenerd/vivz/bucketdrops/DialogMark.java new file mode 100644 index 0000000..3f48796 --- /dev/null +++ b/app/src/main/java/slidenerd/vivz/bucketdrops/DialogMark.java @@ -0,0 +1,67 @@ +package slidenerd.vivz.bucketdrops; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.DialogFragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.ImageButton; + +import slidenerd.vivz.bucketdrops.adapters.CompleteListener; + +/** + * Created by vivz on 04/01/16. + * TODO make it full screen + custom fonts + */ +public class DialogMark extends DialogFragment { + + private ImageButton mBtnClose; + private Button mBtnCompleted; + private View.OnClickListener mBtnClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.btn_completed: + markAsComplete(); + break; + } + dismiss(); + } + }; + private CompleteListener mListener; + + private void markAsComplete() { + Bundle arguments = getArguments(); + if (mListener != null && arguments != null) { + int position = arguments.getInt("POSITION"); + mListener.onComplete(position); + } + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setStyle(DialogFragment.STYLE_NORMAL, R.style.DialogTheme); + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.dialog_mark, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + mBtnClose = (ImageButton) view.findViewById(R.id.btn_close); + mBtnCompleted = (Button) view.findViewById(R.id.btn_completed); + mBtnClose.setOnClickListener(mBtnClickListener); + mBtnCompleted.setOnClickListener(mBtnClickListener); + } + + public void setCompleteListener(CompleteListener mCompleteListener) { + mListener = mCompleteListener; + } +} diff --git a/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/AdapterDrops.java b/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/AdapterDrops.java new file mode 100644 index 0000000..398baba --- /dev/null +++ b/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/AdapterDrops.java @@ -0,0 +1,229 @@ +package slidenerd.vivz.bucketdrops.adapters; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.RecyclerView; +import android.text.format.DateUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.TextView; + +import io.realm.Realm; +import io.realm.RealmResults; +import slidenerd.vivz.bucketdrops.AppBucketDrops; +import slidenerd.vivz.bucketdrops.R; +import slidenerd.vivz.bucketdrops.beans.Drop; +import slidenerd.vivz.bucketdrops.extras.Util; + +/** + * Created by vivz on 30/12/15. + * TODO add a reset listener when the person swipes to delete an item when sorting under complete or incomplete + */ +public class AdapterDrops extends RecyclerView.Adapter implements SwipeListener { + public static final int COUNT_FOOTER = 1; + public static final int COUNT_NO_ITEMS = 1; + public static final int ITEM = 0; + public static final int NO_ITEM = 1; + public static final int FOOTER = 2; + private final ResetListener mResetListener; + private MarkListener mMarkListener; + + private LayoutInflater mInflater; + private Realm mRealm; + private RealmResults mResults; + public static final String TAG = "VIVZ"; + private AddListener mAddListener; + private int mFilterOption; + private Context mContext; + + + public AdapterDrops(Context context, Realm realm, RealmResults results, AddListener listener, MarkListener markListener, ResetListener resetListener) { + mContext = context; + mInflater = LayoutInflater.from(context); + update(results); + mRealm = realm; + mAddListener = listener; + mMarkListener = markListener; + mResetListener = resetListener; + } + + public void update(RealmResults results) { + mResults = results; + mFilterOption = AppBucketDrops.load(mContext); + notifyDataSetChanged(); + + } + + @Override + public long getItemId(int position) { + if (position < mResults.size()) { + return mResults.get(position).getAdded(); + } + return RecyclerView.NO_ID; + } + + @Override + public int getItemCount() { + if (!mResults.isEmpty()) { + return mResults.size() + COUNT_FOOTER; + } else { + if (mFilterOption == Filter.LEAST_TIME_LEFT + || mFilterOption == Filter.MOST_TIME_LEFT + || mFilterOption == Filter.NONE) { + return 0; + } else { + return COUNT_NO_ITEMS + COUNT_FOOTER; + } + } + } + + @Override + public int getItemViewType(int position) { + if (!mResults.isEmpty()) { + if (position < mResults.size()) { + return ITEM; + } else { + return FOOTER; + } + } else { + if (mFilterOption == Filter.COMPLETE || + mFilterOption == Filter.INCOMPLETE) { + if (position == 0) { + return NO_ITEM; + } else { + return FOOTER; + } + } else { + return ITEM; + } + } + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + if (viewType == FOOTER) { + View view = mInflater.inflate(R.layout.footer, parent, false); + return new FooterHolder(view, mAddListener); + } else if (viewType == NO_ITEM) { + View view = mInflater.inflate(R.layout.no_item, parent, false); + return new NoItemsHolder(view); + } else { + View view = mInflater.inflate(R.layout.row_drop, parent, false); + return new DropHolder(view, mMarkListener); + } + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + if (holder instanceof DropHolder) { + DropHolder dropHolder = (DropHolder) holder; + Drop drop = mResults.get(position); + dropHolder.setWhat(drop.getWhat()); + dropHolder.setWhen(drop.getWhen()); + dropHolder.setBackground(drop.isCompleted()); + } + } + + @Override + public void onSwipe(int position) { + if (position < mResults.size()) { + mRealm.beginTransaction(); + mResults.get(position).removeFromRealm(); + mRealm.commitTransaction(); + notifyItemRemoved(position); + } + resetFilterIfEmpty(); + } + + private void resetFilterIfEmpty() { + if (mResults.isEmpty() && (mFilterOption == Filter.COMPLETE || + mFilterOption == Filter.INCOMPLETE)){ + mResetListener.onReset(); + } + } + + public void markComplete(int position) { + if (position < mResults.size()) { + mRealm.beginTransaction(); + mResults.get(position).setCompleted(true); + mRealm.commitTransaction(); + notifyItemChanged(position); + } + } + + public static class DropHolder extends RecyclerView.ViewHolder implements View.OnClickListener { + + TextView mTextWhat; + TextView mTextWhen; + MarkListener mMarkListener; + Context mContext; + View mItemView; + + public DropHolder(View itemView, MarkListener listener) { + super(itemView); + mItemView = itemView; + mContext = itemView.getContext(); + itemView.setOnClickListener(this); + mTextWhat = (TextView) itemView.findViewById(R.id.tv_what); + mTextWhen = (TextView) itemView.findViewById(R.id.tv_when); + mMarkListener = listener; + } + + public void setWhat(String what) { + mTextWhat.setText(what); + } + + @Override + public void onClick(View v) { + mMarkListener.onMark(getAdapterPosition()); + } + + public void setBackground(boolean completed) { + Drawable drawable; + if (completed) { + drawable = ContextCompat.getDrawable(mContext, R.color.bg_drop_complete); + } else { + drawable = ContextCompat.getDrawable(mContext, R.drawable.bg_row_drop); + } + Util.setBackground(mItemView, drawable); + } + + public void setWhen(long when) { + mTextWhen.setText(DateUtils.getRelativeTimeSpanString(when, System.currentTimeMillis(), DateUtils.DAY_IN_MILLIS, DateUtils.FORMAT_ABBREV_ALL)); + } + } + + public static class NoItemsHolder extends RecyclerView.ViewHolder { + + public NoItemsHolder(View itemView) { + super(itemView); + } + } + + public static class FooterHolder extends RecyclerView.ViewHolder implements View.OnClickListener { + + Button mBtnAdd; + AddListener mListener; + + public FooterHolder(View itemView) { + super(itemView); + mBtnAdd = (Button) itemView.findViewById(R.id.btn_footer); + mBtnAdd.setOnClickListener(this); + } + + public FooterHolder(View itemView, AddListener listener) { + super(itemView); + mBtnAdd = (Button) itemView.findViewById(R.id.btn_footer); + mBtnAdd.setOnClickListener(this); + mListener = listener; + } + + @Override + public void onClick(View v) { + mListener.add(); + } + } +} diff --git a/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/AddListener.java b/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/AddListener.java new file mode 100644 index 0000000..6b4d27e --- /dev/null +++ b/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/AddListener.java @@ -0,0 +1,8 @@ +package slidenerd.vivz.bucketdrops.adapters; + +/** + * Created by vivz on 03/01/16. + */ +public interface AddListener { + void add(); +} diff --git a/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/CompleteListener.java b/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/CompleteListener.java new file mode 100644 index 0000000..8a04b3e --- /dev/null +++ b/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/CompleteListener.java @@ -0,0 +1,8 @@ +package slidenerd.vivz.bucketdrops.adapters; + +/** + * Created by vivz on 04/01/16. + */ +public interface CompleteListener { + public void onComplete(int position); +} diff --git a/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/Divider.java b/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/Divider.java new file mode 100644 index 0000000..48b18ce --- /dev/null +++ b/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/Divider.java @@ -0,0 +1,61 @@ +package slidenerd.vivz.bucketdrops.adapters; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.View; + +import slidenerd.vivz.bucketdrops.R; + +/** + * Created by vivz on 03/01/16. + */ +public class Divider extends RecyclerView.ItemDecoration { + + public static final String TAG = "VIVZ"; + private Drawable mDivider; + private int mOrientation; + + public Divider(Context context, int orientation) { + mDivider = ContextCompat.getDrawable(context, R.drawable.divider); + if (orientation != LinearLayoutManager.VERTICAL) { + throw new IllegalArgumentException("This Item Decoration can be used only with a RecyclerView that uses a LinearLayoutManager with vertical orientation"); + } + mOrientation = orientation; + } + + @Override + public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { + if (mOrientation == LinearLayoutManager.VERTICAL) { + drawHorizontalDivider(c, parent, state); + } + } + + private void drawHorizontalDivider(Canvas c, RecyclerView parent, RecyclerView.State state) { + int left, top, right, bottom; + left = parent.getPaddingLeft(); + right = parent.getWidth() - parent.getPaddingRight(); + int count = parent.getChildCount(); + for (int i = 0; i < count; i++) { + if (AdapterDrops.FOOTER != parent.getAdapter().getItemViewType(i)) { + View current = parent.getChildAt(i); + RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) current.getLayoutParams(); + top = current.getTop() - params.topMargin; + bottom = top + mDivider.getIntrinsicHeight(); + mDivider.setBounds(left, top, right, bottom); + mDivider.draw(c); + } + } + } + + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + if (mOrientation == LinearLayoutManager.VERTICAL) { + outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); + } + } +} diff --git a/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/Filter.java b/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/Filter.java new file mode 100644 index 0000000..7b51f91 --- /dev/null +++ b/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/Filter.java @@ -0,0 +1,12 @@ +package slidenerd.vivz.bucketdrops.adapters; + +/** + * Created by vivz on 05/01/16. + */ +public interface Filter { + int NONE = 0; + int MOST_TIME_LEFT = 1; + int LEAST_TIME_LEFT = 2; + int COMPLETE = 3; + int INCOMPLETE = 4; +} diff --git a/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/MarkListener.java b/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/MarkListener.java new file mode 100644 index 0000000..f03e32d --- /dev/null +++ b/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/MarkListener.java @@ -0,0 +1,8 @@ +package slidenerd.vivz.bucketdrops.adapters; + +/** + * Created by vivz on 04/01/16. + */ +public interface MarkListener { + void onMark(int position); +} diff --git a/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/ResetListener.java b/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/ResetListener.java new file mode 100644 index 0000000..5a0d393 --- /dev/null +++ b/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/ResetListener.java @@ -0,0 +1,8 @@ +package slidenerd.vivz.bucketdrops.adapters; + +/** + * Created by vivz on 06/01/16. + */ +public interface ResetListener { + void onReset(); +} diff --git a/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/SimpleTouchCallback.java b/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/SimpleTouchCallback.java new file mode 100644 index 0000000..6e5ceb9 --- /dev/null +++ b/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/SimpleTouchCallback.java @@ -0,0 +1,58 @@ +package slidenerd.vivz.bucketdrops.adapters; + +import android.graphics.Canvas; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.helper.ItemTouchHelper; + +/** + * Created by vivz on 04/01/16. + */ +public class SimpleTouchCallback extends ItemTouchHelper.Callback { + private SwipeListener mListener; + public static final String TAG = "VIVZ"; + + public SimpleTouchCallback(SwipeListener listener) { + mListener = listener; + } + + @Override + public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { + return makeMovementFlags(0, ItemTouchHelper.END); + } + + @Override + public boolean isLongPressDragEnabled() { + return false; + } + + @Override + public boolean isItemViewSwipeEnabled() { + return true; + } + + @Override + public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { + return false; + } + + @Override + public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { + if (viewHolder instanceof AdapterDrops.DropHolder) { + super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); + } + } + + @Override + public void onChildDrawOver(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { + if (viewHolder instanceof AdapterDrops.DropHolder) { + super.onChildDrawOver(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); + } + } + + @Override + public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { + if (viewHolder instanceof AdapterDrops.DropHolder) { + mListener.onSwipe(viewHolder.getLayoutPosition()); + } + } +} diff --git a/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/SwipeListener.java b/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/SwipeListener.java new file mode 100644 index 0000000..28d0e0f --- /dev/null +++ b/app/src/main/java/slidenerd/vivz/bucketdrops/adapters/SwipeListener.java @@ -0,0 +1,8 @@ +package slidenerd.vivz.bucketdrops.adapters; + +/** + * Created by vivz on 04/01/16. + */ +public interface SwipeListener { + void onSwipe(int position); +} diff --git a/app/src/main/java/slidenerd/vivz/bucketdrops/beans/Drop.java b/app/src/main/java/slidenerd/vivz/bucketdrops/beans/Drop.java new file mode 100644 index 0000000..418802b --- /dev/null +++ b/app/src/main/java/slidenerd/vivz/bucketdrops/beans/Drop.java @@ -0,0 +1,57 @@ +package slidenerd.vivz.bucketdrops.beans; + +import io.realm.RealmObject; +import io.realm.annotations.PrimaryKey; + +/** + * Created by vivz on 30/12/15. + */ +public class Drop extends RealmObject { + public Drop(String what, long added, long when, boolean completed) { + this.what = what; + this.added = added; + this.when = when; + this.completed = completed; + } + + private String what; + @PrimaryKey + private long added; + private long when; + private boolean completed; + + public Drop() { + } + + public String getWhat() { + return what; + } + + public void setWhat(String what) { + this.what = what; + } + + public long getAdded() { + return added; + } + + public void setAdded(long added) { + this.added = added; + } + + public long getWhen() { + return when; + } + + public void setWhen(long when) { + this.when = when; + } + + public boolean isCompleted() { + return completed; + } + + public void setCompleted(boolean completed) { + this.completed = completed; + } +} diff --git a/app/src/main/java/slidenerd/vivz/bucketdrops/extras/Util.java b/app/src/main/java/slidenerd/vivz/bucketdrops/extras/Util.java new file mode 100644 index 0000000..1f24253 --- /dev/null +++ b/app/src/main/java/slidenerd/vivz/bucketdrops/extras/Util.java @@ -0,0 +1,36 @@ +package slidenerd.vivz.bucketdrops.extras; + +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.view.View; + +import java.util.List; + +/** + * Created by vivz on 31/12/15. + */ +public class Util { + public static void showViews(List views) { + for (View view : views) { + view.setVisibility(View.VISIBLE); + } + } + + public static void hideViews(List views) { + for (View view : views) { + view.setVisibility(View.GONE); + } + } + + public static boolean moreThanJellyBean() { + return Build.VERSION.SDK_INT > 15; + } + + public static void setBackground(View view, Drawable drawable) { + if (moreThanJellyBean()) { + view.setBackground(drawable); + } else { + view.setBackgroundDrawable(drawable); + } + } +} diff --git a/app/src/main/java/slidenerd/vivz/bucketdrops/widgets/BucketRecyclerView.java b/app/src/main/java/slidenerd/vivz/bucketdrops/widgets/BucketRecyclerView.java new file mode 100644 index 0000000..1c4e07a --- /dev/null +++ b/app/src/main/java/slidenerd/vivz/bucketdrops/widgets/BucketRecyclerView.java @@ -0,0 +1,106 @@ +package slidenerd.vivz.bucketdrops.widgets; + +import android.content.Context; +import android.support.annotation.Nullable; +import android.support.v7.widget.RecyclerView; +import android.util.AttributeSet; +import android.view.View; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import slidenerd.vivz.bucketdrops.extras.Util; + +/** + * Created by vivz on 31/12/15. + */ +public class BucketRecyclerView extends RecyclerView { + + private List mNonEmptyViews = Collections.emptyList(); + private List mEmptyViews = Collections.emptyList(); + private AdapterDataObserver mObserver = new AdapterDataObserver() { + @Override + public void onChanged() { + toggleViews(); + } + + @Override + public void onItemRangeChanged(int positionStart, int itemCount) { + toggleViews(); + } + + @Override + public void onItemRangeChanged(int positionStart, int itemCount, Object payload) { + toggleViews(); + } + + @Override + public void onItemRangeInserted(int positionStart, int itemCount) { + toggleViews(); + } + + @Override + public void onItemRangeRemoved(int positionStart, int itemCount) { + toggleViews(); + } + + @Override + public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) { + toggleViews(); + } + }; + + private void toggleViews() { + if (getAdapter() != null && !mEmptyViews.isEmpty() && !mNonEmptyViews.isEmpty()) { + if (getAdapter().getItemCount() == 0) { + + //show all the empty views + Util.showViews(mEmptyViews); + //hide the RecyclerView + setVisibility(View.GONE); + + //hide all the views which are meant to be hidden + Util.hideViews(mNonEmptyViews); + } else { + //hide all the empty views + Util.showViews(mNonEmptyViews); + + //show the RecyclerView + setVisibility(View.VISIBLE); + + //hide all the views which are meant to be hidden + Util.hideViews(mEmptyViews); + } + } + } + + public BucketRecyclerView(Context context) { + super(context); + } + + public BucketRecyclerView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public BucketRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + public void setAdapter(Adapter adapter) { + super.setAdapter(adapter); + if (adapter != null) { + adapter.registerAdapterDataObserver(mObserver); + } + mObserver.onChanged(); + } + + public void hideIfEmpty(View... views) { + mNonEmptyViews = Arrays.asList(views); + } + + public void showIfEmpty(View... emptyViews) { + mEmptyViews = Arrays.asList(emptyViews); + } +} diff --git a/app/src/main/res/color/btn_add_color.xml b/app/src/main/res/color/btn_add_color.xml new file mode 100644 index 0000000..bcfe559 --- /dev/null +++ b/app/src/main/res/color/btn_add_color.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi/ic_action_add.png b/app/src/main/res/drawable-hdpi/ic_action_add.png new file mode 100644 index 0000000..7800ba3 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_action_add.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_check.png b/app/src/main/res/drawable-hdpi/ic_check.png new file mode 100755 index 0000000..8a6a2dc Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_check.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_close.png b/app/src/main/res/drawable-hdpi/ic_close.png new file mode 100644 index 0000000..0d83919 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_close.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_down_normal.png b/app/src/main/res/drawable-hdpi/ic_down_normal.png new file mode 100755 index 0000000..d0f0563 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_down_normal.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_down_pressed.png b/app/src/main/res/drawable-hdpi/ic_down_pressed.png new file mode 100755 index 0000000..a24dc3d Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_down_pressed.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_drop.png b/app/src/main/res/drawable-hdpi/ic_drop.png new file mode 100755 index 0000000..368228b Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_drop.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_up_normal.png b/app/src/main/res/drawable-hdpi/ic_up_normal.png new file mode 100755 index 0000000..b95a444 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_up_normal.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_up_pressed.png b/app/src/main/res/drawable-hdpi/ic_up_pressed.png new file mode 100755 index 0000000..5c7512e Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_up_pressed.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_action_add.png b/app/src/main/res/drawable-mdpi/ic_action_add.png new file mode 100644 index 0000000..ed40b2b Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_action_add.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_check.png b/app/src/main/res/drawable-mdpi/ic_check.png new file mode 100755 index 0000000..b7bba0f Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_check.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_close.png b/app/src/main/res/drawable-mdpi/ic_close.png new file mode 100644 index 0000000..385abea Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_close.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_down_normal.png b/app/src/main/res/drawable-mdpi/ic_down_normal.png new file mode 100755 index 0000000..15837d2 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_down_normal.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_down_pressed.png b/app/src/main/res/drawable-mdpi/ic_down_pressed.png new file mode 100755 index 0000000..795228b Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_down_pressed.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_drop.png b/app/src/main/res/drawable-mdpi/ic_drop.png new file mode 100755 index 0000000..2360b9a Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_drop.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_up_normal.png b/app/src/main/res/drawable-mdpi/ic_up_normal.png new file mode 100755 index 0000000..0a7db2a Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_up_normal.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_up_pressed.png b/app/src/main/res/drawable-mdpi/ic_up_pressed.png new file mode 100755 index 0000000..5f7806f Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_up_pressed.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_action_add.png b/app/src/main/res/drawable-xhdpi/ic_action_add.png new file mode 100644 index 0000000..185be8a Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_action_add.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_check.png b/app/src/main/res/drawable-xhdpi/ic_check.png new file mode 100755 index 0000000..dda1727 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_check.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_close.png b/app/src/main/res/drawable-xhdpi/ic_close.png new file mode 100644 index 0000000..1b79d0b Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_close.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_down_normal.png b/app/src/main/res/drawable-xhdpi/ic_down_normal.png new file mode 100755 index 0000000..872a298 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_down_normal.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_down_pressed.png b/app/src/main/res/drawable-xhdpi/ic_down_pressed.png new file mode 100755 index 0000000..884f591 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_down_pressed.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_drop.png b/app/src/main/res/drawable-xhdpi/ic_drop.png new file mode 100755 index 0000000..6a82189 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_drop.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_up_normal.png b/app/src/main/res/drawable-xhdpi/ic_up_normal.png new file mode 100755 index 0000000..5e2caa6 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_up_normal.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_up_pressed.png b/app/src/main/res/drawable-xhdpi/ic_up_pressed.png new file mode 100755 index 0000000..be7783a Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_up_pressed.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_add.png b/app/src/main/res/drawable-xxhdpi/ic_action_add.png new file mode 100644 index 0000000..2ab780a Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_action_add.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_check.png b/app/src/main/res/drawable-xxhdpi/ic_check.png new file mode 100755 index 0000000..1ef4645 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_check.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_close.png b/app/src/main/res/drawable-xxhdpi/ic_close.png new file mode 100644 index 0000000..783a624 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_close.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_down_normal.png b/app/src/main/res/drawable-xxhdpi/ic_down_normal.png new file mode 100755 index 0000000..f01e619 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_down_normal.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_down_pressed.png b/app/src/main/res/drawable-xxhdpi/ic_down_pressed.png new file mode 100755 index 0000000..0de927c Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_down_pressed.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_drop.png b/app/src/main/res/drawable-xxhdpi/ic_drop.png new file mode 100755 index 0000000..407e836 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_drop.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_up_normal.png b/app/src/main/res/drawable-xxhdpi/ic_up_normal.png new file mode 100755 index 0000000..b6d5951 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_up_normal.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_up_pressed.png b/app/src/main/res/drawable-xxhdpi/ic_up_pressed.png new file mode 100755 index 0000000..d604e96 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_up_pressed.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_add.png b/app/src/main/res/drawable-xxxhdpi/ic_action_add.png new file mode 100644 index 0000000..e6ca376 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_action_add.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_check.png b/app/src/main/res/drawable-xxxhdpi/ic_check.png new file mode 100755 index 0000000..2dbe64a Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_check.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_close.png b/app/src/main/res/drawable-xxxhdpi/ic_close.png new file mode 100644 index 0000000..6e484ec Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_close.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_drop.png b/app/src/main/res/drawable-xxxhdpi/ic_drop.png new file mode 100755 index 0000000..22f60ee Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_drop.png differ diff --git a/app/src/main/res/drawable/android.png b/app/src/main/res/drawable/android.png new file mode 100644 index 0000000..799d0a1 Binary files /dev/null and b/app/src/main/res/drawable/android.png differ diff --git a/app/src/main/res/drawable/background.png b/app/src/main/res/drawable/background.png new file mode 100755 index 0000000..04b98d6 Binary files /dev/null and b/app/src/main/res/drawable/background.png differ diff --git a/app/src/main/res/drawable/bg_btn_add_it.xml b/app/src/main/res/drawable/bg_btn_add_it.xml new file mode 100644 index 0000000..8751a08 --- /dev/null +++ b/app/src/main/res/drawable/bg_btn_add_it.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_picker_item_background.xml b/app/src/main/res/drawable/bg_picker_item_background.xml new file mode 100644 index 0000000..4c25858 --- /dev/null +++ b/app/src/main/res/drawable/bg_picker_item_background.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_row_drop.xml b/app/src/main/res/drawable/bg_row_drop.xml new file mode 100644 index 0000000..bdc641e --- /dev/null +++ b/app/src/main/res/drawable/bg_row_drop.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/divider.xml b/app/src/main/res/drawable/divider.xml new file mode 100644 index 0000000..3287fa1 --- /dev/null +++ b/app/src/main/res/drawable/divider.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/down_normal.xml b/app/src/main/res/drawable/down_normal.xml new file mode 100644 index 0000000..b2a7723 --- /dev/null +++ b/app/src/main/res/drawable/down_normal.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/down_pressed.xml b/app/src/main/res/drawable/down_pressed.xml new file mode 100644 index 0000000..63dbe60 --- /dev/null +++ b/app/src/main/res/drawable/down_pressed.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/logo_large.png b/app/src/main/res/drawable/logo_large.png new file mode 100644 index 0000000..e0cd775 Binary files /dev/null and b/app/src/main/res/drawable/logo_large.png differ diff --git a/app/src/main/res/drawable/up_normal.xml b/app/src/main/res/drawable/up_normal.xml new file mode 100644 index 0000000..d458a0e --- /dev/null +++ b/app/src/main/res/drawable/up_normal.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/up_pressed.xml b/app/src/main/res/drawable/up_pressed.xml new file mode 100644 index 0000000..60133b6 --- /dev/null +++ b/app/src/main/res/drawable/up_pressed.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 0e4bb05..a1de722 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,16 +1,29 @@ - + + + + + + + + diff --git a/app/src/main/res/layout/bucket_picker_view.xml b/app/src/main/res/layout/bucket_picker_view.xml new file mode 100644 index 0000000..31f4340 --- /dev/null +++ b/app/src/main/res/layout/bucket_picker_view.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_add.xml b/app/src/main/res/layout/dialog_add.xml new file mode 100644 index 0000000..efe2d03 --- /dev/null +++ b/app/src/main/res/layout/dialog_add.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + +