diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 6961a30..1c760bd 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -3,7 +3,7 @@
-
+
diff --git a/app/build.gradle b/app/build.gradle
index 3c6fdb2..4c0868c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,11 +1,18 @@
apply plugin: 'com.android.application'
android {
+ signingConfigs {
+ config {
+ keyAlias 'Bucket Drops'
+ keyPassword 'appCOURSE'
+ storeFile file('/Users/vivz/Desktop/Examples/AndroidExamples/BucketDrops/bucketdrops.jks')
+ storePassword 'bucketDROPS'
+ }
+ }
compileSdkVersion 23
buildToolsVersion "23.0.2"
-
defaultConfig {
- applicationId "slidenerd.vivz.bucketdrops"
+ applicationId "appcourse.vivz.bucketdrops"
minSdkVersion 15
targetSdkVersion 23
versionCode 1
@@ -13,15 +20,21 @@ android {
}
buildTypes {
release {
- minifyEnabled false
+ minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ signingConfig signingConfigs.config
+ }
+ debug {
}
}
}
dependencies {
- compile fileTree(dir: 'libs', include: ['*.jar'])
+ compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
- compile 'com.android.support:appcompat-v7:23.1.1'
+ compile 'com.android.support:appcompat-v7:23.2.0'
compile 'com.github.bumptech.glide:glide:3.6.1'
+ compile 'io.realm:realm-android:0.87.5'
+ compile 'com.android.support:recyclerview-v7:23.2.0'
+ compile 'com.github.halysongoncalves:pugnotification:1.8.1'
}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index 263c64e..6b8024a 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -15,3 +15,18 @@
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
+-keep class io.realm.annotations.RealmModule
+-keep @io.realm.annotations.RealmModule class *
+-keep class io.realm.internal.Keep
+-keep @io.realm.internal.Keep class * { *; }
+-dontwarn javax.**
+-dontwarn io.realm.**
+-keep public class * implements com.bumptech.glide.module.GlideModule
+-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
+ **[] $VALUES;
+ public *;
+}
+-dontwarn com.squareup.okhttp.**
+-dontwarn android.support.v7.**
+-keep class android.support.v7.** { *; }
+-keep interface android.support.v7.** { *; }
\ No newline at end of file
diff --git a/app/src/androidTest/java/slidenerd/vivz/bucketdrops/ApplicationTest.java b/app/src/androidTest/java/appcourse/vivz/bucketdrops/ApplicationTest.java
similarity index 89%
rename from app/src/androidTest/java/slidenerd/vivz/bucketdrops/ApplicationTest.java
rename to app/src/androidTest/java/appcourse/vivz/bucketdrops/ApplicationTest.java
index bae4238..fe8281e 100644
--- a/app/src/androidTest/java/slidenerd/vivz/bucketdrops/ApplicationTest.java
+++ b/app/src/androidTest/java/appcourse/vivz/bucketdrops/ApplicationTest.java
@@ -1,4 +1,4 @@
-package slidenerd.vivz.bucketdrops;
+package appcourse.vivz.bucketdrops;
import android.app.Application;
import android.test.ApplicationTestCase;
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index b2fdab1..1bebfea 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,20 +1,34 @@
+ package="appcourse.vivz.bucketdrops">
-
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/assets/fonts/raleway_thin.ttf b/app/src/main/assets/fonts/raleway_thin.ttf
new file mode 100755
index 0000000..dcc9e4f
Binary files /dev/null and b/app/src/main/assets/fonts/raleway_thin.ttf differ
diff --git a/app/src/main/java/appcourse/vivz/bucketdrops/ActivityMain.java b/app/src/main/java/appcourse/vivz/bucketdrops/ActivityMain.java
new file mode 100644
index 0000000..f9e7b2c
--- /dev/null
+++ b/app/src/main/java/appcourse/vivz/bucketdrops/ActivityMain.java
@@ -0,0 +1,211 @@
+package appcourse.vivz.bucketdrops;
+
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.DefaultItemAnimator;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.Toolbar;
+import android.support.v7.widget.helper.ItemTouchHelper;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageView;
+
+import com.bumptech.glide.Glide;
+
+import io.realm.Realm;
+import io.realm.RealmChangeListener;
+import io.realm.RealmResults;
+import io.realm.Sort;
+import appcourse.vivz.bucketdrops.adapters.AdapterDrops;
+import appcourse.vivz.bucketdrops.adapters.AddListener;
+import appcourse.vivz.bucketdrops.adapters.CompleteListener;
+import appcourse.vivz.bucketdrops.adapters.Divider;
+import appcourse.vivz.bucketdrops.adapters.Filter;
+import appcourse.vivz.bucketdrops.adapters.MarkListener;
+import appcourse.vivz.bucketdrops.adapters.ResetListener;
+import appcourse.vivz.bucketdrops.adapters.SimpleTouchCallback;
+import appcourse.vivz.bucketdrops.beans.Drop;
+import appcourse.vivz.bucketdrops.extras.Util;
+import appcourse.vivz.bucketdrops.widgets.BucketRecyclerView;
+
+public class ActivityMain extends AppCompatActivity {
+
+ public static final String TAG_DIALOG_ADD = "add";
+ public static final String TAG_DIALOG_MARK = "mark";
+ public static final String FIELD_WHEN = "when";
+ public static final String FIELD_COMPLETED = "completed";
+ Toolbar mToolbar;
+ Button mBtnAdd;
+ BucketRecyclerView mRecycler;
+ Realm mRealm;
+ RealmResults 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(), TAG_DIALOG_ADD);
+ }
+
+ private void showDialogMark(int position) {
+ DialogMark dialog = new DialogMark();
+ Bundle bundle = new Bundle();
+ bundle.putInt(DialogMark.EXTRA_POSITION, position);
+ dialog.setArguments(bundle);
+ dialog.setCompleteListener(mCompleteListener);
+ dialog.show(getSupportFragmentManager(), TAG_DIALOG_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();
+ Util.scheduleAlarm(this);
+ }
+
+ @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(FIELD_WHEN);
+ break;
+ case Filter.MOST_TIME_LEFT:
+ mResults = mRealm.where(Drop.class).findAllSortedAsync(FIELD_WHEN, Sort.DESCENDING);
+ break;
+ case Filter.COMPLETE:
+ mResults = mRealm.where(Drop.class).equalTo(FIELD_COMPLETED, true).findAllAsync();
+ break;
+ case Filter.INCOMPLETE:
+ mResults = mRealm.where(Drop.class).equalTo(FIELD_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/appcourse/vivz/bucketdrops/AppBucketDrops.java b/app/src/main/java/appcourse/vivz/bucketdrops/AppBucketDrops.java
new file mode 100644
index 0000000..891d94d
--- /dev/null
+++ b/app/src/main/java/appcourse/vivz/bucketdrops/AppBucketDrops.java
@@ -0,0 +1,54 @@
+package appcourse.vivz.bucketdrops;
+
+import android.app.Application;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.graphics.Typeface;
+import android.preference.PreferenceManager;
+import android.widget.TextView;
+
+import io.realm.Realm;
+import io.realm.RealmConfiguration;
+import appcourse.vivz.bucketdrops.adapters.Filter;
+
+/**
+ * Created by vivz on 30/12/15.
+ * TODO change to custom fonts wherever appropriate
+ */
+public class AppBucketDrops extends Application {
+
+ static String FILTER_OPTION = "filter";
+
+ @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_OPTION, filterOption);
+ editor.apply();
+ }
+
+ public static int load(Context context) {
+ SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context);
+ int filterOption = pref.getInt(FILTER_OPTION, Filter.NONE);
+ return filterOption;
+ }
+
+ public static void setRalewayRegular(Context context, TextView textView) {
+ Typeface typeface = Typeface.createFromAsset(context.getAssets(), "fonts/raleway_thin.ttf");
+ textView.setTypeface(typeface);
+ }
+
+ public static void setRalewayRegular(Context context, TextView... textViews) {
+ Typeface typeface = Typeface.createFromAsset(context.getAssets(), "fonts/raleway_thin.ttf");
+ for (TextView textView : textViews) {
+ textView.setTypeface(typeface);
+ }
+ }
+}
diff --git a/app/src/main/java/appcourse/vivz/bucketdrops/DialogAdd.java b/app/src/main/java/appcourse/vivz/bucketdrops/DialogAdd.java
new file mode 100644
index 0000000..ac429db
--- /dev/null
+++ b/app/src/main/java/appcourse/vivz/bucketdrops/DialogAdd.java
@@ -0,0 +1,82 @@
+package appcourse.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.EditText;
+import android.widget.ImageButton;
+
+import io.realm.Realm;
+import appcourse.vivz.bucketdrops.beans.Drop;
+import appcourse.vivz.bucketdrops.widgets.BucketPickerView;
+
+/**
+ * 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 BucketPickerView 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();
+ long now = System.currentTimeMillis();
+ Realm realm = Realm.getDefaultInstance();
+ Drop drop = new Drop(what, now, mInputWhen.getTime(), 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 = (BucketPickerView) view.findViewById(R.id.bpv_date);
+ mBtnAdd = (Button) view.findViewById(R.id.btn_add_it);
+ AppBucketDrops.setRalewayRegular(getActivity(), mInputWhat, mBtnAdd);
+ mBtnClose.setOnClickListener(mBtnClickListener);
+ mBtnAdd.setOnClickListener(mBtnClickListener);
+ }
+}
diff --git a/app/src/main/java/appcourse/vivz/bucketdrops/DialogMark.java b/app/src/main/java/appcourse/vivz/bucketdrops/DialogMark.java
new file mode 100644
index 0000000..46d66dd
--- /dev/null
+++ b/app/src/main/java/appcourse/vivz/bucketdrops/DialogMark.java
@@ -0,0 +1,69 @@
+package appcourse.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 appcourse.vivz.bucketdrops.adapters.CompleteListener;
+
+/**
+ * Created by vivz on 04/01/16.
+ * TODO custom fonts
+ */
+public class DialogMark extends DialogFragment {
+
+ public static final String EXTRA_POSITION = "position";
+ 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(EXTRA_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);
+ AppBucketDrops.setRalewayRegular(getActivity(), mBtnCompleted);
+ mBtnClose.setOnClickListener(mBtnClickListener);
+ mBtnCompleted.setOnClickListener(mBtnClickListener);
+ }
+
+ public void setCompleteListener(CompleteListener mCompleteListener) {
+ mListener = mCompleteListener;
+ }
+}
diff --git a/app/src/main/java/appcourse/vivz/bucketdrops/adapters/AdapterDrops.java b/app/src/main/java/appcourse/vivz/bucketdrops/adapters/AdapterDrops.java
new file mode 100644
index 0000000..3b49d77
--- /dev/null
+++ b/app/src/main/java/appcourse/vivz/bucketdrops/adapters/AdapterDrops.java
@@ -0,0 +1,231 @@
+package appcourse.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 appcourse.vivz.bucketdrops.AppBucketDrops;
+import appcourse.vivz.bucketdrops.R;
+import appcourse.vivz.bucketdrops.beans.Drop;
+import appcourse.vivz.bucketdrops.extras.Util;
+
+/**
+ * Created by vivz on 30/12/15.
+ */
+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;
+ 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);
+ AppBucketDrops.setRalewayRegular(mContext, mTextWhat, mTextWhen);
+ 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 {
+
+ Context mContext;
+ Button mBtnAdd;
+ AddListener mListener;
+
+ public FooterHolder(View itemView) {
+ super(itemView);
+ mContext = itemView.getContext();
+ mBtnAdd = (Button) itemView.findViewById(R.id.btn_footer);
+ AppBucketDrops.setRalewayRegular(mContext, mBtnAdd);
+ 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/appcourse/vivz/bucketdrops/adapters/AddListener.java b/app/src/main/java/appcourse/vivz/bucketdrops/adapters/AddListener.java
new file mode 100644
index 0000000..c6b6149
--- /dev/null
+++ b/app/src/main/java/appcourse/vivz/bucketdrops/adapters/AddListener.java
@@ -0,0 +1,8 @@
+package appcourse.vivz.bucketdrops.adapters;
+
+/**
+ * Created by vivz on 03/01/16.
+ */
+public interface AddListener {
+ void add();
+}
diff --git a/app/src/main/java/appcourse/vivz/bucketdrops/adapters/CompleteListener.java b/app/src/main/java/appcourse/vivz/bucketdrops/adapters/CompleteListener.java
new file mode 100644
index 0000000..880c7bc
--- /dev/null
+++ b/app/src/main/java/appcourse/vivz/bucketdrops/adapters/CompleteListener.java
@@ -0,0 +1,8 @@
+package appcourse.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/appcourse/vivz/bucketdrops/adapters/Divider.java b/app/src/main/java/appcourse/vivz/bucketdrops/adapters/Divider.java
new file mode 100644
index 0000000..a6443ea
--- /dev/null
+++ b/app/src/main/java/appcourse/vivz/bucketdrops/adapters/Divider.java
@@ -0,0 +1,60 @@
+package appcourse.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 appcourse.vivz.bucketdrops.R;
+
+/**
+ * Created by vivz on 03/01/16.
+ */
+public class Divider extends RecyclerView.ItemDecoration {
+
+ 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/appcourse/vivz/bucketdrops/adapters/Filter.java b/app/src/main/java/appcourse/vivz/bucketdrops/adapters/Filter.java
new file mode 100644
index 0000000..7356c37
--- /dev/null
+++ b/app/src/main/java/appcourse/vivz/bucketdrops/adapters/Filter.java
@@ -0,0 +1,12 @@
+package appcourse.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/appcourse/vivz/bucketdrops/adapters/MarkListener.java b/app/src/main/java/appcourse/vivz/bucketdrops/adapters/MarkListener.java
new file mode 100644
index 0000000..63cd536
--- /dev/null
+++ b/app/src/main/java/appcourse/vivz/bucketdrops/adapters/MarkListener.java
@@ -0,0 +1,8 @@
+package appcourse.vivz.bucketdrops.adapters;
+
+/**
+ * Created by vivz on 04/01/16.
+ */
+public interface MarkListener {
+ void onMark(int position);
+}
diff --git a/app/src/main/java/appcourse/vivz/bucketdrops/adapters/ResetListener.java b/app/src/main/java/appcourse/vivz/bucketdrops/adapters/ResetListener.java
new file mode 100644
index 0000000..50b57aa
--- /dev/null
+++ b/app/src/main/java/appcourse/vivz/bucketdrops/adapters/ResetListener.java
@@ -0,0 +1,8 @@
+package appcourse.vivz.bucketdrops.adapters;
+
+/**
+ * Created by vivz on 06/01/16.
+ */
+public interface ResetListener {
+ void onReset();
+}
diff --git a/app/src/main/java/appcourse/vivz/bucketdrops/adapters/SimpleTouchCallback.java b/app/src/main/java/appcourse/vivz/bucketdrops/adapters/SimpleTouchCallback.java
new file mode 100644
index 0000000..5026f0a
--- /dev/null
+++ b/app/src/main/java/appcourse/vivz/bucketdrops/adapters/SimpleTouchCallback.java
@@ -0,0 +1,57 @@
+package appcourse.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 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/appcourse/vivz/bucketdrops/adapters/SwipeListener.java b/app/src/main/java/appcourse/vivz/bucketdrops/adapters/SwipeListener.java
new file mode 100644
index 0000000..403e4eb
--- /dev/null
+++ b/app/src/main/java/appcourse/vivz/bucketdrops/adapters/SwipeListener.java
@@ -0,0 +1,8 @@
+package appcourse.vivz.bucketdrops.adapters;
+
+/**
+ * Created by vivz on 04/01/16.
+ */
+public interface SwipeListener {
+ void onSwipe(int position);
+}
diff --git a/app/src/main/java/appcourse/vivz/bucketdrops/beans/Drop.java b/app/src/main/java/appcourse/vivz/bucketdrops/beans/Drop.java
new file mode 100644
index 0000000..9516505
--- /dev/null
+++ b/app/src/main/java/appcourse/vivz/bucketdrops/beans/Drop.java
@@ -0,0 +1,57 @@
+package appcourse.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/appcourse/vivz/bucketdrops/extras/Util.java b/app/src/main/java/appcourse/vivz/bucketdrops/extras/Util.java
new file mode 100644
index 0000000..bb446c9
--- /dev/null
+++ b/app/src/main/java/appcourse/vivz/bucketdrops/extras/Util.java
@@ -0,0 +1,52 @@
+package appcourse.vivz.bucketdrops.extras;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.view.View;
+
+import java.util.List;
+
+import appcourse.vivz.bucketdrops.services.NotificationService;
+
+/**
+ * Created by vivz on 31/12/15.
+ */
+public class Util {
+ public static final int DELAY = 1000;
+ public static final int FREQUENCY = 1000 * 3600 * 4;
+
+ 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);
+ }
+ }
+
+ public static void scheduleAlarm(Context context) {
+ AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ Intent intent = new Intent(context, NotificationService.class);
+ PendingIntent pendingIntent = PendingIntent.getService(context, 100, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ manager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, DELAY, FREQUENCY, pendingIntent);
+ }
+}
diff --git a/app/src/main/java/appcourse/vivz/bucketdrops/receivers/BootReceiver.java b/app/src/main/java/appcourse/vivz/bucketdrops/receivers/BootReceiver.java
new file mode 100644
index 0000000..194cf0d
--- /dev/null
+++ b/app/src/main/java/appcourse/vivz/bucketdrops/receivers/BootReceiver.java
@@ -0,0 +1,17 @@
+package appcourse.vivz.bucketdrops.receivers;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import appcourse.vivz.bucketdrops.extras.Util;
+
+public class BootReceiver extends BroadcastReceiver {
+ public BootReceiver() {
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Util.scheduleAlarm(context);
+ }
+}
diff --git a/app/src/main/java/appcourse/vivz/bucketdrops/services/NotificationService.java b/app/src/main/java/appcourse/vivz/bucketdrops/services/NotificationService.java
new file mode 100644
index 0000000..3a7a3df
--- /dev/null
+++ b/app/src/main/java/appcourse/vivz/bucketdrops/services/NotificationService.java
@@ -0,0 +1,72 @@
+package appcourse.vivz.bucketdrops.services;
+
+import android.app.IntentService;
+import android.app.Notification;
+import android.content.Intent;
+
+import br.com.goncalves.pugnotification.notification.PugNotification;
+import io.realm.Realm;
+import io.realm.RealmResults;
+import appcourse.vivz.bucketdrops.ActivityMain;
+import appcourse.vivz.bucketdrops.R;
+import appcourse.vivz.bucketdrops.beans.Drop;
+
+
+/**
+ * An {@link IntentService} subclass for handling asynchronous task requests in
+ * a service on a separate handler thread.
+ *
+ * TODO: Customize class - update intent actions and extra parameters.
+ */
+public class NotificationService extends IntentService {
+
+ public NotificationService() {
+ super("NotificationService");
+ }
+
+ @Override
+ protected void onHandleIntent(Intent intent) {
+ Realm realm = null;
+ try {
+ realm = Realm.getDefaultInstance();
+ RealmResults results = realm.where(Drop.class).equalTo("completed", false).findAll();
+ for (Drop current : results) {
+ if (isNotificationNeeded(current.getAdded(), current.getWhen())) {
+ fireNotification(current);
+ }
+ }
+
+ } finally {
+ if (realm != null) {
+ realm.close();
+ }
+ }
+ }
+
+ private void fireNotification(Drop drop) {
+ String message = getString(R.string.notif_message) + "\"" + drop.getWhat() + "\"";
+ PugNotification.with(this)
+ .load()
+ .title(R.string.notif_title)
+ .message(message)
+ .bigTextStyle(R.string.notif_long_message)
+ .smallIcon(R.drawable.ic_drop)
+ .largeIcon(R.drawable.ic_drop)
+ .flags(Notification.DEFAULT_ALL)
+ .autoCancel(true)
+ .click(ActivityMain.class)
+ .simple()
+ .build();
+ }
+
+ private boolean isNotificationNeeded(long added, long when) {
+ long now = System.currentTimeMillis();
+ if (now > when) {
+ return false;
+ } else {
+ long difference90 = (long) (0.9 * (when - added));
+ return (now > (added + difference90)) ? true : false;
+ }
+ }
+
+}
diff --git a/app/src/main/java/appcourse/vivz/bucketdrops/widgets/BucketPickerView.java b/app/src/main/java/appcourse/vivz/bucketdrops/widgets/BucketPickerView.java
new file mode 100644
index 0000000..72fe267
--- /dev/null
+++ b/app/src/main/java/appcourse/vivz/bucketdrops/widgets/BucketPickerView.java
@@ -0,0 +1,288 @@
+package appcourse.vivz.bucketdrops.widgets;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Parcelable;
+import android.support.v4.content.ContextCompat;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+
+import appcourse.vivz.bucketdrops.AppBucketDrops;
+import appcourse.vivz.bucketdrops.R;
+
+/**
+ * Created by vivz on 10/01/16.
+ */
+public class BucketPickerView extends LinearLayout implements View.OnTouchListener {
+ public static final int LEFT = 0;
+ public static final int TOP = 1;
+ public static final int RIGHT = 2;
+ public static final int BOTTOM = 3;
+ public static final int DELAY = 250;
+ private Calendar mCalendar;
+ private TextView mTextDate;
+ private TextView mTextMonth;
+ private TextView mTextYear;
+ private SimpleDateFormat mFormatter;
+ private String TAG = "VIVZ";
+ private boolean mIncrement;
+ private boolean mDecrement;
+
+ private Drawable mUpNormal;
+ private Drawable mUpPressed;
+ private Drawable mDownNormal;
+ private Drawable mDownPressed;
+
+ private Handler mHandler = new Handler(new Handler.Callback() {
+ @Override
+ public boolean handleMessage(Message msg) {
+ if (mIncrement) {
+ increment(mActiveId);
+ }
+ if (mDecrement) {
+ decrement(mActiveId);
+ }
+ if (mIncrement || mDecrement) {
+ mHandler.sendEmptyMessageDelayed(MESSAGE_WHAT, DELAY);
+ }
+ return true;
+ }
+ });
+ private int MESSAGE_WHAT = 123;
+ private int mActiveId;
+
+ public BucketPickerView(Context context) {
+ super(context);
+ init(context);
+ }
+
+ public BucketPickerView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context);
+ }
+
+ public BucketPickerView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(context);
+ }
+
+ private void init(Context context) {
+ View view = LayoutInflater.from(context).inflate(R.layout.bucket_picker_view, this);
+ mCalendar = Calendar.getInstance();
+ mFormatter = new SimpleDateFormat("MMM");
+ mUpNormal = ContextCompat.getDrawable(context, R.drawable.up_normal);
+ mUpPressed = ContextCompat.getDrawable(context, R.drawable.up_pressed);
+ mDownNormal = ContextCompat.getDrawable(context, R.drawable.down_normal);
+ mDownPressed = ContextCompat.getDrawable(context, R.drawable.down_pressed);
+ }
+
+ @Override
+ protected Parcelable onSaveInstanceState() {
+ Log.d(TAG, "onSaveInstanceState: ");
+ Bundle bundle = new Bundle();
+ bundle.putParcelable("super", super.onSaveInstanceState());
+ bundle.putInt("date", mCalendar.get(Calendar.DATE));
+ bundle.putInt("month", mCalendar.get(Calendar.MONTH));
+ bundle.putInt("year", mCalendar.get(Calendar.YEAR));
+ return bundle;
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ Log.d(TAG, "onRestoreInstanceState: ");
+ if (state instanceof Parcelable) {
+ Bundle bundle = (Bundle) state;
+ state = bundle.getParcelable("super");
+ int date = bundle.getInt("date");
+ int month = bundle.getInt("month");
+ int year = bundle.getInt("year");
+ update(date, month, year, 0, 0, 0);
+ }
+ super.onRestoreInstanceState(state);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mTextDate = (TextView) this.findViewById(R.id.tv_date);
+ mTextMonth = (TextView) this.findViewById(R.id.tv_month);
+ mTextYear = (TextView) this.findViewById(R.id.tv_year);
+ AppBucketDrops.setRalewayRegular(getContext(), mTextDate, mTextMonth, mTextYear);
+ mTextDate.setOnTouchListener(this);
+ mTextMonth.setOnTouchListener(this);
+ mTextYear.setOnTouchListener(this);
+ int date = mCalendar.get(Calendar.DATE);
+ int month = mCalendar.get(Calendar.MONTH);
+ int year = mCalendar.get(Calendar.YEAR);
+ update(date, month, year, 0, 0, 0);
+ }
+
+ private void update(int date, int month, int year, int hour, int minute, int second) {
+ mCalendar.set(Calendar.DATE, date);
+ mCalendar.set(Calendar.MONTH, month);
+ mCalendar.set(Calendar.YEAR, year);
+ mCalendar.set(Calendar.HOUR, hour);
+ mCalendar.set(Calendar.MINUTE, minute);
+ mCalendar.set(Calendar.SECOND, second);
+ mTextYear.setText(year + "");
+ mTextDate.setText(date + "");
+ mTextMonth.setText(mFormatter.format(mCalendar.getTime()));
+ }
+
+ public long getTime() {
+ return mCalendar.getTimeInMillis();
+ }
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ switch (v.getId()) {
+ case R.id.tv_date:
+ processEventsFor(mTextDate, event);
+ break;
+ case R.id.tv_month:
+ processEventsFor(mTextMonth, event);
+ break;
+ case R.id.tv_year:
+ processEventsFor(mTextYear, event);
+ break;
+ }
+ return true;
+ }
+
+ private void processEventsFor(TextView textView, MotionEvent event) {
+ Drawable[] drawables = textView.getCompoundDrawables();
+ if (hasDrawableTop(drawables) && hasDrawableBottom(drawables)) {
+ Rect topBounds = drawables[TOP].getBounds();
+ Rect bottomBounds = drawables[BOTTOM].getBounds();
+ float x = event.getX();
+ float y = event.getY();
+ mActiveId = textView.getId();
+ if (topDrawableHit(textView, topBounds.height(), x, y)) {
+ if (isActionDown(event)) {
+ mIncrement = true;
+ increment(textView.getId());
+ mHandler.removeMessages(MESSAGE_WHAT);
+ mHandler.sendEmptyMessageDelayed(MESSAGE_WHAT, DELAY);
+ toggleDrawable(textView, true);
+ }
+ if (isActionUpOrCancel(event)) {
+ mIncrement = false;
+ toggleDrawable(textView, false);
+ }
+
+ } else if (bottomDrawableHit(textView, bottomBounds.height(), x, y)) {
+ if (isActionDown(event)) {
+ mDecrement = true;
+ decrement(textView.getId());
+ mHandler.removeMessages(MESSAGE_WHAT);
+ mHandler.sendEmptyMessageDelayed(MESSAGE_WHAT, DELAY);
+ toggleDrawable(textView, true);
+ }
+ if (isActionUpOrCancel(event)) {
+ mDecrement = false;
+ toggleDrawable(textView, false);
+ }
+ } else {
+ mIncrement = false;
+ mDecrement = false;
+ toggleDrawable(textView, false);
+ }
+ }
+ }
+
+ private void increment(int id) {
+ switch (id) {
+ case R.id.tv_date:
+ mCalendar.add(Calendar.DATE, 1);
+ break;
+ case R.id.tv_month:
+ mCalendar.add(Calendar.MONTH, 1);
+ break;
+ case R.id.tv_year:
+ mCalendar.add(Calendar.YEAR, 1);
+ break;
+ }
+ set(mCalendar);
+ }
+
+ private void set(Calendar calendar) {
+ int date = calendar.get(Calendar.DATE);
+ int year = calendar.get(Calendar.YEAR);
+ mTextDate.setText(date + "");
+ mTextYear.setText(year + "");
+ mTextMonth.setText(mFormatter.format(mCalendar.getTime()));
+ }
+
+ private void decrement(int id) {
+ switch (id) {
+ case R.id.tv_date:
+ mCalendar.add(Calendar.DATE, -1);
+ break;
+ case R.id.tv_month:
+ mCalendar.add(Calendar.MONTH, -1);
+ break;
+ case R.id.tv_year:
+ mCalendar.add(Calendar.YEAR, -1);
+ break;
+ }
+ set(mCalendar);
+ }
+
+ private boolean isActionDown(MotionEvent event) {
+ return event.getAction() == MotionEvent.ACTION_DOWN;
+ }
+
+ private boolean isActionUpOrCancel(MotionEvent event) {
+ return event.getAction() == MotionEvent.ACTION_UP
+ || event.getAction() == MotionEvent.ACTION_CANCEL;
+ }
+
+ private boolean topDrawableHit(TextView textView, int drawableHeight, float x, float y) {
+ int xmin = textView.getPaddingLeft();
+ int xmax = textView.getWidth() - textView.getPaddingRight();
+ int ymin = textView.getPaddingTop();
+ int ymax = textView.getPaddingTop() + drawableHeight;
+ return x > xmin && x < xmax && y > ymin && y < ymax;
+ }
+
+ private boolean bottomDrawableHit(TextView textView, int drawableHeight, float x, float y) {
+ int xmin = textView.getPaddingLeft();
+ int xmax = textView.getWidth() - textView.getPaddingRight();
+ int ymax = textView.getHeight() - textView.getPaddingBottom();
+ int ymin = ymax - drawableHeight;
+ return x > xmin && x < xmax && y > ymin && y < ymax;
+ }
+
+ private boolean hasDrawableTop(Drawable[] drawables) {
+ return drawables[TOP] != null;
+ }
+
+ private boolean hasDrawableBottom(Drawable[] drawables) {
+ return drawables[BOTTOM] != null;
+ }
+
+ private void toggleDrawable(TextView textView, boolean pressed) {
+ if (pressed) {
+ if (mIncrement) {
+ textView.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.up_pressed, 0, R.drawable.down_normal);
+ }
+ if (mDecrement) {
+ textView.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.up_normal, 0, R.drawable.down_pressed);
+ }
+ } else {
+ textView.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.up_normal, 0, R.drawable.down_normal);
+ }
+ }
+}
diff --git a/app/src/main/java/appcourse/vivz/bucketdrops/widgets/BucketRecyclerView.java b/app/src/main/java/appcourse/vivz/bucketdrops/widgets/BucketRecyclerView.java
new file mode 100644
index 0000000..602d6e8
--- /dev/null
+++ b/app/src/main/java/appcourse/vivz/bucketdrops/widgets/BucketRecyclerView.java
@@ -0,0 +1,106 @@
+package appcourse.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 appcourse.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/java/slidenerd/vivz/bucketdrops/ActivityMain.java b/app/src/main/java/slidenerd/vivz/bucketdrops/ActivityMain.java
deleted file mode 100644
index 8b16200..0000000
--- a/app/src/main/java/slidenerd/vivz/bucketdrops/ActivityMain.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package slidenerd.vivz.bucketdrops;
-
-import android.os.Bundle;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.View;
-import android.widget.Button;
-import android.widget.ImageView;
-import android.widget.Toast;
-
-import com.bumptech.glide.Glide;
-
-public class ActivityMain extends AppCompatActivity {
-
- Toolbar mToolbar;
- Button mBtnAdd;
- private View.OnClickListener mBtnAddListener = new View.OnClickListener() {
-
- @Override
- public void onClick(View v) {
- Toast.makeText(ActivityMain.this, "Button was clicked from anonymous listener pointed to by a variable", Toast.LENGTH_SHORT).show();
- }
- };
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- mToolbar = (Toolbar) findViewById(R.id.toolbar);
- mBtnAdd = (Button) findViewById(R.id.btn_add);
-
- mBtnAdd.setOnClickListener(mBtnAddListener);
- setSupportActionBar(mToolbar);
- initBackgroundImage();
- }
-
- 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/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_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_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_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_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_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/bg_et_drop.xml b/app/src/main/res/drawable/bg_et_drop.xml
new file mode 100644
index 0000000..69355e2
--- /dev/null
+++ b/app/src/main/res/drawable/bg_et_drop.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
\ 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..879310f
--- /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..fa10ac9
--- /dev/null
+++ b/app/src/main/res/drawable/down_normal.xml
@@ -0,0 +1,18 @@
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
\ 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..7a88563
--- /dev/null
+++ b/app/src/main/res/drawable/down_pressed.xml
@@ -0,0 +1,18 @@
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
\ No newline at end of file
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..692ec61
--- /dev/null
+++ b/app/src/main/res/drawable/up_normal.xml
@@ -0,0 +1,18 @@
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
\ 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..38eb67b
--- /dev/null
+++ b/app/src/main/res/drawable/up_pressed.xml
@@ -0,0 +1,18 @@
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
\ 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 e582ca3..8e5cea8 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,20 +1,29 @@
+ tools:context="appcourse.vivz.bucketdrops.ActivityMain">
+
+
-
-
+ android:layout_below="@id/toolbar"
+ app:layoutManager="android.support.v7.widget.LinearLayoutManager" />
+
+
-
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..0c759ac
--- /dev/null
+++ b/app/src/main/res/layout/bucket_picker_view.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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
index 6a1326c..5af35ee 100644
--- a/app/src/main/res/layout/dialog_add.xml
+++ b/app/src/main/res/layout/dialog_add.xml
@@ -1,46 +1,54 @@
-
+
-
+
-
+
-
+
-
+
-
-
\ No newline at end of file
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_mark.xml b/app/src/main/res/layout/dialog_mark.xml
new file mode 100644
index 0000000..2bd7f3f
--- /dev/null
+++ b/app/src/main/res/layout/dialog_mark.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/empty_drops.xml b/app/src/main/res/layout/empty_drops.xml
index 83c6a05..0bdc4aa 100644
--- a/app/src/main/res/layout/empty_drops.xml
+++ b/app/src/main/res/layout/empty_drops.xml
@@ -1,31 +1,36 @@
-
-
+
-
-
\ No newline at end of file
+
+
+
+
+
diff --git a/app/src/main/res/layout/footer.xml b/app/src/main/res/layout/footer.xml
new file mode 100644
index 0000000..179894e
--- /dev/null
+++ b/app/src/main/res/layout/footer.xml
@@ -0,0 +1,13 @@
+
+
diff --git a/app/src/main/res/layout/no_item.xml b/app/src/main/res/layout/no_item.xml
new file mode 100644
index 0000000..d5b5972
--- /dev/null
+++ b/app/src/main/res/layout/no_item.xml
@@ -0,0 +1,10 @@
+
+
diff --git a/app/src/main/res/layout/row_drop.xml b/app/src/main/res/layout/row_drop.xml
new file mode 100644
index 0000000..4dfa3db
--- /dev/null
+++ b/app/src/main/res/layout/row_drop.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/toolbar.xml b/app/src/main/res/layout/toolbar.xml
index 52c055f..3c4cc32 100644
--- a/app/src/main/res/layout/toolbar.xml
+++ b/app/src/main/res/layout/toolbar.xml
@@ -1,7 +1,9 @@
+ android:background="@color/dark_blue"
+ app:popupTheme="@style/ToolbarStyle">
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml
new file mode 100644
index 0000000..7f8aba4
--- /dev/null
+++ b/app/src/main/res/menu/menu_main.xml
@@ -0,0 +1,26 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
old mode 100644
new mode 100755
index cde69bc..3329ebe
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
old mode 100644
new mode 100755
index c133a0c..ffe5cd9
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
old mode 100644
new mode 100755
index bfa42f0..3aa7039
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
old mode 100644
new mode 100755
index 324e72c..f3cd441
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
old mode 100644
new mode 100755
index aee44e1..baf82dc
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/values-v16/styles.xml b/app/src/main/res/values-v16/styles.xml
new file mode 100644
index 0000000..1c34986
--- /dev/null
+++ b/app/src/main/res/values-v16/styles.xml
@@ -0,0 +1,7 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-w320dp/dimens.xml b/app/src/main/res/values-w320dp/dimens.xml
new file mode 100644
index 0000000..643efee
--- /dev/null
+++ b/app/src/main/res/values-w320dp/dimens.xml
@@ -0,0 +1,6 @@
+
+
+ 72dp
+ 12dp
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-w820dp/dimens.xml b/app/src/main/res/values-w820dp/dimens.xml
index 63fc816..ec1b386 100644
--- a/app/src/main/res/values-w820dp/dimens.xml
+++ b/app/src/main/res/values-w820dp/dimens.xml
@@ -3,4 +3,8 @@
(such as screen margins) for screens with more than 820dp of available width. This
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
64dp
+ 32dp
+ 184dp
+ 48sp
+ 32dp
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 07eedc0..72b1609 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -6,4 +6,9 @@
#B691FF
#05FFCA
#241543
+ #BD8E79BB
+ #ED8E79BB
+ #4A8E79BB
+ #E30D0028
+ #000000
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index e3c850b..2a66264 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -19,4 +19,33 @@
28sp
36dp
18sp
+
+
+ 12dp
+
+
+ 22dp
+
+
+ 22dp
+ 22dp
+
+
+ 92dp
+ 24sp
+ 14dp
+ 4dp
+ 16dp
+
+ 24dp
+
+
+ 16dp
+ 64dp
+ 28sp
+ 96dp
+ 16dp
+ 24sp
+ 128dp
+ 60dp
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 8bf3cf7..e4f9936 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -4,4 +4,15 @@
sans-serif-thin
What is it?
Add It
+ Most Time Left
+ Least Time Left
+ Complete
+ Incomplete
+ Add
+ None
+ No Items To Display
+ Achievement
+ "You are nearing your goal "
+ "Congratulations, You are on the verge of accomplishing your goal "
+ Mark Completed
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 5e404d9..5be9dbd 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -1,11 +1,57 @@
+
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/test/java/slidenerd/vivz/bucketdrops/ExampleUnitTest.java b/app/src/test/java/slidenerd/vivz/bucketdrops/ExampleUnitTest.java
index 6a9a3b6..da1090c 100644
--- a/app/src/test/java/slidenerd/vivz/bucketdrops/ExampleUnitTest.java
+++ b/app/src/test/java/slidenerd/vivz/bucketdrops/ExampleUnitTest.java
@@ -1,4 +1,4 @@
-package slidenerd.vivz.bucketdrops;
+package appcourse.vivz.bucketdrops;
import org.junit.Test;
diff --git a/build.gradle b/build.gradle
index b169365..9ba5972 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,7 +5,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.0.0-alpha1'
+ classpath 'com.android.tools.build:gradle:2.0.0-beta6'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index f23df6e..0057b0b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip
+distributionUrl=https://services.gradle.org/distributions/gradle-2.10-all.zip