Merge branch 'tag_items_list_interface_1' into dev
This commit is contained in:
commit
899be44eda
|
@ -1 +1 @@
|
||||||
BackPack
|
packwithme
|
|
@ -0,0 +1,7 @@
|
||||||
|
<component name="ProjectDictionaryState">
|
||||||
|
<dictionary name="tariel">
|
||||||
|
<words>
|
||||||
|
<w>tariel</w>
|
||||||
|
</words>
|
||||||
|
</dictionary>
|
||||||
|
</component>
|
|
@ -5,6 +5,7 @@
|
||||||
<GradleProjectSettings>
|
<GradleProjectSettings>
|
||||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
|
<option name="gradleJvm" value="1.8" />
|
||||||
<option name="modules">
|
<option name="modules">
|
||||||
<set>
|
<set>
|
||||||
<option value="$PROJECT_DIR$" />
|
<option value="$PROJECT_DIR$" />
|
||||||
|
|
|
@ -37,37 +37,10 @@
|
||||||
<ConfirmationsSetting value="0" id="Add" />
|
<ConfirmationsSetting value="0" id="Add" />
|
||||||
<ConfirmationsSetting value="0" id="Remove" />
|
<ConfirmationsSetting value="0" id="Remove" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.7" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectType">
|
<component name="ProjectType">
|
||||||
<option name="id" value="Android" />
|
<option name="id" value="Android" />
|
||||||
</component>
|
</component>
|
||||||
<component name="masterDetails">
|
|
||||||
<states>
|
|
||||||
<state key="ProjectJDKs.UI">
|
|
||||||
<settings>
|
|
||||||
<last-edited>1.8</last-edited>
|
|
||||||
<splitter-proportions>
|
|
||||||
<option name="proportions">
|
|
||||||
<list>
|
|
||||||
<option value="0.2" />
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
</splitter-proportions>
|
|
||||||
</settings>
|
|
||||||
</state>
|
|
||||||
<state key="ScopeChooserConfigurable.UI">
|
|
||||||
<settings>
|
|
||||||
<splitter-proportions>
|
|
||||||
<option name="proportions">
|
|
||||||
<list>
|
|
||||||
<option value="0.2" />
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
</splitter-proportions>
|
|
||||||
</settings>
|
|
||||||
</state>
|
|
||||||
</states>
|
|
||||||
</component>
|
|
||||||
</project>
|
</project>
|
|
@ -28,13 +28,12 @@ dependencies {
|
||||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
testCompile 'junit:junit:4.12'
|
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.google.code.gson:gson:2.6.2'
|
||||||
compile 'com.squareup.retrofit2:retrofit:2.0.1'
|
compile 'com.squareup.retrofit2:retrofit:2.0.1'
|
||||||
compile 'com.squareup.retrofit2:converter-gson:2.0.1'
|
compile 'com.squareup.retrofit2:converter-gson:2.0.1'
|
||||||
compile 'com.squareup.okhttp3:okhttp:3.2.0'
|
compile 'com.squareup.okhttp3:okhttp:3.2.0'
|
||||||
compile 'com.squareup.okhttp:logging-interceptor:2.7.0'
|
compile 'com.squareup.okhttp:logging-interceptor:2.7.0'
|
||||||
|
|
||||||
compile 'com.android.support:support-v4:23.3.0'
|
compile 'com.android.support:support-v4:23.3.0'
|
||||||
compile 'com.android.support:appcompat-v7:23.3.0'
|
compile 'com.android.support:appcompat-v7:23.3.0'
|
||||||
compile 'com.android.support:design:23.3.0'
|
compile 'com.android.support:design:23.3.0'
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
|
android:name=".App"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
package hikapro.com.backpack;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tariel on 27/04/16.
|
||||||
|
*/
|
||||||
|
public class App extends Application {
|
||||||
|
|
||||||
|
private static Context context;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
super.onCreate();
|
||||||
|
App.context = getApplicationContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Context getAppContext() {
|
||||||
|
return App.context;
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,7 @@ public class MainActivity extends Activity implements View.ActivityCallback {
|
||||||
|
|
||||||
private FragmentManager fragmentManager;
|
private FragmentManager fragmentManager;
|
||||||
|
|
||||||
|
|
||||||
private final StateMaintainer stateMaintainer =
|
private final StateMaintainer stateMaintainer =
|
||||||
new StateMaintainer(getFragmentManager(), MainActivity.class.getName());
|
new StateMaintainer(getFragmentManager(), MainActivity.class.getName());
|
||||||
|
|
||||||
|
@ -37,10 +38,10 @@ public class MainActivity extends Activity implements View.ActivityCallback {
|
||||||
|
|
||||||
stateMaintainer.init();
|
stateMaintainer.init();
|
||||||
|
|
||||||
if (fragmentManager.getBackStackEntryCount() == 0) {
|
|
||||||
|
if (fragmentManager.getBackStackEntryCount() == 0 && savedInstanceState == null) {
|
||||||
startSetListFragment();
|
startSetListFragment();
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
Fragment fragment = fragmentManager.findFragmentByTag(SetListFragment.class.getName());
|
Fragment fragment = fragmentManager.findFragmentByTag(SetListFragment.class.getName());
|
||||||
if (fragment != null) {
|
if (fragment != null) {
|
||||||
SetListFragment view = (SetListFragment) fragment;
|
SetListFragment view = (SetListFragment) fragment;
|
||||||
|
@ -51,7 +52,6 @@ public class MainActivity extends Activity implements View.ActivityCallback {
|
||||||
presenter.setView(view);
|
presenter.setView(view);
|
||||||
presenter.setModel(model);
|
presenter.setModel(model);
|
||||||
model.setPresenter(presenter);
|
model.setPresenter(presenter);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fragment = fragmentManager.findFragmentByTag(ItemListFragment.class.getName());
|
fragment = fragmentManager.findFragmentByTag(ItemListFragment.class.getName());
|
||||||
|
@ -128,12 +128,11 @@ public class MainActivity extends Activity implements View.ActivityCallback {
|
||||||
SetModel model = new SetModel();
|
SetModel model = new SetModel();
|
||||||
|
|
||||||
view.setPresenter(presenter);
|
view.setPresenter(presenter);
|
||||||
presenter.setView(view);
|
//presenter.setView(view);
|
||||||
presenter.setModel(model);
|
presenter.setModel(model);
|
||||||
model.setPresenter(presenter);
|
model.setPresenter(presenter);
|
||||||
|
|
||||||
replaceFragment(view, true, SetListFragment.class.getName());
|
replaceFragment(view, false, SetListFragment.class.getName());
|
||||||
|
|
||||||
stateMaintainer.put(presenter);
|
stateMaintainer.put(presenter);
|
||||||
stateMaintainer.put(model);
|
stateMaintainer.put(model);
|
||||||
|
|
||||||
|
|
|
@ -6,20 +6,31 @@ import hikapro.com.backpack.model.entities.Category;
|
||||||
import hikapro.com.backpack.model.entities.Item;
|
import hikapro.com.backpack.model.entities.Item;
|
||||||
import hikapro.com.backpack.model.entities.Set;
|
import hikapro.com.backpack.model.entities.Set;
|
||||||
|
|
||||||
|
import hikapro.com.backpack.model.entities.Timestamp;
|
||||||
|
import hikapro.com.backpack.model.entities.Updates;
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.http.GET;
|
import retrofit2.http.GET;
|
||||||
|
import retrofit2.http.Query;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by tariel on 19/04/16.
|
* Created by tariel on 19/04/16.
|
||||||
*/
|
*/
|
||||||
public interface Api {
|
public interface Api {
|
||||||
|
|
||||||
@GET("/api/v1/backpack/items")
|
@GET("api/v1/backpack/items")
|
||||||
Call<List<Item>> getItems();
|
Call<List<Item>> getItems();
|
||||||
|
|
||||||
@GET("/api/v1/backpack/item_categories")
|
@GET("api/v1/backpack/item_categories")
|
||||||
Call<List<Category>> getItemCategories();
|
Call<List<Category>> getItemCategories();
|
||||||
|
|
||||||
@GET("/api/v1/backpack/sets")
|
@GET("api/v1/backpack/sets")
|
||||||
Call<List<Set>> getSets();
|
Call<List<Set>> getSets();
|
||||||
|
|
||||||
|
@GET("api/v1/backpack/updates/timestamp")
|
||||||
|
Call<Timestamp> getTimestamp();
|
||||||
|
|
||||||
|
@GET("api/v1/backpack/updates/all")
|
||||||
|
Call<Updates> getUpdates(@Query("timestamp") long timestamp);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package hikapro.com.backpack.model;
|
package hikapro.com.backpack.model;
|
||||||
|
|
||||||
|
import android.os.Message;
|
||||||
|
|
||||||
import hikapro.com.backpack.model.entities.Item;
|
import hikapro.com.backpack.model.entities.Item;
|
||||||
import hikapro.com.backpack.presenter.Presenter;
|
import hikapro.com.backpack.presenter.Presenter;
|
||||||
|
|
||||||
|
@ -40,8 +42,8 @@ public class DetailModel implements Model.Detail {
|
||||||
presenter = null;
|
presenter = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Override
|
|
||||||
public void sendMessage(String message) {
|
private void sendMessage(String message) {
|
||||||
presenter.showMessage(message);
|
presenter.showMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,4 +68,9 @@ public class DetailModel implements Model.Detail {
|
||||||
public Presenter.ItemDetail getPresenter() {
|
public Presenter.ItemDetail getPresenter() {
|
||||||
return presenter;
|
return presenter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEvent(Message event) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,48 +1,63 @@
|
||||||
package hikapro.com.backpack.model;
|
package hikapro.com.backpack.model;
|
||||||
|
|
||||||
|
|
||||||
|
import android.os.Message;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import hikapro.com.backpack.model.dao.Command;
|
||||||
|
import hikapro.com.backpack.model.dao.DAO;
|
||||||
|
import hikapro.com.backpack.model.dao.Event;
|
||||||
import hikapro.com.backpack.model.entities.Category;
|
import hikapro.com.backpack.model.entities.Category;
|
||||||
import hikapro.com.backpack.model.entities.Item;
|
import hikapro.com.backpack.model.entities.Item;
|
||||||
import hikapro.com.backpack.presenter.Presenter;
|
import hikapro.com.backpack.presenter.Presenter;
|
||||||
import retrofit2.Call;
|
|
||||||
import retrofit2.Callback;
|
|
||||||
import retrofit2.Response;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by tariel on 22/04/16.
|
* Created by tariel on 22/04/16.
|
||||||
*/
|
*/
|
||||||
public class ItemModel implements Model.Item {
|
public class ItemModel implements Model.Item {
|
||||||
|
|
||||||
private Api api;
|
|
||||||
private Presenter.ItemList presenter;
|
private Presenter.ItemList presenter;
|
||||||
private List<Category> rawCategories;
|
private List<Category> rawCategories;
|
||||||
private List<Category> sortedCategories;
|
private List<Category> sortedCategories;
|
||||||
private List<Item> rawItems;
|
private List<Item> rawItems;
|
||||||
|
|
||||||
|
private DAO dao;
|
||||||
|
private int currentSet;
|
||||||
|
private Hashtable<Integer, Category> categoriesCache;
|
||||||
|
private List<Item> itemsCache;
|
||||||
|
private List<Item> itemsDiscardCache;
|
||||||
|
|
||||||
private Hashtable<Category, List<Item>> items;
|
private Hashtable<Category, List<Item>> items;
|
||||||
|
private Hashtable<Integer, List<Item>> cache;
|
||||||
|
|
||||||
public ItemModel() {
|
public ItemModel() {
|
||||||
this.api = RestClient.getApi();
|
|
||||||
this.rawCategories = new ArrayList<>();
|
this.rawCategories = new ArrayList<>();
|
||||||
this.rawItems = new ArrayList<>();
|
this.rawItems = new ArrayList<>();
|
||||||
this.sortedCategories = new ArrayList<>();
|
this.sortedCategories = new ArrayList<>();
|
||||||
|
|
||||||
|
this.categoriesCache = new Hashtable<>(20, 0.9f);
|
||||||
|
|
||||||
|
this.itemsCache = new ArrayList<>();
|
||||||
|
this.itemsDiscardCache = new ArrayList<>();
|
||||||
|
this.cache = new Hashtable<>(12, 0.9f);
|
||||||
|
this.dao = DAO.getInstance();
|
||||||
|
dao.registerObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// categories -->
|
// categories -->
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Category getCategoryByPosition(int position) {
|
public Category getCategoryByPosition(int position) {
|
||||||
return sortedCategories.get(position);
|
Category ret = null;
|
||||||
}
|
if (cache.containsKey(currentSet))
|
||||||
@Override
|
ret = categoriesCache.get(cache.get(currentSet).get(position).getCategory());
|
||||||
public int getCategoriesCount() {
|
return ret;
|
||||||
return sortedCategories.size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// categories <--
|
// categories <--
|
||||||
|
@ -51,41 +66,108 @@ public class ItemModel implements Model.Item {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int insertItem(Item item) {
|
public int insertItem(Item item) {
|
||||||
|
List<Item> iList = cache.get(currentSet);
|
||||||
|
iList.add(item);
|
||||||
|
Collections.sort(iList);
|
||||||
|
cache.put(currentSet, iList);
|
||||||
|
// TODO write to database
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public boolean deleteItem(int id) {
|
public boolean deleteItem(Item item) {
|
||||||
|
if (isPendingRemoval(item))
|
||||||
|
itemsDiscardCache.remove(item);
|
||||||
|
cache.get(currentSet).remove(item);
|
||||||
|
//TODO write to ds
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Item findItem(int id) {
|
public Item findItem(int id) {
|
||||||
|
List<Item> items = cache.get(currentSet);
|
||||||
Item item = null;
|
Item item = null;
|
||||||
for (Item i : rawItems) {
|
if (items != null)
|
||||||
if (i.getId() == id) {
|
{
|
||||||
item = i;
|
for (Item i : items) {
|
||||||
break;
|
if (i.getId() == id) {
|
||||||
|
item = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public Item getItemByPosition(int categoryId, int position) {
|
public Item getItemByPosition(int position) {
|
||||||
Item ret = null;
|
Item ret = null;
|
||||||
Category category = findSortedCategory(categoryId);
|
if (cache.containsKey(currentSet))
|
||||||
if (category != null) {
|
ret = cache.get(currentSet).get(position);
|
||||||
ret = items.get(category).get(position);
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemsCount(int categoryId) {
|
public void filter(String query) {
|
||||||
int ret = 0;
|
|
||||||
Category category = findSortedCategory(categoryId);
|
if (query.isEmpty()) {
|
||||||
if (category != null) {
|
Message command = Message.obtain();
|
||||||
ret = items.get(category).size();
|
command.what = Command.SET_GET_ITEMS;
|
||||||
|
command.arg1 = presenter.getCurrentSet().getId();
|
||||||
|
dao.executeCommand(command);
|
||||||
|
} else {
|
||||||
|
query = query.toLowerCase();
|
||||||
|
String name;
|
||||||
|
List<Item> newList = new ArrayList<>(20);
|
||||||
|
List<Item> oldList = cache.get(currentSet);
|
||||||
|
for (Item item : oldList) {
|
||||||
|
name = item.getName().toLowerCase();
|
||||||
|
if (name.contains(query)) {
|
||||||
|
newList.add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cache.put(currentSet, newList);
|
||||||
}
|
}
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeaderId(int position) {
|
||||||
|
return cache.containsKey(currentSet) ? cache.get(currentSet).get(position).getCategory() : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemId(int position) {
|
||||||
|
return cache.containsKey(currentSet) ? cache.get(currentSet).get(position).getId() : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
if (cache.containsKey(currentSet))
|
||||||
|
cache.get(currentSet).clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPendingRemoval(Item item) {
|
||||||
|
return itemsDiscardCache.contains(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void pendingRemoveCancel(Item item) {
|
||||||
|
if (itemsDiscardCache.contains(item))
|
||||||
|
itemsDiscardCache.remove(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void pendingRemove(Item item) {
|
||||||
|
itemsDiscardCache.add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemsCount() {
|
||||||
|
boolean is = cache.containsKey(currentSet);
|
||||||
|
return is ? cache.get(currentSet).size() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
// items <--
|
// items <--
|
||||||
|
|
||||||
// events -->
|
// events -->
|
||||||
|
@ -101,56 +183,73 @@ public class ItemModel implements Model.Item {
|
||||||
presenter = null;
|
presenter = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Override
|
|
||||||
public void sendMessage(String message) {
|
private void sendMessage(String message) {
|
||||||
presenter.showMessage(message);
|
presenter.showMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// events <--
|
// events <--
|
||||||
|
|
||||||
// process -->
|
// process -->
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void executeQuery() {
|
public void executeQuery() {
|
||||||
if (rawCategories.isEmpty() || rawItems.isEmpty()) {
|
Message command;
|
||||||
loadCategories();
|
|
||||||
loadItems();
|
if (cache.contains(currentSet)) {
|
||||||
} else {
|
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
|
} else {
|
||||||
|
if (categoriesCache.isEmpty()) {
|
||||||
|
command = Message.obtain();
|
||||||
|
command.what = Command.ITEM_GET_CATEGORIES;
|
||||||
|
dao.executeCommand(command);
|
||||||
|
}
|
||||||
|
command = Message.obtain();
|
||||||
|
command.what = Command.SET_GET_ITEMS;
|
||||||
|
command.arg1 = presenter.getCurrentSet().getId();
|
||||||
|
dao.executeCommand(command);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onEvent(Message event) {
|
||||||
|
|
||||||
|
switch (event.what) {
|
||||||
|
case Event.SET_ITEMS_LOAD_ERROR :
|
||||||
|
break;
|
||||||
|
case Event.ITEM_FROM_SET_ERROR :
|
||||||
|
break;
|
||||||
|
case Event.ITEM_DELETE_ERROR :
|
||||||
|
break;
|
||||||
|
case Event.ITEM_PACK_ERROR :
|
||||||
|
break;
|
||||||
|
case Event.ITEM_UNPACK_ERROR :
|
||||||
|
break;
|
||||||
|
case Event.ITEM_INSERT_ERROR :
|
||||||
|
break;
|
||||||
|
case Event.ITEM_CATEGORY_LOAD_ERROR :
|
||||||
|
break;
|
||||||
|
case Event.SET_ITEMS_LOAD_COMPLETED :
|
||||||
|
List<Item> res = (List<Item>) event.obj;
|
||||||
|
cache.put(event.arg1, res);
|
||||||
|
notifyDataSetChanged();
|
||||||
|
break;
|
||||||
|
case Event.ITEM_CATEGORY_LOAD_COMPLETED :
|
||||||
|
categoriesCache = (Hashtable<Integer, Category>)event.obj;
|
||||||
|
break;
|
||||||
|
case Event.ITEM_FROM_SET_DELETED :
|
||||||
|
break;
|
||||||
|
case Event.ITEM_DELETED :
|
||||||
|
break;
|
||||||
|
case Event.ITEM_PACKED :
|
||||||
|
break;
|
||||||
|
case Event.ITEM_UNPACKED :
|
||||||
|
break;
|
||||||
|
case Event.ITEM_INSERTED :
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
private void loadCategories() {
|
|
||||||
Call<List<Category>> call = api.getItemCategories();
|
|
||||||
call.enqueue(new Callback<List<Category>>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(Call<List<Category>> call, Response<List<Category>> response) {
|
|
||||||
int statusCode = response.code();
|
|
||||||
rawCategories = response.body();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void onFailure(Call<List<Category>> call, Throwable t) {
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
private void loadItems() {
|
|
||||||
Call<List<Item>> call2 = api.getItems();
|
|
||||||
call2.enqueue(new Callback<List<Item>>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(Call<List<Item>> call, Response<List<Item>> response) {
|
|
||||||
int statusCode = response.code();
|
|
||||||
rawItems = response.body();
|
|
||||||
initData();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void onFailure(Call<List<Item>> call, Throwable t) {
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
private void syncData() {
|
|
||||||
// TODO sync data here
|
|
||||||
}
|
|
||||||
// process <--
|
// process <--
|
||||||
|
|
||||||
// other -->
|
// other -->
|
||||||
|
@ -159,6 +258,7 @@ public class ItemModel implements Model.Item {
|
||||||
@Override
|
@Override
|
||||||
public void setPresenter(Presenter.ItemList presenter) {
|
public void setPresenter(Presenter.ItemList presenter) {
|
||||||
this.presenter = presenter;
|
this.presenter = presenter;
|
||||||
|
this.currentSet = presenter.getCurrentSet().getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -204,7 +304,6 @@ public class ItemModel implements Model.Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return category;
|
return category;
|
||||||
|
|
||||||
}
|
}
|
||||||
private Category findCategory(int categoryId) {
|
private Category findCategory(int categoryId) {
|
||||||
Category category = null;
|
Category category = null;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package hikapro.com.backpack.model;
|
package hikapro.com.backpack.model;
|
||||||
|
|
||||||
|
import android.os.Message;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import hikapro.com.backpack.model.entities.Category;
|
import hikapro.com.backpack.model.entities.Category;
|
||||||
|
@ -15,34 +17,43 @@ public interface Model {
|
||||||
interface Base {
|
interface Base {
|
||||||
void onDestroy(boolean isConfigurationChanging);
|
void onDestroy(boolean isConfigurationChanging);
|
||||||
void executeQuery();
|
void executeQuery();
|
||||||
void sendMessage(String message);
|
void notifyDataSetChanged();
|
||||||
|
void onEvent(Message event);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Set extends Base {
|
interface Set extends Base {
|
||||||
hikapro.com.backpack.model.entities.Set getSetByPosition(int position);
|
hikapro.com.backpack.model.entities.Set getSetByPosition(int position);
|
||||||
hikapro.com.backpack.model.entities.Set findSet(int id);
|
hikapro.com.backpack.model.entities.Set findSet(int id);
|
||||||
int getSetsCount();
|
int getSetsCount();
|
||||||
void notifyDataSetChanged();
|
|
||||||
void setPresenter(Presenter.SetList presenter);
|
void setPresenter(Presenter.SetList presenter);
|
||||||
Presenter.SetList getPresenter();
|
Presenter.SetList getPresenter();
|
||||||
|
//GLM
|
||||||
|
List<hikapro.com.backpack.model.entities.Set> getSets(); // tag renamed
|
||||||
|
void setsReorderNotify();
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Item extends Base {
|
interface Item extends Base {
|
||||||
int insertItem(hikapro.com.backpack.model.entities.Item item);
|
int insertItem(hikapro.com.backpack.model.entities.Item item);
|
||||||
boolean deleteItem(int id);
|
boolean deleteItem(hikapro.com.backpack.model.entities.Item item);
|
||||||
|
void filter(String query);
|
||||||
|
int getHeaderId(int position);//TODO review
|
||||||
|
int getItemId(int position);//TODO review
|
||||||
|
void clear();
|
||||||
|
boolean isPendingRemoval(hikapro.com.backpack.model.entities.Item item);
|
||||||
|
void pendingRemove(hikapro.com.backpack.model.entities.Item item);
|
||||||
|
void pendingRemoveCancel(hikapro.com.backpack.model.entities.Item item);
|
||||||
|
int getItemsCount();
|
||||||
|
|
||||||
hikapro.com.backpack.model.entities.Item findItem(int id);
|
hikapro.com.backpack.model.entities.Item findItem(int id);
|
||||||
hikapro.com.backpack.model.entities.Item getItemByPosition(int categoryId, int position);
|
hikapro.com.backpack.model.entities.Item getItemByPosition(int position);
|
||||||
int getItemsCount(int categoryId);
|
|
||||||
hikapro.com.backpack.model.entities.Category getCategoryByPosition(int position);
|
hikapro.com.backpack.model.entities.Category getCategoryByPosition(int position);
|
||||||
int getCategoriesCount();
|
|
||||||
void notifyDataSetChanged();
|
|
||||||
void setPresenter(Presenter.ItemList presenter);
|
void setPresenter(Presenter.ItemList presenter);
|
||||||
Presenter.ItemList getPresenter();
|
Presenter.ItemList getPresenter();
|
||||||
}
|
}
|
||||||
interface Detail extends Base {
|
interface Detail extends Base {
|
||||||
int getCount();
|
int getCount();
|
||||||
hikapro.com.backpack.model.entities.Item findItem(int id);
|
hikapro.com.backpack.model.entities.Item findItem(int id);
|
||||||
void notifyDataSetChanged();
|
|
||||||
void setPresenter(Presenter.ItemDetail presenter);
|
void setPresenter(Presenter.ItemDetail presenter);
|
||||||
Presenter.ItemDetail getPresenter();
|
Presenter.ItemDetail getPresenter();
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import retrofit2.converter.gson.GsonConverterFactory;
|
||||||
*/
|
*/
|
||||||
public class RestClient {
|
public class RestClient {
|
||||||
|
|
||||||
public static final String BASE_URL = "http://hikapro.com";
|
public static final String BASE_URL = "http://hikapro.com/";
|
||||||
|
|
||||||
public static Api getApi() {
|
public static Api getApi() {
|
||||||
|
|
||||||
|
|
|
@ -1,38 +1,43 @@
|
||||||
package hikapro.com.backpack.model;
|
package hikapro.com.backpack.model;
|
||||||
|
|
||||||
|
import android.os.Message;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import hikapro.com.backpack.model.dao.Command;
|
||||||
|
import hikapro.com.backpack.model.dao.DAO;
|
||||||
|
import hikapro.com.backpack.model.dao.Event;
|
||||||
import hikapro.com.backpack.model.entities.Set;
|
import hikapro.com.backpack.model.entities.Set;
|
||||||
import hikapro.com.backpack.presenter.Presenter;
|
import hikapro.com.backpack.presenter.Presenter;
|
||||||
import retrofit2.Call;
|
|
||||||
import retrofit2.Callback;
|
|
||||||
import retrofit2.Response;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by tariel on 20/04/16.
|
* Created by tariel on 20/04/16.
|
||||||
*/
|
*/
|
||||||
public class SetModel implements Model.Set {
|
public class SetModel implements Model.Set {
|
||||||
|
|
||||||
private List<hikapro.com.backpack.model.entities.Set> iList;
|
private List<hikapro.com.backpack.model.entities.Set> cache;
|
||||||
private Api api;
|
|
||||||
private Presenter.SetList presenter;
|
private Presenter.SetList presenter;
|
||||||
|
private DAO dao;
|
||||||
|
|
||||||
|
|
||||||
public SetModel() {
|
public SetModel() {
|
||||||
this.api = RestClient.getApi();
|
this.cache = new ArrayList<>();
|
||||||
this.iList = new ArrayList<>();
|
this.dao = DAO.getInstance();
|
||||||
|
dao.registerObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// sets -->
|
//region sets
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public hikapro.com.backpack.model.entities.Set getSetByPosition(int position) {
|
public hikapro.com.backpack.model.entities.Set getSetByPosition(int position) {
|
||||||
return iList.get(position);
|
return cache.get(position);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public hikapro.com.backpack.model.entities.Set findSet(int id) {
|
public hikapro.com.backpack.model.entities.Set findSet(int id) {
|
||||||
Set ret = null;
|
Set ret = null;
|
||||||
for (Set s : iList) {
|
for (Set s : cache) {
|
||||||
if (s.getId() == id) {
|
if (s.getId() == id) {
|
||||||
ret = s;
|
ret = s;
|
||||||
break;
|
break;
|
||||||
|
@ -43,63 +48,76 @@ public class SetModel implements Model.Set {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSetsCount() {
|
public int getSetsCount() {
|
||||||
return iList.size();
|
return cache.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
// sets <--
|
//endregion
|
||||||
|
|
||||||
// events -->
|
//region events
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy(boolean isConfigurationChanging) {
|
public void onDestroy(boolean isConfigurationChanging) {
|
||||||
if ( !isConfigurationChanging ) {
|
if ( !isConfigurationChanging ) {
|
||||||
presenter = null;
|
presenter = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void notifyDataSetChanged() {
|
public void notifyDataSetChanged() {
|
||||||
presenter.notifyDataSetChanged();
|
presenter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendMessage(String message) {
|
private void sendMessage(String message) {
|
||||||
presenter.showMessage(message);
|
presenter.showMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// events <--
|
//endregion
|
||||||
|
|
||||||
// process -->
|
//region process
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void executeQuery() {
|
public void executeQuery() {
|
||||||
if (iList.isEmpty())
|
Message command = Message.obtain();
|
||||||
loadSets();
|
command.what = Command.SYNC_IF_NOT_EXISTS;
|
||||||
else
|
dao.executeCommand(command);
|
||||||
notifyDataSetChanged();
|
command = Message.obtain();
|
||||||
|
command.what = Command.SET_GET_ALL;
|
||||||
|
dao.executeCommand(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadSets() {
|
@Override
|
||||||
Call<List<hikapro.com.backpack.model.entities.Set>> call = api.getSets();
|
public void onEvent(Message event) {
|
||||||
call.enqueue(new Callback<List<hikapro.com.backpack.model.entities.Set>>() {
|
switch (event.what) {
|
||||||
@Override
|
case Event.SET_LOAD_ERROR :
|
||||||
public void onResponse(Call<List<hikapro.com.backpack.model.entities.Set>> call, Response<List<hikapro.com.backpack.model.entities.Set>> response) {
|
break;
|
||||||
int statusCode = response.code();
|
case Event.SET_ITEMS_LOAD_ERROR :
|
||||||
iList = response.body();
|
break;
|
||||||
|
case Event.SET_REORDER_ERROR :
|
||||||
|
break;
|
||||||
|
case Event.SET_LOAD_COMPLETED :
|
||||||
|
cache = (List<Set>) event.obj;
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
break;
|
||||||
@Override
|
case Event.SET_ITEMS_LOAD_COMPLETED :
|
||||||
public void onFailure(Call<List<hikapro.com.backpack.model.entities.Set>> call, Throwable t) {
|
break;
|
||||||
|
case Event.SET_REORDER_COMPLETED :
|
||||||
}
|
break;
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
private void syncData() {
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setsReorderNotify() {
|
||||||
|
for (int i = 0; i < cache.size(); ++i) {
|
||||||
|
cache.get(i).setLineNumber(i);
|
||||||
|
}
|
||||||
|
Message command = Message.obtain();
|
||||||
|
command.what = Command.SET_REORDER;
|
||||||
|
command.obj = cache;
|
||||||
|
dao.executeCommand(command);
|
||||||
}
|
}
|
||||||
// process <--
|
//endregion
|
||||||
|
|
||||||
// other -->
|
//region other
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setPresenter(Presenter.SetList presenter) {
|
public void setPresenter(Presenter.SetList presenter) {
|
||||||
|
@ -111,12 +129,14 @@ public class SetModel implements Model.Set {
|
||||||
return presenter;
|
return presenter;
|
||||||
}
|
}
|
||||||
|
|
||||||
// other <--
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//GLM
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<hikapro.com.backpack.model.entities.Set> getSets()
|
||||||
|
{
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
package hikapro.com.backpack.model.dao;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tariel on 27/04/16.
|
||||||
|
*/
|
||||||
|
public interface Command {
|
||||||
|
|
||||||
|
int SET_SCOPE_END = 0x77;
|
||||||
|
int ITEM_SCOPE_END = 0x8B;
|
||||||
|
int MY_LIST_SCOPE_END = 0x9F;
|
||||||
|
|
||||||
|
|
||||||
|
int SET_GET_ALL = 0x64;
|
||||||
|
int SET_REORDER = 0x65;
|
||||||
|
int SET_GET_ITEMS = 0x66;
|
||||||
|
|
||||||
|
int ITEM_DELETE_FROM_SET = 0x78;
|
||||||
|
int ITEM_INSERT = 0x79;
|
||||||
|
int ITEM_PACK = 0x7A;
|
||||||
|
int ITEM_UNPACK = 0x7B;
|
||||||
|
int ITEM_GET_CATEGORIES = 0x7C;
|
||||||
|
|
||||||
|
int MY_LIST_POST = 0x8C;
|
||||||
|
int MY_LIST_ITEM_ADD = 0x8D;
|
||||||
|
int MY_LIST_ITEM_DELETE = 0x8E;
|
||||||
|
int MY_LIST_CLEAR = 0x8F;
|
||||||
|
|
||||||
|
int SYNC = 0xA0;
|
||||||
|
int SYNC_IF_NOT_EXISTS = 0xA1;
|
||||||
|
|
||||||
|
int TEST = 0xC8;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,744 @@
|
||||||
|
package hikapro.com.backpack.model.dao;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.database.sqlite.SQLiteException;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.os.Process;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import hikapro.com.backpack.App;
|
||||||
|
import hikapro.com.backpack.model.Api;
|
||||||
|
import hikapro.com.backpack.model.Model;
|
||||||
|
import hikapro.com.backpack.model.RestClient;
|
||||||
|
import hikapro.com.backpack.model.SetModel;
|
||||||
|
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.model.entities.Timestamp;
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tariel on 20/04/16.
|
||||||
|
*/
|
||||||
|
public class DAO {
|
||||||
|
//region Constants
|
||||||
|
private static final int CORE_POOL_SIZE = 1;
|
||||||
|
private static final int CORE_MAX_POOL_SIZE = 1;
|
||||||
|
|
||||||
|
private static final int KEEP_ALIVE_TIME = 1;
|
||||||
|
private static final TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;
|
||||||
|
|
||||||
|
private static final int MY_LIST_ID = 15;
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
private static DAO instance;
|
||||||
|
|
||||||
|
private final ThreadPoolExecutor threadPool;
|
||||||
|
private final Handler handler;
|
||||||
|
private SetModel setModel;
|
||||||
|
private final Api api;
|
||||||
|
private Context context;
|
||||||
|
private DbHelper helper;
|
||||||
|
private Map<String, Model.Base> observers;
|
||||||
|
|
||||||
|
private DAO() {
|
||||||
|
this.context = App.getAppContext();
|
||||||
|
this.helper = new DbHelper(this.context);
|
||||||
|
this.api = RestClient.getApi();
|
||||||
|
final BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<>();
|
||||||
|
this.threadPool = initPool(taskQueue);
|
||||||
|
this.observers = Collections.synchronizedMap(new HashMap<String, Model.Base>());
|
||||||
|
this.handler = initHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
instance = new DAO();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DAO getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerObserver(Model.Base o) {
|
||||||
|
observers.put(o.getClass().getName(), o);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ThreadPoolExecutor initPool (BlockingQueue<Runnable> taskQueue) {
|
||||||
|
ThreadPoolExecutor ret = new ThreadPoolExecutor(
|
||||||
|
CORE_POOL_SIZE
|
||||||
|
,CORE_MAX_POOL_SIZE
|
||||||
|
,KEEP_ALIVE_TIME
|
||||||
|
,KEEP_ALIVE_TIME_UNIT
|
||||||
|
,taskQueue
|
||||||
|
);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Handler initHandler() {
|
||||||
|
Handler ret = new Handler(Looper.getMainLooper()) {
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg) {
|
||||||
|
for (Map.Entry<String, Model.Base> entry : observers.entrySet()) {
|
||||||
|
entry.getValue().onEvent(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void executeCommand(Message command) {
|
||||||
|
|
||||||
|
SetTask setTask;
|
||||||
|
ItemTask itemTask;
|
||||||
|
|
||||||
|
if (command != null) {
|
||||||
|
switch (command.what) {
|
||||||
|
|
||||||
|
case Command.SET_GET_ALL :
|
||||||
|
setTask = new SetTask(Command.SET_GET_ALL,
|
||||||
|
Process.THREAD_PRIORITY_MORE_FAVORABLE);
|
||||||
|
threadPool.execute(setTask);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Command.SET_REORDER :
|
||||||
|
setTask = new SetTask(Command.SET_REORDER,
|
||||||
|
Process.THREAD_PRIORITY_BACKGROUND);
|
||||||
|
setTask.setsToUpdate = (List<Set>) command.obj;
|
||||||
|
threadPool.execute(setTask);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Command.SET_GET_ITEMS :
|
||||||
|
setTask = new SetTask(Command.SET_GET_ITEMS,
|
||||||
|
Process.THREAD_PRIORITY_MORE_FAVORABLE);
|
||||||
|
setTask.setId = command.arg1;
|
||||||
|
threadPool.execute(setTask);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Command.ITEM_GET_CATEGORIES :
|
||||||
|
itemTask = new ItemTask(Command.ITEM_GET_CATEGORIES,
|
||||||
|
Process.THREAD_PRIORITY_MORE_FAVORABLE);
|
||||||
|
threadPool.execute(itemTask);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Command.ITEM_INSERT :
|
||||||
|
itemTask = new ItemTask(Command.ITEM_INSERT,
|
||||||
|
Process.THREAD_PRIORITY_BACKGROUND);
|
||||||
|
itemTask.item = (Item) command.obj;
|
||||||
|
itemTask.setId = command.arg1;
|
||||||
|
threadPool.execute(itemTask);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Command.ITEM_DELETE_FROM_SET :
|
||||||
|
itemTask = new ItemTask(Command.ITEM_DELETE_FROM_SET,
|
||||||
|
Process.THREAD_PRIORITY_BACKGROUND);
|
||||||
|
itemTask.setId = command.arg1;
|
||||||
|
itemTask.itemId = command.arg2;
|
||||||
|
threadPool.execute(itemTask);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Command.ITEM_PACK :
|
||||||
|
itemTask = new ItemTask(Command.ITEM_PACK,
|
||||||
|
Process.THREAD_PRIORITY_BACKGROUND);
|
||||||
|
itemTask.setId = command.arg1;
|
||||||
|
itemTask.itemId = command.arg2;
|
||||||
|
threadPool.execute(itemTask);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Command.ITEM_UNPACK :
|
||||||
|
itemTask = new ItemTask(Command.ITEM_UNPACK,
|
||||||
|
Process.THREAD_PRIORITY_BACKGROUND);
|
||||||
|
itemTask.setId = command.arg1;
|
||||||
|
itemTask.itemId = command.arg2;
|
||||||
|
threadPool.execute(itemTask);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Command.MY_LIST_ITEM_ADD :
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Command.MY_LIST_ITEM_DELETE :
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Command.MY_LIST_POST :
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Command.MY_LIST_CLEAR :
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Command.SYNC :
|
||||||
|
threadPool.execute(new SyncTask(Command.SYNC,
|
||||||
|
Process.THREAD_PRIORITY_BACKGROUND));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Command.SYNC_IF_NOT_EXISTS :
|
||||||
|
threadPool.execute(new SyncTask(Command.SYNC_IF_NOT_EXISTS,
|
||||||
|
Process.THREAD_PRIORITY_MORE_FAVORABLE));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////// DATABASE /////////////////////
|
||||||
|
|
||||||
|
//region Database
|
||||||
|
private SQLiteDatabase getReadDB(){
|
||||||
|
return helper.getReadableDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
private SQLiteDatabase getWriteDB(){
|
||||||
|
return helper.getWritableDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
// inserts
|
||||||
|
private void insertTimestamp(Timestamp timestamp) {
|
||||||
|
if (timestamp != null && timestamp.timestamp > 0) {
|
||||||
|
ContentValues values;
|
||||||
|
SQLiteDatabase db = getWriteDB();
|
||||||
|
try {
|
||||||
|
db.beginTransaction();
|
||||||
|
values = Db.LogTable.toContentValues(timestamp);
|
||||||
|
db.insert(Db.LogTable.TABLE_NAME, null, values);
|
||||||
|
db.setTransactionSuccessful();
|
||||||
|
} finally {
|
||||||
|
db.endTransaction();
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void insertItems(List<Item> items) {
|
||||||
|
if (items != null && !items.isEmpty()) {
|
||||||
|
ContentValues values;
|
||||||
|
SQLiteDatabase db = getWriteDB();
|
||||||
|
try {
|
||||||
|
db.beginTransaction();
|
||||||
|
for (Item item : items) {
|
||||||
|
values = Db.ItemsTable.toContentValues(item);
|
||||||
|
db.insert(Db.ItemsTable.TABLE_NAME, null, values);
|
||||||
|
}
|
||||||
|
db.setTransactionSuccessful();
|
||||||
|
} finally {
|
||||||
|
db.endTransaction();
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void insertCategories(List<Category> categories) {
|
||||||
|
|
||||||
|
if (categories != null && !categories.isEmpty()) {
|
||||||
|
ContentValues values;
|
||||||
|
SQLiteDatabase db = getWriteDB();
|
||||||
|
try {
|
||||||
|
db.beginTransaction();
|
||||||
|
for (Category category : categories) {
|
||||||
|
values = Db.CategoriesTable.toContentValues(category);
|
||||||
|
db.insert(Db.CategoriesTable.TABLE_NAME, null, values);
|
||||||
|
}
|
||||||
|
db.setTransactionSuccessful();
|
||||||
|
} finally {
|
||||||
|
db.endTransaction();
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void insertSets(List<Set> sets) {
|
||||||
|
|
||||||
|
if (sets != null && !sets.isEmpty()) {
|
||||||
|
ContentValues values;
|
||||||
|
int i = 0;
|
||||||
|
SQLiteDatabase db = getWriteDB();
|
||||||
|
try {
|
||||||
|
db.beginTransaction();
|
||||||
|
for (Set set : sets) {
|
||||||
|
values = Db.SetsTable.toContentValues(set, i);
|
||||||
|
db.insert(Db.SetsTable.TABLE_NAME, null, values);
|
||||||
|
insertSetItems(set, db);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
db.setTransactionSuccessful();
|
||||||
|
} finally {
|
||||||
|
db.endTransaction();
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void insertSetItems(Set set, SQLiteDatabase db) {
|
||||||
|
if (set != null && db != null) {
|
||||||
|
if (!set.getItems().isEmpty()) {
|
||||||
|
ContentValues values;
|
||||||
|
int setId = set.getId();
|
||||||
|
try {
|
||||||
|
db.beginTransaction();
|
||||||
|
for (Integer itemid : set.getItems()) {
|
||||||
|
values = Db.SetItemsTable.toContentValues(setId, itemid);
|
||||||
|
db.insert(Db.SetItemsTable.TABLE_NAME, null, values);
|
||||||
|
}
|
||||||
|
db.setTransactionSuccessful();
|
||||||
|
} finally {
|
||||||
|
db.endTransaction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void insertSetItem(int setId, int itemId) {
|
||||||
|
ContentValues values;
|
||||||
|
SQLiteDatabase db = getWriteDB();
|
||||||
|
try {
|
||||||
|
db.beginTransaction();
|
||||||
|
values = Db.SetItemsTable.toContentValues(setId, itemId);
|
||||||
|
db.insert(Db.SetItemsTable.TABLE_NAME, null, values);
|
||||||
|
db.setTransactionSuccessful();
|
||||||
|
} finally {
|
||||||
|
db.endTransaction();
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// reads
|
||||||
|
private boolean LogExist() {
|
||||||
|
boolean ret;
|
||||||
|
SQLiteDatabase db = getReadDB();
|
||||||
|
Cursor cursor = db.query(Db.LogTable.TABLE_NAME,
|
||||||
|
new String[] {Db.LogTable.COLUMN_ID}, null, null, null, null, null, "1");
|
||||||
|
ret = cursor.moveToNext();
|
||||||
|
cursor.close();
|
||||||
|
db.close();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
private List<Item> readItems(int setId) {
|
||||||
|
List<Item> ret = new ArrayList<>(256);
|
||||||
|
Cursor cursor = null;
|
||||||
|
SQLiteDatabase db = null;
|
||||||
|
Item item;
|
||||||
|
String query = String.format(
|
||||||
|
"SELECT * FROM %s a INNER JOIN %s b ON a.%s = b.%s WHERE b.%s = ? AND b.%s <> 1 AND b.%s <> 1",
|
||||||
|
Db.ItemsTable.TABLE_NAME,
|
||||||
|
Db.SetItemsTable.TABLE_NAME,
|
||||||
|
Db.ItemsTable.COLUMN_ID,
|
||||||
|
Db.SetItemsTable.COLUMN_ITEM,
|
||||||
|
Db.SetItemsTable.COLUMN_SET,
|
||||||
|
Db.SetItemsTable.COLUMN_DELETED,
|
||||||
|
Db.SetItemsTable.COLUMN_PACKED);
|
||||||
|
try {
|
||||||
|
db = getReadDB();
|
||||||
|
cursor = db.rawQuery(query, new String[]{String.valueOf(setId)});
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
item = Db.ItemsTable.parseCursor(cursor);
|
||||||
|
ret.add(item);
|
||||||
|
}
|
||||||
|
} catch (SQLiteException e) {
|
||||||
|
//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 Hashtable<Integer, Category> readCategories() {
|
||||||
|
Hashtable<Integer, Category> ret = new Hashtable<>(20, 0.9f);
|
||||||
|
Cursor cursor = null;
|
||||||
|
SQLiteDatabase db = null;
|
||||||
|
Category category;
|
||||||
|
try {
|
||||||
|
db = getReadDB();
|
||||||
|
cursor = db.query(Db.CategoriesTable.TABLE_NAME,
|
||||||
|
new String[]{Db.CategoriesTable.COLUMN_ID,
|
||||||
|
Db.CategoriesTable.COLUMN_NAME},
|
||||||
|
null,null,null,null,null);
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
category = Db.CategoriesTable.parseCursor(cursor);
|
||||||
|
ret.put(category.getId(), category);
|
||||||
|
}
|
||||||
|
} catch (SQLiteException e) {
|
||||||
|
//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<Set> readSets() {
|
||||||
|
List<Set> ret = new ArrayList<>(12);
|
||||||
|
Cursor cursor = null;
|
||||||
|
SQLiteDatabase db = null;
|
||||||
|
Set set;
|
||||||
|
try {
|
||||||
|
db = getReadDB();
|
||||||
|
cursor = db.query(Db.SetsTable.TABLE_NAME,
|
||||||
|
new String[]{Db.SetsTable.COLUMN_ID,
|
||||||
|
Db.SetsTable.COLUMN_ITEMS,
|
||||||
|
Db.SetsTable.COLUMN_LINE_NUMBER,
|
||||||
|
Db.SetsTable.COLUMN_NAME,
|
||||||
|
Db.SetsTable.COLUMN_PHOTO_LOCAL,
|
||||||
|
Db.SetsTable.COLUMN_PHOTO_THUMB_LOCAL,
|
||||||
|
Db.SetsTable.COLUMN_PHOTO_THUMB_URL,
|
||||||
|
Db.SetsTable.COLUMN_PHOTO_THUMBNAIL_LOCAL,
|
||||||
|
Db.SetsTable.COLUMN_PHOTO_THUMBNAIL_URL,
|
||||||
|
Db.SetsTable.COLUMN_PHOTO_URL},
|
||||||
|
null,null,null,null,
|
||||||
|
Db.SetsTable.COLUMN_LINE_NUMBER);
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
set = Db.SetsTable.parseCursor(cursor);
|
||||||
|
ret.add(set);
|
||||||
|
}
|
||||||
|
Collections.sort(ret);
|
||||||
|
} catch (SQLiteException e) {
|
||||||
|
//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;
|
||||||
|
}
|
||||||
|
// updates
|
||||||
|
private int updateSetsOrder(List<Set> reorderedSet) {
|
||||||
|
int ret = 0;
|
||||||
|
SQLiteDatabase db = null;
|
||||||
|
ContentValues values;
|
||||||
|
try {
|
||||||
|
|
||||||
|
db = getWriteDB();
|
||||||
|
db.beginTransaction();
|
||||||
|
for (Set set : reorderedSet) {
|
||||||
|
values = new ContentValues();
|
||||||
|
values.put(Db.SetsTable.COLUMN_LINE_NUMBER, set.getLineNumber());
|
||||||
|
ret += db.update(Db.SetsTable.TABLE_NAME, values, "_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 updateSetItemDeleted(int setId, int itemId, boolean del) {
|
||||||
|
int ret = 0;
|
||||||
|
SQLiteDatabase db = null;
|
||||||
|
ContentValues values;
|
||||||
|
try {
|
||||||
|
db = getWriteDB();
|
||||||
|
db.beginTransaction();
|
||||||
|
values = new ContentValues();
|
||||||
|
values.put(Db.SetItemsTable.COLUMN_DELETED, del);
|
||||||
|
ret = db.update(Db.SetItemsTable.TABLE_NAME, values, String.format("%s = ? AND %s = ?",
|
||||||
|
Db.SetItemsTable.COLUMN_SET, Db.SetItemsTable.COLUMN_ITEM ),
|
||||||
|
new String[]{String.valueOf(setId), String.valueOf(itemId)});
|
||||||
|
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 updateSetItemPacked(int setId, int itemId, boolean pack) {
|
||||||
|
int ret = 0;
|
||||||
|
SQLiteDatabase db = null;
|
||||||
|
ContentValues values;
|
||||||
|
try {
|
||||||
|
db = getWriteDB();
|
||||||
|
db.beginTransaction();
|
||||||
|
|
||||||
|
values = new ContentValues();
|
||||||
|
values.put(Db.SetItemsTable.COLUMN_PACKED, pack);
|
||||||
|
ret = db.update(Db.SetItemsTable.TABLE_NAME, values, String.format("%s = ? AND %s = ?",
|
||||||
|
Db.SetItemsTable.COLUMN_SET, Db.SetItemsTable.COLUMN_ITEM ),
|
||||||
|
new String[]{String.valueOf(setId), String.valueOf(itemId)});
|
||||||
|
|
||||||
|
if (pack) {
|
||||||
|
values = Db.SetItemsTable.toContentValues(MY_LIST_ID, itemId);
|
||||||
|
db.insert(Db.SetItemsTable.TABLE_NAME, null, values);
|
||||||
|
} else {
|
||||||
|
db.delete(Db.SetItemsTable.TABLE_NAME, String.format("%s = ? AND %s = ?",
|
||||||
|
Db.SetItemsTable.COLUMN_SET, Db.SetItemsTable.COLUMN_ITEM ),
|
||||||
|
new String[]{String.valueOf(MY_LIST_ID), String.valueOf(itemId) });
|
||||||
|
}
|
||||||
|
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 //////////////////
|
||||||
|
|
||||||
|
//region Task classes
|
||||||
|
|
||||||
|
// MY LIST CLASS
|
||||||
|
private class MyListTask implements Runnable {
|
||||||
|
int currentCommand;
|
||||||
|
int priority;
|
||||||
|
|
||||||
|
|
||||||
|
public MyListTask(int command, int priority) {
|
||||||
|
this.currentCommand = command;
|
||||||
|
this.priority = priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
android.os.Process.setThreadPriority(priority);
|
||||||
|
Message message = Message.obtain();
|
||||||
|
switch (currentCommand) {
|
||||||
|
|
||||||
|
}
|
||||||
|
handler.sendMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ITEM CLASS
|
||||||
|
private class ItemTask implements Runnable {
|
||||||
|
int currentCommand;
|
||||||
|
int priority;
|
||||||
|
int setId;
|
||||||
|
int itemId;
|
||||||
|
Item item;
|
||||||
|
|
||||||
|
public ItemTask(int command, int priority) {
|
||||||
|
this.currentCommand = command;
|
||||||
|
this.setId = -1;
|
||||||
|
this.itemId = -1;
|
||||||
|
this.priority = priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
android.os.Process.setThreadPriority(priority);
|
||||||
|
Message message = Message.obtain();
|
||||||
|
switch (currentCommand) {
|
||||||
|
|
||||||
|
case Command.ITEM_DELETE_FROM_SET :
|
||||||
|
message.arg1 = updateSetItemDeleted(setId, itemId, true);
|
||||||
|
if (message.arg1 > 0)
|
||||||
|
message.what = Event.ITEM_FROM_SET_DELETED;
|
||||||
|
else
|
||||||
|
message.what = Event.ITEM_FROM_SET_ERROR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Command.ITEM_INSERT :
|
||||||
|
List<Item> items = new ArrayList<>();
|
||||||
|
items.add(item);
|
||||||
|
if (items.isEmpty())
|
||||||
|
message.what = Event.ITEM_INSERT_ERROR;
|
||||||
|
else {
|
||||||
|
insertItems(items);
|
||||||
|
insertSetItem(setId, item.getId());
|
||||||
|
message.what = Event.ITEM_INSERTED;
|
||||||
|
message.arg1 = setId;
|
||||||
|
message.arg2 = item.getId();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Command.ITEM_PACK :
|
||||||
|
message.arg1 = updateSetItemPacked(setId, itemId, true);
|
||||||
|
if (message.arg1 > 0)
|
||||||
|
message.what = Event.ITEM_PACKED;
|
||||||
|
else
|
||||||
|
message.what = Event.ITEM_PACK_ERROR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Command.ITEM_UNPACK :
|
||||||
|
message.arg1 = updateSetItemPacked(setId, itemId, false);
|
||||||
|
if (message.arg1 > 0)
|
||||||
|
message.what = Event.ITEM_UNPACKED;
|
||||||
|
else
|
||||||
|
message.what = Event.ITEM_UNPACK_ERROR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Command.ITEM_GET_CATEGORIES :
|
||||||
|
Hashtable<Integer, Category> res = readCategories();
|
||||||
|
if (res.isEmpty())
|
||||||
|
message.what = Event.ITEM_CATEGORY_LOAD_ERROR;
|
||||||
|
else {
|
||||||
|
message.what = Event.ITEM_CATEGORY_LOAD_COMPLETED;
|
||||||
|
message.obj = res;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
handler.sendMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// SET CLASS
|
||||||
|
private class SetTask implements Runnable {
|
||||||
|
int currentCommand;
|
||||||
|
int priority;
|
||||||
|
int setId;
|
||||||
|
List<Set> setsToUpdate;
|
||||||
|
|
||||||
|
public SetTask(int command, int priority) {
|
||||||
|
this.currentCommand = command;
|
||||||
|
this.setId = -1;
|
||||||
|
this.setsToUpdate = new ArrayList<>();
|
||||||
|
this.priority = priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
android.os.Process.setThreadPriority(priority);
|
||||||
|
Message message = Message.obtain();
|
||||||
|
switch (currentCommand) {
|
||||||
|
|
||||||
|
case Command.SET_GET_ALL :
|
||||||
|
List<Set> sets = readSets();
|
||||||
|
if (sets.isEmpty())
|
||||||
|
message.what = Event.SET_LOAD_ERROR;
|
||||||
|
else {
|
||||||
|
message.what = Event.SET_LOAD_COMPLETED;
|
||||||
|
message.obj = sets;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Command.SET_GET_ITEMS :
|
||||||
|
List<Item> items = readItems(setId);
|
||||||
|
if (items.isEmpty())
|
||||||
|
message.what = Event.SET_ITEMS_LOAD_ERROR;
|
||||||
|
else {
|
||||||
|
Collections.sort(items);
|
||||||
|
message.what = Event.SET_ITEMS_LOAD_COMPLETED;
|
||||||
|
message.obj = items;
|
||||||
|
message.arg1 = setId;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Command.SET_REORDER :
|
||||||
|
message.arg1 = updateSetsOrder(setsToUpdate);
|
||||||
|
if (message.arg1 > 0)
|
||||||
|
message.what = Event.SET_REORDER_COMPLETED;
|
||||||
|
else
|
||||||
|
message.what = Event.SET_REORDER_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
handler.sendMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// SYNC CLASS
|
||||||
|
private class SyncTask implements Runnable {
|
||||||
|
int currentCommand;
|
||||||
|
int priority;
|
||||||
|
int statusCode;
|
||||||
|
|
||||||
|
public SyncTask(int command, int priority) {
|
||||||
|
this.currentCommand = command;
|
||||||
|
this.priority = priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
android.os.Process.setThreadPriority(priority);
|
||||||
|
Message message = Message.obtain();
|
||||||
|
|
||||||
|
switch (currentCommand) {
|
||||||
|
case Command.SYNC:
|
||||||
|
try {
|
||||||
|
Call<List<Set>> call = api.getSets();
|
||||||
|
call.enqueue(new Callback<List<Set>>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<List<hikapro.com.backpack.model.entities.Set>> call, Response<List<Set>> response) {
|
||||||
|
statusCode = response.code();
|
||||||
|
// TODO
|
||||||
|
// check if first time
|
||||||
|
// if not check for updates else
|
||||||
|
// insert into database here
|
||||||
|
insertSets(response.body());
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<List<hikapro.com.backpack.model.entities.Set>> call, Throwable t) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
message.what = Event.SYNC_COMPLETED;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
message.what = Event.SYNC_FAILED;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
message.arg1 = statusCode;
|
||||||
|
handler.sendMessage(message);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Command.SYNC_IF_NOT_EXISTS:
|
||||||
|
if (LogExist()) {
|
||||||
|
message.what = Event.SYNC_COMPLETED;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
try {
|
||||||
|
Response<List<Set>> response0 = api.getSets().execute();
|
||||||
|
insertSets(response0.body());
|
||||||
|
statusCode = response0.code();
|
||||||
|
Response<List<Category>> response1 = api.getItemCategories().execute();
|
||||||
|
insertCategories(response1.body());
|
||||||
|
statusCode = response1.code();
|
||||||
|
Response<List<Item>> response2 = api.getItems().execute();
|
||||||
|
insertItems(response2.body());
|
||||||
|
statusCode = response2.code();
|
||||||
|
Response<Timestamp> response3 = api.getTimestamp().execute();
|
||||||
|
insertTimestamp(response3.body());
|
||||||
|
statusCode = response3.code();
|
||||||
|
message.what = Event.SYNC_COMPLETED;
|
||||||
|
} catch (IOException e ){
|
||||||
|
message.what = Event.SYNC_FAILED;
|
||||||
|
} finally {
|
||||||
|
message.arg1 = statusCode;
|
||||||
|
handler.sendMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package hikapro.com.backpack.model.database;
|
package hikapro.com.backpack.model.dao;
|
||||||
|
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
@ -12,6 +12,8 @@ import java.util.List;
|
||||||
import hikapro.com.backpack.model.entities.Category;
|
import hikapro.com.backpack.model.entities.Category;
|
||||||
import hikapro.com.backpack.model.entities.Item;
|
import hikapro.com.backpack.model.entities.Item;
|
||||||
import hikapro.com.backpack.model.entities.Set;
|
import hikapro.com.backpack.model.entities.Set;
|
||||||
|
import hikapro.com.backpack.model.entities.Timestamp;
|
||||||
|
import hikapro.com.backpack.model.entities.UpdateLog;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by tariel on 20/04/16.
|
* Created by tariel on 20/04/16.
|
||||||
|
@ -23,10 +25,10 @@ public class Db {
|
||||||
|
|
||||||
public abstract static class CategoriesTable {
|
public abstract static class CategoriesTable {
|
||||||
|
|
||||||
public static final String TABLE_NAME = "CATEGORIES";
|
public static final String TABLE_NAME = "categories";
|
||||||
|
|
||||||
public static final String COLUMN_ID = "_id";
|
public static final String COLUMN_ID = "_id";
|
||||||
public static final String COLUMN_NAME = "NAME";
|
public static final String COLUMN_NAME = "name";
|
||||||
|
|
||||||
public static final String CREATE =
|
public static final String CREATE =
|
||||||
"CREATE TABLE " + TABLE_NAME + " (" +
|
"CREATE TABLE " + TABLE_NAME + " (" +
|
||||||
|
@ -51,17 +53,17 @@ public class Db {
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract static class ItemsTable {
|
public abstract static class ItemsTable {
|
||||||
public static final String TABLE_NAME = "ITEMS";
|
public static final String TABLE_NAME = "items";
|
||||||
|
|
||||||
public static final String COLUMN_ID = "_id";
|
public static final String COLUMN_ID = "_id";
|
||||||
public static final String COLUMN_NAME = "NAME";
|
public static final String COLUMN_NAME = "name";
|
||||||
public static final String COLUMN_CATEGORY = "CATEGORY";
|
public static final String COLUMN_CATEGORY = "category";
|
||||||
public static final String COLUMN_DESCRIPTION = "DESCRIPTION";
|
public static final String COLUMN_DESCRIPTION = "description";
|
||||||
public static final String COLUMN_BUY_URLS = "BUY_URLS";
|
public static final String COLUMN_BUY_URLS = "buy_urls";
|
||||||
public static final String COLUMN_PHOTO_URL = "PHOTO_URL";
|
public static final String COLUMN_PHOTO_URL = "photo_url";
|
||||||
public static final String COLUMN_PHOTO_THUMB_URL = "PHOTO_THUMB_URL";
|
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_LOCAL = "photo_local";
|
||||||
public static final String COLUMN_PHOTO_THUMB_LOCAL = "PHOTO_THUMB_LOCAL";
|
public static final String COLUMN_PHOTO_THUMB_LOCAL = "photo_thumb_local";
|
||||||
|
|
||||||
|
|
||||||
public static final String CREATE =
|
public static final String CREATE =
|
||||||
|
@ -124,17 +126,19 @@ public class Db {
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract static class SetsTable {
|
public abstract static class SetsTable {
|
||||||
public static final String TABLE_NAME = "SETS";
|
public static final String TABLE_NAME = "sets";
|
||||||
|
|
||||||
public static final String COLUMN_ID = "_id";
|
public static final String COLUMN_ID = "_id";
|
||||||
public static final String COLUMN_NAME = "NAME";
|
public static final String COLUMN_NAME = "name";
|
||||||
public static final String COLUMN_ITEMS = "ITEMS";
|
public static final String COLUMN_ITEMS = "items";
|
||||||
public static final String COLUMN_PHOTO_URL = "PHOTO_URL";
|
public static final String COLUMN_PHOTO_URL = "photo_url";
|
||||||
public static final String COLUMN_PHOTO_THUMB_URL = "PHOTO_THUMB_URL";
|
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_LOCAL = "photo_local";
|
||||||
public static final String COLUMN_PHOTO_THUMB_LOCAL = "PHOTO_THUMB_LOCAL";
|
public static final String COLUMN_PHOTO_THUMB_LOCAL = "photo_thumb_local";
|
||||||
public static final String COLUMN_PHOTO_THUMBNAIL_URL = "PHOTO_THUMBNAIL_URL";
|
public static final String COLUMN_PHOTO_THUMBNAIL_URL = "photo_thumbnail_url";
|
||||||
public static final String COLUMN_PHOTO_THUMBNAIL_LOCAL = "PHOTO_THUMBNAIL_LOCAL";
|
public static final String COLUMN_PHOTO_THUMBNAIL_LOCAL = "photo_thumbnail_local";
|
||||||
|
public static final String COLUMN_LINE_NUMBER = "line_num";
|
||||||
|
|
||||||
|
|
||||||
public static final String CREATE =
|
public static final String CREATE =
|
||||||
"CREATE TABLE " + TABLE_NAME + " (" +
|
"CREATE TABLE " + TABLE_NAME + " (" +
|
||||||
|
@ -146,10 +150,11 @@ public class Db {
|
||||||
COLUMN_PHOTO_LOCAL + " TEXT, " +
|
COLUMN_PHOTO_LOCAL + " TEXT, " +
|
||||||
COLUMN_PHOTO_THUMB_LOCAL + " TEXT, " +
|
COLUMN_PHOTO_THUMB_LOCAL + " TEXT, " +
|
||||||
COLUMN_PHOTO_THUMBNAIL_URL + " TEXT, " +
|
COLUMN_PHOTO_THUMBNAIL_URL + " TEXT, " +
|
||||||
|
COLUMN_LINE_NUMBER + " INTEGER, " +
|
||||||
COLUMN_PHOTO_THUMBNAIL_LOCAL + " TEXT" +
|
COLUMN_PHOTO_THUMBNAIL_LOCAL + " TEXT" +
|
||||||
" ); ";
|
" ); ";
|
||||||
|
|
||||||
public static ContentValues toContentValues(Set set) {
|
public static ContentValues toContentValues(Set set, int lineNumber) {
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put(COLUMN_ID, set.getId());
|
values.put(COLUMN_ID, set.getId());
|
||||||
values.put(COLUMN_NAME, set.getName());
|
values.put(COLUMN_NAME, set.getName());
|
||||||
|
@ -164,6 +169,7 @@ public class Db {
|
||||||
values.put(COLUMN_PHOTO_URL, set.getPhoto());
|
values.put(COLUMN_PHOTO_URL, set.getPhoto());
|
||||||
values.put(COLUMN_PHOTO_THUMB_URL, set.getPhotoThumb());
|
values.put(COLUMN_PHOTO_THUMB_URL, set.getPhotoThumb());
|
||||||
values.put(COLUMN_PHOTO_THUMBNAIL_URL, set.getPhotoThumbnail());
|
values.put(COLUMN_PHOTO_THUMBNAIL_URL, set.getPhotoThumbnail());
|
||||||
|
values.put(COLUMN_LINE_NUMBER, lineNumber);
|
||||||
/*
|
/*
|
||||||
values.put(COLUMN_PHOTO_LOCAL, "");
|
values.put(COLUMN_PHOTO_LOCAL, "");
|
||||||
values.put(COLUMN_PHOTO_THUMB_LOCAL, "");
|
values.put(COLUMN_PHOTO_THUMB_LOCAL, "");
|
||||||
|
@ -187,9 +193,68 @@ public class Db {
|
||||||
set.setPhoto(cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_PHOTO_URL)));
|
set.setPhoto(cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_PHOTO_URL)));
|
||||||
set.setPhotoThumb(cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_PHOTO_THUMB_URL)));
|
set.setPhotoThumb(cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_PHOTO_THUMB_URL)));
|
||||||
set.setPhotoThumbnail(cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_PHOTO_THUMBNAIL_URL)));
|
set.setPhotoThumbnail(cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_PHOTO_THUMBNAIL_URL)));
|
||||||
|
set.setLineNumber(cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_LINE_NUMBER)));
|
||||||
|
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract static class LogTable {
|
||||||
|
|
||||||
|
public static final String TABLE_NAME = "update_log";
|
||||||
|
|
||||||
|
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 CREATE =
|
||||||
|
"CREATE TABLE " + TABLE_NAME + " (" +
|
||||||
|
COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
|
||||||
|
COLUMN_TIMESTAMP + " INTEGER NOT NULL, " +
|
||||||
|
COLUMN_MODIFIED_DATETIME + " INTEGER NOT NULL DEFAULT current_timestamp" +
|
||||||
|
" ); ";
|
||||||
|
|
||||||
|
public static ContentValues toContentValues(Timestamp timestamp) {
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
|
||||||
|
values.put(COLUMN_TIMESTAMP, timestamp.timestamp);
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
public static UpdateLog parseCursor(Cursor cursor) {
|
||||||
|
UpdateLog log = new UpdateLog();
|
||||||
|
log.setTimestamp(cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_TIMESTAMP)));
|
||||||
|
log.setModifiedDatetime(cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_MODIFIED_DATETIME)));
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract static class SetItemsTable {
|
||||||
|
|
||||||
|
public static final String TABLE_NAME = "set_items";
|
||||||
|
|
||||||
|
public static final String COLUMN_ID = "_id";
|
||||||
|
public static final String COLUMN_SET = "setId";
|
||||||
|
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 CREATE =
|
||||||
|
"CREATE TABLE " + TABLE_NAME + " (" +
|
||||||
|
COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
|
||||||
|
COLUMN_SET + " INTEGER NOT NULL, " +
|
||||||
|
COLUMN_DELETED + " NUMERIC, " +
|
||||||
|
COLUMN_PACKED + " NUMERIC, " +
|
||||||
|
COLUMN_ITEM + " INTEGER NOT NULL" +
|
||||||
|
" ); ";
|
||||||
|
|
||||||
|
public static ContentValues toContentValues(int setId, int itemId) {
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(COLUMN_SET, setId);
|
||||||
|
values.put(COLUMN_ITEM, itemId);
|
||||||
|
values.put(COLUMN_DELETED, 0);
|
||||||
|
values.put(COLUMN_PACKED, 0);
|
||||||
|
return values;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package hikapro.com.backpack.model.database;
|
package hikapro.com.backpack.model.dao;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
@ -38,6 +38,8 @@ public class DbHelper extends SQLiteOpenHelper {
|
||||||
db.execSQL(Db.ItemsTable.CREATE);
|
db.execSQL(Db.ItemsTable.CREATE);
|
||||||
db.execSQL(Db.CategoriesTable.CREATE);
|
db.execSQL(Db.CategoriesTable.CREATE);
|
||||||
db.execSQL(Db.SetsTable.CREATE);
|
db.execSQL(Db.SetsTable.CREATE);
|
||||||
|
db.execSQL(Db.LogTable.CREATE);
|
||||||
|
db.execSQL(Db.SetItemsTable.CREATE);
|
||||||
|
|
||||||
if (oldVersion < 2) {
|
if (oldVersion < 2) {
|
||||||
// place the logic here
|
// place the logic here
|
|
@ -0,0 +1,53 @@
|
||||||
|
package hikapro.com.backpack.model.dao;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tariel on 27/04/16.
|
||||||
|
*/
|
||||||
|
public interface Event {
|
||||||
|
|
||||||
|
int SET_SCOPE_END = 0x13;
|
||||||
|
int ITEM_SCOPE_END = 0x27;
|
||||||
|
int MY_LIST_SCOPE_END = 0x3B;
|
||||||
|
|
||||||
|
int SET_LOAD_ERROR = -0x1;
|
||||||
|
int SET_REORDER_ERROR = -0x2;
|
||||||
|
int SET_ITEMS_LOAD_ERROR = -0x3;
|
||||||
|
|
||||||
|
|
||||||
|
int SET_LOAD_COMPLETED = 0x1;
|
||||||
|
int SET_REORDER_COMPLETED = 0x2;
|
||||||
|
int SET_ITEMS_LOAD_COMPLETED = 0x3;
|
||||||
|
|
||||||
|
|
||||||
|
int ITEM_FROM_SET_ERROR = -0x14;
|
||||||
|
int ITEM_INSERT_ERROR = -0x15;
|
||||||
|
int ITEM_DELETE_ERROR = -0x16;
|
||||||
|
int ITEM_PACK_ERROR = -0x17;
|
||||||
|
int ITEM_UNPACK_ERROR = -0x18;
|
||||||
|
int ITEM_CATEGORY_LOAD_ERROR = -0x19;
|
||||||
|
|
||||||
|
int ITEM_FROM_SET_DELETED = 0x14;
|
||||||
|
int ITEM_INSERTED = 0x15;
|
||||||
|
int ITEM_DELETED = 0x16;
|
||||||
|
int ITEM_PACKED = 0x17;
|
||||||
|
int ITEM_UNPACKED = 0x18;
|
||||||
|
int ITEM_CATEGORY_LOAD_COMPLETED = 0x19;
|
||||||
|
|
||||||
|
int MY_LIST_POST_ERROR = -0x28;
|
||||||
|
int MY_LIST_ITEM_ADD_ERROR = -0x29;
|
||||||
|
int MY_LIST_ITEM_DELETE_ERROR = -0x2A;
|
||||||
|
int MY_LIST_CLEAR_ERROR = -0x2B;
|
||||||
|
|
||||||
|
int MY_LIST_POSTED = 0x28;
|
||||||
|
int MY_LIST_ITEM_ADDED = 0x29;
|
||||||
|
int MY_LIST_ITEM_DELETED = 0x2A;
|
||||||
|
int MY_LIST_CLEARED = 0x2B;
|
||||||
|
|
||||||
|
int SYNC_FAILED = -0x3C;
|
||||||
|
int SYNC_COMPLETED = 0x3C;
|
||||||
|
|
||||||
|
int NOT_IMPLEMENTED = 0x50;
|
||||||
|
int NOT_UNDERSTAND = 0x51;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package hikapro.com.backpack.model.dao;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tariel on 27/04/16.
|
||||||
|
*/
|
||||||
|
public class Test {
|
||||||
|
private static Test ourInstance = new Test();
|
||||||
|
|
||||||
|
public static Test getInstance() {
|
||||||
|
return ourInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Test() {
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,26 +0,0 @@
|
||||||
package hikapro.com.backpack.model.database;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by tariel on 20/04/16.
|
|
||||||
*/
|
|
||||||
public class DAO {
|
|
||||||
|
|
||||||
private Context context;
|
|
||||||
private DbHelper helper;
|
|
||||||
|
|
||||||
public DAO(Context context) {
|
|
||||||
this.context = context;
|
|
||||||
this.helper = new DbHelper(this.context);
|
|
||||||
}
|
|
||||||
|
|
||||||
private SQLiteDatabase getReadDB(){
|
|
||||||
return helper.getReadableDatabase();
|
|
||||||
}
|
|
||||||
|
|
||||||
private SQLiteDatabase getWriteDB(){
|
|
||||||
return helper.getWritableDatabase();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -10,7 +10,7 @@ import java.util.List;
|
||||||
/**
|
/**
|
||||||
* Created by tariel on 02/04/16.
|
* Created by tariel on 02/04/16.
|
||||||
*/
|
*/
|
||||||
public class Set implements Serializable {
|
public class Set implements Comparable<Set>, Serializable {
|
||||||
|
|
||||||
@SerializedName("id")
|
@SerializedName("id")
|
||||||
@Expose
|
@Expose
|
||||||
|
@ -31,6 +31,8 @@ public class Set implements Serializable {
|
||||||
@Expose
|
@Expose
|
||||||
private String photoThumbnail;
|
private String photoThumbnail;
|
||||||
|
|
||||||
|
private int lineNumber;
|
||||||
|
|
||||||
public Set() {
|
public Set() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +93,14 @@ public class Set implements Serializable {
|
||||||
this.photoThumbnail = photoThumbnail;
|
this.photoThumbnail = photoThumbnail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getLineNumber() {
|
||||||
|
return lineNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLineNumber(int lineNumber) {
|
||||||
|
this.lineNumber = lineNumber;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int result = name != null ? name.hashCode() : 0;
|
int result = name != null ? name.hashCode() : 0;
|
||||||
|
@ -109,4 +119,10 @@ public class Set implements Serializable {
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Set another) {
|
||||||
|
int cmp = Integer.valueOf(lineNumber).compareTo(Integer.valueOf(another.lineNumber));
|
||||||
|
return (cmp != 0 ? cmp : name.compareTo(another.name));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
package hikapro.com.backpack.model.entities;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.Expose;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tariel on 27/04/16.
|
||||||
|
*/
|
||||||
|
public class Timestamp {
|
||||||
|
|
||||||
|
@SerializedName("timestamp")
|
||||||
|
@Expose
|
||||||
|
public long timestamp;
|
||||||
|
|
||||||
|
public Timestamp() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package hikapro.com.backpack.model.entities;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tariel on 27/04/16.
|
||||||
|
*/
|
||||||
|
public class UpdateLog {
|
||||||
|
|
||||||
|
private long timestamp;
|
||||||
|
private long modifiedDatetime;
|
||||||
|
|
||||||
|
public UpdateLog() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTimestamp() {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTimestamp(long timestamp) {
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getModifiedDatetime() {
|
||||||
|
return modifiedDatetime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModifiedDatetime(long modifiedDatetime) {
|
||||||
|
this.modifiedDatetime = modifiedDatetime;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
package hikapro.com.backpack.model.entities;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.Expose;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tariel on 27/04/16.
|
||||||
|
*/
|
||||||
|
public class Updates {
|
||||||
|
|
||||||
|
@SerializedName("items")
|
||||||
|
@Expose
|
||||||
|
public List<Integer> items = new ArrayList<>();
|
||||||
|
|
||||||
|
@SerializedName("items_deleted_ids")
|
||||||
|
@Expose
|
||||||
|
public List<Integer> itemsDeletedIds = new ArrayList<>();
|
||||||
|
|
||||||
|
@SerializedName("item_categories")
|
||||||
|
@Expose
|
||||||
|
public List<Integer> itemCategories = new ArrayList<>();
|
||||||
|
|
||||||
|
@SerializedName("item_categories_deleted_ids")
|
||||||
|
@Expose
|
||||||
|
public List<Integer> itemCategoriesDeletedIds = new ArrayList<>();
|
||||||
|
|
||||||
|
@SerializedName("sets")
|
||||||
|
@Expose
|
||||||
|
public List<Integer> sets = new ArrayList<>();
|
||||||
|
|
||||||
|
@SerializedName("sets_deleted_ids")
|
||||||
|
@Expose
|
||||||
|
public List<Integer> setsDeletedIds = new ArrayList<>();
|
||||||
|
|
||||||
|
@SerializedName("timestamp")
|
||||||
|
@Expose
|
||||||
|
public long timestamp;
|
||||||
|
}
|
|
@ -2,27 +2,24 @@ package hikapro.com.backpack.presenter;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v7.widget.DefaultItemAnimator;
|
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import hikapro.com.backpack.R;
|
import hikapro.com.backpack.R;
|
||||||
import hikapro.com.backpack.model.ItemModel;
|
|
||||||
import hikapro.com.backpack.model.Model;
|
import hikapro.com.backpack.model.Model;
|
||||||
import hikapro.com.backpack.model.entities.Item;
|
import hikapro.com.backpack.model.entities.Item;
|
||||||
import hikapro.com.backpack.model.entities.Set;
|
import hikapro.com.backpack.model.entities.Set;
|
||||||
import hikapro.com.backpack.presenter.adapters.CategoryListAdapter;
|
import hikapro.com.backpack.presenter.adapters.helper.items.DividerDecoration;
|
||||||
import hikapro.com.backpack.presenter.adapters.ItemListAdapter;
|
import hikapro.com.backpack.presenter.adapters.ItemListAdapter;
|
||||||
|
import hikapro.com.backpack.presenter.adapters.helper.items.ItemSwipeCallback;
|
||||||
|
import hikapro.com.backpack.presenter.adapters.helper.items.StickyHeaderDecoration;
|
||||||
import hikapro.com.backpack.view.View;
|
import hikapro.com.backpack.view.View;
|
||||||
import hikapro.com.backpack.view.recycler.CategoryViewHolder;
|
|
||||||
import hikapro.com.backpack.view.recycler.ItemViewHolder;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by tariel on 20/04/16.
|
* Created by tariel on 20/04/16.
|
||||||
|
@ -34,10 +31,12 @@ public class ItemListPresenter implements Presenter.ItemList {
|
||||||
private WeakReference<View.ItemList> view;
|
private WeakReference<View.ItemList> view;
|
||||||
private Model.Item model;
|
private Model.Item model;
|
||||||
private Set set;
|
private Set set;
|
||||||
private CategoryListAdapter categoryListAdapter;
|
private ItemListAdapter adapter;
|
||||||
|
RecyclerView recycler;
|
||||||
|
|
||||||
public ItemListPresenter() {
|
public ItemListPresenter() {
|
||||||
this.categoryListAdapter = new CategoryListAdapter(this);
|
this.adapter = new ItemListAdapter(this);
|
||||||
|
adapter.setHasStableIds(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// life cycle -->
|
// life cycle -->
|
||||||
|
@ -52,14 +51,30 @@ public class ItemListPresenter implements Presenter.ItemList {
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public android.view.View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public android.view.View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
/*
|
||||||
if (savedInstanceState != null)
|
if (savedInstanceState != null)
|
||||||
set = (Set) savedInstanceState.getSerializable(BUNDLE_SET_LIST_KEY);
|
set = (Set) savedInstanceState.getSerializable(BUNDLE_SET_LIST_KEY);*/
|
||||||
android.view.View view = inflater.inflate(R.layout.fragment_item_list, container, false);
|
android.view.View view = inflater.inflate(R.layout.fragment_item_list, container, false);
|
||||||
LinearLayoutManager llm = new LinearLayoutManager(getActivityContext());
|
LinearLayoutManager llm = new LinearLayoutManager(getActivityContext());
|
||||||
RecyclerView mainRecycler = (RecyclerView) view.findViewById(R.id.categories_main_recycler);
|
recycler = (RecyclerView) view.findViewById(R.id.items_recycler);
|
||||||
mainRecycler.setLayoutManager(llm);
|
recycler.setLayoutManager(llm);
|
||||||
mainRecycler.setAdapter(categoryListAdapter);
|
recycler.setAdapter(adapter);
|
||||||
mainRecycler.setItemAnimator(new DefaultItemAnimator());
|
|
||||||
|
final StickyHeaderDecoration decoration = new StickyHeaderDecoration(adapter);
|
||||||
|
recycler.addItemDecoration(decoration);
|
||||||
|
recycler.addItemDecoration(new DividerDecoration(getActivityContext()));
|
||||||
|
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
|
||||||
|
@Override
|
||||||
|
public void onChanged() {
|
||||||
|
decoration.invalidateHeaders();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ItemSwipeCallback itemSwipeCallback = new ItemSwipeCallback(0, ItemTouchHelper.LEFT, adapter, getActivityContext());
|
||||||
|
|
||||||
|
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(itemSwipeCallback);
|
||||||
|
itemTouchHelper.attachToRecyclerView(recycler);
|
||||||
|
adapter.setUndoOn(true);
|
||||||
|
|
||||||
model.executeQuery();
|
model.executeQuery();
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
@ -71,68 +86,11 @@ public class ItemListPresenter implements Presenter.ItemList {
|
||||||
|
|
||||||
// life cycle <--
|
// life cycle <--
|
||||||
|
|
||||||
// recycler -->
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CategoryViewHolder createViewHolderCategory(ViewGroup parent, int viewType) {
|
|
||||||
CategoryViewHolder viewHolder;
|
|
||||||
android.view.View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.section,
|
|
||||||
parent, false);
|
|
||||||
viewHolder = new CategoryViewHolder(v);
|
|
||||||
return viewHolder;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void bindViewHolderCategory(CategoryViewHolder holder, int position) {
|
|
||||||
final hikapro.com.backpack.model.entities.Category category = model.getCategoryByPosition(position);
|
|
||||||
holder.sectionText.setText(category.getName());
|
|
||||||
LinearLayoutManager llm = new LinearLayoutManager(getActivityContext());
|
|
||||||
holder.itemsRecycler.setLayoutManager(llm);
|
|
||||||
ItemListAdapter itemListAdapter = new ItemListAdapter(this);
|
|
||||||
itemListAdapter.setCategoryId(category.getId());
|
|
||||||
holder.itemsRecycler.setAdapter(itemListAdapter);
|
|
||||||
holder.itemsRecycler.setItemAnimator(new DefaultItemAnimator());
|
|
||||||
categoryListAdapter.addItemAdapter(itemListAdapter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemViewHolder createViewHolderItem(ViewGroup parent, int viewType) {
|
|
||||||
ItemViewHolder viewHolder;
|
|
||||||
android.view.View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item,
|
|
||||||
parent, false);
|
|
||||||
viewHolder = new ItemViewHolder(v);
|
|
||||||
return viewHolder;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void bindViewHolderItem(final ItemViewHolder holder, final int position, int categoryId) {
|
|
||||||
|
|
||||||
hikapro.com.backpack.model.entities.Item item = model.getItemByPosition(categoryId, position);
|
|
||||||
holder.title.setText(item.getName());
|
|
||||||
holder.id = item.getId();
|
|
||||||
holder.title.setOnClickListener(new android.view.View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(android.view.View view) {
|
|
||||||
clickItem(holder.id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public int getItemsCount(int categoryId) {
|
|
||||||
return model.getItemsCount(categoryId);//TODO category Id
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public int getCategoriesCount() {
|
|
||||||
return model.getCategoriesCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// recycler <--
|
|
||||||
|
|
||||||
// process -->
|
// process -->
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyDataSetChanged() {
|
public void notifyDataSetChanged() {
|
||||||
categoryListAdapter.notifyDataSetChanged();
|
adapter.notifyDataSetChanged();
|
||||||
categoryListAdapter.notifyItemAdapters();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -156,6 +114,12 @@ public class ItemListPresenter implements Presenter.ItemList {
|
||||||
public void setModel(Model.Item model) {
|
public void setModel(Model.Item model) {
|
||||||
this.model = model;
|
this.model = model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Model.Item getModel() {
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Context getAppContext() {
|
public Context getAppContext() {
|
||||||
try {
|
try {
|
||||||
|
@ -186,6 +150,11 @@ public class ItemListPresenter implements Presenter.ItemList {
|
||||||
throw new NullPointerException("View is unavailable");
|
throw new NullPointerException("View is unavailable");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void filter(String query) {
|
||||||
|
adapter.filter(query);
|
||||||
|
recycler.scrollToPosition(0);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set getCurrentSet() {
|
public Set getCurrentSet() {
|
||||||
|
|
|
@ -2,13 +2,13 @@ package hikapro.com.backpack.presenter;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import hikapro.com.backpack.model.Model;
|
import hikapro.com.backpack.model.Model;
|
||||||
import hikapro.com.backpack.model.entities.Item;
|
import hikapro.com.backpack.model.entities.Item;
|
||||||
import hikapro.com.backpack.model.entities.Set;
|
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.DetailViewHolder;
|
||||||
import hikapro.com.backpack.view.recycler.ItemViewHolder;
|
import hikapro.com.backpack.view.recycler.ItemViewHolder;
|
||||||
import hikapro.com.backpack.view.recycler.SetViewHolder;
|
import hikapro.com.backpack.view.recycler.SetViewHolder;
|
||||||
|
@ -34,24 +34,26 @@ public interface Presenter {
|
||||||
void setModel(Model.Set model);
|
void setModel(Model.Set model);
|
||||||
void notifyDataSetChanged();
|
void notifyDataSetChanged();
|
||||||
void showMessage(String message);
|
void showMessage(String message);
|
||||||
|
|
||||||
|
//GLM_add_resources_SetList
|
||||||
|
void onItemDismiss(int position);
|
||||||
|
boolean onItemMove(int fromPosition, int toPosition);
|
||||||
|
void onStartDrag(RecyclerView.ViewHolder viewHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ItemList extends Base {
|
interface ItemList extends Base {
|
||||||
ItemViewHolder createViewHolderItem(ViewGroup parent, int viewType);
|
|
||||||
void bindViewHolderItem(ItemViewHolder holder, int position, int categoryId);
|
|
||||||
int getItemsCount(int categoryId);
|
|
||||||
CategoryViewHolder createViewHolderCategory(ViewGroup parent, int viewType);
|
|
||||||
void bindViewHolderCategory(CategoryViewHolder holder, int position);
|
|
||||||
int getCategoriesCount();
|
|
||||||
void onDestroy(boolean isChangingConfiguration);
|
void onDestroy(boolean isChangingConfiguration);
|
||||||
android.view.View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState);
|
android.view.View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState);
|
||||||
void setView(hikapro.com.backpack.view.View.ItemList view);
|
void setView(hikapro.com.backpack.view.View.ItemList view);
|
||||||
void setModel(Model.Item model);
|
void setModel(Model.Item model);
|
||||||
|
Model.Item getModel();
|
||||||
void notifyDataSetChanged();
|
void notifyDataSetChanged();
|
||||||
Set getCurrentSet();
|
Set getCurrentSet();
|
||||||
void showMessage(String message);
|
void showMessage(String message);
|
||||||
void onSaveInstanceState(Bundle outState);
|
void onSaveInstanceState(Bundle outState);
|
||||||
void clickItem(int itemId);
|
void clickItem(int itemId);
|
||||||
|
void filter(String query);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ItemDetail extends Base {
|
interface ItemDetail extends Base {
|
||||||
|
|
|
@ -5,17 +5,20 @@ import android.os.Bundle;
|
||||||
import android.support.v7.widget.DefaultItemAnimator;
|
import android.support.v7.widget.DefaultItemAnimator;
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
import hikapro.com.backpack.R;
|
import hikapro.com.backpack.R;
|
||||||
import hikapro.com.backpack.model.SetModel;
|
|
||||||
import hikapro.com.backpack.model.Model;
|
import hikapro.com.backpack.model.Model;
|
||||||
import hikapro.com.backpack.model.entities.Set;
|
import hikapro.com.backpack.model.entities.Set;
|
||||||
import hikapro.com.backpack.presenter.adapters.SetListAdapter;
|
import hikapro.com.backpack.presenter.adapters.SetListAdapter;
|
||||||
|
import hikapro.com.backpack.presenter.adapters.helper.sets.OnStartDragListener;
|
||||||
|
import hikapro.com.backpack.presenter.adapters.helper.sets.SimpleItemTouchHelperCallback;
|
||||||
import hikapro.com.backpack.view.View;
|
import hikapro.com.backpack.view.View;
|
||||||
import hikapro.com.backpack.view.recycler.SetViewHolder;
|
import hikapro.com.backpack.view.recycler.SetViewHolder;
|
||||||
|
|
||||||
|
@ -28,12 +31,34 @@ public class SetListPresenter implements Presenter.SetList {
|
||||||
private Model.Set model;
|
private Model.Set model;
|
||||||
private SetListAdapter adapter;
|
private SetListAdapter adapter;
|
||||||
|
|
||||||
|
|
||||||
|
//GLM_add_resources_SetList
|
||||||
|
private OnStartDragListener mDragStartListener;
|
||||||
|
private ItemTouchHelper mItemTouchHelper;
|
||||||
|
|
||||||
public SetListPresenter() {
|
public SetListPresenter() {
|
||||||
this.adapter = new SetListAdapter(this);
|
this.adapter = new SetListAdapter(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// life cycle -->
|
// life cycle -->
|
||||||
|
|
||||||
|
|
||||||
|
//GLM_add_resources_SetList
|
||||||
|
@Override
|
||||||
|
public void onItemDismiss(int position) {
|
||||||
|
model.getSets().remove(position);
|
||||||
|
adapter.notifyItemRemoved(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
//GLM_add_resources_SetList
|
||||||
|
@Override
|
||||||
|
public boolean onItemMove(int fromPosition, int toPosition) {
|
||||||
|
Collections.swap(model.getSets(), fromPosition, toPosition);
|
||||||
|
adapter.notifyItemMoved(fromPosition, toPosition);
|
||||||
|
model.setsReorderNotify();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy(boolean isChangingConfiguration) {
|
public void onDestroy(boolean isChangingConfiguration) {
|
||||||
view = null;
|
view = null;
|
||||||
|
@ -52,6 +77,12 @@ public class SetListPresenter implements Presenter.SetList {
|
||||||
setRecycler.setAdapter(adapter);
|
setRecycler.setAdapter(adapter);
|
||||||
setRecycler.setItemAnimator(new DefaultItemAnimator());
|
setRecycler.setItemAnimator(new DefaultItemAnimator());
|
||||||
model.executeQuery();
|
model.executeQuery();
|
||||||
|
|
||||||
|
//GLM_add_resources_SetList
|
||||||
|
ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(adapter);
|
||||||
|
mItemTouchHelper = new ItemTouchHelper(callback);
|
||||||
|
mItemTouchHelper.attachToRecyclerView(setRecycler);
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,6 +112,17 @@ public class SetListPresenter implements Presenter.SetList {
|
||||||
showMessage("There is no view in presenter");
|
showMessage("There is no view in presenter");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
//GLM_add_resources_SetList
|
||||||
|
holder.cardView.setOnLongClickListener(new android.view.View.OnLongClickListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onLongClick(android.view.View v) {
|
||||||
|
|
||||||
|
mDragStartListener.onStartDrag(holder);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public int getSetsCount() {
|
public int getSetsCount() {
|
||||||
|
@ -128,6 +170,7 @@ public class SetListPresenter implements Presenter.SetList {
|
||||||
@Override
|
@Override
|
||||||
public void setView(View.SetList view) {
|
public void setView(View.SetList view) {
|
||||||
this.view = new WeakReference<>(view);
|
this.view = new WeakReference<>(view);
|
||||||
|
this.mDragStartListener = getView().getOnStartDragListener();
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setModel(Model.Set model) {
|
public void setModel(Model.Set model) {
|
||||||
|
@ -147,5 +190,9 @@ public class SetListPresenter implements Presenter.SetList {
|
||||||
throw new NullPointerException("View is unavailable");
|
throw new NullPointerException("View is unavailable");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//GLM_add_resources_SetList
|
||||||
|
@Override
|
||||||
|
public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
|
||||||
|
mItemTouchHelper.startDrag(viewHolder);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
package hikapro.com.backpack.presenter.adapters;
|
|
||||||
|
|
||||||
import android.support.v7.widget.RecyclerView;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import hikapro.com.backpack.presenter.Presenter;
|
|
||||||
import hikapro.com.backpack.view.recycler.CategoryViewHolder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by tariel on 20/04/16.
|
|
||||||
*/
|
|
||||||
public class CategoryListAdapter extends RecyclerView.Adapter<CategoryViewHolder> {
|
|
||||||
|
|
||||||
private Presenter.ItemList presenter;
|
|
||||||
private List<ItemListAdapter> itemAdapters;
|
|
||||||
|
|
||||||
public CategoryListAdapter(Presenter.ItemList presenter) {
|
|
||||||
this.presenter = presenter;
|
|
||||||
this.itemAdapters = new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemCount() {
|
|
||||||
return presenter.getCategoriesCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBindViewHolder(CategoryViewHolder holder, int position) {
|
|
||||||
presenter.bindViewHolderCategory(holder, position);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CategoryViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
|
||||||
return presenter.createViewHolderCategory(parent, viewType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addItemAdapter(ItemListAdapter adapter) {
|
|
||||||
itemAdapters.add(adapter);
|
|
||||||
adapter.notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
public void notifyItemAdapters() {
|
|
||||||
for (ItemListAdapter adapter : itemAdapters) {
|
|
||||||
adapter.notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,18 +1,35 @@
|
||||||
package hikapro.com.backpack.presenter.adapters;
|
package hikapro.com.backpack.presenter.adapters;
|
||||||
|
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.os.Handler;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import hikapro.com.backpack.R;
|
||||||
|
import hikapro.com.backpack.model.Model;
|
||||||
|
import hikapro.com.backpack.model.entities.Category;
|
||||||
|
import hikapro.com.backpack.model.entities.Item;
|
||||||
|
import hikapro.com.backpack.presenter.ItemListPresenter;
|
||||||
import hikapro.com.backpack.presenter.Presenter;
|
import hikapro.com.backpack.presenter.Presenter;
|
||||||
|
import hikapro.com.backpack.presenter.adapters.helper.items.StickyHeaderAdapter;
|
||||||
|
import hikapro.com.backpack.view.recycler.HeaderViewHolder;
|
||||||
import hikapro.com.backpack.view.recycler.ItemViewHolder;
|
import hikapro.com.backpack.view.recycler.ItemViewHolder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by tariel on 20/04/16.
|
* Created by tariel on 01/05/16.
|
||||||
*/
|
*/
|
||||||
public class ItemListAdapter extends RecyclerView.Adapter<ItemViewHolder> {
|
public class ItemListAdapter extends RecyclerView.Adapter<ItemViewHolder> implements StickyHeaderAdapter<HeaderViewHolder> {
|
||||||
|
|
||||||
|
private static final int PENDING_REMOVAL_TIMEOUT = 4000; // 4sec
|
||||||
|
|
||||||
|
boolean undoOn; // is undo on, you can turn it on from the toolbar menu
|
||||||
|
private Handler handler = new Handler(); // hanlder for running delayed runnables
|
||||||
|
HashMap<Item, Runnable> pendingRunables = new HashMap<>(); // map of items to pending runnables, so we can cancel a removal if need be
|
||||||
private Presenter.ItemList presenter;
|
private Presenter.ItemList presenter;
|
||||||
private int categoryId;
|
|
||||||
|
|
||||||
public ItemListAdapter(Presenter.ItemList presenter) {
|
public ItemListAdapter(Presenter.ItemList presenter) {
|
||||||
this.presenter = presenter;
|
this.presenter = presenter;
|
||||||
|
@ -20,19 +37,151 @@ public class ItemListAdapter extends RecyclerView.Adapter<ItemViewHolder> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemCount() {
|
public int getItemCount() {
|
||||||
return presenter.getItemsCount(categoryId);
|
int res = presenter.getModel().getItemsCount();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int position) {
|
||||||
|
return presenter.getModel().getItemByPosition(position).getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(final ItemViewHolder holder, final int position) {
|
||||||
|
|
||||||
|
final Item item = presenter.getModel().getItemByPosition(position);
|
||||||
|
if (presenter.getModel().isPendingRemoval(item)) {
|
||||||
|
// we need to show the "undo" state of the row
|
||||||
|
holder.itemView.setBackgroundColor(Color.RED);
|
||||||
|
holder.title.setVisibility(View.GONE);
|
||||||
|
holder.undoButton.setVisibility(View.VISIBLE);
|
||||||
|
holder.undoButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
// user wants to undo the removal, let's cancel the pending task
|
||||||
|
Runnable pendingRemovalRunnable = pendingRunables.get(item);
|
||||||
|
pendingRunables.remove(item);
|
||||||
|
if (pendingRemovalRunnable != null) handler.removeCallbacks(pendingRemovalRunnable);
|
||||||
|
presenter.getModel().pendingRemoveCancel(item);
|
||||||
|
// this will rebind the row in "normal" state
|
||||||
|
notifyItemChanged(position);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
holder.title.setVisibility(View.VISIBLE);
|
||||||
|
holder.title.setText(item.getName());
|
||||||
|
holder.id = item.getId();
|
||||||
|
holder.title.setOnClickListener(new android.view.View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
presenter.clickItem(holder.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
holder.categoryId = item.getCategory();
|
||||||
|
holder.itemView.setBackgroundColor(0x33FF99);
|
||||||
|
holder.undoButton.setVisibility(View.GONE);
|
||||||
|
holder.undoButton.setOnClickListener(null);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||||
return presenter.createViewHolderItem(parent, viewType);
|
ItemViewHolder viewHolder;
|
||||||
|
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_item,
|
||||||
|
parent, false);
|
||||||
|
viewHolder = new ItemViewHolder(v);
|
||||||
|
return viewHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUndoOn(boolean undoOn) {
|
||||||
|
this.undoOn = undoOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUndoOn() {
|
||||||
|
return undoOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(Item item) {
|
||||||
|
presenter.getModel().insertItem(item);
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
presenter.getModel().clear();
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void filter(String query) {
|
||||||
|
presenter.getModel().filter(query);
|
||||||
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(ItemViewHolder holder, int position) {
|
public void setHasStableIds(boolean hasStableIds) {
|
||||||
presenter.bindViewHolderItem(holder, position, categoryId);
|
super.setHasStableIds(hasStableIds);
|
||||||
}
|
}
|
||||||
public void setCategoryId(int categoryId) {
|
|
||||||
this.categoryId = categoryId;
|
@Override
|
||||||
|
public long getHeaderId(int position) {
|
||||||
|
/*if (position == 0) {
|
||||||
|
return -1;
|
||||||
|
} else {*/
|
||||||
|
return presenter.getModel().getHeaderId(position);
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HeaderViewHolder onCreateHeaderViewHolder(ViewGroup parent) {
|
||||||
|
HeaderViewHolder viewHolder;
|
||||||
|
View v = LayoutInflater.from(parent.getContext())
|
||||||
|
.inflate(R.layout.view_header, parent, false);
|
||||||
|
viewHolder = new HeaderViewHolder(v);
|
||||||
|
return viewHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindHeaderViewHolder(HeaderViewHolder holder, int position) {
|
||||||
|
Category category = presenter.getModel().getCategoryByPosition(position);
|
||||||
|
holder.id = category.getId();
|
||||||
|
holder.title.setText(category.getName());
|
||||||
|
holder.title.setBackgroundColor(0x2B1E15);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pendingRemoval(final int position) {
|
||||||
|
final Item item = presenter.getModel().getItemByPosition(position);
|
||||||
|
|
||||||
|
if (! presenter.getModel().isPendingRemoval(item)) {
|
||||||
|
presenter.getModel().pendingRemove(item);
|
||||||
|
// this will redraw row in "undo" state
|
||||||
|
notifyItemChanged(position);
|
||||||
|
// let's create, store and post a runnable to remove the item
|
||||||
|
Runnable pendingRemovalRunnable = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
remove(item, position);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
handler.postDelayed(pendingRemovalRunnable, PENDING_REMOVAL_TIMEOUT);
|
||||||
|
pendingRunables.put(item, pendingRemovalRunnable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(Item item, int position) {
|
||||||
|
presenter.getModel().deleteItem(item);
|
||||||
|
notifyItemRemoved(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(int position) {
|
||||||
|
Item item = presenter.getModel().getItemByPosition(position);
|
||||||
|
presenter.getModel().deleteItem(item);
|
||||||
|
notifyItemRemoved(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPendingRemoval(int position) {
|
||||||
|
Item item = presenter.getModel().getItemByPosition(position);
|
||||||
|
return presenter.getModel().isPendingRemoval(item);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,12 +4,13 @@ import android.support.v7.widget.RecyclerView;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import hikapro.com.backpack.presenter.SetListPresenter;
|
import hikapro.com.backpack.presenter.SetListPresenter;
|
||||||
|
import hikapro.com.backpack.presenter.adapters.helper.sets.ItemTouchHelperAdapter;
|
||||||
import hikapro.com.backpack.view.recycler.SetViewHolder;
|
import hikapro.com.backpack.view.recycler.SetViewHolder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by tariel on 20/04/16.
|
* Created by tariel on 20/04/16.
|
||||||
*/
|
*/
|
||||||
public class SetListAdapter extends RecyclerView.Adapter<SetViewHolder> {
|
public class SetListAdapter extends RecyclerView.Adapter<SetViewHolder> implements ItemTouchHelperAdapter{
|
||||||
|
|
||||||
private SetListPresenter presenter;
|
private SetListPresenter presenter;
|
||||||
|
|
||||||
|
@ -31,4 +32,16 @@ public class SetListAdapter extends RecyclerView.Adapter<SetViewHolder> {
|
||||||
public int getItemCount() {
|
public int getItemCount() {
|
||||||
return presenter.getSetsCount();
|
return presenter.getSetsCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//GLM_add_resources_SetList
|
||||||
|
@Override
|
||||||
|
public void onItemDismiss(int position) {
|
||||||
|
presenter.onItemDismiss(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
//GLM_add_resources_SetList
|
||||||
|
@Override
|
||||||
|
public boolean onItemMove(int fromPosition, int toPosition) {
|
||||||
|
return presenter.onItemMove(fromPosition, toPosition);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
package hikapro.com.backpack.presenter.adapters.helper.items;
|
||||||
|
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tariel on 30/04/16.
|
||||||
|
*/
|
||||||
|
public class DimensionCalculator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populates {@link Rect} with margins for any view.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param margins rect to populate
|
||||||
|
* @param view for which to get margins
|
||||||
|
*/
|
||||||
|
public void initMargins(Rect margins, View view) {
|
||||||
|
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
|
||||||
|
|
||||||
|
if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
|
||||||
|
ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) layoutParams;
|
||||||
|
initMarginRect(margins, marginLayoutParams);
|
||||||
|
} else {
|
||||||
|
margins.set(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts {@link ViewGroup.MarginLayoutParams} into a representative {@link Rect}.
|
||||||
|
*
|
||||||
|
* @param marginRect Rect to be initialized with margins coordinates, where
|
||||||
|
* {@link ViewGroup.MarginLayoutParams#leftMargin} is equivalent to {@link Rect#left}, etc.
|
||||||
|
* @param marginLayoutParams margins to populate the Rect with
|
||||||
|
*/
|
||||||
|
private void initMarginRect(Rect marginRect, ViewGroup.MarginLayoutParams marginLayoutParams) {
|
||||||
|
marginRect.set(
|
||||||
|
marginLayoutParams.leftMargin,
|
||||||
|
marginLayoutParams.topMargin,
|
||||||
|
marginLayoutParams.rightMargin,
|
||||||
|
marginLayoutParams.bottomMargin
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
package hikapro.com.backpack.presenter.adapters.helper.items;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.TypedArray;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
|
||||||
|
public class DividerDecoration extends RecyclerView.ItemDecoration {
|
||||||
|
|
||||||
|
private static final int[] ATTRS = new int[]{
|
||||||
|
android.R.attr.listDivider
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
|
||||||
|
|
||||||
|
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
|
||||||
|
|
||||||
|
private Drawable mDivider;
|
||||||
|
|
||||||
|
public DividerDecoration(Context context) {
|
||||||
|
final TypedArray a = context.obtainStyledAttributes(ATTRS);
|
||||||
|
mDivider = a.getDrawable(0);
|
||||||
|
a.recycle();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getOrientation(RecyclerView parent) {
|
||||||
|
LinearLayoutManager layoutManager;
|
||||||
|
try {
|
||||||
|
layoutManager = (LinearLayoutManager) parent.getLayoutManager();
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
throw new IllegalStateException("DividerDecoration can only be used with a " +
|
||||||
|
"LinearLayoutManager.", e);
|
||||||
|
}
|
||||||
|
return layoutManager.getOrientation();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
|
||||||
|
super.onDraw(c, parent, state);
|
||||||
|
|
||||||
|
if (getOrientation(parent) == VERTICAL_LIST) {
|
||||||
|
drawVertical(c, parent);
|
||||||
|
} else {
|
||||||
|
drawHorizontal(c, parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawVertical(Canvas c, RecyclerView parent) {
|
||||||
|
final int left = parent.getPaddingLeft();
|
||||||
|
final int right = parent.getWidth() - parent.getPaddingRight();
|
||||||
|
final int recyclerViewTop = parent.getPaddingTop();
|
||||||
|
final int recyclerViewBottom = parent.getHeight() - parent.getPaddingBottom();
|
||||||
|
final int childCount = parent.getChildCount();
|
||||||
|
for (int i = 0; i < childCount; i++) {
|
||||||
|
final View child = parent.getChildAt(i);
|
||||||
|
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
|
||||||
|
.getLayoutParams();
|
||||||
|
final int top = Math.max(recyclerViewTop, child.getBottom() + params.bottomMargin);
|
||||||
|
final int bottom = Math.min(recyclerViewBottom, top + mDivider.getIntrinsicHeight());
|
||||||
|
mDivider.setBounds(left, top, right, bottom);
|
||||||
|
mDivider.draw(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawHorizontal(Canvas c, RecyclerView parent) {
|
||||||
|
final int top = parent.getPaddingTop();
|
||||||
|
final int bottom = parent.getHeight() - parent.getPaddingBottom();
|
||||||
|
final int recyclerViewLeft = parent.getPaddingLeft();
|
||||||
|
final int recyclerViewRight = parent.getWidth() - parent.getPaddingRight();
|
||||||
|
final int childCount = parent.getChildCount();
|
||||||
|
for (int i = 0; i < childCount; i++) {
|
||||||
|
final View child = parent.getChildAt(i);
|
||||||
|
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
|
||||||
|
.getLayoutParams();
|
||||||
|
final int left = Math.max(recyclerViewLeft, child.getRight() + params.rightMargin);
|
||||||
|
final int right = Math.min(recyclerViewRight, left + mDivider.getIntrinsicHeight());
|
||||||
|
mDivider.setBounds(left, top, right, bottom);
|
||||||
|
mDivider.draw(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
|
||||||
|
super.getItemOffsets(outRect, view, parent, state);
|
||||||
|
if (getOrientation(parent) == VERTICAL_LIST) {
|
||||||
|
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
|
||||||
|
} else {
|
||||||
|
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,256 @@
|
||||||
|
package hikapro.com.backpack.presenter.adapters.helper.items;
|
||||||
|
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tariel on 30/04/16.
|
||||||
|
*/
|
||||||
|
public class HeaderPositionCalculator {
|
||||||
|
|
||||||
|
private final StickyHeaderAdapter adapter;
|
||||||
|
private final HeaderProvider headerProvider;
|
||||||
|
private final DimensionCalculator dimensionCalculator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The following fields are used as buffers for internal calculations. Their sole purpose is to avoid
|
||||||
|
* allocating new Rect every time we need one.
|
||||||
|
*/
|
||||||
|
private final Rect tempRect1 = new Rect();
|
||||||
|
private final Rect tempRect2 = new Rect();
|
||||||
|
|
||||||
|
public HeaderPositionCalculator(StickyHeaderAdapter adapter, HeaderProvider headerProvider,
|
||||||
|
DimensionCalculator dimensionCalculator) {
|
||||||
|
this.adapter = adapter;
|
||||||
|
this.headerProvider = headerProvider;
|
||||||
|
this.dimensionCalculator = dimensionCalculator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if a view should have a sticky header.
|
||||||
|
* The view has a sticky header if:
|
||||||
|
* 1. It is the first element in the recycler view
|
||||||
|
* 2. It has a valid ID associated to its position
|
||||||
|
*
|
||||||
|
* @param itemView given by the RecyclerView
|
||||||
|
* @param orientation of the Recyclerview
|
||||||
|
* @param position of the list item in question
|
||||||
|
* @return True if the view should have a sticky header
|
||||||
|
*/
|
||||||
|
public boolean hasStickyHeader(View itemView, int orientation, int position) {
|
||||||
|
int offset, margin;
|
||||||
|
dimensionCalculator.initMargins(tempRect1, itemView);
|
||||||
|
if (orientation == LinearLayout.VERTICAL) {
|
||||||
|
offset = itemView.getTop();
|
||||||
|
margin = tempRect1.top;
|
||||||
|
} else {
|
||||||
|
offset = itemView.getLeft();
|
||||||
|
margin = tempRect1.left;
|
||||||
|
}
|
||||||
|
boolean ret = offset <= margin;
|
||||||
|
ret = ret && adapter.getHeaderId(position) >= 0;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if an item in the list should have a header that is different than the item in the
|
||||||
|
* list that immediately precedes it. Items with no headers will always return false.
|
||||||
|
*
|
||||||
|
* @param position of the list item in questions
|
||||||
|
* @param isReverseLayout TRUE if layout manager has flag isReverseLayout
|
||||||
|
* @return true if this item has a different header than the previous item in the list
|
||||||
|
*/
|
||||||
|
public boolean hasNewHeader(int position) {
|
||||||
|
if (indexOutOfBounds(position)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
long headerId = adapter.getHeaderId(position);
|
||||||
|
|
||||||
|
if (headerId < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
long nextItemHeaderId = -1;//TODO -1
|
||||||
|
int nextItemPosition = position - 1; // TODO -1
|
||||||
|
if (!indexOutOfBounds(nextItemPosition)) {
|
||||||
|
nextItemHeaderId = adapter.getHeaderId(nextItemPosition);
|
||||||
|
}
|
||||||
|
int firstItemPosition = 0;
|
||||||
|
|
||||||
|
return position == firstItemPosition || headerId != nextItemHeaderId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean indexOutOfBounds(int position) {
|
||||||
|
return position < 0 || position >= adapter.getItemCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initHeaderBounds(Rect bounds, RecyclerView recyclerView, View header, View firstView, boolean firstHeader) {
|
||||||
|
initDefaultHeaderOffset(bounds, recyclerView, header, firstView, LinearLayout.VERTICAL);
|
||||||
|
|
||||||
|
if (firstHeader && isStickyHeaderBeingPushedOffscreen(recyclerView, header)) {
|
||||||
|
View viewAfterNextHeader = getFirstViewUnobscuredByHeader(recyclerView, header);
|
||||||
|
int firstViewUnderHeaderPosition = recyclerView.getChildAdapterPosition(viewAfterNextHeader);
|
||||||
|
View secondHeader = headerProvider.getHeader(recyclerView, firstViewUnderHeaderPosition);
|
||||||
|
translateHeaderWithNextHeader(recyclerView, LinearLayout.VERTICAL, bounds,
|
||||||
|
header, viewAfterNextHeader, secondHeader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initDefaultHeaderOffset(Rect headerMargins, RecyclerView recyclerView, View header, View firstView, int orientation) {
|
||||||
|
int translationX, translationY;
|
||||||
|
dimensionCalculator.initMargins(tempRect1, header);
|
||||||
|
|
||||||
|
ViewGroup.LayoutParams layoutParams = firstView.getLayoutParams();
|
||||||
|
int leftMargin = 0;
|
||||||
|
int topMargin = 0;
|
||||||
|
if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
|
||||||
|
ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) layoutParams;
|
||||||
|
leftMargin = marginLayoutParams.leftMargin;
|
||||||
|
topMargin = marginLayoutParams.topMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orientation == LinearLayoutManager.VERTICAL) {
|
||||||
|
translationX = firstView.getLeft() - leftMargin + tempRect1.left;
|
||||||
|
translationY = Math.max(
|
||||||
|
firstView.getTop() - topMargin - header.getHeight() - tempRect1.bottom,
|
||||||
|
getListTop(recyclerView) + tempRect1.top);
|
||||||
|
} else {
|
||||||
|
translationY = firstView.getTop() - topMargin + tempRect1.top;
|
||||||
|
translationX = Math.max(
|
||||||
|
firstView.getLeft() - leftMargin - header.getWidth() - tempRect1.right,
|
||||||
|
getListLeft(recyclerView) + tempRect1.left);
|
||||||
|
}
|
||||||
|
|
||||||
|
headerMargins.set(translationX, translationY, translationX + header.getWidth(),
|
||||||
|
translationY + header.getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isStickyHeaderBeingPushedOffscreen(RecyclerView recyclerView, View stickyHeader) {
|
||||||
|
View viewAfterHeader = getFirstViewUnobscuredByHeader(recyclerView, stickyHeader);
|
||||||
|
int firstViewUnderHeaderPosition = recyclerView.getChildAdapterPosition(viewAfterHeader);
|
||||||
|
if (firstViewUnderHeaderPosition == RecyclerView.NO_POSITION) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int orientation = LinearLayoutManager.VERTICAL;
|
||||||
|
|
||||||
|
if (firstViewUnderHeaderPosition > 0 && hasNewHeader(firstViewUnderHeaderPosition)) {
|
||||||
|
View nextHeader = headerProvider.getHeader(recyclerView, firstViewUnderHeaderPosition);
|
||||||
|
dimensionCalculator.initMargins(tempRect1, nextHeader);
|
||||||
|
dimensionCalculator.initMargins(tempRect2, stickyHeader);
|
||||||
|
|
||||||
|
if (orientation == LinearLayoutManager.VERTICAL) {
|
||||||
|
int topOfNextHeader = viewAfterHeader.getTop() - tempRect1.bottom - nextHeader.getHeight() - tempRect1.top;
|
||||||
|
int bottomOfThisHeader = recyclerView.getPaddingTop() + stickyHeader.getBottom() + tempRect2.top + tempRect2.bottom;
|
||||||
|
if (topOfNextHeader < bottomOfThisHeader) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int leftOfNextHeader = viewAfterHeader.getLeft() - tempRect1.right - nextHeader.getWidth() - tempRect1.left;
|
||||||
|
int rightOfThisHeader = recyclerView.getPaddingLeft() + stickyHeader.getRight() + tempRect2.left + tempRect2.right;
|
||||||
|
if (leftOfNextHeader < rightOfThisHeader) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void translateHeaderWithNextHeader(RecyclerView recyclerView, int orientation, Rect translation,
|
||||||
|
View currentHeader, View viewAfterNextHeader, View nextHeader) {
|
||||||
|
dimensionCalculator.initMargins(tempRect1, nextHeader);
|
||||||
|
dimensionCalculator.initMargins(tempRect2, currentHeader);
|
||||||
|
if (orientation == LinearLayoutManager.VERTICAL) {
|
||||||
|
int topOfStickyHeader = getListTop(recyclerView) + tempRect2.top + tempRect2.bottom;
|
||||||
|
int shiftFromNextHeader = viewAfterNextHeader.getTop() - nextHeader.getHeight() - tempRect1.bottom - tempRect1.top - currentHeader.getHeight() - topOfStickyHeader;
|
||||||
|
if (shiftFromNextHeader < topOfStickyHeader) {
|
||||||
|
translation.top += shiftFromNextHeader;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int leftOfStickyHeader = getListLeft(recyclerView) + tempRect2.left + tempRect2.right;
|
||||||
|
int shiftFromNextHeader = viewAfterNextHeader.getLeft() - nextHeader.getWidth() - tempRect1.right - tempRect1.left - currentHeader.getWidth() - leftOfStickyHeader;
|
||||||
|
if (shiftFromNextHeader < leftOfStickyHeader) {
|
||||||
|
translation.left += shiftFromNextHeader;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the first item currently in the RecyclerView that is not obscured by a header.
|
||||||
|
*
|
||||||
|
* @param parent Recyclerview containing all the list items
|
||||||
|
* @return first item that is fully beneath a header
|
||||||
|
*/
|
||||||
|
private View getFirstViewUnobscuredByHeader(RecyclerView parent, View firstHeader) {
|
||||||
|
int step = 1;
|
||||||
|
int from = 0;
|
||||||
|
for (int i = from; i >= 0 && i <= parent.getChildCount() - 1; i += step) {
|
||||||
|
View child = parent.getChildAt(i);
|
||||||
|
if (!itemIsObscuredByHeader(parent, child, firstHeader, LinearLayout.VERTICAL)) {
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if an item is obscured by a header
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param parent
|
||||||
|
* @param item to determine if obscured by header
|
||||||
|
* @param header that might be obscuring the item
|
||||||
|
* @param orientation of the {@link RecyclerView}
|
||||||
|
* @return true if the item view is obscured by the header view
|
||||||
|
*/
|
||||||
|
private boolean itemIsObscuredByHeader(RecyclerView parent, View item, View header, int orientation) {
|
||||||
|
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) item.getLayoutParams();
|
||||||
|
dimensionCalculator.initMargins(tempRect1, header);
|
||||||
|
|
||||||
|
int adapterPosition = parent.getChildAdapterPosition(item);
|
||||||
|
if (adapterPosition == RecyclerView.NO_POSITION || headerProvider.getHeader(parent, adapterPosition) != header) {
|
||||||
|
// Resolves https://github.com/timehop/sticky-headers-recyclerview/issues/36
|
||||||
|
// Handles an edge case where a trailing header is smaller than the current sticky header.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orientation == LinearLayoutManager.VERTICAL) {
|
||||||
|
int itemTop = item.getTop() - layoutParams.topMargin;
|
||||||
|
int headerBottom = getListTop(parent) + header.getBottom() + tempRect1.bottom + tempRect1.top;
|
||||||
|
if (itemTop >= headerBottom) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int itemLeft = item.getLeft() - layoutParams.leftMargin;
|
||||||
|
int headerRight = getListLeft(parent) + header.getRight() + tempRect1.right + tempRect1.left;
|
||||||
|
if (itemLeft >= headerRight) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getListTop(RecyclerView view) {
|
||||||
|
if (view.getLayoutManager().getClipToPadding()) {
|
||||||
|
return view.getPaddingTop();
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getListLeft(RecyclerView view) {
|
||||||
|
if (view.getLayoutManager().getClipToPadding()) {
|
||||||
|
return view.getPaddingLeft();
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package hikapro.com.backpack.presenter.adapters.helper.items;
|
||||||
|
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tariel on 30/04/16.
|
||||||
|
*/
|
||||||
|
public interface HeaderProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will provide a header view for a given position in the RecyclerView
|
||||||
|
*
|
||||||
|
* @param recyclerView that will display the header
|
||||||
|
* @param position that will be headed by the header
|
||||||
|
* @return a header view for the given position and list
|
||||||
|
*/
|
||||||
|
View getHeader(RecyclerView recyclerView, int position);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: describe this functionality and its necessity
|
||||||
|
*/
|
||||||
|
void invalidate();
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
package hikapro.com.backpack.presenter.adapters.helper.items;
|
||||||
|
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tariel on 30/04/16.
|
||||||
|
*/
|
||||||
|
public class HeaderRenderer {
|
||||||
|
|
||||||
|
private final DimensionCalculator dimensionCalculator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The following field is used as a buffer for internal calculations. Its sole purpose is to avoid
|
||||||
|
* allocating new Rect every time we need one.
|
||||||
|
*/
|
||||||
|
private final Rect mTempRect = new Rect();
|
||||||
|
|
||||||
|
public HeaderRenderer() {
|
||||||
|
this.dimensionCalculator = new DimensionCalculator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws a header to a canvas, offsetting by some x and y amount
|
||||||
|
*
|
||||||
|
* @param recyclerView the parent recycler view for drawing the header into
|
||||||
|
* @param canvas the canvas on which to draw the header
|
||||||
|
* @param header the view to draw as the header
|
||||||
|
* @param offset a Rect used to define the x/y offset of the header. Specify x/y offset by setting
|
||||||
|
* the {@link Rect#left} and {@link Rect#top} properties, respectively.
|
||||||
|
*/
|
||||||
|
public void drawHeader(RecyclerView recyclerView, Canvas canvas, View header, Rect offset) {
|
||||||
|
canvas.save();
|
||||||
|
|
||||||
|
if (recyclerView.getLayoutManager().getClipToPadding()) {
|
||||||
|
// Clip drawing of headers to the padding of the RecyclerView. Avoids drawing in the padding
|
||||||
|
initClipRectForHeader(mTempRect, recyclerView, header);
|
||||||
|
canvas.clipRect(mTempRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.translate(offset.left, offset.top);
|
||||||
|
|
||||||
|
header.draw(canvas);
|
||||||
|
canvas.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a clipping rect for the header based on the margins of the header and the padding of the
|
||||||
|
* recycler.
|
||||||
|
* FIXME: Currently right margin in VERTICAL orientation and bottom margin in HORIZONTAL
|
||||||
|
* orientation are clipped so they look accurate, but the headers are not being drawn at the
|
||||||
|
* correctly smaller width and height respectively.
|
||||||
|
*
|
||||||
|
* @param clipRect {@link Rect} for clipping a provided header to the padding of a recycler view
|
||||||
|
* @param recyclerView for which to provide a header
|
||||||
|
* @param header for clipping
|
||||||
|
*/
|
||||||
|
private void initClipRectForHeader(Rect clipRect, RecyclerView recyclerView, View header) {
|
||||||
|
dimensionCalculator.initMargins(clipRect, header);
|
||||||
|
|
||||||
|
clipRect.set(
|
||||||
|
recyclerView.getPaddingLeft(),
|
||||||
|
recyclerView.getPaddingTop(),
|
||||||
|
recyclerView.getWidth() - recyclerView.getPaddingRight() - clipRect.right,
|
||||||
|
recyclerView.getHeight() - recyclerView.getPaddingBottom());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
package hikapro.com.backpack.presenter.adapters.helper.items;
|
||||||
|
|
||||||
|
import android.support.v4.util.LongSparseArray;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tariel on 30/04/16.
|
||||||
|
*/
|
||||||
|
public class HeaderViewCache implements HeaderProvider {
|
||||||
|
|
||||||
|
private final StickyHeaderAdapter adapter;
|
||||||
|
private final LongSparseArray<View> headerViews = new LongSparseArray<>();
|
||||||
|
|
||||||
|
public HeaderViewCache(StickyHeaderAdapter adapter) {
|
||||||
|
this.adapter = adapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getHeader(RecyclerView parent, int position) {
|
||||||
|
long headerId = adapter.getHeaderId(position);
|
||||||
|
|
||||||
|
View header = headerViews.get(headerId);
|
||||||
|
if (header == null) {
|
||||||
|
//TODO - recycle views
|
||||||
|
RecyclerView.ViewHolder viewHolder = adapter.onCreateHeaderViewHolder(parent);
|
||||||
|
adapter.onBindHeaderViewHolder(viewHolder, position);
|
||||||
|
header = viewHolder.itemView;
|
||||||
|
if (header.getLayoutParams() == null) {
|
||||||
|
header.setLayoutParams(new ViewGroup.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||||
|
}
|
||||||
|
|
||||||
|
int widthSpec;
|
||||||
|
int heightSpec;
|
||||||
|
|
||||||
|
widthSpec = View.MeasureSpec.makeMeasureSpec(parent.getWidth(), View.MeasureSpec.EXACTLY);
|
||||||
|
heightSpec = View.MeasureSpec.makeMeasureSpec(parent.getHeight(), View.MeasureSpec.UNSPECIFIED);
|
||||||
|
|
||||||
|
int childWidth = ViewGroup.getChildMeasureSpec(widthSpec,
|
||||||
|
parent.getPaddingLeft() + parent.getPaddingRight(), header.getLayoutParams().width);
|
||||||
|
int childHeight = ViewGroup.getChildMeasureSpec(heightSpec,
|
||||||
|
parent.getPaddingTop() + parent.getPaddingBottom(), header.getLayoutParams().height);
|
||||||
|
header.measure(childWidth, childHeight);
|
||||||
|
header.layout(0, 0, header.getMeasuredWidth(), header.getMeasuredHeight());
|
||||||
|
headerViews.put(headerId, header);
|
||||||
|
}
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invalidate() {
|
||||||
|
headerViews.clear();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
package hikapro.com.backpack.presenter.adapters.helper.items;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.PorterDuff;
|
||||||
|
import android.graphics.drawable.ColorDrawable;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.support.v4.content.ContextCompat;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import hikapro.com.backpack.R;
|
||||||
|
import hikapro.com.backpack.presenter.adapters.ItemListAdapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tariel on 02/05/16.
|
||||||
|
*/
|
||||||
|
public class ItemSwipeCallback extends ItemTouchHelper.SimpleCallback {
|
||||||
|
|
||||||
|
// we want to cache these and not allocate anything repeatedly in the onChildDraw method
|
||||||
|
Drawable background;
|
||||||
|
Drawable xMark;
|
||||||
|
int xMarkMargin;
|
||||||
|
boolean initiated;
|
||||||
|
ItemListAdapter adapter;
|
||||||
|
Context context;
|
||||||
|
|
||||||
|
public ItemSwipeCallback(int dragDirs, int swipeDirs, ItemListAdapter adapter, Context context) {
|
||||||
|
super(dragDirs, swipeDirs);
|
||||||
|
this.adapter = adapter;
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
background = new ColorDrawable(Color.RED);
|
||||||
|
xMark = ContextCompat.getDrawable(context, R.drawable.ic_clear_24dp);
|
||||||
|
xMark.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP);
|
||||||
|
xMarkMargin = (int) context.getResources().getDimension(R.dimen.ic_clear_margin);
|
||||||
|
initiated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// not important, we don't want drag & drop
|
||||||
|
@Override
|
||||||
|
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
|
||||||
|
int position = viewHolder.getAdapterPosition();
|
||||||
|
if (adapter.isUndoOn() && adapter.isPendingRemoval(position)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return super.getSwipeDirs(recyclerView, viewHolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
|
||||||
|
int swipedPosition = viewHolder.getAdapterPosition();
|
||||||
|
|
||||||
|
boolean undoOn = adapter.isUndoOn();
|
||||||
|
if (undoOn) {
|
||||||
|
adapter.pendingRemoval(swipedPosition);
|
||||||
|
} else {
|
||||||
|
adapter.remove(swipedPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
|
||||||
|
View itemView = viewHolder.itemView;
|
||||||
|
|
||||||
|
// not sure why, but this method get's called for viewholder that are already swiped away
|
||||||
|
if (viewHolder.getAdapterPosition() == -1) {
|
||||||
|
// not interested in those
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!initiated) {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw red background
|
||||||
|
background.setBounds(itemView.getRight() + (int) dX, itemView.getTop(), itemView.getRight(), itemView.getBottom());
|
||||||
|
background.draw(c);
|
||||||
|
|
||||||
|
// draw x mark
|
||||||
|
int itemHeight = itemView.getBottom() - itemView.getTop();
|
||||||
|
int intrinsicWidth = xMark.getIntrinsicWidth();
|
||||||
|
int intrinsicHeight = xMark.getIntrinsicWidth();
|
||||||
|
|
||||||
|
int xMarkLeft = itemView.getRight() - xMarkMargin - intrinsicWidth;
|
||||||
|
int xMarkRight = itemView.getRight() - xMarkMargin;
|
||||||
|
int xMarkTop = itemView.getTop() + (itemHeight - intrinsicHeight)/2;
|
||||||
|
int xMarkBottom = xMarkTop + intrinsicHeight;
|
||||||
|
xMark.setBounds(xMarkLeft, xMarkTop, xMarkRight, xMarkBottom);
|
||||||
|
|
||||||
|
xMark.draw(c);
|
||||||
|
|
||||||
|
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
package hikapro.com.backpack.presenter.adapters.helper.items;
|
||||||
|
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.drawable.ColorDrawable;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tariel on 02/05/16.
|
||||||
|
*/
|
||||||
|
public class ItemSwipeDecoration extends RecyclerView.ItemDecoration {
|
||||||
|
|
||||||
|
// we want to cache this and not allocate anything repeatedly in the onDraw method
|
||||||
|
Drawable background;
|
||||||
|
boolean initiated;
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
background = new ColorDrawable(Color.RED);
|
||||||
|
initiated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
|
||||||
|
|
||||||
|
if (!initiated) {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
// only if animation is in progress
|
||||||
|
if (parent.getItemAnimator().isRunning()) {
|
||||||
|
|
||||||
|
// some items might be animating down and some items might be animating up to close the gap left by the removed item
|
||||||
|
// this is not exclusive, both movement can be happening at the same time
|
||||||
|
// to reproduce this leave just enough items so the first one and the last one would be just a little off screen
|
||||||
|
// then remove one from the middle
|
||||||
|
|
||||||
|
// find first child with translationY > 0
|
||||||
|
// and last one with translationY < 0
|
||||||
|
// we're after a rect that is not covered in recycler-view views at this point in time
|
||||||
|
View lastViewComingDown = null;
|
||||||
|
View firstViewComingUp = null;
|
||||||
|
|
||||||
|
// this is fixed
|
||||||
|
int left = 0;
|
||||||
|
int right = parent.getWidth();
|
||||||
|
|
||||||
|
// this we need to find out
|
||||||
|
int top = 0;
|
||||||
|
int bottom = 0;
|
||||||
|
|
||||||
|
// find relevant translating views
|
||||||
|
int childCount = parent.getLayoutManager().getChildCount();
|
||||||
|
for (int i = 0; i < childCount; i++) {
|
||||||
|
View child = parent.getLayoutManager().getChildAt(i);
|
||||||
|
if (child.getTranslationY() < 0) {
|
||||||
|
// view is coming down
|
||||||
|
lastViewComingDown = child;
|
||||||
|
} else if (child.getTranslationY() > 0) {
|
||||||
|
// view is coming up
|
||||||
|
if (firstViewComingUp == null) {
|
||||||
|
firstViewComingUp = child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastViewComingDown != null && firstViewComingUp != null) {
|
||||||
|
// views are coming down AND going up to fill the void
|
||||||
|
top = lastViewComingDown.getBottom() + (int) lastViewComingDown.getTranslationY();
|
||||||
|
bottom = firstViewComingUp.getTop() + (int) firstViewComingUp.getTranslationY();
|
||||||
|
} else if (lastViewComingDown != null) {
|
||||||
|
// views are going down to fill the void
|
||||||
|
top = lastViewComingDown.getBottom() + (int) lastViewComingDown.getTranslationY();
|
||||||
|
bottom = lastViewComingDown.getBottom();
|
||||||
|
} else if (firstViewComingUp != null) {
|
||||||
|
// views are coming up to fill the void
|
||||||
|
top = firstViewComingUp.getTop();
|
||||||
|
bottom = firstViewComingUp.getTop() + (int) firstViewComingUp.getTranslationY();
|
||||||
|
}
|
||||||
|
|
||||||
|
background.setBounds(left, top, right, bottom);
|
||||||
|
background.draw(c);
|
||||||
|
|
||||||
|
}
|
||||||
|
super.onDraw(c, parent, state);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package hikapro.com.backpack.presenter.adapters.helper.items;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tariel on 30/04/16.
|
||||||
|
*/
|
||||||
|
public interface ItemVisibilityAdapter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Return true the specified adapter position is visible, false otherwise
|
||||||
|
*
|
||||||
|
* The implementation of this method will typically return true if
|
||||||
|
* the position is between the layout manager's findFirstVisibleItemPosition
|
||||||
|
* and findLastVisibleItemPosition (inclusive).
|
||||||
|
*
|
||||||
|
* @param position the adapter position
|
||||||
|
*/
|
||||||
|
boolean isPositionVisible(final int position);
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package hikapro.com.backpack.presenter.adapters.helper.items;
|
||||||
|
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tariel on 01/05/16.
|
||||||
|
*/
|
||||||
|
public interface StickyHeaderAdapter<VH extends RecyclerView.ViewHolder> {
|
||||||
|
|
||||||
|
long getHeaderId(int position);
|
||||||
|
VH onCreateHeaderViewHolder(ViewGroup parent);
|
||||||
|
void onBindHeaderViewHolder(VH holder, int position);
|
||||||
|
int getItemCount();
|
||||||
|
}
|
|
@ -0,0 +1,158 @@
|
||||||
|
package hikapro.com.backpack.presenter.adapters.helper.items;
|
||||||
|
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tariel on 01/05/16.
|
||||||
|
*/
|
||||||
|
public class StickyHeaderDecoration extends RecyclerView.ItemDecoration {
|
||||||
|
|
||||||
|
private final StickyHeaderAdapter adapter;
|
||||||
|
private final ItemVisibilityAdapter visibilityAdapter;
|
||||||
|
private final SparseArray<Rect> headerRects = new SparseArray<>();
|
||||||
|
private final HeaderProvider headerProvider;
|
||||||
|
private final HeaderPositionCalculator headerPositionCalculator;
|
||||||
|
private final HeaderRenderer renderer;
|
||||||
|
private final DimensionCalculator dimensionCalculator;
|
||||||
|
|
||||||
|
private final Rect rect = new Rect();
|
||||||
|
|
||||||
|
|
||||||
|
public StickyHeaderDecoration(StickyHeaderAdapter adapter) {
|
||||||
|
this(adapter, new DimensionCalculator(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private StickyHeaderDecoration(StickyHeaderAdapter adapter,
|
||||||
|
DimensionCalculator dimensionCalculator, ItemVisibilityAdapter visibilityAdapter) {
|
||||||
|
this(adapter, dimensionCalculator, new HeaderRenderer(), new HeaderViewCache(adapter), visibilityAdapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private StickyHeaderDecoration(StickyHeaderAdapter adapter, DimensionCalculator dimensionCalculator,
|
||||||
|
HeaderRenderer headerRenderer, HeaderProvider headerProvider,
|
||||||
|
ItemVisibilityAdapter visibilityAdapter) {
|
||||||
|
this(adapter, headerRenderer, dimensionCalculator, headerProvider,
|
||||||
|
new HeaderPositionCalculator(adapter, headerProvider,
|
||||||
|
dimensionCalculator), visibilityAdapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private StickyHeaderDecoration(StickyHeaderAdapter adapter, HeaderRenderer headerRenderer,
|
||||||
|
DimensionCalculator dimensionCalculator, HeaderProvider headerProvider,
|
||||||
|
HeaderPositionCalculator headerPositionCalculator, ItemVisibilityAdapter visibilityAdapter) {
|
||||||
|
this.adapter = adapter;
|
||||||
|
this.headerProvider = headerProvider;
|
||||||
|
this.renderer = headerRenderer;
|
||||||
|
this.dimensionCalculator = dimensionCalculator;
|
||||||
|
this.headerPositionCalculator = headerPositionCalculator;
|
||||||
|
this.visibilityAdapter = visibilityAdapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
|
||||||
|
super.getItemOffsets(outRect, view, parent, state);
|
||||||
|
|
||||||
|
int itemPosition = parent.getChildAdapterPosition(view);
|
||||||
|
if (itemPosition == RecyclerView.NO_POSITION) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (headerPositionCalculator.hasNewHeader(itemPosition)) {
|
||||||
|
View header = getHeaderView(parent, itemPosition);
|
||||||
|
setItemOffsetsForHeader(outRect, header, LinearLayout.VERTICAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the offsets for the first item in a section to make room for the header view
|
||||||
|
*
|
||||||
|
* @param itemOffsets rectangle to define offsets for the item
|
||||||
|
* @param header view used to calculate offset for the item
|
||||||
|
* @param orientation used to calculate offset for the item
|
||||||
|
*/
|
||||||
|
private void setItemOffsetsForHeader(Rect itemOffsets, View header, int orientation) {
|
||||||
|
dimensionCalculator.initMargins(rect, header);
|
||||||
|
if (orientation == LinearLayoutManager.VERTICAL) {
|
||||||
|
itemOffsets.top = header.getHeight() + rect.top + rect.bottom;
|
||||||
|
} else {
|
||||||
|
itemOffsets.left = header.getWidth() + rect.left +
|
||||||
|
rect.right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
|
||||||
|
super.onDrawOver(c, parent, state);
|
||||||
|
|
||||||
|
final int childCount = parent.getChildCount();
|
||||||
|
if (childCount <= 0 || adapter.getItemCount() <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < childCount; i++) {
|
||||||
|
View itemView = parent.getChildAt(i);
|
||||||
|
int position = parent.getChildAdapterPosition(itemView);
|
||||||
|
if (position == RecyclerView.NO_POSITION) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean hasStickyHeader = headerPositionCalculator.hasStickyHeader(itemView, LinearLayout.VERTICAL, position);
|
||||||
|
if (hasStickyHeader || headerPositionCalculator.hasNewHeader(position)) {
|
||||||
|
View header = headerProvider.getHeader(parent, position);
|
||||||
|
//re-use existing Rect, if any.
|
||||||
|
Rect headerOffset = headerRects.get(position);
|
||||||
|
if (headerOffset == null) {
|
||||||
|
headerOffset = new Rect();
|
||||||
|
headerRects.put(position, headerOffset);
|
||||||
|
}
|
||||||
|
headerPositionCalculator.initHeaderBounds(headerOffset, parent, header, itemView, hasStickyHeader);
|
||||||
|
renderer.drawHeader(parent, c, header, headerOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the position of the header under the specified (x, y) coordinates.
|
||||||
|
*
|
||||||
|
* @param x x-coordinate
|
||||||
|
* @param y y-coordinate
|
||||||
|
* @return position of header, or -1 if not found
|
||||||
|
*/
|
||||||
|
public int findHeaderPositionUnder(int x, int y) {
|
||||||
|
for (int i = 0; i < headerRects.size(); i++) {
|
||||||
|
Rect rect = headerRects.get(headerRects.keyAt(i));
|
||||||
|
if (rect.contains(x, y)) {
|
||||||
|
int position = headerRects.keyAt(i);
|
||||||
|
if (visibilityAdapter == null || visibilityAdapter.isPositionVisible(position)) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the header view for the associated position. If it doesn't exist yet, it will be
|
||||||
|
* created, measured, and laid out.
|
||||||
|
*
|
||||||
|
* @param parent the recyclerview
|
||||||
|
* @param position the position to get the header view for
|
||||||
|
* @return Header view
|
||||||
|
*/
|
||||||
|
public View getHeaderView(RecyclerView parent, int position) {
|
||||||
|
return headerProvider.getHeader(parent, position);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidates cached headers. This does not invalidate the recyclerview, you should do that manually after
|
||||||
|
* calling this method.
|
||||||
|
*/
|
||||||
|
public void invalidateHeaders() {
|
||||||
|
headerProvider.invalidate();
|
||||||
|
headerRects.clear();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package hikapro.com.backpack.presenter.adapters.helper.sets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by N551 on 25.04.2016.
|
||||||
|
*/
|
||||||
|
//GLM_add_resources_SetList
|
||||||
|
public interface ItemTouchHelperAdapter {
|
||||||
|
|
||||||
|
boolean onItemMove(int fromPosition, int toPosition);
|
||||||
|
|
||||||
|
void onItemDismiss(int position);
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package hikapro.com.backpack.presenter.adapters.helper.sets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by N551 on 25.04.2016.
|
||||||
|
*/
|
||||||
|
//GLM_add_resources_SetList
|
||||||
|
public interface ItemTouchHelperViewHolder {
|
||||||
|
|
||||||
|
void onItemSelected();
|
||||||
|
|
||||||
|
void onItemClear();
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package hikapro.com.backpack.presenter.adapters.helper.sets;
|
||||||
|
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by N551 on 25.04.2016.
|
||||||
|
*/
|
||||||
|
//GLM_add_resources_SetList
|
||||||
|
public interface OnStartDragListener {
|
||||||
|
|
||||||
|
void onStartDrag(RecyclerView.ViewHolder viewHolder);
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
package hikapro.com.backpack.presenter.adapters.helper.sets;
|
||||||
|
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by N551 on 25.04.2016.
|
||||||
|
*/
|
||||||
|
//GLM_add_resources_SetList
|
||||||
|
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
|
||||||
|
public static final float ALPHA_FULL = 1.0f;
|
||||||
|
|
||||||
|
private final ItemTouchHelperAdapter mAdapter;
|
||||||
|
|
||||||
|
public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
|
||||||
|
mAdapter = adapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLongPressDragEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isItemViewSwipeEnabled() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
|
||||||
|
|
||||||
|
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
|
||||||
|
final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
|
||||||
|
return makeMovementFlags(dragFlags, swipeFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
|
||||||
|
if (source.getItemViewType() != target.getItemViewType()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify the adapter of the move
|
||||||
|
mAdapter.onItemMove(source.getAdapterPosition(), target.getAdapterPosition());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSwiped(RecyclerView.ViewHolder viewHolder, int i) {
|
||||||
|
// Notify the adapter of the dismissal
|
||||||
|
mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
|
||||||
|
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
|
||||||
|
// Fade out the view as it is swiped out of the parent's bounds
|
||||||
|
final float alpha = ALPHA_FULL - Math.abs(dX) / (float) viewHolder.itemView.getWidth();
|
||||||
|
viewHolder.itemView.setAlpha(alpha);
|
||||||
|
viewHolder.itemView.setTranslationX(dX);
|
||||||
|
} else {
|
||||||
|
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
|
||||||
|
// We only want the active item to change
|
||||||
|
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
|
||||||
|
if (viewHolder instanceof ItemTouchHelperViewHolder) {
|
||||||
|
// Let the view holder know that this item is being moved or dragged
|
||||||
|
ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
|
||||||
|
itemViewHolder.onItemSelected();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onSelectedChanged(viewHolder, actionState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
|
||||||
|
super.clearView(recyclerView, viewHolder);
|
||||||
|
|
||||||
|
viewHolder.itemView.setAlpha(ALPHA_FULL);
|
||||||
|
|
||||||
|
if (viewHolder instanceof ItemTouchHelperViewHolder) {
|
||||||
|
// Tell the view holder it's time to restore the idle state
|
||||||
|
ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
|
||||||
|
itemViewHolder.onItemClear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,11 @@
|
||||||
package hikapro.com.backpack.view;
|
package hikapro.com.backpack.view;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import hikapro.com.backpack.model.entities.Item;
|
import hikapro.com.backpack.model.entities.Item;
|
||||||
import hikapro.com.backpack.model.entities.Set;
|
import hikapro.com.backpack.model.entities.Set;
|
||||||
import hikapro.com.backpack.presenter.Presenter;
|
import hikapro.com.backpack.presenter.Presenter;
|
||||||
|
import hikapro.com.backpack.presenter.adapters.helper.sets.OnStartDragListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by tariel on 19/04/16.
|
* Created by tariel on 19/04/16.
|
||||||
|
@ -19,6 +19,9 @@ public interface View {
|
||||||
interface SetList extends Base {
|
interface SetList extends Base {
|
||||||
void showItemList(Set set);
|
void showItemList(Set set);
|
||||||
void setPresenter(Presenter.SetList presenter);
|
void setPresenter(Presenter.SetList presenter);
|
||||||
|
|
||||||
|
//GLM_add_resources_SetList
|
||||||
|
OnStartDragListener getOnStartDragListener();
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ItemList extends Base {
|
interface ItemList extends Base {
|
||||||
|
|
|
@ -7,8 +7,12 @@ import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.SearchView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import hikapro.com.backpack.R;
|
import hikapro.com.backpack.R;
|
||||||
|
@ -18,7 +22,8 @@ import hikapro.com.backpack.presenter.ItemListPresenter;
|
||||||
import hikapro.com.backpack.presenter.Presenter;
|
import hikapro.com.backpack.presenter.Presenter;
|
||||||
|
|
||||||
|
|
||||||
public class ItemListFragment extends Fragment implements hikapro.com.backpack.view.View.ItemList {
|
public class ItemListFragment extends Fragment implements hikapro.com.backpack.view.View.ItemList,
|
||||||
|
SearchView.OnQueryTextListener {
|
||||||
|
|
||||||
private static final String BUNDLE_SET_KEY = "BUNDLE_SET_KEY";
|
private static final String BUNDLE_SET_KEY = "BUNDLE_SET_KEY";
|
||||||
private hikapro.com.backpack.view.View.ActivityCallback activityCallback;
|
private hikapro.com.backpack.view.View.ActivityCallback activityCallback;
|
||||||
|
@ -40,6 +45,34 @@ public class ItemListFragment extends Fragment implements hikapro.com.backpack.v
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
|
|
||||||
|
inflater.inflate(R.menu.menu_main, menu);
|
||||||
|
|
||||||
|
final MenuItem item = menu.findItem(R.id.action_search);
|
||||||
|
final SearchView searchView = (SearchView) item.getActionView();
|
||||||
|
searchView.setOnQueryTextListener(this);
|
||||||
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onQueryTextSubmit(String query) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onQueryTextChange(String newText) {
|
||||||
|
presenter.filter(newText);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
// life cycle -->
|
// life cycle -->
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(Context context) {
|
public void onAttach(Context context) {
|
||||||
|
@ -65,14 +98,15 @@ public class ItemListFragment extends Fragment implements hikapro.com.backpack.v
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
setHasOptionsMenu(true);
|
||||||
Log.i(this.toString(), "onCreate");
|
Log.i(this.toString(), "onCreate");
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
// Inflate the layout for this fragment
|
// Inflate the layout for this fragment
|
||||||
View view = presenter.onCreateView(inflater, container, savedInstanceState);
|
|
||||||
presenter.setView(this);
|
presenter.setView(this);
|
||||||
|
View view = presenter.onCreateView(inflater, container, savedInstanceState);
|
||||||
Log.i(this.toString(), "onCreateView");
|
Log.i(this.toString(), "onCreateView");
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,21 @@
|
||||||
package hikapro.com.backpack.view.fragments;
|
package hikapro.com.backpack.view.fragments;
|
||||||
|
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import hikapro.com.backpack.R;
|
|
||||||
import hikapro.com.backpack.model.entities.Set;
|
import hikapro.com.backpack.model.entities.Set;
|
||||||
import hikapro.com.backpack.presenter.Presenter;
|
import hikapro.com.backpack.presenter.Presenter;
|
||||||
import hikapro.com.backpack.presenter.SetListPresenter;
|
import hikapro.com.backpack.presenter.adapters.helper.sets.OnStartDragListener;
|
||||||
|
|
||||||
public class SetListFragment extends Fragment implements hikapro.com.backpack.view.View.SetList {
|
public class SetListFragment extends Fragment implements hikapro.com.backpack.view.View.SetList,
|
||||||
|
OnStartDragListener {
|
||||||
|
|
||||||
private Presenter.SetList presenter;
|
private Presenter.SetList presenter;
|
||||||
private hikapro.com.backpack.view.View.ActivityCallback activityCallback;
|
private hikapro.com.backpack.view.View.ActivityCallback activityCallback;
|
||||||
|
@ -60,10 +59,12 @@ public class SetListFragment extends Fragment implements hikapro.com.backpack.vi
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
// Inflate the layout for this fragment
|
|
||||||
View view = presenter.onCreateView(inflater, container, savedInstanceState);
|
|
||||||
presenter.setView(this);
|
|
||||||
Log.i(this.toString(), "onCreateView");
|
Log.i(this.toString(), "onCreateView");
|
||||||
|
// Inflate the layout for this fragment
|
||||||
|
presenter.setView(this);
|
||||||
|
View view = presenter.onCreateView(inflater, container, savedInstanceState);
|
||||||
|
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
|
@ -130,4 +131,17 @@ public class SetListFragment extends Fragment implements hikapro.com.backpack.vi
|
||||||
public void setPresenter(Presenter.SetList presenter) {
|
public void setPresenter(Presenter.SetList presenter) {
|
||||||
this.presenter = presenter;
|
this.presenter = presenter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//GLM_add_resources_SetList
|
||||||
|
@Override
|
||||||
|
public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
|
||||||
|
presenter.onStartDrag(viewHolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
//GLM_add_resources_SetList
|
||||||
|
@Override
|
||||||
|
public OnStartDragListener getOnStartDragListener() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
package hikapro.com.backpack.view.recycler;
|
|
||||||
|
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
|
||||||
import android.support.v7.widget.RecyclerView;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import hikapro.com.backpack.R;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by tariel on 20/04/16.
|
|
||||||
*/
|
|
||||||
public class CategoryViewHolder extends RecyclerView.ViewHolder {
|
|
||||||
|
|
||||||
public LinearLayout section;
|
|
||||||
public TextView sectionText;
|
|
||||||
public RecyclerView itemsRecycler;
|
|
||||||
|
|
||||||
public CategoryViewHolder(View v) {
|
|
||||||
super(v);
|
|
||||||
setupViews(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupViews(View view) {
|
|
||||||
section = (LinearLayout)view.findViewById(R.id.linear);
|
|
||||||
sectionText = (TextView)view.findViewById(R.id.section_text);
|
|
||||||
itemsRecycler = (RecyclerView) view.findViewById(R.id.category_inner_recycler);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
package hikapro.com.backpack.view.recycler;
|
||||||
|
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import hikapro.com.backpack.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tariel on 01/05/16.
|
||||||
|
*/
|
||||||
|
public class HeaderViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
|
public int id;
|
||||||
|
public TextView title;
|
||||||
|
|
||||||
|
public HeaderViewHolder(View v) {
|
||||||
|
super(v);
|
||||||
|
setupViews(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupViews(View view) {
|
||||||
|
title = (TextView) view.findViewById(R.id.header);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,18 +2,21 @@ package hikapro.com.backpack.view.recycler;
|
||||||
|
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.widget.Button;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import hikapro.com.backpack.R;
|
import hikapro.com.backpack.R;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by tariel on 20/04/16.
|
* Created by tariel on 01/05/16.
|
||||||
*/
|
*/
|
||||||
public class ItemViewHolder extends RecyclerView.ViewHolder {
|
public class ItemViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
public TextView title;
|
|
||||||
public int id;
|
public int id;
|
||||||
public int categoryId;
|
public int categoryId;
|
||||||
|
public TextView title;
|
||||||
|
public Button undoButton;
|
||||||
|
|
||||||
public ItemViewHolder(View v) {
|
public ItemViewHolder(View v) {
|
||||||
super(v);
|
super(v);
|
||||||
|
@ -21,6 +24,7 @@ public class ItemViewHolder extends RecyclerView.ViewHolder {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupViews(View view) {
|
private void setupViews(View view) {
|
||||||
title = (TextView) view.findViewById(R.id.item_text);
|
title = (TextView) view.findViewById(R.id.item_txt);
|
||||||
|
undoButton = (Button) view.findViewById(R.id.undo_button);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +1,53 @@
|
||||||
package hikapro.com.backpack.view.recycler;
|
package hikapro.com.backpack.view.recycler;
|
||||||
|
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
import android.support.v7.widget.CardView;
|
import android.support.v7.widget.CardView;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import hikapro.com.backpack.R;
|
import hikapro.com.backpack.R;
|
||||||
|
import hikapro.com.backpack.presenter.adapters.helper.sets.ItemTouchHelperViewHolder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by tariel on 20/04/16.
|
* Created by tariel on 20/04/16.
|
||||||
*/
|
*/
|
||||||
public class SetViewHolder extends RecyclerView.ViewHolder {
|
public class SetViewHolder extends RecyclerView.ViewHolder implements ItemTouchHelperViewHolder{
|
||||||
|
|
||||||
public CardView cardView;
|
public CardView cardView;
|
||||||
public TextView textView;
|
public TextView textView;
|
||||||
|
|
||||||
|
//GLM_add_resources_SetList
|
||||||
|
private View view;
|
||||||
|
private Drawable drawable;
|
||||||
|
|
||||||
public SetViewHolder(View v) {
|
public SetViewHolder(View v) {
|
||||||
super(v);
|
super(v);
|
||||||
|
//
|
||||||
|
this.view = v;
|
||||||
|
|
||||||
|
//
|
||||||
setupViews(v);
|
setupViews(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupViews(View view) {
|
private void setupViews(View view) {
|
||||||
cardView = (CardView) view.findViewById(R.id.card_view_set);
|
cardView = (CardView) view.findViewById(R.id.card_view_set);
|
||||||
textView = (TextView) view.findViewById(R.id.set_text);
|
textView = (TextView) view.findViewById(R.id.set_text);
|
||||||
|
|
||||||
|
this.view = view;
|
||||||
|
drawable = view.getBackground();
|
||||||
|
}
|
||||||
|
|
||||||
|
//GLM_add_resources_SetList
|
||||||
|
@Override
|
||||||
|
public void onItemClear() {
|
||||||
|
view.setBackground(drawable);
|
||||||
|
}
|
||||||
|
|
||||||
|
//GLM_add_resources_SetList
|
||||||
|
@Override
|
||||||
|
public void onItemSelected() {
|
||||||
|
view.setBackgroundColor(Color.GRAY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
|
||||||
|
</vector>
|
|
@ -6,7 +6,7 @@
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<android.support.v7.widget.RecyclerView
|
<android.support.v7.widget.RecyclerView
|
||||||
android:id="@+id/categories_main_recycler"
|
android:id="@+id/items_recycler"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:scrollbars="vertical"
|
android:scrollbars="vertical"
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
|
|
||||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:background="@android:color/transparent"
|
|
||||||
android:textSize="10sp"
|
|
||||||
android:id="@+id/item_text"
|
|
||||||
android:textStyle="bold" />
|
|
|
@ -1,25 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:id="@+id/linear">
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:paddingLeft="16dp"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:textAllCaps="true"
|
|
||||||
android:background="@android:color/transparent"
|
|
||||||
android:textSize="16sp"
|
|
||||||
android:id="@+id/section_text"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<android.support.v7.widget.RecyclerView
|
|
||||||
android:id="@+id/category_inner_recycler"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/sticky_header_container"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"/>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:background="#001F3F"
|
||||||
|
android:textSize="28sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
tools:text="Animals starting with A"
|
||||||
|
android:id="@+id/header"
|
||||||
|
tools:context=".MainActivity"/>
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
>
|
||||||
|
<TextView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:clickable="true"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:textSize="14sp"
|
||||||
|
tools:text="Aardvark"
|
||||||
|
android:id="@+id/item_txt"
|
||||||
|
tools:context=".MainActivity"/>
|
||||||
|
<Button
|
||||||
|
android:id="@+id/undo_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Undo"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:layout_gravity="end|center_vertical"
|
||||||
|
style="@style/Base.Widget.AppCompat.Button.Borderless"/>
|
||||||
|
</FrameLayout>
|
|
@ -0,0 +1,20 @@
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
tools:context=".MainActivity">
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_settings"
|
||||||
|
android:orderInCategory="1"
|
||||||
|
android:title="Settings"
|
||||||
|
android:showAsAction="never" />
|
||||||
|
app:showAsAction="never" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_search"
|
||||||
|
android:icon="@android:drawable/ic_menu_search"
|
||||||
|
android:showAsAction="always|collapseActionView"
|
||||||
|
app:showAsAction="always|collapseActionView"
|
||||||
|
android:actionViewClass="android.widget.SearchView"
|
||||||
|
android:visible="true"
|
||||||
|
android:title="Search"/>
|
||||||
|
|
||||||
|
</menu>
|
|
@ -2,4 +2,5 @@
|
||||||
<!-- Default screen margins, per the Android Design guidelines. -->
|
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||||
|
<dimen name="ic_clear_margin">16dp</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in New Issue