diff --git a/.idea/misc.xml b/.idea/misc.xml index 5d19981..fbb6828 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -37,7 +37,7 @@ - + diff --git a/app/build.gradle b/app/build.gradle index b8a8cf2..324d086 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -24,11 +24,16 @@ android { } } +repositories { + mavenCentral() +} + dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' + compile 'com.google.code.gson:gson:2.6.2' compile 'com.squareup.retrofit2:retrofit:2.0.1' compile 'com.squareup.retrofit2:converter-gson:2.0.1' @@ -38,4 +43,5 @@ dependencies { compile 'com.android.support:appcompat-v7:23.3.0' compile 'com.android.support:design:23.3.0' compile 'com.android.support:cardview-v7:23.3.0' + compile 'com.facebook.android:facebook-android-sdk:4.11.0' } diff --git a/app/libs/socialauth-4.4.jar b/app/libs/socialauth-4.4.jar new file mode 100644 index 0000000..ed8ecf6 Binary files /dev/null and b/app/libs/socialauth-4.4.jar differ diff --git a/app/libs/socialauth-android-3.2.jar b/app/libs/socialauth-android-3.2.jar new file mode 100644 index 0000000..04cc9d3 Binary files /dev/null and b/app/libs/socialauth-android-3.2.jar differ diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 64e5780..dc7c65f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,6 +3,8 @@ package="com.hikapro.backpack"> + + + @@ -18,6 +21,13 @@ + + + \ No newline at end of file diff --git a/app/src/main/assets/fonts/Ubuntu-B.ttf b/app/src/main/assets/fonts/Ubuntu-B.ttf new file mode 100644 index 0000000..c0142fe Binary files /dev/null and b/app/src/main/assets/fonts/Ubuntu-B.ttf differ diff --git a/app/src/main/assets/fonts/Ubuntu-M.ttf b/app/src/main/assets/fonts/Ubuntu-M.ttf new file mode 100644 index 0000000..4a776d3 Binary files /dev/null and b/app/src/main/assets/fonts/Ubuntu-M.ttf differ diff --git a/app/src/main/java/com/hikapro/backpack/FlowLayout.java b/app/src/main/java/com/hikapro/backpack/FlowLayout.java new file mode 100644 index 0000000..7846c87 --- /dev/null +++ b/app/src/main/java/com/hikapro/backpack/FlowLayout.java @@ -0,0 +1,108 @@ +package com.hikapro.backpack; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; + +/** + * Created by tariel on 22/05/16. + */ +public class FlowLayout extends ViewGroup { + + private int PADDING_X; + private int PADDING_Y; + private int mHeight; + + public FlowLayout(Context context) { + super(context); + setPaddings(0,0); + } + + protected void setPaddings(int V, int H){ + PADDING_X = H; + PADDING_Y = V; + } + + protected void setPaddings(Context ctx, AttributeSet attrs){ + TypedArray a = ctx + .obtainStyledAttributes(attrs, R.styleable.FlowLayout); + String H = a.getString(R.styleable.FlowLayout_paddingX); + String V = a.getString(R.styleable.FlowLayout_paddingY); + if (H == null || V == null) + setPaddings(V == null ? 0 : Integer.parseInt(V), H == null ? 0 :Integer.parseInt(H)); + else { + setPaddings(Integer.parseInt(V), Integer.parseInt(H)); + a.recycle(); + } + + } + + public FlowLayout(Context context, AttributeSet attrs) { + super(context, attrs); + setPaddings(context,attrs); + } + + public FlowLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + setPaddings(context,attrs); + } + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + assert (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED); + final int width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight(); + int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom(); + final int count = getChildCount(); + int xpos = getPaddingLeft(); + int ypos = getPaddingTop(); + int childHeightMeasureSpec; + if(MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) + childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST); + else + childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + mHeight = 0; + for(int i = 0; i < count; i++) { + final View child = getChildAt(i); + if(child.getVisibility() != GONE) { + child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), childHeightMeasureSpec); + final int childw = child.getMeasuredWidth(); + mHeight = Math.max(mHeight, child.getMeasuredHeight() + PADDING_Y); + if(xpos + childw > width) { + xpos = getPaddingLeft(); + ypos += mHeight; + } + xpos += childw + PADDING_X; + } + } + if(MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED) { + height = ypos + mHeight; + } else if(MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) { + if(ypos + mHeight < height) { + height = ypos + mHeight; + } + } + height += 5; // Fudge to avoid clipping bottom of last row. + setMeasuredDimension(width, height); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + final int width = r - l; + int xpos = getPaddingLeft(); + int ypos = getPaddingTop(); + for(int i = 0; i < getChildCount(); i++) { + final View child = getChildAt(i); + if(child.getVisibility() != GONE) { + final int childw = child.getMeasuredWidth(); + final int childh = child.getMeasuredHeight(); + if(xpos + childw > width) { + xpos = getPaddingLeft(); + ypos += mHeight; + } + child.layout(xpos, ypos, xpos + childw, ypos + childh); + xpos += childw + PADDING_X; + } + } + } +} diff --git a/app/src/main/java/com/hikapro/backpack/MainActivity.java b/app/src/main/java/com/hikapro/backpack/MainActivity.java index f22a430..9282095 100644 --- a/app/src/main/java/com/hikapro/backpack/MainActivity.java +++ b/app/src/main/java/com/hikapro/backpack/MainActivity.java @@ -7,22 +7,28 @@ import android.app.FragmentTransaction; import android.os.Bundle; import android.util.Log; +import com.hikapro.backpack.model.AddModel; import com.hikapro.backpack.model.DetailModel; import com.hikapro.backpack.model.ItemModel; import com.hikapro.backpack.model.PackedModel; import com.hikapro.backpack.model.SetModel; +import com.hikapro.backpack.model.ShareModel; import com.hikapro.backpack.model.entities.Item; import com.hikapro.backpack.model.entities.Set; +import com.hikapro.backpack.presenter.AddPresenter; import com.hikapro.backpack.presenter.ItemDetailPresenter; import com.hikapro.backpack.presenter.ItemListPresenter; import com.hikapro.backpack.presenter.PackedListPresenter; import com.hikapro.backpack.presenter.Presenter; import com.hikapro.backpack.presenter.SetListPresenter; +import com.hikapro.backpack.presenter.SharePresenter; import com.hikapro.backpack.view.View; +import com.hikapro.backpack.view.fragments.AddFragment; import com.hikapro.backpack.view.fragments.ItemDetailFragment; import com.hikapro.backpack.view.fragments.ItemListFragment; import com.hikapro.backpack.view.fragments.PackedListFragment; import com.hikapro.backpack.view.fragments.SetListFragment; +import com.hikapro.backpack.view.fragments.ShareFragment; public class MainActivity extends Activity implements View.ActivityCallback { @@ -82,6 +88,7 @@ public class MainActivity extends Activity implements View.ActivityCallback { presenter.setModel(model); model.setPresenter(presenter); } + fragment = fragmentManager.findFragmentByTag(PackedListFragment.class.getName()); if (fragment != null) { PackedListFragment view = (PackedListFragment) fragment; @@ -93,6 +100,30 @@ public class MainActivity extends Activity implements View.ActivityCallback { presenter.setModel(model); model.setPresenter(presenter); } + + fragment = fragmentManager.findFragmentByTag(ShareFragment.class.getName()); + if (fragment != null) { + ShareFragment view = (ShareFragment) fragment; + SharePresenter presenter = stateMaintainer.get(SharePresenter.class.getName()); + ShareModel model = stateMaintainer.get(ShareModel.class.getName()); + + view.setPresenter(presenter); + presenter.setView(view); + presenter.setModel(model); + model.setPresenter(presenter); + } + + fragment = fragmentManager.findFragmentByTag(AddFragment.class.getName()); + if (fragment != null) { + AddFragment view = (AddFragment) fragment; + AddPresenter presenter = stateMaintainer.get(AddPresenter.class.getName()); + AddModel model = stateMaintainer.get(AddModel.class.getName()); + + view.setPresenter(presenter); + presenter.setView(view); + presenter.setModel(model); + model.setPresenter(presenter); + } } Log.i("On create", "Activity"); } @@ -147,7 +178,6 @@ public class MainActivity extends Activity implements View.ActivityCallback { presenter.setModel(model); model.setPresenter(presenter); - //replaceFragment(view, false, SetListFragment.class.getName(), false, false); replaceFragment(view, SetListFragment.class.getName(), 0); stateMaintainer.put(presenter); stateMaintainer.put(model); @@ -166,7 +196,6 @@ public class MainActivity extends Activity implements View.ActivityCallback { presenter.setModel(model); model.setPresenter(presenter); - //replaceFragment(view, true, ItemListFragment.class.getName(), true, true); replaceFragment(view, ItemListFragment.class.getName(), Presenter.ADD_TO_BACKSTACK | Presenter.TRANSITION_X); @@ -191,7 +220,6 @@ public class MainActivity extends Activity implements View.ActivityCallback { presenter.setModel(model); model.setPresenter(presenter); - //replaceFragment(view, true, ItemListFragment.class.getName(), true, true); replaceFragment(view, PackedListFragment.class.getName(), Presenter.ADD_TO_BACKSTACK | Presenter.TRANSITION_Y); @@ -212,7 +240,6 @@ public class MainActivity extends Activity implements View.ActivityCallback { presenter.setModel(model); model.setPresenter(presenter); - //replaceFragment(view, true, ItemDetailFragment.class.getName(), true, true); replaceFragment(view, ItemDetailFragment.class.getName(), Presenter.ADD_TO_BACKSTACK | Presenter.TRANSITION_X); @@ -220,20 +247,41 @@ public class MainActivity extends Activity implements View.ActivityCallback { stateMaintainer.put(model); } - private void replaceFragment(Fragment fragment, boolean addBackStack, String tag, - boolean transition, boolean x) { - FragmentTransaction transaction = fragmentManager.beginTransaction(); - if (transition) { - if (x) - transaction.setCustomAnimations(R.animator.slide_in_left_x, R.animator.slide_out_right_x, - R.animator.slide_in_right_x, R.animator.slide_out_left_x); - } + @Override + public void startShareFragment(int setId) { - transaction.replace(R.id.container, fragment, tag); - if (addBackStack) - transaction.addToBackStack(null); - transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); - transaction.commit(); + ShareFragment view = ShareFragment.construct(); + SharePresenter presenter = new SharePresenter(); + ShareModel model = new ShareModel(); + + view.setPresenter(presenter); + presenter.setView(view); + presenter.setModel(model); + model.setPresenter(presenter); + + replaceFragment(view, ShareFragment.class.getName(), + Presenter.ADD_TO_BACKSTACK | Presenter.TRANSITION_X); + + stateMaintainer.put(presenter); + stateMaintainer.put(model); + } + + @Override + public void startAddFragment(Set set) { + AddFragment view = AddFragment.newFromSet(set); + AddPresenter presenter = new AddPresenter(); + AddModel model = new AddModel(); + + view.setPresenter(presenter); + presenter.setView(view); + presenter.setModel(model); + model.setPresenter(presenter); + + replaceFragment(view, AddFragment.class.getName(), + Presenter.ADD_TO_BACKSTACK | Presenter.TRANSITION_X); + + stateMaintainer.put(presenter); + stateMaintainer.put(model); } private void replaceFragment(Fragment fragment, String tag, int flags) { diff --git a/app/src/main/java/com/hikapro/backpack/model/AddModel.java b/app/src/main/java/com/hikapro/backpack/model/AddModel.java new file mode 100644 index 0000000..48d61ce --- /dev/null +++ b/app/src/main/java/com/hikapro/backpack/model/AddModel.java @@ -0,0 +1,154 @@ +package com.hikapro.backpack.model; + +import android.os.Message; +import android.widget.Toast; + +import com.hikapro.backpack.App; +import com.hikapro.backpack.model.dao.Command; +import com.hikapro.backpack.model.dao.DAO; +import com.hikapro.backpack.model.dao.Event; +import com.hikapro.backpack.model.entities.Category; +import com.hikapro.backpack.model.entities.Item; +import com.hikapro.backpack.presenter.Presenter; + +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.List; + +/** + * Created by tariel on 18/05/16. + */ +public class AddModel implements Model.Add { + + private Presenter.Add presenter; + private DAO dao; + private List filteredItems; + private List categoriesCache; + + public AddModel() { + this.filteredItems = new ArrayList<>(256); + this.categoriesCache = new ArrayList<>(20); + this.dao = DAO.getInstance(); + dao.registerObserver(this); + } + + @Override + public void onEvent(Message event) { + + switch (event.what) { + + case Event.ITEM_LIKE_LOAD_ERROR : + if (!filteredItems.isEmpty()) { + filteredItems.clear(); + } + notifyDataSetChanged(); + break; + + case Event.ITEM_CATEGORY_LOAD_ERROR : + break; + + case Event.ITEM_INSERT_ERROR : + Toast.makeText(App.getAppContext(), "Item not inserted!", Toast.LENGTH_SHORT).show(); + break; + + case Event.ITEM_LIKE_LOAD_COMPLETED : + filteredItems = (List) event.obj; + notifyDataSetChanged(); + break; + + case Event.ITEM_CATEGORY_LOAD_COMPLETED : + Hashtable res = (Hashtable)event.obj; + categoriesCache = new ArrayList<>(res.values()); // TODO check utilization + break; + + case Event.ITEM_INSERTED : + Toast.makeText(App.getAppContext(), "New item inserted", Toast.LENGTH_SHORT).show(); + break; + } + } + + @Override + public void onDestroy(boolean isConfigurationChanging) { + if ( !isConfigurationChanging ) { + presenter = null; + } + } + + @Override + public void executeQuery() { + Message command; + if (categoriesCache.isEmpty()) { + command = Message.obtain(); + command.what = Command.ITEM_GET_CATEGORIES; + dao.executeCommand(command); + } + } + + @Override + public void add(Item item, int setId) { + Message command; + command = Message.obtain(); + command.what = Command.ITEM_INSERT; + command.obj = item; + command.arg1 = setId; + dao.executeCommand(command); + } + + @Override + public void filter(String query, int checkThisSet) { + + if (!query.isEmpty()) { + Message command = Message.obtain(); + command.what = Command.ITEM_GET_LIKE; + command.arg1 = checkThisSet; + query = query.toLowerCase(); + command.obj = query; + dao.executeCommand(command); + } + } + + @Override + public void notifyDataSetChanged() { + boolean res = !filteredItems.isEmpty(); + presenter.notifyDataSetChanged(res); + } + + @Override + public int getItemsCount() { + return filteredItems.size(); + } + + @Override + public Item getItemByPosition(int position) { + return filteredItems.get(position); + } + + @Override + public int getCategoriesCount() { + return categoriesCache.size(); + } + + @Override + public Category getCategoryByPosition(int position) { + return categoriesCache.get(position); + } + + @Override + public Category getCategoryById(int id) { + for (Category category : categoriesCache) { + if (category.getId() == id) + return category; + } + return null; + } + + @Override + public void setPresenter(Presenter.Add presenter) { + this.presenter = presenter; + } + + @Override + public Presenter.Add getPresenter() { + return presenter; + } +} diff --git a/app/src/main/java/com/hikapro/backpack/model/Api.java b/app/src/main/java/com/hikapro/backpack/model/Api.java index 2cd2d68..218f39d 100644 --- a/app/src/main/java/com/hikapro/backpack/model/Api.java +++ b/app/src/main/java/com/hikapro/backpack/model/Api.java @@ -18,13 +18,13 @@ import retrofit2.http.Query; public interface Api { @GET("api/v1/backpack/items") - Call> getItems(); + Call> getItems(@Query("locale") String locale); @GET("api/v1/backpack/item_categories") - Call> getItemCategories(); + Call> getItemCategories(@Query("locale") String locale); @GET("api/v1/backpack/sets") - Call> getSets(); + Call> getSets(@Query("locale") String locale); @GET("api/v1/backpack/updates/timestamp") Call getTimestamp(); diff --git a/app/src/main/java/com/hikapro/backpack/model/ItemModel.java b/app/src/main/java/com/hikapro/backpack/model/ItemModel.java index c6e6c3b..4d2120e 100644 --- a/app/src/main/java/com/hikapro/backpack/model/ItemModel.java +++ b/app/src/main/java/com/hikapro/backpack/model/ItemModel.java @@ -2,12 +2,14 @@ package com.hikapro.backpack.model; import android.os.Message; +import android.widget.Toast; import java.util.ArrayList; import java.util.Collections; import java.util.Hashtable; import java.util.List; +import com.hikapro.backpack.App; import com.hikapro.backpack.model.dao.Command; import com.hikapro.backpack.model.dao.DAO; import com.hikapro.backpack.model.dao.Event; @@ -228,6 +230,15 @@ public class ItemModel implements Model.Item { // nothing } + @Override + public void restoreSet(int setId) { + Message command; + command = Message.obtain(); + command.what = Command.SET_RESTORE_DEFAULT; + command.arg1 = presenter.getCurrentSet().getId(); + dao.executeCommand(command); + } + @Override public void executeQuery() { Message command; @@ -259,6 +270,8 @@ public class ItemModel implements Model.Item { break; case Event.SET_UNPACK_ERROR : break; + case Event.SET_RESTORE_ERROR : + break; case Event.ITEM_FROM_SET_ERROR : break; case Event.ITEM_DELETE_ERROR : @@ -309,6 +322,12 @@ public class ItemModel implements Model.Item { break; case Event.ITEM_INSERTED : break; + case Event.SET_RESTORE_COMPLETED : + if (presenter != null) { + presenter.notifyDataSetChanged(); + } + Toast.makeText(App.getAppContext(), "Restore completed", Toast.LENGTH_SHORT).show(); + break; } } diff --git a/app/src/main/java/com/hikapro/backpack/model/Model.java b/app/src/main/java/com/hikapro/backpack/model/Model.java index 277a77f..f5920bc 100644 --- a/app/src/main/java/com/hikapro/backpack/model/Model.java +++ b/app/src/main/java/com/hikapro/backpack/model/Model.java @@ -5,6 +5,8 @@ import android.os.Message; import java.util.List; +import com.hikapro.backpack.model.entities.Category; +import com.hikapro.backpack.model.entities.Item; import com.hikapro.backpack.presenter.Presenter; /** @@ -27,6 +29,7 @@ public interface Model { Presenter.SetList getPresenter(); //GLM List getSets(); // tag renamed + void setsReorderNotify(); } @@ -54,6 +57,7 @@ public interface Model { void packItem(int itemId); void unpackItem(int itemId); void unpackSet(int setId); + void restoreSet(int setId); } interface Detail extends Base { @@ -64,6 +68,24 @@ public interface Model { Presenter.ItemDetail getPresenter(); } + interface Share extends Base { + void setPresenter(Presenter.Share presenter); + Presenter.Share getPresenter(); + + } + + interface Add extends Base { + void setPresenter(Presenter.Add presenter); + Presenter.Add getPresenter(); + void filter(String query, int checkThisSet); + int getItemsCount(); + com.hikapro.backpack.model.entities.Item getItemByPosition(int position); + int getCategoriesCount(); + Category getCategoryByPosition(int position); + Category getCategoryById(int id); + void add(com.hikapro.backpack.model.entities.Item item, int setId); + } + } diff --git a/app/src/main/java/com/hikapro/backpack/model/NetworkUtil.java b/app/src/main/java/com/hikapro/backpack/model/NetworkUtil.java new file mode 100644 index 0000000..10d2728 --- /dev/null +++ b/app/src/main/java/com/hikapro/backpack/model/NetworkUtil.java @@ -0,0 +1,43 @@ +package com.hikapro.backpack.model; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; + +import java.net.InetAddress; + +/** + * Created by tariel on 29/05/16. + */ +public class NetworkUtil { + + public static boolean isConnectedToNetwork(Context context) { + ConnectivityManager cm = + (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); + + NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); + boolean isConnected = activeNetwork != null && + activeNetwork.isConnectedOrConnecting(); + return isConnected; + } + + public static boolean isInternetAvailable() { + boolean ret; + try { + InetAddress ipAddr = InetAddress.getByName("hikapro.com"); + ret = ipAddr.equals("") ? false : true; + } catch (Exception e) { + ret = false; + } + return ret; + } + + public static int getConnectionType(Context context) { + ConnectivityManager cm = + (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); + + NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); + return activeNetwork.getType(); + //ConnectivityManager.TYPE_WIFI; + } +} diff --git a/app/src/main/java/com/hikapro/backpack/model/RestClient.java b/app/src/main/java/com/hikapro/backpack/model/RestClient.java index 83c0466..f3874d7 100644 --- a/app/src/main/java/com/hikapro/backpack/model/RestClient.java +++ b/app/src/main/java/com/hikapro/backpack/model/RestClient.java @@ -11,7 +11,7 @@ import retrofit2.converter.gson.GsonConverterFactory; */ public class RestClient { - public static final String BASE_URL = "http://hikapro.hikapro/"; + public static final String BASE_URL = "http://hikapro.com/"; public static Api getApi() { diff --git a/app/src/main/java/com/hikapro/backpack/model/SetModel.java b/app/src/main/java/com/hikapro/backpack/model/SetModel.java index 000681f..aadb3eb 100644 --- a/app/src/main/java/com/hikapro/backpack/model/SetModel.java +++ b/app/src/main/java/com/hikapro/backpack/model/SetModel.java @@ -1,10 +1,13 @@ package com.hikapro.backpack.model; import android.os.Message; +import android.widget.Toast; import java.util.ArrayList; import java.util.List; +import com.hikapro.backpack.App; +import com.hikapro.backpack.R; import com.hikapro.backpack.model.dao.Command; import com.hikapro.backpack.model.dao.DAO; import com.hikapro.backpack.model.dao.Event; @@ -67,18 +70,16 @@ public class SetModel implements Model.Set { } - private void sendMessage(String message) { - presenter.showMessage(message); - } - //endregion //region process @Override public void executeQuery() { + if (presenter != null) + presenter.startProgress(); Message command = Message.obtain(); - command.what = Command.SYNC_IF_NOT_EXISTS; + command.what = Command.SYNC; dao.executeCommand(command); command = Message.obtain(); command.what = Command.SET_GET_ALL; @@ -88,13 +89,27 @@ public class SetModel implements Model.Set { @Override public void onEvent(Message event) { switch (event.what) { + case Event.SYNC_NO_CONNECTION : + if (presenter != null) + presenter.stopProgress(); + Toast.makeText(App.getAppContext(), R.string.no_connection, Toast.LENGTH_SHORT).show(); + break; + case Event.SYNC_FAILED : + if (presenter != null) + presenter.stopProgress(); + Toast.makeText(App.getAppContext(), "SYNC FAILED", Toast.LENGTH_SHORT).show(); + break; case Event.SET_LOAD_ERROR : + if (presenter != null) + presenter.stopProgress(); break; case Event.SET_ITEMS_LOAD_ERROR : break; case Event.SET_REORDER_ERROR : break; case Event.SET_LOAD_COMPLETED : + if (presenter != null) + presenter.stopProgress(); cache = (List) event.obj; notifyDataSetChanged(); break; diff --git a/app/src/main/java/com/hikapro/backpack/model/ShareModel.java b/app/src/main/java/com/hikapro/backpack/model/ShareModel.java new file mode 100644 index 0000000..4ba48fd --- /dev/null +++ b/app/src/main/java/com/hikapro/backpack/model/ShareModel.java @@ -0,0 +1,50 @@ +package com.hikapro.backpack.model; + +import android.os.Message; + +import com.hikapro.backpack.model.dao.DAO; +import com.hikapro.backpack.presenter.Presenter; + +/** + * Created by tariel on 16/05/16. + */ +public class ShareModel implements Model.Share { + + private Presenter.Share presenter; + private DAO dao; + + public ShareModel() { + this.dao = DAO.getInstance(); + dao.registerObserver(this); + } + + @Override + public void onDestroy(boolean isConfigurationChanging) { + + } + + @Override + public void executeQuery() { + + } + + @Override + public void notifyDataSetChanged() { + + } + + @Override + public void onEvent(Message event) { + + } + + @Override + public void setPresenter(Presenter.Share presenter) { + this.presenter = presenter; + } + + @Override + public Presenter.Share getPresenter() { + return presenter; + } +} diff --git a/app/src/main/java/com/hikapro/backpack/model/dao/Command.java b/app/src/main/java/com/hikapro/backpack/model/dao/Command.java index baaa42a..5aa6f89 100644 --- a/app/src/main/java/com/hikapro/backpack/model/dao/Command.java +++ b/app/src/main/java/com/hikapro/backpack/model/dao/Command.java @@ -15,6 +15,7 @@ public interface Command { int SET_GET_ITEMS = 0x66; int SET_GET_PACKED_ITEMS = 0x67; int SET_UNPACK_ITEMS = 0x68; + int SET_RESTORE_DEFAULT = 0x69; int ITEM_DELETE_FROM_SET = 0x78; int ITEM_INSERT = 0x79; @@ -22,6 +23,7 @@ public interface Command { int ITEM_UNPACK = 0x7B; int ITEM_GET_CATEGORIES = 0x7C; int ITEM_GET_IMAGE = 0x7D; + int ITEM_GET_LIKE = 0x7E; int MY_LIST_POST = 0x8C; int MY_LIST_ITEM_ADD = 0x8D; diff --git a/app/src/main/java/com/hikapro/backpack/model/dao/DAO.java b/app/src/main/java/com/hikapro/backpack/model/dao/DAO.java index b3dab3f..1c407c8 100644 --- a/app/src/main/java/com/hikapro/backpack/model/dao/DAO.java +++ b/app/src/main/java/com/hikapro/backpack/model/dao/DAO.java @@ -18,6 +18,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Hashtable; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; @@ -27,14 +28,15 @@ import java.util.concurrent.TimeUnit; import com.hikapro.backpack.App; import com.hikapro.backpack.model.Api; import com.hikapro.backpack.model.Model; +import com.hikapro.backpack.model.NetworkUtil; import com.hikapro.backpack.model.RestClient; import com.hikapro.backpack.model.SetModel; import com.hikapro.backpack.model.entities.Category; import com.hikapro.backpack.model.entities.Item; import com.hikapro.backpack.model.entities.Set; import com.hikapro.backpack.model.entities.Timestamp; -import retrofit2.Call; -import retrofit2.Callback; +import com.hikapro.backpack.model.entities.UpdateLog; + import retrofit2.Response; /** @@ -147,6 +149,14 @@ public class DAO { Process.THREAD_PRIORITY_DEFAULT); setTask.setId = command.arg1; threadPool.execute(setTask); + break; + + case Command.SET_RESTORE_DEFAULT : + setTask = new SetTask(Command.SET_RESTORE_DEFAULT, + Process.THREAD_PRIORITY_DEFAULT); + setTask.setId = command.arg1; + threadPool.execute(setTask); + break; case Command.ITEM_GET_CATEGORIES : itemTask = new ItemTask(Command.ITEM_GET_CATEGORIES, @@ -196,6 +206,14 @@ public class DAO { } break; + case Command.ITEM_GET_LIKE : + itemTask = new ItemTask(Command.ITEM_GET_LIKE, + Process.THREAD_PRIORITY_MORE_FAVORABLE); + itemTask.query = (String) command.obj; + itemTask.setId = command.arg1; + threadPool.execute(itemTask); + break; + case Command.MY_LIST_ITEM_ADD : break; @@ -248,6 +266,7 @@ public class DAO { } } } + private void insertItems(List items) { if (items != null && !items.isEmpty()) { ContentValues values; @@ -265,6 +284,55 @@ public class DAO { } } } + + private long insertItem(Item item) { + long ret = 0; + SQLiteDatabase db = null; + ContentValues values; + Cursor cursor = null; + if (item != null) { + try { + if (item.getId() < 0) { + db = getWriteDB(); + db.beginTransaction(); + String query = String.format("SELECT %s FROM %s WHERE %s = 1 ORDER BY %s DESC LIMIT 1", + Db.ItemsTable.COLUMN_ID, + Db.ItemsTable.TABLE_NAME, + Db.ItemsTable.COLUMN_USER_DEFINED, + Db.ItemsTable.COLUMN_ID); + cursor = db.rawQuery(query, null); + + if (cursor.moveToNext()) { + int id = cursor.getInt(0); + item.setId(id + 1); + } else { + query = String.format("SELECT max(%s) FROM %s", + Db.ItemsTable.COLUMN_ID, + Db.ItemsTable.TABLE_NAME); + cursor = db.rawQuery(query, null); + if (cursor.moveToNext()) { + int maxId = cursor.getInt(0); + item.setId(maxId + 0x400); + } + } + values = Db.ItemsTable.toContentValues(item); + ret = db.insert(Db.ItemsTable.TABLE_NAME, null, values); + db.setTransactionSuccessful(); + } else { + ret = item.getId(); + } + } finally { + if (cursor != null) + cursor.close(); + if (db != null) { + db.endTransaction(); + db.close(); + } + } + } + return ret; + } + private void insertCategories(List categories) { if (categories != null && !categories.isEmpty()) { @@ -283,6 +351,7 @@ public class DAO { } } } + private void insertSets(List sets) { if (sets != null && !sets.isEmpty()) { @@ -304,6 +373,7 @@ public class DAO { } } } + private void insertSetItems(Set set, SQLiteDatabase db) { if (set != null && db != null) { if (!set.getItems().isEmpty()) { @@ -322,12 +392,13 @@ public class DAO { } } } - private void insertSetItem(int setId, int itemId) { + + private void insertSetItem(int setId, int itemId, boolean userDefined) { ContentValues values; SQLiteDatabase db = getWriteDB(); try { db.beginTransaction(); - values = Db.SetItemsTable.toContentValues(setId, itemId); + values = Db.SetItemsTable.toContentValues(setId, itemId, userDefined); db.insert(Db.SetItemsTable.TABLE_NAME, null, values); db.setTransactionSuccessful(); } finally { @@ -335,8 +406,9 @@ public class DAO { db.close(); } } + // reads - private boolean LogExist() { + private boolean logExist() { boolean ret; SQLiteDatabase db = getReadDB(); Cursor cursor = db.query(Db.LogTable.TABLE_NAME, @@ -347,6 +419,26 @@ public class DAO { return ret; } + private UpdateLog readLastLog() { + UpdateLog ret = null; + SQLiteDatabase db = null; + Cursor cursor = null; + try { + db = getReadDB(); + String q = String.format("SELECT * FROM %s ORDER BY %s DESC LIMIT 1", + Db.LogTable.TABLE_NAME, Db.LogTable.COLUMN_ID); + cursor = db.rawQuery(q,null); + if (cursor.moveToNext()) + ret = Db.LogTable.parseCursor(cursor); + } finally { + if (cursor != null) + cursor.close(); + if (db != null) + db.close(); + } + return ret; + } + private Item findItem(int id) { Item ret = null; Cursor cursor = null; @@ -376,7 +468,7 @@ public class DAO { SQLiteDatabase db = null; Item item; String query = String.format( - "SELECT a.%s, a.%s, a.%s, a.%s, a.%s, a.%s, a.%s, a.%s, a.%s FROM %s a INNER JOIN %s b ON a.%s = b.%s WHERE b.%s = ? AND b.%s <> 1 AND b.%s %s 1", + "SELECT a.%s, a.%s, a.%s, a.%s, a.%s, a.%s, a.%s, a.%s, a.%s, a.%s FROM %s a INNER JOIN %s b ON a.%s = b.%s WHERE b.%s = ? AND b.%s <> 1 AND b.%s %s 1", Db.ItemsTable.COLUMN_ID, Db.ItemsTable.COLUMN_NAME, @@ -387,6 +479,7 @@ public class DAO { Db.ItemsTable.COLUMN_PHOTO_THUMB_URL, Db.ItemsTable.COLUMN_PHOTO_LOCAL, Db.ItemsTable.COLUMN_PHOTO_THUMB_LOCAL, + Db.ItemsTable.COLUMN_USER_DEFINED, Db.ItemsTable.TABLE_NAME, Db.SetItemsTable.TABLE_NAME, @@ -407,6 +500,8 @@ public class DAO { //TODO write to log here } catch (Exception e) { + int i = 0; + String s = null; //TODO write to log here } finally { if (cursor != null) @@ -416,6 +511,81 @@ public class DAO { } return ret; } + + private List readItemsLike(String like) { + List ret = new ArrayList<>(256); + Cursor cursor = null; + SQLiteDatabase db = null; + Item item; + String query = String.format("SELECT * FROM %s WHERE %s LIKE %s", + Db.ItemsTable.TABLE_NAME, + Db.ItemsTable.COLUMN_NAME, + '\''+like+'%'+'\''); + try { + db = getReadDB(); + cursor = db.rawQuery(query, null); + while (cursor.moveToNext()) { + item = Db.ItemsTable.parseCursor(cursor); + ret.add(item); + } + } catch (SQLiteException e) { + e.toString(); + //TODO write to log here + + } catch (Exception e) { + //TODO write to log here + } finally { + if (cursor != null) + cursor.close(); + if (db != null) + db.close(); + } + return ret; + } + + private List readItemsLike(String like, int checkThisSet) { + List ret = new ArrayList<>(256); + Cursor cursor = null; + Cursor cursor2 = null; + SQLiteDatabase db = null; + Item item; + String query = String.format("SELECT * FROM %s WHERE %s LIKE %s", + Db.ItemsTable.TABLE_NAME, + Db.ItemsTable.COLUMN_NAME, + '\''+like+'%'+'\''); + try { + db = getReadDB(); + cursor = db.rawQuery(query, null); + while (cursor.moveToNext()) { + item = Db.ItemsTable.parseCursor(cursor); + query = String.format("SELECT * FROM %s WHERE %s = %d AND %s = %d LIMIT 1", + Db.SetItemsTable.TABLE_NAME, + Db.SetItemsTable.COLUMN_ITEM, + item.getId(), + Db.SetItemsTable.COLUMN_SET, + checkThisSet + ); + cursor2 = db.rawQuery(query, null); + if (cursor2.moveToNext()) + item.InList = true; + ret.add(item); + } + } catch (SQLiteException e) { + e.toString(); + //TODO write to log here + } catch (Exception e) { + //TODO write to log here + } finally { + if (cursor != null) + cursor.close(); + if (cursor2 != null) + cursor2.close(); + if (db != null) + db.close(); + } + return ret; + } + private Hashtable readCategories() { Hashtable ret = new Hashtable<>(20, 0.9f); Cursor cursor = null; @@ -485,6 +655,7 @@ public class DAO { } return ret; } + // updates private int updateItemLocalPic(int id, String path) { int ret = 0; @@ -540,6 +711,7 @@ public class DAO { } return ret; } + private int updateSetItemDeleted(int setId, int itemId, boolean del) { int ret = 0; SQLiteDatabase db = null; @@ -575,16 +747,6 @@ public class DAO { try { db = getWriteDB(); db.beginTransaction(); - - /* - String query = String.format("UPDATE %s SET %s = %d where %s = %d", - Db.SetItemsTable.TABLE_NAME, - Db.SetItemsTable.COLUMN_PACKED, - pack, - Db.SetItemsTable.COLUMN_SET, - setId); - Cursor cursor = db.rawQuery(query, null);*/ - values = new ContentValues(); values.put(Db.SetItemsTable.COLUMN_PACKED, pack); ret = db.update(Db.SetItemsTable.TABLE_NAME, values, String.format("%s = ?", @@ -651,6 +813,171 @@ public class DAO { } return ret; } + + private int updateSetRestoreDefault(int setId) { + int ret = 0; + SQLiteDatabase db = null; + ContentValues values; + Set set; + try { + db = getWriteDB(); + db.beginTransaction(); + values = new ContentValues(); + values.put(Db.SetItemsTable.COLUMN_PACKED, false); + values.put(Db.SetItemsTable.COLUMN_DELETED, false); + ret = db.update(Db.SetItemsTable.TABLE_NAME, + values, + String.format("%s = ?", + Db.SetItemsTable.COLUMN_SET), + new String[]{String.valueOf(setId)}); + + set = readSet(db, setId); + if (set != null) { + values = new ContentValues(); + values.put(Db.SetsTable.COLUMN_PACKED_QTY, 0); + ret += db.update(Db.SetsTable.TABLE_NAME, values, String.format("%s = ?", + Db.SetsTable.COLUMN_ID), + new String[]{String.valueOf(setId)}); + } + ret += db.delete(Db.SetItemsTable.TABLE_NAME, + String.format("%s = ? AND %s = ?", Db.SetItemsTable.COLUMN_SET, Db.SetItemsTable.COLUMN_USER_DEFINED), + new String[]{String.valueOf(setId), String.valueOf(1)}); + db.setTransactionSuccessful(); + } catch (SQLiteException e) { + //TODO write to log here + + } catch (Exception e) { + //TODO write to log here + } finally { + if (db != null) { + db.endTransaction(); + db.close(); + } + } + return ret; + } + + private int updateSetNames(List sets) { + int ret = 0; + SQLiteDatabase db = null; + ContentValues values; + + try { + db = getWriteDB(); + db.beginTransaction(); + for (Set set : sets) { + values = new ContentValues(); + values.put(Db.SetsTable.COLUMN_NAME, set.getName()); + ret += db.update(Db.SetsTable.TABLE_NAME, values, String.format("%s = ?", + Db.SetsTable.COLUMN_ID), + new String[]{String.valueOf(set.getId())}); + } + db.setTransactionSuccessful(); + } catch (SQLiteException e) { + //TODO write to log here + + } catch (Exception e) { + //TODO write to log here + } finally { + if (db != null) { + db.endTransaction(); + db.close(); + } + } + return ret; + } + + private int updateCategoryNames(List categories) { + int ret = 0; + SQLiteDatabase db = null; + ContentValues values; + + try { + db = getWriteDB(); + db.beginTransaction(); + for (Category category : categories) { + values = new ContentValues(); + values.put(Db.CategoriesTable.COLUMN_NAME, category.getName()); + ret += db.update(Db.CategoriesTable.TABLE_NAME, values, String.format("%s = ?", + Db.CategoriesTable.COLUMN_ID), + new String[]{String.valueOf(category.getId())}); + } + db.setTransactionSuccessful(); + } catch (SQLiteException e) { + //TODO write to log here + + } catch (Exception e) { + //TODO write to log here + } finally { + if (db != null) { + db.endTransaction(); + db.close(); + } + } + return ret; + } + + private int updateItemNames(List items) { + int ret = 0; + SQLiteDatabase db = null; + ContentValues values; + + try { + db = getWriteDB(); + db.beginTransaction(); + for (Item item : items) { + values = new ContentValues(); + values.put(Db.ItemsTable.COLUMN_NAME, item.getName()); + values.put(Db.ItemsTable.COLUMN_DESCRIPTION, item.getDescription()); + ret += db.update(Db.ItemsTable.TABLE_NAME, values, String.format("%s = ?", + Db.ItemsTable.COLUMN_ID), + new String[]{String.valueOf(item.getId())}); + } + db.setTransactionSuccessful(); + } catch (SQLiteException e) { + //TODO write to log here + + } catch (Exception e) { + //TODO write to log here + } finally { + if (db != null) { + db.endTransaction(); + db.close(); + } + } + return ret; + } + + private int updateLogLocale(int id, String newLocale) { + int ret = 0; + SQLiteDatabase db = null; + ContentValues values; + + try { + db = getWriteDB(); + db.beginTransaction(); + + values = new ContentValues(); + values.put(Db.LogTable.COLUMN_LOCALE, newLocale); + + ret = db.update(Db.LogTable.TABLE_NAME, values, String.format("%s = ?", + Db.ItemsTable.COLUMN_ID), + new String[]{String.valueOf(id)}); + + db.setTransactionSuccessful(); + } catch (SQLiteException e) { + //TODO write to log here + + } catch (Exception e) { + //TODO write to log here + } finally { + if (db != null) { + db.endTransaction(); + db.close(); + } + } + return ret; + } //endregion /////////////////////// TASK CLASSES ////////////////// @@ -685,6 +1012,7 @@ public class DAO { int setId; int itemId; Item item; + String query; public ItemTask(int command, int priority) { this.currentCommand = command; @@ -708,16 +1036,13 @@ public class DAO { break; case Command.ITEM_INSERT : - List items = new ArrayList<>(); - items.add(item); - if (items.isEmpty()) - message.what = Event.ITEM_INSERT_ERROR; - else { - insertItems(items); - insertSetItem(setId, item.getId()); + if (insertItem(item) > 0) { + insertSetItem(setId, item.getId(), item.isUserDefined()); message.what = Event.ITEM_INSERTED; message.arg1 = setId; message.arg2 = item.getId(); + } else { + message.what = Event.ITEM_INSERT_ERROR; } break; @@ -746,6 +1071,16 @@ public class DAO { message.obj = res; } break; + + case Command.ITEM_GET_LIKE : + List itemsLike = readItemsLike(query, setId); + if (itemsLike.isEmpty()) { + message.what = Event.ITEM_LIKE_LOAD_ERROR; + } else { + message.what = Event.ITEM_LIKE_LOAD_COMPLETED; + message.obj = itemsLike; + } + break; } handler.sendMessage(message); } @@ -821,6 +1156,14 @@ public class DAO { else message.what = Event.SET_UNPACK_ERROR; break; + + case Command.SET_RESTORE_DEFAULT : + message.arg1 = updateSetRestoreDefault(setId); + if (message.arg1 > 0) + message.what = Event.SET_RESTORE_COMPLETED; + else + message.what = Event.SET_RESTORE_ERROR; + break; } handler.sendMessage(message); } @@ -830,10 +1173,12 @@ public class DAO { int currentCommand; int priority; int statusCode; + String locale; public SyncTask(int command, int priority) { this.currentCommand = command; this.priority = priority; + this.locale = Locale.getDefault().getLanguage(); } @Override @@ -844,22 +1189,47 @@ public class DAO { switch (currentCommand) { case Command.SYNC: try { - Call> call = api.getSets(); - call.enqueue(new Callback>() { - @Override - public void onResponse(Call> call, Response> response) { - statusCode = response.code(); - // TODO - // check if first time - // if not check for updates else - // insert into database here - insertSets(response.body()); + UpdateLog log = readLastLog(); + if (log != null) { + if (log.getLocale().equals(locale)) + message.what = Event.SYNC_COMPLETED; + else { + if (!NetworkUtil.isInternetAvailable()) { + message.what = Event.SYNC_FAILED; + } else { + Response> response0 = api.getSets(locale).execute(); + updateSetNames(response0.body()); + statusCode = response0.code(); + Response> response1 = api.getItemCategories(locale).execute(); + updateCategoryNames(response1.body()); + statusCode = response1.code(); + Response> response2 = api.getItems(locale).execute(); + updateItemNames(response2.body()); + statusCode = response2.code(); + updateLogLocale(log.getId(), locale); + message.what = Event.SYNC_COMPLETED; + } } - @Override - public void onFailure(Call> call, Throwable t) { + + } else { + if (!NetworkUtil.isInternetAvailable()) { + message.what = Event.SYNC_NO_CONNECTION; + } else { + Response> response0 = api.getSets(locale).execute(); + insertSets(response0.body()); + statusCode = response0.code(); + Response> response1 = api.getItemCategories(locale).execute(); + insertCategories(response1.body()); + statusCode = response1.code(); + Response> response2 = api.getItems(locale).execute(); + insertItems(response2.body()); + statusCode = response2.code(); + Response response3 = api.getTimestamp().execute(); + insertTimestamp(response3.body()); + statusCode = response3.code(); + message.what = Event.SYNC_COMPLETED; } - }); - message.what = Event.SYNC_COMPLETED; + } } catch (Exception e) { message.what = Event.SYNC_FAILED; @@ -871,24 +1241,27 @@ public class DAO { break; case Command.SYNC_IF_NOT_EXISTS: - if (LogExist()) { + if (logExist()) { message.what = Event.SYNC_COMPLETED; } else { - try { - Response> response0 = api.getSets().execute(); - insertSets(response0.body()); - statusCode = response0.code(); - Response> response1 = api.getItemCategories().execute(); - insertCategories(response1.body()); - statusCode = response1.code(); - Response> response2 = api.getItems().execute(); - insertItems(response2.body()); - statusCode = response2.code(); - Response response3 = api.getTimestamp().execute(); - insertTimestamp(response3.body()); - statusCode = response3.code(); - message.what = Event.SYNC_COMPLETED; + if (!NetworkUtil.isInternetAvailable()) { + message.what = Event.SYNC_NO_CONNECTION; + } else { + Response> response0 = api.getSets(locale).execute(); + insertSets(response0.body()); + statusCode = response0.code(); + Response> response1 = api.getItemCategories(locale).execute(); + insertCategories(response1.body()); + statusCode = response1.code(); + Response> response2 = api.getItems(locale).execute(); + insertItems(response2.body()); + statusCode = response2.code(); + Response response3 = api.getTimestamp().execute(); + insertTimestamp(response3.body()); + statusCode = response3.code(); + message.what = Event.SYNC_COMPLETED; + } } catch (IOException e ){ message.what = Event.SYNC_FAILED; } finally { diff --git a/app/src/main/java/com/hikapro/backpack/model/dao/Db.java b/app/src/main/java/com/hikapro/backpack/model/dao/Db.java index 44d583a..c70216b 100644 --- a/app/src/main/java/com/hikapro/backpack/model/dao/Db.java +++ b/app/src/main/java/com/hikapro/backpack/model/dao/Db.java @@ -8,6 +8,7 @@ import com.google.gson.reflect.TypeToken; import java.lang.reflect.Type; import java.util.List; +import java.util.Locale; import com.hikapro.backpack.model.entities.Category; import com.hikapro.backpack.model.entities.Item; @@ -64,6 +65,7 @@ public class Db { public static final String COLUMN_PHOTO_THUMB_URL = "photo_thumb_url"; public static final String COLUMN_PHOTO_LOCAL = "photo_local"; public static final String COLUMN_PHOTO_THUMB_LOCAL = "photo_thumb_local"; + public static final String COLUMN_USER_DEFINED = "user_defined"; public static final String CREATE = @@ -76,6 +78,7 @@ public class Db { COLUMN_PHOTO_URL + " TEXT, " + COLUMN_PHOTO_THUMB_URL + " TEXT, " + COLUMN_PHOTO_LOCAL + " TEXT, " + + COLUMN_USER_DEFINED + " NUMERIC, " + COLUMN_PHOTO_THUMB_LOCAL + " TEXT" + " ); "; @@ -98,6 +101,8 @@ public class Db { values.put(COLUMN_PHOTO_THUMB_URL, item.getPhotoThumbUrl()); if (item.getPhotoLocal() != null) values.put(COLUMN_PHOTO_LOCAL, item.getPhotoLocal()); + + values.put(COLUMN_USER_DEFINED, item.isUserDefined()); /* values.put(COLUMN_PHOTO_THUMB_LOCAL, item.getName()); */ @@ -122,6 +127,8 @@ public class Db { item.setPhotoUrl(cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_PHOTO_URL))); item.setPhotoThumbUrl(cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_PHOTO_THUMB_URL))); item.setPhotoLocal(cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_PHOTO_LOCAL))); + short ud = cursor.getShort(cursor.getColumnIndexOrThrow(COLUMN_USER_DEFINED)); + item.setUserDefined(ud != 0); return item; } @@ -215,11 +222,13 @@ public class Db { public static final String COLUMN_ID = "_id"; public static final String COLUMN_MODIFIED_DATETIME = "modified_datetime"; public static final String COLUMN_TIMESTAMP = "timestamp"; + public static final String COLUMN_LOCALE = "locale"; public static final String CREATE = "CREATE TABLE " + TABLE_NAME + " (" + COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + COLUMN_TIMESTAMP + " INTEGER NOT NULL, " + + COLUMN_LOCALE + " TEXT, " + COLUMN_MODIFIED_DATETIME + " INTEGER NOT NULL DEFAULT current_timestamp" + " ); "; @@ -227,13 +236,16 @@ public class Db { ContentValues values = new ContentValues(); values.put(COLUMN_TIMESTAMP, timestamp.timestamp); + values.put(COLUMN_LOCALE, Locale.getDefault().getLanguage()); return values; } public static UpdateLog parseCursor(Cursor cursor) { UpdateLog log = new UpdateLog(); + log.setId(cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_ID))); log.setTimestamp(cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_TIMESTAMP))); log.setModifiedDatetime(cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_MODIFIED_DATETIME))); + log.setLocale(cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_LOCALE))); return log; } } @@ -247,6 +259,7 @@ public class Db { public static final String COLUMN_ITEM = "itemId"; public static final String COLUMN_DELETED = "deleted"; public static final String COLUMN_PACKED = "packed"; + public static final String COLUMN_USER_DEFINED = "user_defined"; public static final String CREATE = "CREATE TABLE " + TABLE_NAME + " (" + @@ -254,6 +267,7 @@ public class Db { COLUMN_SET + " INTEGER NOT NULL, " + COLUMN_DELETED + " NUMERIC, " + COLUMN_PACKED + " NUMERIC, " + + COLUMN_USER_DEFINED + " NUMERIC, " + COLUMN_ITEM + " INTEGER NOT NULL" + " ); "; @@ -263,6 +277,17 @@ public class Db { values.put(COLUMN_ITEM, itemId); values.put(COLUMN_DELETED, 0); values.put(COLUMN_PACKED, 0); + values.put(COLUMN_USER_DEFINED, 0); + return values; + } + + public static ContentValues toContentValues(int setId, int itemId, boolean userDefined) { + ContentValues values = new ContentValues(); + values.put(COLUMN_SET, setId); + values.put(COLUMN_ITEM, itemId); + values.put(COLUMN_DELETED, 0); + values.put(COLUMN_PACKED, 0); + values.put(COLUMN_USER_DEFINED, userDefined); return values; } } diff --git a/app/src/main/java/com/hikapro/backpack/model/dao/Event.java b/app/src/main/java/com/hikapro/backpack/model/dao/Event.java index ffd4a74..ea03d07 100644 --- a/app/src/main/java/com/hikapro/backpack/model/dao/Event.java +++ b/app/src/main/java/com/hikapro/backpack/model/dao/Event.java @@ -14,6 +14,7 @@ public interface Event { int SET_ITEMS_LOAD_ERROR = -0x3; int SET_PACKED_LOAD_ERROR = -0x4; int SET_UNPACK_ERROR = -0x5; + int SET_RESTORE_ERROR = -0x6; int SET_LOAD_COMPLETED = 0x1; @@ -21,6 +22,7 @@ public interface Event { int SET_ITEMS_LOAD_COMPLETED = 0x3; int SET_PACKED_LOAD_COMPLETED = 0x4; int SET_UNPACK_COMPLETED = 0x5; + int SET_RESTORE_COMPLETED = 0x6; int ITEM_FROM_SET_ERROR = -0x14; @@ -30,6 +32,7 @@ public interface Event { int ITEM_UNPACK_ERROR = -0x18; int ITEM_CATEGORY_LOAD_ERROR = -0x19; int ITEM_IMAGE_LOAD_ERROR = -0x1A; + int ITEM_LIKE_LOAD_ERROR = -0x1B; int ITEM_FROM_SET_DELETED = 0x14; int ITEM_INSERTED = 0x15; @@ -38,6 +41,7 @@ public interface Event { int ITEM_UNPACKED = 0x18; int ITEM_CATEGORY_LOAD_COMPLETED = 0x19; int ITEM_IMAGE_LOAD_COMPLETED = 0x1A; + int ITEM_LIKE_LOAD_COMPLETED = 0x1B; int MY_LIST_POST_ERROR = -0x28; @@ -51,6 +55,7 @@ public interface Event { int MY_LIST_CLEARED = 0x2B; int SYNC_FAILED = -0x3C; + int SYNC_NO_CONNECTION = -0x3D; int SYNC_COMPLETED = 0x3C; int NOT_IMPLEMENTED = 0x50; diff --git a/app/src/main/java/com/hikapro/backpack/model/entities/Item.java b/app/src/main/java/com/hikapro/backpack/model/entities/Item.java index 7293ab6..ca53163 100644 --- a/app/src/main/java/com/hikapro/backpack/model/entities/Item.java +++ b/app/src/main/java/com/hikapro/backpack/model/entities/Item.java @@ -36,9 +36,19 @@ public class Item implements Comparable, Serializable { private String photoLocal; + private boolean userDefined; + + public boolean InList; + public Item() { } + public Item(String name, int category) { + this.id = -1; + this.name = name; + this.category = category; + } + public Item(int id, String name, int category, String description, List buyUrls, String photoUrl, String photoThumbUrl) { this.id = id; @@ -114,6 +124,14 @@ public class Item implements Comparable, Serializable { this.photoLocal = photoLocal; } + public boolean isUserDefined() { + return userDefined; + } + + public void setUserDefined(boolean userDefined) { + this.userDefined = userDefined; + } + @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; diff --git a/app/src/main/java/com/hikapro/backpack/model/entities/UpdateLog.java b/app/src/main/java/com/hikapro/backpack/model/entities/UpdateLog.java index 5507436..ee33e54 100644 --- a/app/src/main/java/com/hikapro/backpack/model/entities/UpdateLog.java +++ b/app/src/main/java/com/hikapro/backpack/model/entities/UpdateLog.java @@ -5,12 +5,22 @@ package com.hikapro.backpack.model.entities; */ public class UpdateLog { + private int id; private long timestamp; private long modifiedDatetime; + private String locale; public UpdateLog() { } + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + public long getTimestamp() { return timestamp; } @@ -26,4 +36,12 @@ public class UpdateLog { public void setModifiedDatetime(long modifiedDatetime) { this.modifiedDatetime = modifiedDatetime; } + + public String getLocale() { + return locale; + } + + public void setLocale(String locale) { + this.locale = locale; + } } diff --git a/app/src/main/java/com/hikapro/backpack/presenter/AddPresenter.java b/app/src/main/java/com/hikapro/backpack/presenter/AddPresenter.java new file mode 100644 index 0000000..0db093d --- /dev/null +++ b/app/src/main/java/com/hikapro/backpack/presenter/AddPresenter.java @@ -0,0 +1,328 @@ +package com.hikapro.backpack.presenter; + +import android.app.ActionBar; +import android.app.Activity; +import android.app.Fragment; +import android.content.Context; +import android.graphics.Color; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.support.v7.widget.DefaultItemAnimator; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.SearchView; +import android.widget.Toast; + +import com.hikapro.backpack.R; +import com.hikapro.backpack.model.Model; +import com.hikapro.backpack.model.entities.Category; +import com.hikapro.backpack.model.entities.Item; +import com.hikapro.backpack.presenter.adapters.AddListAdapter; +import com.hikapro.backpack.presenter.adapters.helper.items.DividerDecoration; +import com.hikapro.backpack.view.View; + +import java.lang.ref.WeakReference; + +/** + * Created by tariel on 18/05/16. + */ +public class AddPresenter implements Presenter.Add { + + private WeakReference view; + private Model.Add model; + + private AddListAdapter adapter; + private RecyclerView recycler; + private ViewGroup categoryContainer; + private ViewGroup categoryContainerMain; + private boolean isContainerAlreadyInitialised; + private Item newItem; + private Item selectedItem; + private Button currentCategoryButton; + private Button cancelButton; + private Button saveButton; + private SearchView searchView; + private boolean canSave; + + + public AddPresenter() { + this.adapter = new AddListAdapter(this); + } + + @Override + public void setView(View.Add view) { + this.view = new WeakReference<>(view); + } + + @Override + public void setModel(Model.Add model) { + this.model = model; + + } + + @Override + public Model.Add getModel() { + return model; + } + + @Override + public void onDestroy(boolean isChangingConfiguration) { + view = null; + model.onDestroy(isChangingConfiguration); + if ( !isChangingConfiguration ) { + model = null; + } + isContainerAlreadyInitialised = false; + } + + @Override + public android.view.View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + android.view.View view = inflater.inflate(R.layout.fragment_add, container, false); + model.executeQuery(); + LinearLayoutManager llm = new LinearLayoutManager(getActivityContext()); + recycler = (RecyclerView) view.findViewById(R.id.add_item_recycler); + recycler.setLayoutManager(llm); + recycler.setAdapter(adapter); + recycler.setItemAnimator(new DefaultItemAnimator()); + recycler.addItemDecoration(new DividerDecoration(getActivityContext())); + categoryContainer = (ViewGroup) view.findViewById(R.id.add_item_category_flow); + categoryContainerMain = (ViewGroup) view.findViewById(R.id.add_item_category_container); + categoryContainerMain.setVisibility(android.view.View.GONE); + recycler.setVisibility(android.view.View.GONE); + + Activity activity = (Activity) getActivityContext(); + if (activity != null) { + ActionBar actionBar = activity.getActionBar(); + if (actionBar != null) { + ViewGroup custActionBarView = (ViewGroup) inflater.inflate(R.layout.add_cust_actionbar, null); + actionBar.setDisplayShowHomeEnabled(false); + actionBar.setDisplayShowTitleEnabled(false); + actionBar.setDisplayShowCustomEnabled(true); + actionBar.setDisplayHomeAsUpEnabled(false); + actionBar.setCustomView(custActionBarView); + + cancelButton = (Button) custActionBarView.findViewById(R.id.action_add_cancel); + saveButton = (Button) custActionBarView.findViewById(R.id.action_add_save); + cancelButton.setOnClickListener(new ActionBarButtonClickListener()); + saveButton.setOnClickListener(new ActionBarButtonClickListener()); + } + } + + searchView = (SearchView) view.findViewById(R.id.add_search); + searchView.setIconified(false); + searchView.setIconifiedByDefault(false); + searchView.setQueryHint("Enter a new item name"); + searchView.setSubmitButtonEnabled(false); + searchView.setBottom(20); + /* + Drawable d = getActivityContext().getResources().getDrawable( R.drawable.search_divider ); + searchView.setDividerDrawable(d);*/ + + int magId = searchView.getContext().getResources().getIdentifier("android:id/search_mag_icon", null, null); + ImageView magImage = (ImageView) searchView.findViewById(magId); + magImage.setLayoutParams(new LinearLayout.LayoutParams(0, 0)); + searchView.setMinimumHeight(40); + searchView.setOnQueryTextListener(new SearchTextListener()); +/* + int searchPlateId = searchView.getContext().getResources().getIdentifier("android:id/search_plate", null, null); + // Getting the 'search_plate' LinearLayout. + android.view.View searchPlate = searchView.findViewById(searchPlateId); + // Setting background of 'search_plate' to earlier defined drawable. + searchPlate.setBackgroundResource(R.drawable.search_divider); + +*/ + + return view; + } + + @Override + public Context getAppContext() { + try { + return getView().getAppContext(); + } catch (NullPointerException e) { + return null; + } + } + + @Override + public Context getActivityContext() { + try { + return getView().getActivityContext(); + } catch (NullPointerException e) { + return null; + } + } + + @Override + public void notifyDataSetChanged(boolean found) { + adapter.notifyDataSetChanged(); + if (found) { + categoryContainerMain.setVisibility(android.view.View.GONE); + recycler.setVisibility(android.view.View.VISIBLE); + currentCategoryButton = null; + } else { + categoryContainerMain.setVisibility(android.view.View.VISIBLE); + recycler.setVisibility(android.view.View.GONE); + initSelectCategoryContainer(); + } + } + + @Override + public void onAddItemClick(Item item) { + searchView.setQuery(item.getName(), false); + if (!item.InList) + selectedItem = item; + setSaveButtonAccess(); + } + + private void setSaveButtonAccess() { + + if (searchView.getQuery().length() > 0 && currentCategoryButton != null + || selectedItem != null) + canSave = true; + else + canSave = false; + + if (canSave) + saveButton.setTextColor(saveButton.getResources().getColor(R.color.save_green)); + else + saveButton.setTextColor(saveButton.getResources().getColor(R.color.white)); + } + + private boolean checkUserInput() { + if (!canSave) { + if (searchView.getQuery().length() == 0) + Toast.makeText(getActivityContext(), "Please, enter a name", Toast.LENGTH_SHORT).show(); + else if (categoryContainerMain.getVisibility() == android.view.View.VISIBLE) + Toast.makeText(getActivityContext(), "Please, select a category", Toast.LENGTH_SHORT).show(); + else + Toast.makeText(getActivityContext(), "Already in List!", Toast.LENGTH_SHORT).show(); + return false; + } + return true; + } + + private void initSelectCategoryContainer() { + Button button; + Category category; + if (! isContainerAlreadyInitialised) { + + for (int i = 0; i < model.getCategoriesCount(); ++i) { + category = model.getCategoryByPosition(i); + button = (Button) LayoutInflater.from(getActivityContext()).inflate( + R.layout.category_button, null); + button.setId(category.getId()); + button.setText(category.getName()); + button.setOnClickListener(new CategoryButtonClickListener()); + categoryContainer.addView(button); + + if (currentCategoryButton != null) { + if (button.getId() == currentCategoryButton.getId()) { + currentCategoryButton = button; + Drawable d = currentCategoryButton.getBackground(); + PorterDuffColorFilter filter = new PorterDuffColorFilter(Color.GREEN, PorterDuff.Mode.SRC_ATOP); + d.setColorFilter(filter); + } + } + } + setSaveButtonAccess(); + isContainerAlreadyInitialised = true; + } + } + + private View.Add getView() throws NullPointerException { + if ( view != null ) + return view.get(); + else + throw new NullPointerException("View is unavailable"); + } + + private class CategoryButtonClickListener implements android.view.View.OnClickListener { + @Override + public void onClick(android.view.View v) { + + Drawable d = v.getBackground(); + PorterDuffColorFilter filter = new PorterDuffColorFilter(Color.GREEN, PorterDuff.Mode.SRC_ATOP); + d.setColorFilter(filter); + + if (currentCategoryButton != null) { + d = currentCategoryButton.getBackground(); + currentCategoryButton.invalidateDrawable(d); + d.clearColorFilter(); + } + + currentCategoryButton = (Button) v; + Toast.makeText(getActivityContext(), "Id " + currentCategoryButton.getId(), Toast.LENGTH_SHORT).show(); + setSaveButtonAccess(); + } + } + + private class ActionBarButtonClickListener implements android.view.View.OnClickListener { + @Override + public void onClick(android.view.View v) { + Fragment fragment = (Fragment) getView(); + switch (v.getId()) + { + case R.id.action_add_cancel : + Toast.makeText(getActivityContext(), "Cancel", Toast.LENGTH_SHORT).show(); + searchView.clearFocus(); + if (fragment != null) + fragment.getFragmentManager().popBackStack(); + break; + + case R.id.action_add_save : + if (checkUserInput()) { + if (selectedItem != null) { + model.add(selectedItem, getView().getSet().getId()); + } else { + newItem = new Item(searchView.getQuery().toString(), currentCategoryButton.getId()); + newItem.setUserDefined(true); + model.add(newItem, getView().getSet().getId()); + } + searchView.clearFocus(); + if (fragment != null) + fragment.getFragmentManager().popBackStack(); + } + break; + } + } + } + + private class SearchTextListener implements SearchView.OnQueryTextListener { + + public SearchTextListener() { + super(); + } + + @Override + public boolean onQueryTextChange(String newText) { + model.filter(newText, getView().getSet().getId()); + if (newText.isEmpty()) { + if (currentCategoryButton != null) { + Drawable d = currentCategoryButton.getBackground(); + currentCategoryButton.invalidateDrawable(d); + d.clearColorFilter(); + currentCategoryButton = null; + } + } + selectedItem = null; + setSaveButtonAccess(); + return true; + } + + @Override + public boolean onQueryTextSubmit(String query) { + return false; + } + } +} diff --git a/app/src/main/java/com/hikapro/backpack/presenter/ItemListPresenter.java b/app/src/main/java/com/hikapro/backpack/presenter/ItemListPresenter.java index f190732..2000ed0 100644 --- a/app/src/main/java/com/hikapro/backpack/presenter/ItemListPresenter.java +++ b/app/src/main/java/com/hikapro/backpack/presenter/ItemListPresenter.java @@ -2,7 +2,9 @@ package com.hikapro.backpack.presenter; import android.app.ActionBar; import android.app.Activity; +import android.app.AlertDialog; import android.content.Context; +import android.content.DialogInterface; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; @@ -97,10 +99,15 @@ public class ItemListPresenter implements Presenter.ItemList { }); Activity activity = (Activity) getActivityContext(); if (activity != null) { + activity.invalidateOptionsMenu(); ActionBar actionBar = activity.getActionBar(); if (actionBar != null) { actionBar.show(); actionBar.setTitle(set.getName()); + actionBar.setDisplayShowHomeEnabled(false); + actionBar.setDisplayShowTitleEnabled(true); + actionBar.setDisplayShowCustomEnabled(false); + actionBar.setDisplayHomeAsUpEnabled(true); } } /* @@ -229,4 +236,45 @@ public class ItemListPresenter implements Presenter.ItemList { public Set getCurrentSet() { return set; } + + @Override + public void unpack(int setId) { + model.unpackSet(setId); + } + + @Override + public void restore(final int setId) { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivityContext(), AlertDialog.THEME_HOLO_DARK); + + builder.setMessage(R.string.dlg_restore_txt) + .setTitle(R.string.dlg_restore_header); + + builder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + model.restoreSet(setId); + } + }); + builder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // User cancelled the dialog + } + }); + AlertDialog dialog = builder.create(); + dialog.show(); + + //Button button = dialog.getButton(DialogInterface.BUTTON_POSITIVE); + //button.setBackgroundColor(Color.GREEN); + /* + Drawable d = button.getBackground(); + PorterDuffColorFilter filter = new PorterDuffColorFilter(Color.GREEN, PorterDuff.Mode.SRC_ATOP); + d.setColorFilter(filter);*/ + //button = dialog.getButton(DialogInterface.BUTTON_NEGATIVE); + //button.setBackgroundColor(Color.GRAY); + /* + d = button.getBackground(); + filter = new PorterDuffColorFilter(Color.GRAY, PorterDuff.Mode.SRC_ATOP); + d.setColorFilter(filter);*/ + + + } } diff --git a/app/src/main/java/com/hikapro/backpack/presenter/PackedListPresenter.java b/app/src/main/java/com/hikapro/backpack/presenter/PackedListPresenter.java index 04942f7..eab29ac 100644 --- a/app/src/main/java/com/hikapro/backpack/presenter/PackedListPresenter.java +++ b/app/src/main/java/com/hikapro/backpack/presenter/PackedListPresenter.java @@ -1,5 +1,7 @@ package com.hikapro.backpack.presenter; +import android.app.ActionBar; +import android.app.Activity; import android.app.Fragment; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; @@ -99,6 +101,19 @@ public class PackedListPresenter extends ItemListPresenter { model.getPackedQty(), model.getActiveItemsCount()); packedCount.setText(str); */ + Activity activity = (Activity) getActivityContext(); + if (activity != null) { + activity.invalidateOptionsMenu(); + ActionBar actionBar = activity.getActionBar(); + if (actionBar != null) { + actionBar.show(); + actionBar.setTitle(set.getName()); + actionBar.setDisplayShowHomeEnabled(false); + actionBar.setDisplayShowTitleEnabled(true); + actionBar.setDisplayShowCustomEnabled(false); + actionBar.setDisplayHomeAsUpEnabled(true); + } + } return view; } diff --git a/app/src/main/java/com/hikapro/backpack/presenter/Presenter.java b/app/src/main/java/com/hikapro/backpack/presenter/Presenter.java index ad7e968..13f0d57 100644 --- a/app/src/main/java/com/hikapro/backpack/presenter/Presenter.java +++ b/app/src/main/java/com/hikapro/backpack/presenter/Presenter.java @@ -10,6 +10,7 @@ import android.view.ViewGroup; import com.hikapro.backpack.model.Model; import com.hikapro.backpack.model.entities.Item; import com.hikapro.backpack.model.entities.Set; +import com.hikapro.backpack.view.View; /** * Created by tariel on 19/04/16. @@ -33,7 +34,8 @@ public interface Presenter { void setModel(Model.Set model); Model.Set getModel(); void notifyDataSetChanged(); - void showMessage(String message); + void startProgress(); + void stopProgress(); //GLM_add_resources_SetList void onItemDismiss(int position); @@ -56,6 +58,8 @@ public interface Presenter { void onSaveInstanceState(Bundle outState); void showDetails(int itemId); void filter(String query); + void unpack(int setId); + void restore(int setId); } interface ItemDetail extends Base { @@ -71,6 +75,25 @@ public interface Presenter { void displayPicture(Bitmap bitmap); } + interface Share extends Base { + void setView(View.Share view); + void setModel(Model.Share model); + Model.Share getModel(); + void onDestroy(boolean isChangingConfiguration); + android.view.View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState); + + } + + interface Add extends Base { + void setView(View.Add view); + void setModel(Model.Add model); + Model.Add getModel(); + void onDestroy(boolean isChangingConfiguration); + android.view.View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState); + void notifyDataSetChanged(boolean found); + void onAddItemClick(Item item); + } + } diff --git a/app/src/main/java/com/hikapro/backpack/presenter/SetListPresenter.java b/app/src/main/java/com/hikapro/backpack/presenter/SetListPresenter.java index 23a3d80..482560e 100644 --- a/app/src/main/java/com/hikapro/backpack/presenter/SetListPresenter.java +++ b/app/src/main/java/com/hikapro/backpack/presenter/SetListPresenter.java @@ -9,6 +9,7 @@ import android.support.v7.widget.RecyclerView; import android.support.v7.widget.helper.ItemTouchHelper; import android.view.LayoutInflater; import android.view.ViewGroup; +import android.widget.ProgressBar; import android.widget.Toast; import java.lang.ref.WeakReference; @@ -31,6 +32,9 @@ public class SetListPresenter implements Presenter.SetList { private WeakReference view; private Model.Set model; private SetListAdapter adapter; + private ViewGroup progressBarContainer; + private ProgressBar progressBar; + private RecyclerView setRecycler; //GLM_add_resources_SetList @@ -72,8 +76,12 @@ public class SetListPresenter implements Presenter.SetList { public android.view.View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { android.view.View view = inflater.inflate(R.layout.fragment_set_list, container, false); + + progressBarContainer = (ViewGroup) view.findViewById(R.id.set_progress_container); + progressBar = (ProgressBar) progressBarContainer.findViewById(R.id.set_progress); + LinearLayoutManager llm = new LinearLayoutManager(getActivityContext()); - RecyclerView setRecycler = (RecyclerView) view.findViewById(R.id.set_recycler); + setRecycler = (RecyclerView) view.findViewById(R.id.set_recycler); setRecycler.setLayoutManager(llm); setRecycler.setAdapter(adapter); setRecycler.setItemAnimator(new DefaultItemAnimator()); @@ -134,11 +142,6 @@ public class SetListPresenter implements Presenter.SetList { return model; } - @Override - public void showMessage(String message) { - Toast.makeText(getView().getAppContext(), message, Toast.LENGTH_SHORT).show(); - } - // other impl <-- private View.SetList getView() throws NullPointerException { @@ -148,6 +151,18 @@ public class SetListPresenter implements Presenter.SetList { throw new NullPointerException("View is unavailable"); } + @Override + public void startProgress() { + setRecycler.setVisibility(android.view.View.GONE); + progressBarContainer.setVisibility(android.view.View.VISIBLE); + } + + @Override + public void stopProgress() { + setRecycler.setVisibility(android.view.View.VISIBLE); + progressBarContainer.setVisibility(android.view.View.GONE); + } + //GLM_add_resources_SetList @Override public void onStartDrag(RecyclerView.ViewHolder viewHolder) { @@ -158,7 +173,7 @@ public class SetListPresenter implements Presenter.SetList { if (getView() != null) getView().showItemList(set); else - showMessage("There is no view in presenter"); + Toast.makeText(getActivityContext(), "There is no view in presenter", Toast.LENGTH_SHORT).show(); } public void onLongClick(SetViewHolder holder) { diff --git a/app/src/main/java/com/hikapro/backpack/presenter/SharePresenter.java b/app/src/main/java/com/hikapro/backpack/presenter/SharePresenter.java new file mode 100644 index 0000000..4c9268e --- /dev/null +++ b/app/src/main/java/com/hikapro/backpack/presenter/SharePresenter.java @@ -0,0 +1,134 @@ +package com.hikapro.backpack.presenter; + +import android.app.Activity; +import android.content.Context; +import android.net.Uri; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.ViewGroup; +import android.widget.Button; + +import com.facebook.CallbackManager; +import com.facebook.FacebookCallback; +import com.facebook.FacebookException; +import com.facebook.FacebookSdk; +import com.facebook.appevents.AppEventsLogger; +import com.facebook.share.Sharer; +import com.facebook.share.model.ShareHashtag; +import com.facebook.share.model.ShareLinkContent; +import com.facebook.share.widget.ShareDialog; +import com.hikapro.backpack.R; +import com.hikapro.backpack.model.Model; +import com.hikapro.backpack.view.View; + +import java.lang.ref.WeakReference; + +/** + * Created by tariel on 16/05/16. + */ +public class SharePresenter implements Presenter.Share { + + private ShareDialog shareDialog; + private CallbackManager callbackManager; + + private Button facebookButton; + private Button twitterButton; + + private WeakReference view; + private Model.Share model; + + @Override + public Context getAppContext() { + try { + return getView().getAppContext(); + } catch (NullPointerException e) { + return null; + } + } + + @Override + public Context getActivityContext() { + try { + return getView().getActivityContext(); + } catch (NullPointerException e) { + return null; + } + } + + @Override + public void setView(View.Share view) { + this.view = new WeakReference<>(view); + + } + + @Override + public void setModel(Model.Share model) { + this.model = model; + } + + @Override + public Model.Share getModel() { + return model; + } + + @Override + public void onDestroy(boolean isChangingConfiguration) { + view = null; + model.onDestroy(isChangingConfiguration); + if ( !isChangingConfiguration ) { + model = null; + } + } + + @Override + public android.view.View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + android.view.View v = inflater.inflate(R.layout.fragment_share, container, false); + + FacebookSdk.sdkInitialize(getAppContext()); + //AppEventsLogger.activateApp(getActivityContext()); + callbackManager = CallbackManager.Factory.create(); + shareDialog = new ShareDialog((Activity) getActivityContext()); + facebookButton = (Button) v.findViewById(R.id.facebook_share_button); + twitterButton = (Button) v.findViewById(R.id.twitter_share_button); + shareDialog.registerCallback(callbackManager, new + + FacebookCallback() { + @Override + public void onSuccess(Sharer.Result result) {} + + @Override + public void onCancel() {} + + @Override + public void onError(FacebookException error) {} + }); + facebookButton.setOnClickListener(new android.view.View.OnClickListener() { + @Override + public void onClick(android.view.View v) { + if (ShareDialog.canShow(ShareLinkContent.class)) { + + + ShareLinkContent linkContent = new ShareLinkContent.Builder() + .setContentTitle("Test Pack With Me app") + .setContentDescription("Test of facebook integration") + .setContentUrl(Uri.parse("http://developers.facebook.com/android")) + .setShareHashtag(new ShareHashtag.Builder() + .setHashtag("#PackWithMe") + .build()) + .build(); + + shareDialog.show(linkContent); + } + } + }); + return v; + } + + private View.Share getView() throws NullPointerException { + if ( view != null ) + return view.get(); + else + throw new NullPointerException("View is unavailable"); + } +} diff --git a/app/src/main/java/com/hikapro/backpack/presenter/adapters/AddListAdapter.java b/app/src/main/java/com/hikapro/backpack/presenter/adapters/AddListAdapter.java new file mode 100644 index 0000000..8b45761 --- /dev/null +++ b/app/src/main/java/com/hikapro/backpack/presenter/adapters/AddListAdapter.java @@ -0,0 +1,53 @@ +package com.hikapro.backpack.presenter.adapters; + +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; + +import com.hikapro.backpack.R; +import com.hikapro.backpack.model.entities.Item; +import com.hikapro.backpack.presenter.Presenter; +import com.hikapro.backpack.view.recycler.AddItemViewHolder; +import com.hikapro.backpack.view.recycler.ItemViewHolder; + +/** + * Created by tariel on 18/05/16. + */ +public class AddListAdapter extends RecyclerView.Adapter { + + private Presenter.Add presenter; + + public AddListAdapter(Presenter.Add presenter) { + this.presenter = presenter; + } + + @Override + public int getItemCount() { + return presenter.getModel().getItemsCount(); + } + + @Override + public void onBindViewHolder(AddItemViewHolder holder, int position) { + final Item item = presenter.getModel().getItemByPosition(position); + holder.name.setText(item.getName()); + holder.category.setText(presenter.getModel().getCategoryById(item.getCategory()).getName()); + holder.alreadyInList.setVisibility(item.InList ? View.VISIBLE : View.GONE); + holder.item.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + presenter.onAddItemClick(item); + } + }); + } + + @Override + public AddItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + AddItemViewHolder viewHolder; + View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_add, + parent, false); + viewHolder = new AddItemViewHolder(v); + return viewHolder; + } +} diff --git a/app/src/main/java/com/hikapro/backpack/presenter/adapters/ItemListAdapter.java b/app/src/main/java/com/hikapro/backpack/presenter/adapters/ItemListAdapter.java index 83289ee..ce2b6fc 100644 --- a/app/src/main/java/com/hikapro/backpack/presenter/adapters/ItemListAdapter.java +++ b/app/src/main/java/com/hikapro/backpack/presenter/adapters/ItemListAdapter.java @@ -1,6 +1,7 @@ package com.hikapro.backpack.presenter.adapters; import android.graphics.Color; +import android.graphics.Typeface; import android.os.Handler; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; @@ -29,6 +30,7 @@ public class ItemListAdapter extends RecyclerView.Adapter implem HashMap pendingRunables = new HashMap<>(); // map of items to pending runnables, so we can cancel a removal if need be private Presenter.ItemList presenter; private boolean checkAll; + private Typeface mainFace; public ItemListAdapter(Presenter.ItemList presenter) { this.presenter = presenter; @@ -54,8 +56,8 @@ public class ItemListAdapter extends RecyclerView.Adapter implem // we need to show the "undo" state of the row holder.itemView.setBackgroundColor(Color.RED); holder.checkBox.setVisibility(View.GONE); - holder.undoButton.setVisibility(View.VISIBLE); - holder.undoButton.setOnClickListener(new View.OnClickListener() { + holder.swipeGroup.setVisibility(View.VISIBLE); + holder.deleteButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // user wants to undo the removal, let's cancel the pending task @@ -68,9 +70,16 @@ public class ItemListAdapter extends RecyclerView.Adapter implem } }); } else { + /* + if (mainFace == null) + mainFace = Typeface.createFromAsset(presenter.getAppContext().getAssets(), + "fonts/Ubuntu-B.ttf");*/ + holder.checkBox.setVisibility(View.VISIBLE); holder.checkBox.setChecked(checkAll); holder.checkBox.setText(item.getName() + " " + item.getId() + " pos " + position);//TODO del + holder.checkBox.setTypeface(mainFace); + holder.swipeGroup.setVisibility(View.GONE); holder.id = item.getId(); holder.checkBox.setOnClickListener(new android.view.View.OnClickListener() { @Override @@ -91,8 +100,7 @@ public class ItemListAdapter extends RecyclerView.Adapter implem } }); holder.itemView.setBackgroundColor(0x33FF99); - holder.undoButton.setVisibility(View.GONE); - holder.undoButton.setOnClickListener(null); + holder.deleteButton.setOnClickListener(null); } } diff --git a/app/src/main/java/com/hikapro/backpack/presenter/adapters/SetListAdapter.java b/app/src/main/java/com/hikapro/backpack/presenter/adapters/SetListAdapter.java index 5a3ef18..bfa7f9d 100644 --- a/app/src/main/java/com/hikapro/backpack/presenter/adapters/SetListAdapter.java +++ b/app/src/main/java/com/hikapro/backpack/presenter/adapters/SetListAdapter.java @@ -1,5 +1,6 @@ package com.hikapro.backpack.presenter.adapters; +import android.graphics.Typeface; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; @@ -17,6 +18,7 @@ public class SetListAdapter extends RecyclerView.Adapter impleme private SetListPresenter presenter; private String rightBracket; + private Typeface mainFace; public SetListAdapter(SetListPresenter presenter) { this.presenter = presenter; @@ -36,7 +38,13 @@ public class SetListAdapter extends RecyclerView.Adapter impleme this.rightBracket = ""; } + if (mainFace == null) { + mainFace = Typeface.createFromAsset(presenter.getAppContext().getAssets(), + "fonts/Ubuntu-B.ttf"); + } + holder.textView.setText(set.getName() + " " + rightBracket); + holder.textView.setTypeface(mainFace); String info = String.format("%s %d / %d", presenter.getActivityContext().getResources().getString(R.string.packed), set.getPackedQty(), diff --git a/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/ItemSwipeCallback.java b/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/ItemSwipeCallback.java index 21aa37d..7feeccf 100644 --- a/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/ItemSwipeCallback.java +++ b/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/ItemSwipeCallback.java @@ -10,6 +10,7 @@ import android.support.v4.content.ContextCompat; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.helper.ItemTouchHelper; import android.view.View; +import android.view.ViewGroup; import com.hikapro.backpack.R; import com.hikapro.backpack.presenter.adapters.ItemListAdapter; @@ -21,6 +22,7 @@ public class ItemSwipeCallback extends ItemTouchHelper.SimpleCallback { // we want to cache these and not allocate anything repeatedly in the onChildDraw method Drawable background; + ViewGroup viewGroup; Drawable xMark; int xMarkMargin; boolean initiated; @@ -82,11 +84,21 @@ public class ItemSwipeCallback extends ItemTouchHelper.SimpleCallback { init(); } + if (-(c.getWidth() * 0.6) > dX) { + this.onChildDrawOver(c, recyclerView, viewHolder, dX, dY, actionState, false); + return; + } + // draw red background - background.setBounds(itemView.getRight() + (int) dX, itemView.getTop(), itemView.getRight(), itemView.getBottom()); - background.draw(c); + //viewGroup.setLeft(itemView.getRight() + (int) dX); + //if ((itemView.getRight() + (int)dX) >= c.getWidth() * 0.6) { + background.setBounds(itemView.getRight() + (int) dX, itemView.getTop(), itemView.getRight(), itemView.getBottom()); + background.draw(c); + //viewGroup.draw(c); + //} // draw x mark + int itemHeight = itemView.getBottom() - itemView.getTop(); int intrinsicWidth = xMark.getIntrinsicWidth(); int intrinsicHeight = xMark.getIntrinsicWidth(); diff --git a/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/swipe/BaseSwipeListAdapter.java b/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/swipe/BaseSwipeListAdapter.java new file mode 100644 index 0000000..387f381 --- /dev/null +++ b/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/swipe/BaseSwipeListAdapter.java @@ -0,0 +1,13 @@ +package com.hikapro.backpack.presenter.adapters.helper.items.swipe; + +import android.widget.BaseAdapter; + +/** + * Created by tariel on 18/06/16. + */ +public abstract class BaseSwipeListAdapter extends BaseAdapter { + + public boolean getSwipeEnableByPosition(int position) { + return true; + } +} diff --git a/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/swipe/SwipeMenu.java b/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/swipe/SwipeMenu.java new file mode 100644 index 0000000..d647ffc --- /dev/null +++ b/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/swipe/SwipeMenu.java @@ -0,0 +1,49 @@ +package com.hikapro.backpack.presenter.adapters.helper.items.swipe; + +import android.content.Context; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by tariel on 18/06/16. + */ +public class SwipeMenu { + + private Context mContext; + private List mItems; + private int mViewType; + + public SwipeMenu(Context context) { + mContext = context; + mItems = new ArrayList(); + } + + public Context getContext() { + return mContext; + } + + public void addMenuItem(SwipeMenuItem item) { + mItems.add(item); + } + + public void removeMenuItem(SwipeMenuItem item) { + mItems.remove(item); + } + + public List getMenuItems() { + return mItems; + } + + public SwipeMenuItem getMenuItem(int index) { + return mItems.get(index); + } + + public int getViewType() { + return mViewType; + } + + public void setViewType(int viewType) { + this.mViewType = viewType; + } +} diff --git a/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/swipe/SwipeMenuAdapter.java b/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/swipe/SwipeMenuAdapter.java new file mode 100644 index 0000000..9e6c9c2 --- /dev/null +++ b/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/swipe/SwipeMenuAdapter.java @@ -0,0 +1,144 @@ +package com.hikapro.backpack.presenter.adapters.helper.items.swipe; + +import android.content.Context; +import android.database.DataSetObserver; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ListAdapter; +import android.widget.WrapperListAdapter; + +/** + * Created by tariel on 18/06/16. + */ +public class SwipeMenuAdapter implements WrapperListAdapter, + SwipeMenuView.OnSwipeItemClickListener { + + private ListAdapter mAdapter; + private Context mContext; + private SwipeMenuListView.OnMenuItemClickListener onMenuItemClickListener; + + public SwipeMenuAdapter(Context context, ListAdapter adapter) { + mAdapter = adapter; + mContext = context; + } + + @Override + public int getCount() { + return mAdapter.getCount(); + } + + @Override + public Object getItem(int position) { + return mAdapter.getItem(position); + } + + @Override + public long getItemId(int position) { + return mAdapter.getItemId(position); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + SwipeMenuLayout layout = null; + if (convertView == null) { + View contentView = mAdapter.getView(position, convertView, parent); + SwipeMenu menu = new SwipeMenu(mContext); + menu.setViewType(getItemViewType(position)); + createMenu(menu); + SwipeMenuView menuView = new SwipeMenuView(menu, + (SwipeMenuListView) parent); + menuView.setOnSwipeItemClickListener(this); + SwipeMenuListView listView = (SwipeMenuListView) parent; + layout = new SwipeMenuLayout(contentView, menuView, + listView.getCloseInterpolator(), + listView.getOpenInterpolator()); + layout.setPosition(position); + } else { + layout = (SwipeMenuLayout) convertView; + layout.closeMenu(); + layout.setPosition(position); + View view = mAdapter.getView(position, layout.getContentView(), + parent); + } + if (mAdapter instanceof BaseSwipeListAdapter) { + boolean swipEnable = (((BaseSwipeListAdapter) mAdapter).getSwipeEnableByPosition(position)); + layout.setSwipEnable(swipEnable); + } + return layout; + } + + public void createMenu(SwipeMenu menu) { + // Test Code + SwipeMenuItem item = new SwipeMenuItem(mContext); + item.setTitle("Item 1"); + item.setBackground(new ColorDrawable(Color.GRAY)); + item.setWidth(300); + menu.addMenuItem(item); + + item = new SwipeMenuItem(mContext); + item.setTitle("Item 2"); + item.setBackground(new ColorDrawable(Color.RED)); + item.setWidth(300); + menu.addMenuItem(item); + } + + @Override + public void onItemClick(SwipeMenuView view, SwipeMenu menu, int index) { + if (onMenuItemClickListener != null) { + onMenuItemClickListener.onMenuItemClick(view.getPosition(), menu, + index); + } + } + + public void setOnSwipeItemClickListener( + SwipeMenuListView.OnMenuItemClickListener onMenuItemClickListener) { + this.onMenuItemClickListener = onMenuItemClickListener; + } + + @Override + public void registerDataSetObserver(DataSetObserver observer) { + mAdapter.registerDataSetObserver(observer); + } + + @Override + public void unregisterDataSetObserver(DataSetObserver observer) { + mAdapter.unregisterDataSetObserver(observer); + } + + @Override + public boolean areAllItemsEnabled() { + return mAdapter.areAllItemsEnabled(); + } + + @Override + public boolean isEnabled(int position) { + return mAdapter.isEnabled(position); + } + + @Override + public boolean hasStableIds() { + return mAdapter.hasStableIds(); + } + + @Override + public int getItemViewType(int position) { + return mAdapter.getItemViewType(position); + } + + @Override + public int getViewTypeCount() { + return mAdapter.getViewTypeCount(); + } + + @Override + public boolean isEmpty() { + return mAdapter.isEmpty(); + } + + @Override + public ListAdapter getWrappedAdapter() { + return mAdapter; + } +} diff --git a/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/swipe/SwipeMenuCreator.java b/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/swipe/SwipeMenuCreator.java new file mode 100644 index 0000000..5b6b3f6 --- /dev/null +++ b/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/swipe/SwipeMenuCreator.java @@ -0,0 +1,8 @@ +package com.hikapro.backpack.presenter.adapters.helper.items.swipe; + +/** + * Created by tariel on 18/06/16. + */ +public interface SwipeMenuCreator { + void create(SwipeMenu menu); +} diff --git a/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/swipe/SwipeMenuItem.java b/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/swipe/SwipeMenuItem.java new file mode 100644 index 0000000..ca9630d --- /dev/null +++ b/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/swipe/SwipeMenuItem.java @@ -0,0 +1,91 @@ +package com.hikapro.backpack.presenter.adapters.helper.items.swipe; + +import android.content.Context; +import android.graphics.drawable.Drawable; + +/** + * Created by tariel on 18/06/16. + */ +public class SwipeMenuItem { + + private int id; + private Context mContext; + private String title; + private Drawable icon; + private Drawable background; + private int titleColor; + private int titleSize; + private int width; + + public SwipeMenuItem(Context context) { + mContext = context; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getTitleColor() { + return titleColor; + } + + public int getTitleSize() { + return titleSize; + } + + public void setTitleSize(int titleSize) { + this.titleSize = titleSize; + } + + public void setTitleColor(int titleColor) { + this.titleColor = titleColor; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public void setTitle(int resId) { + setTitle(mContext.getString(resId)); + } + + public Drawable getIcon() { + return icon; + } + + public void setIcon(Drawable icon) { + this.icon = icon; + } + + public void setIcon(int resId) { + this.icon = mContext.getResources().getDrawable(resId); + } + + public Drawable getBackground() { + return background; + } + + public void setBackground(Drawable background) { + this.background = background; + } + + public void setBackground(int resId) { + this.background = mContext.getResources().getDrawable(resId); + } + + public int getWidth() { + return width; + } + + public void setWidth(int width) { + this.width = width; + } +} diff --git a/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/swipe/SwipeMenuLayout.java b/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/swipe/SwipeMenuLayout.java new file mode 100644 index 0000000..479e8f1 --- /dev/null +++ b/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/swipe/SwipeMenuLayout.java @@ -0,0 +1,344 @@ +package com.hikapro.backpack.presenter.adapters.helper.items.swipe; + +import android.content.Context; +import android.support.v4.view.GestureDetectorCompat; +import android.support.v4.widget.ScrollerCompat; +import android.util.AttributeSet; +import android.util.Log; +import android.util.TypedValue; +import android.view.GestureDetector.OnGestureListener; +import android.view.GestureDetector.SimpleOnGestureListener; +import android.view.MotionEvent; +import android.view.View; +import android.view.animation.Interpolator; +import android.widget.AbsListView; +import android.widget.FrameLayout; + +/** + * Created by tariel on 18/06/16. + */ +public class SwipeMenuLayout extends FrameLayout { + + private static final int CONTENT_VIEW_ID = 1; + private static final int MENU_VIEW_ID = 2; + + private static final int STATE_CLOSE = 0; + private static final int STATE_OPEN = 1; + + private int mSwipeDirection; + + private View mContentView; + private SwipeMenuView mMenuView; + private int mDownX; + private int state = STATE_CLOSE; + private GestureDetectorCompat mGestureDetector; + private OnGestureListener mGestureListener; + private boolean isFling; + private int MIN_FLING = dp2px(15); + private int MAX_VELOCITYX = -dp2px(500); + private ScrollerCompat mOpenScroller; + private ScrollerCompat mCloseScroller; + private int mBaseX; + private int position; + private Interpolator mCloseInterpolator; + private Interpolator mOpenInterpolator; + + private boolean mSwipEnable = true; + + public SwipeMenuLayout(View contentView, SwipeMenuView menuView) { + this(contentView, menuView, null, null); + } + + public SwipeMenuLayout(View contentView, SwipeMenuView menuView, + Interpolator closeInterpolator, Interpolator openInterpolator) { + super(contentView.getContext()); + mCloseInterpolator = closeInterpolator; + mOpenInterpolator = openInterpolator; + mContentView = contentView; + mMenuView = menuView; + mMenuView.setLayout(this); + init(); + } + + // private SwipeMenuLayout(Context context, AttributeSet attrs, int + // defStyle) { + // super(context, attrs, defStyle); + // } + + private SwipeMenuLayout(Context context, AttributeSet attrs) { + super(context, attrs); + } + + private SwipeMenuLayout(Context context) { + super(context); + } + + public int getPosition() { + return position; + } + + public void setPosition(int position) { + this.position = position; + mMenuView.setPosition(position); + } + + public void setSwipeDirection(int swipeDirection) { + mSwipeDirection = swipeDirection; + } + + private void init() { + setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT, + LayoutParams.WRAP_CONTENT)); + mGestureListener = new SimpleOnGestureListener() { + @Override + public boolean onDown(MotionEvent e) { + isFling = false; + return true; + } + + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, + float velocityX, float velocityY) { + // TODO + if (Math.abs(e1.getX() - e2.getX()) > MIN_FLING + && velocityX < MAX_VELOCITYX) { + isFling = true; + } + // Log.i("byz", MAX_VELOCITYX + ", velocityX = " + velocityX); + return super.onFling(e1, e2, velocityX, velocityY); + } + }; + mGestureDetector = new GestureDetectorCompat(getContext(), + mGestureListener); + + // mScroller = ScrollerCompat.create(getContext(), new + // BounceInterpolator()); + if (mCloseInterpolator != null) { + mCloseScroller = ScrollerCompat.create(getContext(), + mCloseInterpolator); + } else { + mCloseScroller = ScrollerCompat.create(getContext()); + } + if (mOpenInterpolator != null) { + mOpenScroller = ScrollerCompat.create(getContext(), + mOpenInterpolator); + } else { + mOpenScroller = ScrollerCompat.create(getContext()); + } + + LayoutParams contentParams = new LayoutParams( + LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); + mContentView.setLayoutParams(contentParams); + if (mContentView.getId() < 1) { + mContentView.setId(CONTENT_VIEW_ID); + } + + mMenuView.setId(MENU_VIEW_ID); + mMenuView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT)); + + addView(mContentView); + addView(mMenuView); + + // if (mContentView.getBackground() == null) { + // mContentView.setBackgroundColor(Color.WHITE); + // } + + // in android 2.x, MenuView height is MATCH_PARENT is not work. + // getViewTreeObserver().addOnGlobalLayoutListener( + // new OnGlobalLayoutListener() { + // @Override + // public void onGlobalLayout() { + // setMenuHeight(mContentView.getHeight()); + // // getViewTreeObserver() + // // .removeGlobalOnLayoutListener(this); + // } + // }); + + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + } + + public boolean onSwipe(MotionEvent event) { + mGestureDetector.onTouchEvent(event); + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + mDownX = (int) event.getX(); + isFling = false; + break; + case MotionEvent.ACTION_MOVE: + // Log.i("byz", "downX = " + mDownX + ", moveX = " + event.getX()); + int dis = (int) (mDownX - event.getX()); + if (state == STATE_OPEN) { + dis += mMenuView.getWidth()*mSwipeDirection;; + } + swipe(dis); + break; + case MotionEvent.ACTION_UP: + if ((isFling || Math.abs(mDownX - event.getX()) > (mMenuView.getWidth() / 2)) && + Math.signum(mDownX - event.getX()) == mSwipeDirection) { + // open + smoothOpenMenu(); + } else { + // close + smoothCloseMenu(); + return false; + } + break; + } + return true; + } + + public boolean isOpen() { + return state == STATE_OPEN; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + return super.onTouchEvent(event); + } + + private void swipe(int dis) { + if(!mSwipEnable){ + return ; + } + if (Math.signum(dis) != mSwipeDirection) { + dis = 0; + } else if (Math.abs(dis) > mMenuView.getWidth()) { + dis = mMenuView.getWidth()*mSwipeDirection; + } + + mContentView.layout(-dis, mContentView.getTop(), + mContentView.getWidth() -dis, getMeasuredHeight()); + + if (mSwipeDirection == SwipeMenuListView.DIRECTION_LEFT) { + + mMenuView.layout(mContentView.getWidth() - dis, mMenuView.getTop(), + mContentView.getWidth() + mMenuView.getWidth() - dis, + mMenuView.getBottom()); + } else { + mMenuView.layout(-mMenuView.getWidth() - dis, mMenuView.getTop(), + - dis, mMenuView.getBottom()); + } + } + + @Override + public void computeScroll() { + if (state == STATE_OPEN) { + if (mOpenScroller.computeScrollOffset()) { + swipe(mOpenScroller.getCurrX()*mSwipeDirection); + postInvalidate(); + } + } else { + if (mCloseScroller.computeScrollOffset()) { + swipe((mBaseX - mCloseScroller.getCurrX())*mSwipeDirection); + postInvalidate(); + } + } + } + + public void smoothCloseMenu() { + state = STATE_CLOSE; + if (mSwipeDirection == SwipeMenuListView.DIRECTION_LEFT) { + mBaseX = -mContentView.getLeft(); + mCloseScroller.startScroll(0, 0, mMenuView.getWidth(), 0, 350); + } else { + mBaseX = mMenuView.getRight(); + mCloseScroller.startScroll(0, 0, mMenuView.getWidth(), 0, 350); + } + postInvalidate(); + } + + public void smoothOpenMenu() { + if(!mSwipEnable){ + return ; + } + state = STATE_OPEN; + if (mSwipeDirection == SwipeMenuListView.DIRECTION_LEFT) { + mOpenScroller.startScroll(-mContentView.getLeft(), 0, mMenuView.getWidth(), 0, 350); + } else { + mOpenScroller.startScroll(mContentView.getLeft(), 0, mMenuView.getWidth(), 0, 350); + } + postInvalidate(); + } + + public void closeMenu() { + if (mCloseScroller.computeScrollOffset()) { + mCloseScroller.abortAnimation(); + } + if (state == STATE_OPEN) { + state = STATE_CLOSE; + swipe(0); + } + } + + public void openMenu() { + if(!mSwipEnable){ + return ; + } + if (state == STATE_CLOSE) { + state = STATE_OPEN; + swipe(mMenuView.getWidth() * mSwipeDirection); + } + } + + public View getContentView() { + return mContentView; + } + + public SwipeMenuView getMenuView() { + return mMenuView; + } + + private int dp2px(int dp) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, + getContext().getResources().getDisplayMetrics()); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + mMenuView.measure(MeasureSpec.makeMeasureSpec(0, + MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec( + getMeasuredHeight(), MeasureSpec.EXACTLY)); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + mContentView.layout(0, 0, getMeasuredWidth(), + mContentView.getMeasuredHeight()); + if (mSwipeDirection == SwipeMenuListView.DIRECTION_LEFT) { + mMenuView.layout(getMeasuredWidth(), 0, + getMeasuredWidth() + mMenuView.getMeasuredWidth(), + mContentView.getMeasuredHeight()); + } else { + mMenuView.layout(-mMenuView.getMeasuredWidth(), 0, + 0, mContentView.getMeasuredHeight()); + } + } + + public void setMenuHeight(int measuredHeight) { + Log.i("byz", "pos = " + position + ", height = " + measuredHeight); + LayoutParams params = (LayoutParams) mMenuView.getLayoutParams(); + if (params.height != measuredHeight) { + params.height = measuredHeight; + mMenuView.setLayoutParams(mMenuView.getLayoutParams()); + } + } + + public void setSwipEnable(boolean swipEnable){ + mSwipEnable = swipEnable; + } + + public boolean getSwipEnable(){ + return mSwipEnable; + } +} diff --git a/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/swipe/SwipeMenuListView.java b/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/swipe/SwipeMenuListView.java new file mode 100644 index 0000000..41f1be2 --- /dev/null +++ b/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/swipe/SwipeMenuListView.java @@ -0,0 +1,339 @@ +package com.hikapro.backpack.presenter.adapters.helper.items.swipe; + +import android.content.Context; +import android.support.v4.view.MotionEventCompat; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.MotionEvent; +import android.view.View; +import android.view.animation.Interpolator; +import android.widget.ListAdapter; +import android.widget.ListView; + +/** + * Created by tariel on 18/06/16. + */ +public class SwipeMenuListView extends ListView { + + private static final int TOUCH_STATE_NONE = 0; + private static final int TOUCH_STATE_X = 1; + private static final int TOUCH_STATE_Y = 2; + + public static final int DIRECTION_LEFT = 1; + public static final int DIRECTION_RIGHT = -1; + private int mDirection = 1;//swipe from right to left by default + + private int MAX_Y = 5; + private int MAX_X = 3; + private float mDownX; + private float mDownY; + private int mTouchState; + private int mTouchPosition; + private SwipeMenuLayout mTouchView; + private OnSwipeListener mOnSwipeListener; + + private SwipeMenuCreator mMenuCreator; + private OnMenuItemClickListener mOnMenuItemClickListener; + private OnMenuStateChangeListener mOnMenuStateChangeListener; + private Interpolator mCloseInterpolator; + private Interpolator mOpenInterpolator; + + public SwipeMenuListView(Context context) { + super(context); + init(); + } + + public SwipeMenuListView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + public SwipeMenuListView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + private void init() { + MAX_X = dp2px(MAX_X); + MAX_Y = dp2px(MAX_Y); + mTouchState = TOUCH_STATE_NONE; + } + + @Override + public void setAdapter(ListAdapter adapter) { + super.setAdapter(new SwipeMenuAdapter(getContext(), adapter) { + @Override + public void createMenu(SwipeMenu menu) { + if (mMenuCreator != null) { + mMenuCreator.create(menu); + } + } + + @Override + public void onItemClick(SwipeMenuView view, SwipeMenu menu, + int index) { + boolean flag = false; + if (mOnMenuItemClickListener != null) { + flag = mOnMenuItemClickListener.onMenuItemClick( + view.getPosition(), menu, index); + } + if (mTouchView != null && !flag) { + mTouchView.smoothCloseMenu(); + } + } + }); + } + + public void setCloseInterpolator(Interpolator interpolator) { + mCloseInterpolator = interpolator; + } + + public void setOpenInterpolator(Interpolator interpolator) { + mOpenInterpolator = interpolator; + } + + public Interpolator getOpenInterpolator() { + return mOpenInterpolator; + } + + public Interpolator getCloseInterpolator() { + return mCloseInterpolator; + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + //在拦截处处理,在滑动设置了点击事件的地方也能swip,点击时又不能影响原来的点击事件 + int action = ev.getAction(); + switch (action) { + case MotionEvent.ACTION_DOWN: + mDownX = ev.getX(); + mDownY = ev.getY(); + boolean handled = super.onInterceptTouchEvent(ev); + mTouchState = TOUCH_STATE_NONE; + mTouchPosition = pointToPosition((int) ev.getX(), (int) ev.getY()); + View view = getChildAt(mTouchPosition - getFirstVisiblePosition()); + + //只在空的时候赋值 以免每次触摸都赋值,会有多个open状态 + if (view instanceof SwipeMenuLayout) { + //如果有打开了 就拦截. + if (mTouchView != null && mTouchView.isOpen() && !inRangeOfView(mTouchView.getMenuView(), ev)) { + return true; + } + mTouchView = (SwipeMenuLayout) view; + mTouchView.setSwipeDirection(mDirection); + } + //如果摸在另外个view + if (mTouchView != null && mTouchView.isOpen() && view != mTouchView) { + handled = true; + } + + if (mTouchView != null) { + mTouchView.onSwipe(ev); + } + return handled; + case MotionEvent.ACTION_MOVE: + float dy = Math.abs((ev.getY() - mDownY)); + float dx = Math.abs((ev.getX() - mDownX)); + if (Math.abs(dy) > MAX_Y || Math.abs(dx) > MAX_X) { + //每次拦截的down都把触摸状态设置成了TOUCH_STATE_NONE 只有返回true才会走onTouchEvent 所以写在这里就够了 + if (mTouchState == TOUCH_STATE_NONE) { + if (Math.abs(dy) > MAX_Y) { + mTouchState = TOUCH_STATE_Y; + } else if (dx > MAX_X) { + mTouchState = TOUCH_STATE_X; + if (mOnSwipeListener != null) { + mOnSwipeListener.onSwipeStart(mTouchPosition); + } + } + } + return true; + } + } + return super.onInterceptTouchEvent(ev); + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + if (ev.getAction() != MotionEvent.ACTION_DOWN && mTouchView == null) + return super.onTouchEvent(ev); + int action = ev.getAction(); + switch (action) { + case MotionEvent.ACTION_DOWN: + int oldPos = mTouchPosition; + mDownX = ev.getX(); + mDownY = ev.getY(); + mTouchState = TOUCH_STATE_NONE; + + mTouchPosition = pointToPosition((int) ev.getX(), (int) ev.getY()); + + if (mTouchPosition == oldPos && mTouchView != null + && mTouchView.isOpen()) { + mTouchState = TOUCH_STATE_X; + mTouchView.onSwipe(ev); + return true; + } + + View view = getChildAt(mTouchPosition - getFirstVisiblePosition()); + + if (mTouchView != null && mTouchView.isOpen()) { + mTouchView.smoothCloseMenu(); + mTouchView = null; + // return super.onTouchEvent(ev); + // try to cancel the touch event + MotionEvent cancelEvent = MotionEvent.obtain(ev); + cancelEvent.setAction(MotionEvent.ACTION_CANCEL); + onTouchEvent(cancelEvent); + if (mOnMenuStateChangeListener != null) { + mOnMenuStateChangeListener.onMenuClose(oldPos); + } + return true; + } + if (view instanceof SwipeMenuLayout) { + mTouchView = (SwipeMenuLayout) view; + mTouchView.setSwipeDirection(mDirection); + } + if (mTouchView != null) { + mTouchView.onSwipe(ev); + } + break; + case MotionEvent.ACTION_MOVE: + //有些可能有header,要减去header再判断 + mTouchPosition = pointToPosition((int) ev.getX(), (int) ev.getY()) - getHeaderViewsCount(); + //如果滑动了一下没完全展现,就收回去,这时候mTouchView已经赋值,再滑动另外一个不可以swip的view + //会导致mTouchView swip 。 所以要用位置判断是否滑动的是一个view + if (!mTouchView.getSwipEnable() || mTouchPosition != mTouchView.getPosition()) { + break; + } + float dy = Math.abs((ev.getY() - mDownY)); + float dx = Math.abs((ev.getX() - mDownX)); + if (mTouchState == TOUCH_STATE_X) { + if (mTouchView != null) { + mTouchView.onSwipe(ev); + } + getSelector().setState(new int[]{0}); + ev.setAction(MotionEvent.ACTION_CANCEL); + super.onTouchEvent(ev); + return true; + } else if (mTouchState == TOUCH_STATE_NONE) { + if (Math.abs(dy) > MAX_Y) { + mTouchState = TOUCH_STATE_Y; + } else if (dx > MAX_X) { + mTouchState = TOUCH_STATE_X; + if (mOnSwipeListener != null) { + mOnSwipeListener.onSwipeStart(mTouchPosition); + } + } + } + break; + case MotionEvent.ACTION_UP: + if (mTouchState == TOUCH_STATE_X) { + if (mTouchView != null) { + boolean isBeforeOpen = mTouchView.isOpen(); + mTouchView.onSwipe(ev); + boolean isAfterOpen = mTouchView.isOpen(); + if (isBeforeOpen != isAfterOpen && mOnMenuStateChangeListener != null) { + if (isAfterOpen) { + mOnMenuStateChangeListener.onMenuOpen(mTouchPosition); + } else { + mOnMenuStateChangeListener.onMenuClose(mTouchPosition); + } + } + if (!isAfterOpen) { + mTouchPosition = -1; + mTouchView = null; + } + } + if (mOnSwipeListener != null) { + mOnSwipeListener.onSwipeEnd(mTouchPosition); + } + ev.setAction(MotionEvent.ACTION_CANCEL); + super.onTouchEvent(ev); + return true; + } + break; + } + return super.onTouchEvent(ev); + } + + public void smoothOpenMenu(int position) { + if (position >= getFirstVisiblePosition() + && position <= getLastVisiblePosition()) { + View view = getChildAt(position - getFirstVisiblePosition()); + if (view instanceof SwipeMenuLayout) { + mTouchPosition = position; + if (mTouchView != null && mTouchView.isOpen()) { + mTouchView.smoothCloseMenu(); + } + mTouchView = (SwipeMenuLayout) view; + mTouchView.setSwipeDirection(mDirection); + mTouchView.smoothOpenMenu(); + } + } + } + + public void smoothCloseMenu(){ + if (mTouchView != null && mTouchView.isOpen()) { + mTouchView.smoothCloseMenu(); + } + } + + private int dp2px(int dp) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, + getContext().getResources().getDisplayMetrics()); + } + + public void setMenuCreator(SwipeMenuCreator menuCreator) { + this.mMenuCreator = menuCreator; + } + + public void setOnMenuItemClickListener( + OnMenuItemClickListener onMenuItemClickListener) { + this.mOnMenuItemClickListener = onMenuItemClickListener; + } + + public void setOnSwipeListener(OnSwipeListener onSwipeListener) { + this.mOnSwipeListener = onSwipeListener; + } + + public void setOnMenuStateChangeListener(OnMenuStateChangeListener onMenuStateChangeListener) { + mOnMenuStateChangeListener = onMenuStateChangeListener; + } + + public static interface OnMenuItemClickListener { + boolean onMenuItemClick(int position, SwipeMenu menu, int index); + } + + public static interface OnSwipeListener { + void onSwipeStart(int position); + + void onSwipeEnd(int position); + } + + public static interface OnMenuStateChangeListener { + void onMenuOpen(int position); + + void onMenuClose(int position); + } + + public void setSwipeDirection(int direction) { + mDirection = direction; + } + + /** + * 判断点击事件是否在某个view内 + * + * @param view + * @param ev + * @return + */ + public static boolean inRangeOfView(View view, MotionEvent ev) { + int[] location = new int[2]; + view.getLocationOnScreen(location); + int x = location[0]; + int y = location[1]; + if (ev.getRawX() < x || ev.getRawX() > (x + view.getWidth()) || ev.getRawY() < y || ev.getRawY() > (y + view.getHeight())) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/swipe/SwipeMenuView.java b/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/swipe/SwipeMenuView.java new file mode 100644 index 0000000..6d9d1ea --- /dev/null +++ b/app/src/main/java/com/hikapro/backpack/presenter/adapters/helper/items/swipe/SwipeMenuView.java @@ -0,0 +1,100 @@ +package com.hikapro.backpack.presenter.adapters.helper.items.swipe; + +import java.util.List; +import android.text.TextUtils; +import android.view.Gravity; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +/** + * Created by tariel on 18/06/16. + */ +public class SwipeMenuView extends LinearLayout implements OnClickListener { + + private SwipeMenuListView mListView; + private SwipeMenuLayout mLayout; + private SwipeMenu mMenu; + private OnSwipeItemClickListener onItemClickListener; + private int position; + + public int getPosition() { + return position; + } + + public void setPosition(int position) { + this.position = position; + } + + public SwipeMenuView(SwipeMenu menu, SwipeMenuListView listView) { + super(menu.getContext()); + mListView = listView; + mMenu = menu; + List items = menu.getMenuItems(); + int id = 0; + for (SwipeMenuItem item : items) { + addItem(item, id++); + } + } + + private void addItem(SwipeMenuItem item, int id) { + LayoutParams params = new LayoutParams(item.getWidth(), + LayoutParams.MATCH_PARENT); + LinearLayout parent = new LinearLayout(getContext()); + parent.setId(id); + parent.setGravity(Gravity.CENTER); + parent.setOrientation(LinearLayout.VERTICAL); + parent.setLayoutParams(params); + parent.setBackgroundDrawable(item.getBackground()); + parent.setOnClickListener(this); + addView(parent); + + if (item.getIcon() != null) { + parent.addView(createIcon(item)); + } + if (!TextUtils.isEmpty(item.getTitle())) { + parent.addView(createTitle(item)); + } + + } + + private ImageView createIcon(SwipeMenuItem item) { + ImageView iv = new ImageView(getContext()); + iv.setImageDrawable(item.getIcon()); + return iv; + } + + private TextView createTitle(SwipeMenuItem item) { + TextView tv = new TextView(getContext()); + tv.setText(item.getTitle()); + tv.setGravity(Gravity.CENTER); + tv.setTextSize(item.getTitleSize()); + tv.setTextColor(item.getTitleColor()); + return tv; + } + + @Override + public void onClick(View v) { + if (onItemClickListener != null && mLayout.isOpen()) { + onItemClickListener.onItemClick(this, mMenu, v.getId()); + } + } + + public OnSwipeItemClickListener getOnSwipeItemClickListener() { + return onItemClickListener; + } + + public void setOnSwipeItemClickListener(OnSwipeItemClickListener onItemClickListener) { + this.onItemClickListener = onItemClickListener; + } + + public void setLayout(SwipeMenuLayout mLayout) { + this.mLayout = mLayout; + } + + public static interface OnSwipeItemClickListener { + void onItemClick(SwipeMenuView view, SwipeMenu menu, int index); + } +} diff --git a/app/src/main/java/com/hikapro/backpack/view/View.java b/app/src/main/java/com/hikapro/backpack/view/View.java index fae4e55..a29536b 100644 --- a/app/src/main/java/com/hikapro/backpack/view/View.java +++ b/app/src/main/java/com/hikapro/backpack/view/View.java @@ -35,11 +35,23 @@ public interface View { Item getItem(); } + interface Share extends Base { + void setPresenter(Presenter.Share presenter); + } + + interface Add extends Base { + void setPresenter(Presenter.Add presenter); + void setNewItem(Item item); + Set getSet(); + } + interface ActivityCallback { void startSetListFragment(); void startItemListFragment(Set set); void startPackedListFragment(Set set); void startItemDetailFragment(Item item); + void startShareFragment(int setId); + void startAddFragment(Set set); } } diff --git a/app/src/main/java/com/hikapro/backpack/view/fragments/AddFragment.java b/app/src/main/java/com/hikapro/backpack/view/fragments/AddFragment.java new file mode 100644 index 0000000..8d79497 --- /dev/null +++ b/app/src/main/java/com/hikapro/backpack/view/fragments/AddFragment.java @@ -0,0 +1,160 @@ +package com.hikapro.backpack.view.fragments; + + +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; +import android.app.Fragment; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.SearchView; + +import com.hikapro.backpack.R; +import com.hikapro.backpack.model.entities.Item; +import com.hikapro.backpack.model.entities.Set; +import com.hikapro.backpack.presenter.Presenter; + +/** + * A simple {@link Fragment} subclass. + */ +public class AddFragment extends Fragment implements com.hikapro.backpack.view.View.Add { + + protected static final String BUNDLE_SET_KEY = "BUNDLE_SET_KEY"; + private Presenter.Add presenter; + private com.hikapro.backpack.view.View.ActivityCallback activityCallback; + + public static AddFragment construct() { + return new AddFragment(); + } + + public static AddFragment newFromSet(Set set) { + AddFragment ret = AddFragment.construct(); + Bundle args = new Bundle(); + args.putSerializable(BUNDLE_SET_KEY, set); + ret.setArguments(args); + return ret; + } + + + public AddFragment() { + // Required empty public constructor + } + + // life cycle --> + @Override + public void onAttach(Context context) { + super.onAttach(context); + try { + activityCallback = (com.hikapro.backpack.view.View.ActivityCallback) context; + } catch (ClassCastException e) { + throw new ClassCastException(context.toString() + + " must implement activityCallback"); + } + } + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + try { + activityCallback = (com.hikapro.backpack.view.View.ActivityCallback) activity; + } catch (ClassCastException e) { + throw new ClassCastException(activity.toString() + + " must implement activityCallback"); + } + Log.i(this.toString(), " onAttach"); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // setHasOptionsMenu(true); + Log.i(this.toString(), " onCreate"); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + presenter.setView(this); + View view = presenter.onCreateView(inflater, container, savedInstanceState); + Log.i(this.toString(), " onCreateView"); + return view; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + Log.i(this.toString(), " onActivityCreated"); + } + + @Override + public void onStart() { + super.onStart(); + Log.i(this.toString(), " onStart"); + } + @Override + public void onResume() { + super.onResume(); + Log.i(this.toString(), " onResume"); + } + @Override + public void onStop() { + super.onStop(); + Log.i(this.toString(), " onStop"); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + presenter.onDestroy(true); // TODO isChangingConfigurations + Log.i(this.toString(), " onDestroyView"); + } + + @Override + public void onDestroy() { + super.onDestroy(); + presenter.onDestroy(false); // TODO isChangingConfigurations + Log.i(this.toString(), " onDestroy"); + } + + @Override + public void onDetach() { + super.onDetach(); + Log.i(this.toString(), " onDetach"); + } + + @Override + public Context getAppContext() { + return this.getActivity().getApplicationContext(); + } + + @Override + public Context getActivityContext() { + return this.getActivity(); + } + + @Override + public void setPresenter(Presenter.Add presenter) { + this.presenter = presenter; + } + + @Override + public void setNewItem(Item item) { + + } + + public Set getSet() { + return (Set) getArguments().getSerializable(BUNDLE_SET_KEY); + } +/* + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + inflater.inflate(R.menu.menu_add, menu); + super.onCreateOptionsMenu(menu, inflater); + } + +*/ +} diff --git a/app/src/main/java/com/hikapro/backpack/view/fragments/ItemListFragment.java b/app/src/main/java/com/hikapro/backpack/view/fragments/ItemListFragment.java index 1ebd3f4..7a8b305 100644 --- a/app/src/main/java/com/hikapro/backpack/view/fragments/ItemListFragment.java +++ b/app/src/main/java/com/hikapro/backpack/view/fragments/ItemListFragment.java @@ -5,6 +5,7 @@ import android.app.Activity; import android.app.Fragment; import android.content.Context; import android.os.Bundle; +import android.support.v4.app.NavUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; @@ -71,18 +72,25 @@ public class ItemListFragment extends Fragment implements com.hikapro.backpack.v public boolean onOptionsItemSelected(MenuItem item) { boolean ret; switch (item.getItemId()) { + case android.R.id.home: + this.getFragmentManager().popBackStack(); + ret = true; + break; case R.id.action_share : - Toast.makeText(getActivityContext(), "Share", Toast.LENGTH_SHORT).show(); + activityCallback.startShareFragment(getSet().getId()); ret = true; break; case R.id.action_unpack_my_bag : - Toast.makeText(getActivityContext(), "Unpack my bag", Toast.LENGTH_SHORT).show(); + presenter.unpack(getSet().getId()); ret = true; break; case R.id.action_restore_to_default : - Toast.makeText(getActivityContext(), "Restore to default", Toast.LENGTH_SHORT).show(); + presenter.restore(getSet().getId()); ret = true; break; + case R.id.action_add : + activityCallback.startAddFragment(getSet()); + ret = true; default: ret = super.onOptionsItemSelected(item); } @@ -175,7 +183,7 @@ public class ItemListFragment extends Fragment implements com.hikapro.backpack.v @Override public void showItemDetail(Item item) { activityCallback.startItemDetailFragment(item); - } + }//TODO del? @Override public void showPackedItems(Set set) { diff --git a/app/src/main/java/com/hikapro/backpack/view/fragments/ShareFragment.java b/app/src/main/java/com/hikapro/backpack/view/fragments/ShareFragment.java new file mode 100644 index 0000000..4d59cbb --- /dev/null +++ b/app/src/main/java/com/hikapro/backpack/view/fragments/ShareFragment.java @@ -0,0 +1,79 @@ +package com.hikapro.backpack.view.fragments; + + +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; +import android.app.Fragment; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.hikapro.backpack.R; +import com.hikapro.backpack.presenter.Presenter; + +/** + * A simple {@link Fragment} subclass. + */ +public class ShareFragment extends Fragment implements com.hikapro.backpack.view.View.Share { + + private Presenter.Share presenter; + private com.hikapro.backpack.view.View.ActivityCallback activityCallback; + + + public ShareFragment() { + // Required empty public constructor + } + + public static ShareFragment construct() { + ShareFragment ret = new ShareFragment(); + return ret; + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + try { + activityCallback = (com.hikapro.backpack.view.View.ActivityCallback) context; + } catch (ClassCastException e) { + throw new ClassCastException(context.toString() + + " must implement activityCallback"); + } + } + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + try { + activityCallback = (com.hikapro.backpack.view.View.ActivityCallback) activity; + } catch (ClassCastException e) { + throw new ClassCastException(activity.toString() + + " must implement activityCallback"); + } + Log.i(this.toString(), "onAttach"); + } + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + presenter.setView(this); + View v = presenter.onCreateView(inflater, container, savedInstanceState); + return v; + } + + @Override + public void setPresenter(Presenter.Share presenter) { + this.presenter = presenter; + } + + @Override + public Context getAppContext() { + return this.getActivity().getApplicationContext(); + } + + @Override + public Context getActivityContext() { + return this.getActivity(); + } +} diff --git a/app/src/main/java/com/hikapro/backpack/view/recycler/AddItemViewHolder.java b/app/src/main/java/com/hikapro/backpack/view/recycler/AddItemViewHolder.java new file mode 100644 index 0000000..a36abe5 --- /dev/null +++ b/app/src/main/java/com/hikapro/backpack/view/recycler/AddItemViewHolder.java @@ -0,0 +1,32 @@ +package com.hikapro.backpack.view.recycler; + +import android.support.v7.widget.RecyclerView; +import android.view.View; + +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.hikapro.backpack.R; + +/** + * Created by tariel on 18/05/16. + */ +public class AddItemViewHolder extends RecyclerView.ViewHolder { + + public TextView name; + public TextView category; + public TextView alreadyInList; + public RelativeLayout item; + + public AddItemViewHolder(View itemView) { + super(itemView); + setupViews(itemView); + } + + private void setupViews(View view) { + item = (RelativeLayout) view.findViewById(R.id.add_item_item); + name = (TextView) item.findViewById(R.id.add_item_name); + category = (TextView) item.findViewById(R.id.add_item_category); + alreadyInList = (TextView) item.findViewById(R.id.add_already_in_list); + } +} diff --git a/app/src/main/java/com/hikapro/backpack/view/recycler/ItemViewHolder.java b/app/src/main/java/com/hikapro/backpack/view/recycler/ItemViewHolder.java index 3b1cb90..d851e0f 100644 --- a/app/src/main/java/com/hikapro/backpack/view/recycler/ItemViewHolder.java +++ b/app/src/main/java/com/hikapro/backpack/view/recycler/ItemViewHolder.java @@ -2,6 +2,7 @@ package com.hikapro.backpack.view.recycler; import android.support.v7.widget.RecyclerView; import android.view.View; +import android.view.ViewGroup; import android.widget.Button; import android.widget.CheckBox; import android.widget.ImageButton; @@ -16,8 +17,10 @@ public class ItemViewHolder extends RecyclerView.ViewHolder { public int id; public CheckBox checkBox; - public Button undoButton; + public Button leaveAtHomeButton; + public Button deleteButton; public ImageButton infoButton; + public ViewGroup swipeGroup; public ItemViewHolder(View v) { super(v); @@ -25,9 +28,11 @@ public class ItemViewHolder extends RecyclerView.ViewHolder { } private void setupViews(View view) { - infoButton = (ImageButton) view.findViewById(R.id.info_button); - checkBox = (CheckBox) view.findViewById(R.id.item_checkbox); - undoButton = (Button) view.findViewById(R.id.undo_button); + infoButton = (ImageButton) view.findViewById(R.id.info_button); + checkBox = (CheckBox) view.findViewById(R.id.item_checkbox); + leaveAtHomeButton = (Button) view.findViewById(R.id.leave_at_home_button); + deleteButton = (Button) view.findViewById(R.id.delete_button); + swipeGroup = (ViewGroup) view.findViewById((R.id.swipe_container)); } } diff --git a/app/src/main/res/drawable/facebook_48.png b/app/src/main/res/drawable/facebook_48.png new file mode 100644 index 0000000..eb0a202 Binary files /dev/null and b/app/src/main/res/drawable/facebook_48.png differ diff --git a/app/src/main/res/drawable/pic.png b/app/src/main/res/drawable/pic.png new file mode 100644 index 0000000..7ab8b3a Binary files /dev/null and b/app/src/main/res/drawable/pic.png differ diff --git a/app/src/main/res/drawable/search_divider.xml b/app/src/main/res/drawable/search_divider.xml new file mode 100644 index 0000000..d70309e --- /dev/null +++ b/app/src/main/res/drawable/search_divider.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/twitter_48.png b/app/src/main/res/drawable/twitter_48.png new file mode 100644 index 0000000..c3e985b Binary files /dev/null and b/app/src/main/res/drawable/twitter_48.png differ diff --git a/app/src/main/res/layout/add_cust_actionbar.xml b/app/src/main/res/layout/add_cust_actionbar.xml new file mode 100644 index 0000000..2f6a61e --- /dev/null +++ b/app/src/main/res/layout/add_cust_actionbar.xml @@ -0,0 +1,34 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/divider.xml b/app/src/main/res/layout/divider.xml new file mode 100644 index 0000000..3509b84 --- /dev/null +++ b/app/src/main/res/layout/divider.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/footer.xml b/app/src/main/res/layout/footer.xml index d9885a0..24b5c5a 100644 --- a/app/src/main/res/layout/footer.xml +++ b/app/src/main/res/layout/footer.xml @@ -6,21 +6,19 @@ android:orientation="vertical" android:animateLayoutChanges="true" android:id="@+id/item_list_footer" - android:background="#33D3D3D3" + android:background="@color/colorFooterbackground" android:layout_gravity="bottom" > - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_add.xml b/app/src/main/res/layout/fragment_add.xml new file mode 100644 index 0000000..93cd3a5 --- /dev/null +++ b/app/src/main/res/layout/fragment_add.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_item_detail.xml b/app/src/main/res/layout/fragment_item_detail.xml index 7c72fe6..8ed0fe2 100644 --- a/app/src/main/res/layout/fragment_item_detail.xml +++ b/app/src/main/res/layout/fragment_item_detail.xml @@ -3,7 +3,8 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - tools:context="com.hikapro.backpack.view.fragments.ItemDetailFragment"> + tools:context="com.hikapro.backpack.view.fragments.ItemDetailFragment" + android:background="@color/colorUiMainbackground"> - - - diff --git a/app/src/main/res/layout/fragment_item_list.xml b/app/src/main/res/layout/fragment_item_list.xml index 87c0787..f4da14b 100644 --- a/app/src/main/res/layout/fragment_item_list.xml +++ b/app/src/main/res/layout/fragment_item_list.xml @@ -8,7 +8,8 @@ + android:orientation="vertical" + android:background="@color/colorUiMainbackground2"> + android:background="@color/colorFooterbackground"> diff --git a/app/src/main/res/layout/fragment_packed_list.xml b/app/src/main/res/layout/fragment_packed_list.xml index f238f47..fc10ed7 100644 --- a/app/src/main/res/layout/fragment_packed_list.xml +++ b/app/src/main/res/layout/fragment_packed_list.xml @@ -12,37 +12,36 @@ android:visibility="visible" android:layout_alignParentTop="true" android:animateLayoutChanges="true" - android:background="#80968AA7"> + android:background="@color/colorFooterbackground">