From f95b8d11b7540f038494a6b56fb4bfd73faaa94a Mon Sep 17 00:00:00 2001 From: Tariel Hlontsi Date: Sun, 24 Apr 2016 20:52:40 +0300 Subject: [PATCH] StateMaintainer, ItemDetailFragment were added + minor architecture changes --- app/build.gradle | 4 +- .../hikapro/com/backpack/MainActivity.java | 156 +++++++++++++++++- .../hikapro/com/backpack/StateMaintainer.java | 97 +++++++++++ .../com/backpack/model/DetailModel.java | 69 ++++++++ .../hikapro/com/backpack/model/ItemModel.java | 38 ++++- .../hikapro/com/backpack/model/Model.java | 13 ++ .../hikapro/com/backpack/model/SetModel.java | 24 ++- .../com/backpack/model/entities/Item.java | 3 +- .../presenter/ItemDetailPresenter.java | 147 +++++++++++++++++ .../backpack/presenter/ItemListPresenter.java | 34 ++-- .../com/backpack/presenter/Presenter.java | 19 +++ .../backpack/presenter/SetListPresenter.java | 1 - .../presenter/adapters/ItemDetailAdapter.java | 40 +++++ .../java/hikapro/com/backpack/view/View.java | 7 +- .../view/fragments/ItemDetailFragment.java | 145 ++++++++++++++++ .../view/fragments/ItemListFragment.java | 13 +- .../view/fragments/SetListFragment.java | 2 +- .../view/recycler/DetailViewHolder.java | 29 ++++ .../main/res/layout/fragment_item_detail.xml | 17 ++ app/src/main/res/layout/item_detail.xml | 38 +++++ app/src/main/res/values-v21/styles.xml | 8 + app/src/main/res/values/strings.xml | 3 + app/src/main/res/values/styles.xml | 2 +- 23 files changed, 866 insertions(+), 43 deletions(-) create mode 100644 app/src/main/java/hikapro/com/backpack/StateMaintainer.java create mode 100644 app/src/main/java/hikapro/com/backpack/model/DetailModel.java create mode 100644 app/src/main/java/hikapro/com/backpack/presenter/ItemDetailPresenter.java create mode 100644 app/src/main/java/hikapro/com/backpack/presenter/adapters/ItemDetailAdapter.java create mode 100644 app/src/main/java/hikapro/com/backpack/view/fragments/ItemDetailFragment.java create mode 100644 app/src/main/java/hikapro/com/backpack/view/recycler/DetailViewHolder.java create mode 100644 app/src/main/res/layout/fragment_item_detail.xml create mode 100644 app/src/main/res/layout/item_detail.xml create mode 100644 app/src/main/res/values-v21/styles.xml diff --git a/app/build.gradle b/app/build.gradle index 88aa64f..0ae0a65 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -28,15 +28,15 @@ dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' + + compile 'com.android.support:support-v4:23.3.0' 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' compile 'com.squareup.okhttp3:okhttp:3.2.0' - compile 'com.squareup.okhttp:logging-interceptor:2.7.0' compile 'com.android.support:support-v4:23.3.0' compile 'com.android.support:appcompat-v7:23.3.0' compile 'com.android.support:design:23.3.0' - compile 'com.android.support:support-v4:23.3.0' compile 'com.android.support:cardview-v7:23.3.0' } diff --git a/app/src/main/java/hikapro/com/backpack/MainActivity.java b/app/src/main/java/hikapro/com/backpack/MainActivity.java index 522520e..2d27772 100644 --- a/app/src/main/java/hikapro/com/backpack/MainActivity.java +++ b/app/src/main/java/hikapro/com/backpack/MainActivity.java @@ -5,44 +5,182 @@ import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.os.Bundle; +import android.util.Log; +import hikapro.com.backpack.model.DetailModel; +import hikapro.com.backpack.model.ItemModel; +import hikapro.com.backpack.model.SetModel; +import hikapro.com.backpack.model.entities.Item; import hikapro.com.backpack.model.entities.Set; +import hikapro.com.backpack.presenter.ItemDetailPresenter; +import hikapro.com.backpack.presenter.ItemListPresenter; +import hikapro.com.backpack.presenter.SetListPresenter; import hikapro.com.backpack.view.View; +import hikapro.com.backpack.view.fragments.ItemDetailFragment; import hikapro.com.backpack.view.fragments.ItemListFragment; import hikapro.com.backpack.view.fragments.SetListFragment; public class MainActivity extends Activity implements View.ActivityCallback { - private static String TAG = "TAG"; - private FragmentManager fragmentManager; + private final StateMaintainer stateMaintainer = + new StateMaintainer(getFragmentManager(), MainActivity.class.getName()); + + // life cycle --> + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); fragmentManager = getFragmentManager(); - Fragment fragment = fragmentManager.findFragmentByTag(TAG); - if (fragment == null) - replaceFragment(SetListFragment.construct(), false); + stateMaintainer.init(); + + if (fragmentManager.getBackStackEntryCount() == 0) { + startSetListFragment(); + } else { + + Fragment fragment = fragmentManager.findFragmentByTag(SetListFragment.class.getName()); + if (fragment != null) { + SetListFragment view = (SetListFragment) fragment; + SetListPresenter presenter = stateMaintainer.get(SetListPresenter.class.getName()); + SetModel model = stateMaintainer.get(SetModel.class.getName()); + + view.setPresenter(presenter); + presenter.setView(view); + presenter.setModel(model); + model.setPresenter(presenter); + + } + + fragment = fragmentManager.findFragmentByTag(ItemListFragment.class.getName()); + if (fragment != null) { + ItemListFragment view = (ItemListFragment) fragment; + ItemListPresenter presenter = stateMaintainer.get(ItemListPresenter.class.getName()); + ItemModel model = stateMaintainer.get(ItemModel.class.getName()); + + view.setPresenter(presenter); + presenter.setView(view); + presenter.setModel(model); + model.setPresenter(presenter); + + } + + fragment = fragmentManager.findFragmentByTag(ItemDetailFragment.class.getName()); + if (fragment != null) { + ItemDetailFragment view = (ItemDetailFragment) fragment; + ItemDetailPresenter presenter = stateMaintainer.get(ItemDetailPresenter.class.getName()); + DetailModel model = stateMaintainer.get(DetailModel.class.getName()); + + view.setPresenter(presenter); + presenter.setView(view); + presenter.setModel(model); + model.setPresenter(presenter); + } + } + Log.i("On create", "Activity"); + } + + @Override + protected void onStart() { + super.onStart(); + Log.i("onStart", "Activity"); + } + + @Override + protected void onRestart() { + super.onRestart(); + Log.i("onRestart", "Activity"); + } + + @Override + protected void onResume() { + super.onResume(); + Log.i("onResume", "Activity"); + } + + @Override + protected void onPause() { + super.onPause(); + Log.i("onPause", "Activity"); + } + + @Override + protected void onStop() { + super.onStop(); + Log.i("onStop", "Activity"); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + Log.i("onDestroy", "Activity"); + } + // life cycle <-- + + + @Override + public void startSetListFragment() { + + SetListFragment view = SetListFragment.construct(); + SetListPresenter presenter = new SetListPresenter(); + SetModel model = new SetModel(); + + view.setPresenter(presenter); + presenter.setView(view); + presenter.setModel(model); + model.setPresenter(presenter); + + replaceFragment(view, true, SetListFragment.class.getName()); + + stateMaintainer.put(presenter); + stateMaintainer.put(model); + } @Override public void startItemListFragment(Set set) { - replaceFragment(ItemListFragment.newFromSet(set), true); + + ItemListFragment view = ItemListFragment.newFromSet(set); + ItemListPresenter presenter = new ItemListPresenter(); + ItemModel model = new ItemModel(); + + view.setPresenter(presenter); + presenter.setView(view); + presenter.setModel(model); + model.setPresenter(presenter); + + replaceFragment(view, true, ItemListFragment.class.getName()); + + stateMaintainer.put(presenter); + stateMaintainer.put(model); } @Override - public void startItemDetailFragment() { + public void startItemDetailFragment(Item item) { + ItemDetailFragment view = ItemDetailFragment.newFromItem(item); + ItemDetailPresenter presenter = new ItemDetailPresenter(); + DetailModel model = new DetailModel(); + + view.setPresenter(presenter); + presenter.setView(view); + presenter.setModel(model); + model.setPresenter(presenter); + + replaceFragment(view, true, ItemDetailFragment.class.getName()); + + stateMaintainer.put(presenter); + stateMaintainer.put(model); } - private void replaceFragment(Fragment fragment, boolean addBackStack) { + private void replaceFragment(Fragment fragment, boolean addBackStack, String tag) { FragmentTransaction transaction = fragmentManager.beginTransaction(); - transaction.replace(R.id.container, fragment, TAG); + transaction.replace(R.id.container, fragment, tag); if (addBackStack) transaction.addToBackStack(null); + transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); transaction.commit(); } } diff --git a/app/src/main/java/hikapro/com/backpack/StateMaintainer.java b/app/src/main/java/hikapro/com/backpack/StateMaintainer.java new file mode 100644 index 0000000..7e21532 --- /dev/null +++ b/app/src/main/java/hikapro/com/backpack/StateMaintainer.java @@ -0,0 +1,97 @@ +package hikapro.com.backpack; + +import android.app.Fragment; +import android.app.FragmentManager; +import android.os.Bundle; +import android.util.Log; + +import java.lang.ref.WeakReference; +import java.util.HashMap; + +/** + * Created by tariel on 24/04/16. + */ +public class StateMaintainer { + + protected final String TAG = getClass().getSimpleName(); + private final String stateMaintainerTag; + private final WeakReference fragmentManager; + private StateMngFragment stateMngFragment; + private boolean isRecreating; + + + public StateMaintainer(FragmentManager fragmentManager, String stateMaintainerTAG) { + this.fragmentManager = new WeakReference<>(fragmentManager); + this.stateMaintainerTag = stateMaintainerTAG; + } + + public boolean init() { + try { + stateMngFragment = (StateMngFragment) + fragmentManager.get().findFragmentByTag(stateMaintainerTag); + + if (stateMngFragment == null) { + stateMngFragment = new StateMngFragment(); + fragmentManager.get().beginTransaction() + .add(stateMngFragment, stateMaintainerTag).commit(); + isRecreating = false; + return true; + } else { + isRecreating = true; + return false; + } + } catch (NullPointerException e) { + return false; + } + } + + public boolean wasRecreated() { return isRecreating; } + + public void put(String key, Object obj) { + stateMngFragment.put(key, obj); + } + + public void put(Object obj) { + put(obj.getClass().getName(), obj); + } + + public T get(String key) { + return stateMngFragment.get(key); + + } + + public boolean hasKey(String key) { + return stateMngFragment.get(key) != null; + } + + + public static class StateMngFragment extends Fragment { + + private HashMap data = new HashMap<>(); + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // Grants that the fragment will be preserved + setRetainInstance(true); + } + + + public void put(String key, Object obj) { + data.put(key, obj); + Log.i(this.toString(), String.format("Put object %s Total count %d", key, data.size())); + } + + + public void put(Object object) { + put(object.getClass().getName(), object); + } + + + @SuppressWarnings("unchecked") + public T get(String key) { + Log.i(this.toString(), String.format("Get object %s Total count %d", key, data.size())); + return (T) data.get(key); + } + } +} diff --git a/app/src/main/java/hikapro/com/backpack/model/DetailModel.java b/app/src/main/java/hikapro/com/backpack/model/DetailModel.java new file mode 100644 index 0000000..0abe09f --- /dev/null +++ b/app/src/main/java/hikapro/com/backpack/model/DetailModel.java @@ -0,0 +1,69 @@ +package hikapro.com.backpack.model; + +import hikapro.com.backpack.model.entities.Item; +import hikapro.com.backpack.presenter.Presenter; + +/** + * Created by tariel on 23/04/16. + */ +public class DetailModel implements Model.Detail { + + private Presenter.ItemDetail presenter; + private Item item; + + public DetailModel() { + + } + + // detail --> + + @Override + public int getCount() { + return 1; + } + @Override + public Item findItem(int id) { + return item; + } + + // detail <-- + + // events --> + + @Override + public void notifyDataSetChanged() { + presenter.notifyDataSetChanged(); + } + @Override + public void onDestroy(boolean isConfigurationChanging) { + if ( !isConfigurationChanging ) { + presenter = null; + } + } + @Override + public void sendMessage(String message) { + presenter.showMessage(message); + } + + // events <-- + + // process --> + @Override + public void executeQuery() { + notifyDataSetChanged(); + } + // process <-- + + + @Override + public void setPresenter(Presenter.ItemDetail presenter) { + this.presenter = presenter; + this.item = presenter.getCurrentItem(); + + } + + @Override + public Presenter.ItemDetail getPresenter() { + return presenter; + } +} diff --git a/app/src/main/java/hikapro/com/backpack/model/ItemModel.java b/app/src/main/java/hikapro/com/backpack/model/ItemModel.java index 6f9fa19..2bff2bc 100644 --- a/app/src/main/java/hikapro/com/backpack/model/ItemModel.java +++ b/app/src/main/java/hikapro/com/backpack/model/ItemModel.java @@ -27,9 +27,8 @@ public class ItemModel implements Model.Item { private Hashtable> items; - public ItemModel(Presenter.ItemList presenter) { + public ItemModel() { this.api = RestClient.getApi(); - this.presenter = presenter; this.rawCategories = new ArrayList<>(); this.rawItems = new ArrayList<>(); this.sortedCategories = new ArrayList<>(); @@ -59,8 +58,15 @@ public class ItemModel implements Model.Item { return false; } @Override - public Item findItem(int id) { // TODO rename to find - return null; + public Item findItem(int id) { + Item item = null; + for (Item i : rawItems) { + if (i.getId() == id) { + item = i; + break; + } + } + return item; } @Override public Item getItemByPosition(int categoryId, int position) { @@ -91,7 +97,9 @@ public class ItemModel implements Model.Item { @Override public void onDestroy(boolean isConfigurationChanging) { - + if ( !isConfigurationChanging ) { + presenter = null; + } } @Override public void sendMessage(String message) { @@ -103,8 +111,13 @@ public class ItemModel implements Model.Item { @Override public void executeQuery() { - loadCategories(); - loadItems(); + if (rawCategories.isEmpty() || rawItems.isEmpty()) { + loadCategories(); + loadItems(); + } else { + notifyDataSetChanged(); + } + } private void loadCategories() { Call> call = api.getItemCategories(); @@ -142,6 +155,17 @@ public class ItemModel implements Model.Item { // other --> + + @Override + public void setPresenter(Presenter.ItemList presenter) { + this.presenter = presenter; + } + + @Override + public Presenter.ItemList getPresenter() { + return presenter; + } + private void initData() { List ids = presenter.getCurrentSet().getItems(); List sortedItems = new ArrayList<>(ids.size()); diff --git a/app/src/main/java/hikapro/com/backpack/model/Model.java b/app/src/main/java/hikapro/com/backpack/model/Model.java index 96ab146..0f89f31 100644 --- a/app/src/main/java/hikapro/com/backpack/model/Model.java +++ b/app/src/main/java/hikapro/com/backpack/model/Model.java @@ -5,6 +5,7 @@ import java.util.List; import hikapro.com.backpack.model.entities.Category; import hikapro.com.backpack.model.entities.Item; import hikapro.com.backpack.model.entities.Set; +import hikapro.com.backpack.presenter.Presenter; /** * Created by tariel on 19/04/16. @@ -22,6 +23,8 @@ public interface Model { hikapro.com.backpack.model.entities.Set findSet(int id); int getSetsCount(); void notifyDataSetChanged(); + void setPresenter(Presenter.SetList presenter); + Presenter.SetList getPresenter(); } interface Item extends Base { @@ -33,6 +36,16 @@ public interface Model { hikapro.com.backpack.model.entities.Category getCategoryByPosition(int position); int getCategoriesCount(); void notifyDataSetChanged(); + void setPresenter(Presenter.ItemList presenter); + Presenter.ItemList getPresenter(); + } + interface Detail extends Base { + int getCount(); + hikapro.com.backpack.model.entities.Item findItem(int id); + void notifyDataSetChanged(); + void setPresenter(Presenter.ItemDetail presenter); + Presenter.ItemDetail getPresenter(); + } } diff --git a/app/src/main/java/hikapro/com/backpack/model/SetModel.java b/app/src/main/java/hikapro/com/backpack/model/SetModel.java index abc5bae..e796815 100644 --- a/app/src/main/java/hikapro/com/backpack/model/SetModel.java +++ b/app/src/main/java/hikapro/com/backpack/model/SetModel.java @@ -18,10 +18,9 @@ public class SetModel implements Model.Set { private Api api; private Presenter.SetList presenter; - public SetModel(Presenter.SetList presenter) { + public SetModel() { this.api = RestClient.getApi(); this.iList = new ArrayList<>(); - this.presenter = presenter; } // sets --> @@ -53,6 +52,9 @@ public class SetModel implements Model.Set { @Override public void onDestroy(boolean isConfigurationChanging) { + if ( !isConfigurationChanging ) { + presenter = null; + } } @Override @@ -71,6 +73,13 @@ public class SetModel implements Model.Set { @Override public void executeQuery() { + if (iList.isEmpty()) + loadSets(); + else + notifyDataSetChanged(); + } + + private void loadSets() { Call> call = api.getSets(); call.enqueue(new Callback>() { @Override @@ -91,6 +100,17 @@ public class SetModel implements Model.Set { // process <-- // other --> + + @Override + public void setPresenter(Presenter.SetList presenter) { + this.presenter = presenter; + } + + @Override + public Presenter.SetList getPresenter() { + return presenter; + } + // other <-- diff --git a/app/src/main/java/hikapro/com/backpack/model/entities/Item.java b/app/src/main/java/hikapro/com/backpack/model/entities/Item.java index 078727c..10adc19 100644 --- a/app/src/main/java/hikapro/com/backpack/model/entities/Item.java +++ b/app/src/main/java/hikapro/com/backpack/model/entities/Item.java @@ -3,13 +3,14 @@ package hikapro.com.backpack.model.entities; import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; +import java.io.Serializable; import java.util.ArrayList; import java.util.List; /** * Created by tariel on 02/04/16. */ -public class Item implements Comparable { +public class Item implements Comparable, Serializable { @SerializedName("id") @Expose diff --git a/app/src/main/java/hikapro/com/backpack/presenter/ItemDetailPresenter.java b/app/src/main/java/hikapro/com/backpack/presenter/ItemDetailPresenter.java new file mode 100644 index 0000000..daffca3 --- /dev/null +++ b/app/src/main/java/hikapro/com/backpack/presenter/ItemDetailPresenter.java @@ -0,0 +1,147 @@ +package hikapro.com.backpack.presenter; + +import android.content.Context; +import android.os.Bundle; +import android.support.v7.widget.DefaultItemAnimator; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.ViewGroup; +import android.widget.Toast; + +import java.lang.ref.WeakReference; + +import hikapro.com.backpack.R; +import hikapro.com.backpack.model.Model; +import hikapro.com.backpack.model.entities.Item; +import hikapro.com.backpack.presenter.adapters.ItemDetailAdapter; +import hikapro.com.backpack.view.View; +import hikapro.com.backpack.view.recycler.DetailViewHolder; + +/** + * Created by tariel on 23/04/16. + */ +public class ItemDetailPresenter implements Presenter.ItemDetail { + + private WeakReference view; + private Model.Detail model; + private ItemDetailAdapter adapter; + private Item item; + + public ItemDetailPresenter() { + this.adapter = new ItemDetailAdapter(this); + } + + // life cycle --> + + @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 view = inflater.inflate(R.layout.fragment_item_detail, container, false); + LinearLayoutManager llm = new LinearLayoutManager(getActivityContext()); + RecyclerView detailRecycler = (RecyclerView) view.findViewById(R.id.item_detail_recycler); + detailRecycler.setLayoutManager(llm); + detailRecycler.setAdapter(adapter); + detailRecycler.setItemAnimator(new DefaultItemAnimator()); + model.executeQuery(); + return view; + } + @Override + public void onSaveInstanceState(Bundle outState) { + + } + // life cycle <-- + + // recycler --> + + @Override + public int getItemsCount() { + return model.getCount(); + } + @Override + public void bindViewHolder(DetailViewHolder holder, int position) { + hikapro.com.backpack.model.entities.Item item = model.findItem(position); + holder.title.setText(item.getName()); + holder.description.setText(item.getDescription()); + holder.title.setOnClickListener(new android.view.View.OnClickListener() { + @Override + public void onClick(android.view.View view) { + showMessage("On detail click"); + } + }); + } + @Override + public DetailViewHolder createViewHolder(ViewGroup parent, int viewType) { + DetailViewHolder viewHolder; + android.view.View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_detail, + parent, false); + viewHolder = new DetailViewHolder(v); + return viewHolder; + } + + // recycler <-- + + // process --> + + @Override + public void notifyDataSetChanged() { + adapter.notifyDataSetChanged(); + } + + // process <-- + + // other impl --> + + @Override + public void setView(View.ItemDetail view) { + this.view = new WeakReference<>(view); + this.item = getView().getItem(); + } + @Override + public void setModel(Model.Detail model) { + this.model = model; + } + + @Override + public Item getCurrentItem() { + return item; + } + + @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 showMessage(String message) { + Toast.makeText(getView().getAppContext(), message, Toast.LENGTH_SHORT).show(); + } + + // other impl <-- + + private View.ItemDetail getView() throws NullPointerException { + if ( view != null ) + return view.get(); + else + throw new NullPointerException("View is unavailable"); + } +} diff --git a/app/src/main/java/hikapro/com/backpack/presenter/ItemListPresenter.java b/app/src/main/java/hikapro/com/backpack/presenter/ItemListPresenter.java index 8e46596..97e6193 100644 --- a/app/src/main/java/hikapro/com/backpack/presenter/ItemListPresenter.java +++ b/app/src/main/java/hikapro/com/backpack/presenter/ItemListPresenter.java @@ -16,6 +16,7 @@ import java.util.List; import hikapro.com.backpack.R; import hikapro.com.backpack.model.ItemModel; import hikapro.com.backpack.model.Model; +import hikapro.com.backpack.model.entities.Item; import hikapro.com.backpack.model.entities.Set; import hikapro.com.backpack.presenter.adapters.CategoryListAdapter; import hikapro.com.backpack.presenter.adapters.ItemListAdapter; @@ -35,11 +36,8 @@ public class ItemListPresenter implements Presenter.ItemList { private Set set; private CategoryListAdapter categoryListAdapter; - public ItemListPresenter(View.ItemList view, Set set) { - this.view = new WeakReference<>(view); - this.set = set; + public ItemListPresenter() { this.categoryListAdapter = new CategoryListAdapter(this); - setModel(new ItemModel(this)); } // life cycle --> @@ -113,7 +111,7 @@ public class ItemListPresenter implements Presenter.ItemList { holder.title.setOnClickListener(new android.view.View.OnClickListener() { @Override public void onClick(android.view.View view) { - showMessage("Position " + position + " Id " + holder.id); + clickItem(holder.id); } }); } @@ -121,6 +119,11 @@ public class ItemListPresenter implements Presenter.ItemList { public int getItemsCount(int categoryId) { return model.getItemsCount(categoryId);//TODO category Id } + @Override + public int getCategoriesCount() { + return model.getCategoriesCount(); + } + // recycler <-- @@ -132,6 +135,14 @@ public class ItemListPresenter implements Presenter.ItemList { categoryListAdapter.notifyItemAdapters(); } + @Override + public void clickItem(int itemId) { + Item item = model.findItem(itemId); + if (item != null) + getView().showItemDetail(item); + else + showMessage(String.format("Item with Id %d is not found.", itemId)); + } // process <-- // other impl --> @@ -139,6 +150,11 @@ public class ItemListPresenter implements Presenter.ItemList { @Override public void setView(View.ItemList view) { this.view = new WeakReference<>(view); + this.set = getView().getSet(); + } + @Override + public void setModel(Model.Item model) { + this.model = model; } @Override public Context getAppContext() { @@ -157,10 +173,6 @@ public class ItemListPresenter implements Presenter.ItemList { } } @Override - public void setModel(Model.Item model) { - this.model = model; - } - @Override public void showMessage(String message) { Toast.makeText(getView().getAppContext(), message, Toast.LENGTH_SHORT).show(); } @@ -174,10 +186,6 @@ public class ItemListPresenter implements Presenter.ItemList { throw new NullPointerException("View is unavailable"); } - @Override - public int getCategoriesCount() { - return model.getCategoriesCount(); - } @Override public Set getCurrentSet() { diff --git a/app/src/main/java/hikapro/com/backpack/presenter/Presenter.java b/app/src/main/java/hikapro/com/backpack/presenter/Presenter.java index c0175ea..f7d927a 100644 --- a/app/src/main/java/hikapro/com/backpack/presenter/Presenter.java +++ b/app/src/main/java/hikapro/com/backpack/presenter/Presenter.java @@ -6,8 +6,10 @@ import android.view.LayoutInflater; import android.view.ViewGroup; import hikapro.com.backpack.model.Model; +import hikapro.com.backpack.model.entities.Item; import hikapro.com.backpack.model.entities.Set; import hikapro.com.backpack.view.recycler.CategoryViewHolder; +import hikapro.com.backpack.view.recycler.DetailViewHolder; import hikapro.com.backpack.view.recycler.ItemViewHolder; import hikapro.com.backpack.view.recycler.SetViewHolder; @@ -49,6 +51,23 @@ public interface Presenter { Set getCurrentSet(); void showMessage(String message); void onSaveInstanceState(Bundle outState); + void clickItem(int itemId); + } + + interface ItemDetail extends Base { + void setView(hikapro.com.backpack.view.View.ItemDetail view); + void setModel(Model.Detail model); + void notifyDataSetChanged(); + void showMessage(String message); + int getItemsCount(); + void bindViewHolder(DetailViewHolder holder, int position); + DetailViewHolder createViewHolder(ViewGroup parent, int viewType); + void onDestroy(boolean isChangingConfiguration); + android.view.View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState); + void onSaveInstanceState(Bundle outState); + Item getCurrentItem(); + + } diff --git a/app/src/main/java/hikapro/com/backpack/presenter/SetListPresenter.java b/app/src/main/java/hikapro/com/backpack/presenter/SetListPresenter.java index 4038ddf..11cd528 100644 --- a/app/src/main/java/hikapro/com/backpack/presenter/SetListPresenter.java +++ b/app/src/main/java/hikapro/com/backpack/presenter/SetListPresenter.java @@ -30,7 +30,6 @@ public class SetListPresenter implements Presenter.SetList { public SetListPresenter() { this.adapter = new SetListAdapter(this); - setModel(new SetModel(this)); } // life cycle --> diff --git a/app/src/main/java/hikapro/com/backpack/presenter/adapters/ItemDetailAdapter.java b/app/src/main/java/hikapro/com/backpack/presenter/adapters/ItemDetailAdapter.java new file mode 100644 index 0000000..bbf1a00 --- /dev/null +++ b/app/src/main/java/hikapro/com/backpack/presenter/adapters/ItemDetailAdapter.java @@ -0,0 +1,40 @@ +package hikapro.com.backpack.presenter.adapters; + +import android.support.v7.widget.RecyclerView; +import android.view.ViewGroup; + +import hikapro.com.backpack.presenter.Presenter; +import hikapro.com.backpack.view.recycler.DetailViewHolder; + +/** + * Created by tariel on 23/04/16. + */ +public class ItemDetailAdapter extends RecyclerView.Adapter { + + private Presenter.ItemDetail presenter; + private int itemId; + + public ItemDetailAdapter(Presenter.ItemDetail presenter) { + this.presenter = presenter; + } + + @Override + public int getItemCount() { + return presenter.getItemsCount(); + } + + @Override + public void onBindViewHolder(DetailViewHolder holder, int position) { + presenter.bindViewHolder(holder, position); + + } + + @Override + public DetailViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return presenter.createViewHolder(parent, viewType); + } + + public void setItemId(int id) { + this.itemId = id; + } +} diff --git a/app/src/main/java/hikapro/com/backpack/view/View.java b/app/src/main/java/hikapro/com/backpack/view/View.java index 2df7e47..547ce9f 100644 --- a/app/src/main/java/hikapro/com/backpack/view/View.java +++ b/app/src/main/java/hikapro/com/backpack/view/View.java @@ -24,13 +24,16 @@ public interface View { interface ItemList extends Base { void showItemDetail(Item item); void setPresenter(Presenter.ItemList presenter); + Set getSet(); } interface ItemDetail extends Base { - + void setPresenter(Presenter.ItemDetail presenter); + Item getItem(); } interface ActivityCallback { + void startSetListFragment(); void startItemListFragment(Set set); - void startItemDetailFragment(); + void startItemDetailFragment(Item item); } } diff --git a/app/src/main/java/hikapro/com/backpack/view/fragments/ItemDetailFragment.java b/app/src/main/java/hikapro/com/backpack/view/fragments/ItemDetailFragment.java new file mode 100644 index 0000000..9673463 --- /dev/null +++ b/app/src/main/java/hikapro/com/backpack/view/fragments/ItemDetailFragment.java @@ -0,0 +1,145 @@ +package hikapro.com.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 hikapro.com.backpack.model.entities.Item; +import hikapro.com.backpack.presenter.Presenter; + +/** + * A simple {@link Fragment} subclass. + */ +public class ItemDetailFragment extends Fragment implements hikapro.com.backpack.view.View.ItemDetail { + + private static final String BUNDLE_ITEM_KEY = "BUNDLE_ITEM_KEY"; + + private Presenter.ItemDetail presenter; + private hikapro.com.backpack.view.View.ActivityCallback activityCallback; + + + public ItemDetailFragment() { + // Required empty public constructor + } + + protected static ItemDetailFragment construct() { + return new ItemDetailFragment(); + } + + public static ItemDetailFragment newFromItem(Item item) { + ItemDetailFragment ret = ItemDetailFragment.construct(); + Bundle args = new Bundle(); + args.putSerializable(BUNDLE_ITEM_KEY, item); + ret.setArguments(args); + return ret; + } + + // life cycle --> + @Override + public void onAttach(Context context) { + super.onAttach(context); + try { + activityCallback = (hikapro.com.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 = (hikapro.com.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); + Log.i(this.toString(), "onCreate"); + } + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + View view = presenter.onCreateView(inflater, container, savedInstanceState); + presenter.setView(this); + 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 void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + Log.i(this.toString(), "onSaveInstanceState"); + } + + // life cycle <-- + + @Override + public void setPresenter(Presenter.ItemDetail presenter) { + this.presenter = presenter; + } + + @Override + public Context getAppContext() { + return this.getActivity().getApplicationContext(); + } + + @Override + public Context getActivityContext() { + return this.getActivity(); + } + + @Override + public Item getItem() { + Bundle args = getArguments(); + Item item = (Item) args.getSerializable(BUNDLE_ITEM_KEY); + return item; + } +} diff --git a/app/src/main/java/hikapro/com/backpack/view/fragments/ItemListFragment.java b/app/src/main/java/hikapro/com/backpack/view/fragments/ItemListFragment.java index c6644ac..36bef71 100644 --- a/app/src/main/java/hikapro/com/backpack/view/fragments/ItemListFragment.java +++ b/app/src/main/java/hikapro/com/backpack/view/fragments/ItemListFragment.java @@ -22,8 +22,7 @@ public class ItemListFragment extends Fragment implements hikapro.com.backpack.v private static final String BUNDLE_SET_KEY = "BUNDLE_SET_KEY"; private hikapro.com.backpack.view.View.ActivityCallback activityCallback; - private Presenter.ItemList presenter; - + private Presenter.ItemList presenter; public ItemListFragment() { // Required empty public constructor @@ -38,7 +37,6 @@ public class ItemListFragment extends Fragment implements hikapro.com.backpack.v Bundle args = new Bundle(); args.putSerializable(BUNDLE_SET_KEY, set); ret.setArguments(args); - ret.setPresenter(new ItemListPresenter(ret, set)); return ret; } @@ -74,6 +72,7 @@ public class ItemListFragment extends Fragment implements hikapro.com.backpack.v Bundle savedInstanceState) { // Inflate the layout for this fragment View view = presenter.onCreateView(inflater, container, savedInstanceState); + presenter.setView(this); Log.i(this.toString(), "onCreateView"); return view; } @@ -106,6 +105,7 @@ public class ItemListFragment extends Fragment implements hikapro.com.backpack.v @Override public void onDestroy() { super.onDestroy(); + presenter.onDestroy(false); // TODO isChangingConfigurations Log.i(this.toString(), "onDestroy"); } @Override @@ -123,7 +123,7 @@ public class ItemListFragment extends Fragment implements hikapro.com.backpack.v @Override public void showItemDetail(Item item) { - //TODO not implemented + activityCallback.startItemDetailFragment(item); } @Override @@ -141,4 +141,9 @@ public class ItemListFragment extends Fragment implements hikapro.com.backpack.v return this.getActivity(); } + public Set getSet() { + return (Set) getArguments().getSerializable(BUNDLE_SET_KEY); + } + + } diff --git a/app/src/main/java/hikapro/com/backpack/view/fragments/SetListFragment.java b/app/src/main/java/hikapro/com/backpack/view/fragments/SetListFragment.java index 3e0ee28..79c88b6 100644 --- a/app/src/main/java/hikapro/com/backpack/view/fragments/SetListFragment.java +++ b/app/src/main/java/hikapro/com/backpack/view/fragments/SetListFragment.java @@ -55,7 +55,6 @@ public class SetListFragment extends Fragment implements hikapro.com.backpack.vi @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setPresenter(new SetListPresenter()); Log.i(this.toString(), "onCreate"); } @Override @@ -101,6 +100,7 @@ public class SetListFragment extends Fragment implements hikapro.com.backpack.vi @Override public void onDestroy() { super.onDestroy(); + presenter.onDestroy(false); // TODO isChangingConfigurations Log.i(this.toString(), "onDestroy"); } @Override diff --git a/app/src/main/java/hikapro/com/backpack/view/recycler/DetailViewHolder.java b/app/src/main/java/hikapro/com/backpack/view/recycler/DetailViewHolder.java new file mode 100644 index 0000000..ed2e380 --- /dev/null +++ b/app/src/main/java/hikapro/com/backpack/view/recycler/DetailViewHolder.java @@ -0,0 +1,29 @@ +package hikapro.com.backpack.view.recycler; + +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import hikapro.com.backpack.R; + +/** + * Created by tariel on 23/04/16. + */ +public class DetailViewHolder extends RecyclerView.ViewHolder { + + public TextView title; + public TextView description; + public ImageView photo; + + public DetailViewHolder(View v) { + super(v); + setupViews(v); + } + + private void setupViews(View view) { + title = (TextView) view.findViewById(R.id.item_title); + description = (TextView) view.findViewById(R.id.item_description); + photo = (ImageView) view.findViewById(R.id.item_photo); + } +} diff --git a/app/src/main/res/layout/fragment_item_detail.xml b/app/src/main/res/layout/fragment_item_detail.xml new file mode 100644 index 0000000..0daaa99 --- /dev/null +++ b/app/src/main/res/layout/fragment_item_detail.xml @@ -0,0 +1,17 @@ + + + + + + + + diff --git a/app/src/main/res/layout/item_detail.xml b/app/src/main/res/layout/item_detail.xml new file mode 100644 index 0000000..abf0f22 --- /dev/null +++ b/app/src/main/res/layout/item_detail.xml @@ -0,0 +1,38 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml new file mode 100644 index 0000000..76d6fac --- /dev/null +++ b/app/src/main/res/values-v21/styles.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b77dfd1..9f83240 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,6 @@ BackPack + + + Hello blank fragment diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 5885930..f927816 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,7 +1,7 @@ -