Basic DAO implementation

This commit is contained in:
Tariel Hlontsi 2016-04-29 12:45:57 +03:00
parent 3c123f127d
commit b76ffeabd9
19 changed files with 1159 additions and 112 deletions

View File

@ -4,6 +4,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<application
android:name=".App"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"

View File

@ -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;
}
}

View File

@ -10,6 +10,7 @@ import android.util.Log;
import hikapro.com.backpack.model.DetailModel;
import hikapro.com.backpack.model.ItemModel;
import hikapro.com.backpack.model.SetModel;
import hikapro.com.backpack.model.database.DAO;
import hikapro.com.backpack.model.entities.Item;
import hikapro.com.backpack.model.entities.Set;
import hikapro.com.backpack.presenter.ItemDetailPresenter;
@ -24,6 +25,7 @@ public class MainActivity extends Activity implements View.ActivityCallback {
private FragmentManager fragmentManager;
private final StateMaintainer stateMaintainer =
new StateMaintainer(getFragmentManager(), MainActivity.class.getName());

View File

@ -6,20 +6,31 @@ 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 hikapro.com.backpack.model.entities.Updates;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
/**
* Created by tariel on 19/04/16.
*/
public interface Api {
@GET("/api/v1/backpack/items")
@GET("api/v1/backpack/items")
Call<List<Item>> getItems();
@GET("/api/v1/backpack/item_categories")
@GET("api/v1/backpack/item_categories")
Call<List<Category>> getItemCategories();
@GET("/api/v1/backpack/sets")
@GET("api/v1/backpack/sets")
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);
}

View File

@ -1,5 +1,7 @@
package hikapro.com.backpack.model;
import android.os.Message;
import hikapro.com.backpack.model.entities.Item;
import hikapro.com.backpack.presenter.Presenter;
@ -66,4 +68,9 @@ public class DetailModel implements Model.Detail {
public Presenter.ItemDetail getPresenter() {
return presenter;
}
@Override
public void onEvent(Message event) {
}
}

View File

@ -1,14 +1,20 @@
package hikapro.com.backpack.model;
import android.os.Message;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Hashtable;
import java.util.List;
import hikapro.com.backpack.model.database.Command;
import hikapro.com.backpack.model.database.DAO;
import hikapro.com.backpack.model.database.Event;
import hikapro.com.backpack.model.entities.Category;
import hikapro.com.backpack.model.entities.Item;
import hikapro.com.backpack.model.entities.Set;
import hikapro.com.backpack.presenter.Presenter;
import retrofit2.Call;
import retrofit2.Callback;
@ -19,19 +25,21 @@ import retrofit2.Response;
*/
public class ItemModel implements Model.Item {
private Api api;
private Presenter.ItemList presenter;
private List<Category> rawCategories;
private List<Category> sortedCategories;
private List<Item> rawItems;
private DAO dao;
private Hashtable<Category, List<Item>> items;
private Hashtable<Integer, Hashtable<String, List<Item>>> cache;
public ItemModel() {
this.api = RestClient.getApi();
this.rawCategories = new ArrayList<>();
this.rawItems = new ArrayList<>();
this.sortedCategories = new ArrayList<>();
this.cache = new Hashtable<>(16, 0.9f);
this.dao = DAO.getInstance();
}
// categories -->
@ -111,46 +119,45 @@ public class ItemModel implements Model.Item {
@Override
public void executeQuery() {
if (rawCategories.isEmpty() || rawItems.isEmpty()) {
loadCategories();
loadItems();
} else {
Message 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.SET_ITEMS_LOAD_COMPLETED :
Hashtable<String, List<Item>> res = (Hashtable<String, List<Item>>) event.obj;
cache.put(event.arg1, res);
notifyDataSetChanged();
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 <--
// other -->

View File

@ -1,5 +1,7 @@
package hikapro.com.backpack.model;
import android.os.Message;
import java.util.List;
import hikapro.com.backpack.model.entities.Category;
@ -15,14 +17,15 @@ public interface Model {
interface Base {
void onDestroy(boolean isConfigurationChanging);
void executeQuery();
void notifyDataSetChanged();
void sendMessage(String message);
void onEvent(Message event);
}
interface Set extends Base {
hikapro.com.backpack.model.entities.Set getSetByPosition(int position);
hikapro.com.backpack.model.entities.Set findSet(int id);
int getSetsCount();
void notifyDataSetChanged();
void setPresenter(Presenter.SetList presenter);
Presenter.SetList getPresenter();
}
@ -35,14 +38,12 @@ public interface Model {
int getItemsCount(int categoryId);
hikapro.com.backpack.model.entities.Category getCategoryByPosition(int position);
int getCategoriesCount();
void notifyDataSetChanged();
void setPresenter(Presenter.ItemList presenter);
Presenter.ItemList getPresenter();
}
interface Detail extends Base {
int getCount();
hikapro.com.backpack.model.entities.Item findItem(int id);
void notifyDataSetChanged();
void setPresenter(Presenter.ItemDetail presenter);
Presenter.ItemDetail getPresenter();

View File

@ -11,7 +11,7 @@ import retrofit2.converter.gson.GsonConverterFactory;
*/
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() {

View File

@ -1,38 +1,43 @@
package hikapro.com.backpack.model;
import android.os.Message;
import java.util.ArrayList;
import java.util.List;
import hikapro.com.backpack.model.database.Command;
import hikapro.com.backpack.model.database.DAO;
import hikapro.com.backpack.model.database.Event;
import hikapro.com.backpack.model.entities.Set;
import hikapro.com.backpack.presenter.Presenter;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Created by tariel on 20/04/16.
*/
public class SetModel implements Model.Set {
private List<hikapro.com.backpack.model.entities.Set> iList;
private Api api;
private List<hikapro.com.backpack.model.entities.Set> cache;
private Presenter.SetList presenter;
private DAO dao;
public SetModel() {
this.api = RestClient.getApi();
this.iList = new ArrayList<>();
this.cache = new ArrayList<>();
this.dao = DAO.getInstance();
dao.registerObserver(this);
}
// sets -->
//region sets
@Override
public hikapro.com.backpack.model.entities.Set getSetByPosition(int position) {
return iList.get(position);
return cache.get(position);
}
@Override
public hikapro.com.backpack.model.entities.Set findSet(int id) {
Set ret = null;
for (Set s : iList) {
for (Set s : cache) {
if (s.getId() == id) {
ret = s;
break;
@ -43,19 +48,18 @@ public class SetModel implements Model.Set {
@Override
public int getSetsCount() {
return iList.size();
return cache.size();
}
// sets <--
//endregion
// events -->
//region events
@Override
public void onDestroy(boolean isConfigurationChanging) {
if ( !isConfigurationChanging ) {
presenter = null;
}
}
@Override
public void notifyDataSetChanged() {
@ -67,39 +71,42 @@ public class SetModel implements Model.Set {
presenter.showMessage(message);
}
// events <--
//endregion
// process -->
//region process
@Override
public void executeQuery() {
if (iList.isEmpty())
loadSets();
else
notifyDataSetChanged();
Message command = Message.obtain();
command.what = Command.SYNC_IF_NOT_EXISTS;
dao.executeCommand(command);
command = Message.obtain();
command.what = Command.SET_GET_ALL;
dao.executeCommand(command);
}
private void loadSets() {
Call<List<hikapro.com.backpack.model.entities.Set>> call = api.getSets();
call.enqueue(new Callback<List<hikapro.com.backpack.model.entities.Set>>() {
@Override
public void onResponse(Call<List<hikapro.com.backpack.model.entities.Set>> call, Response<List<hikapro.com.backpack.model.entities.Set>> response) {
int statusCode = response.code();
iList = response.body();
public void onEvent(Message event) {
switch (event.what) {
case Event.SET_LOAD_ERROR :
break;
case Event.SET_ITEMS_LOAD_ERROR :
break;
case Event.SET_REORDER_ERROR :
break;
case Event.SET_LOAD_COMPLETED :
cache = (List<Set>) event.obj;
notifyDataSetChanged();
break;
case Event.SET_ITEMS_LOAD_COMPLETED :
break;
case Event.SET_REORDER_COMPLETED :
break;
}
@Override
public void onFailure(Call<List<hikapro.com.backpack.model.entities.Set>> call, Throwable t) {
}
//endregion
}
});
}
private void syncData() {
}
// process <--
// other -->
//region other
@Override
public void setPresenter(Presenter.SetList presenter) {
@ -111,7 +118,7 @@ public class SetModel implements Model.Set {
return presenter;
}
// other <--
//endregion

View File

@ -0,0 +1,32 @@
package hikapro.com.backpack.model.database;
/**
* 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 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;
}

View File

@ -1,21 +1,198 @@
package hikapro.com.backpack.model.database;
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.Objects;
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;
public DAO(Context context) {
this.context = context;
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_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();
}
@ -23,4 +200,544 @@ public class DAO {
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, String> readCategories() {
Hashtable<Integer, String> 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.getName());
}
} 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;
}
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);
Hashtable<Integer, String> categories = readCategories();
Hashtable<String, List<Item>> result = new Hashtable<>(20, 0.9f);
String categoryName;
for (Item item : items) {
categoryName = categories.get(item.getCategory());
if (result.containsKey(categoryName)) {
result.get(categoryName).add(item);
} else {
List<Item> innerList = new ArrayList<>(20);
innerList.add(item);
result.put(categoryName, innerList);
}
}
message.what = Event.SET_ITEMS_LOAD_COMPLETED;
message.obj = result;
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
}

View File

@ -2,6 +2,7 @@ package hikapro.com.backpack.model.database;
import android.content.ContentValues;
import android.database.Cursor;
import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
@ -12,6 +13,8 @@ import java.util.List;
import hikapro.com.backpack.model.entities.Category;
import hikapro.com.backpack.model.entities.Item;
import hikapro.com.backpack.model.entities.Set;
import hikapro.com.backpack.model.entities.Timestamp;
import hikapro.com.backpack.model.entities.UpdateLog;
/**
* Created by tariel on 20/04/16.
@ -23,10 +26,10 @@ public class Db {
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_NAME = "NAME";
public static final String COLUMN_NAME = "name";
public static final String CREATE =
"CREATE TABLE " + TABLE_NAME + " (" +
@ -51,17 +54,17 @@ public class Db {
}
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_NAME = "NAME";
public static final String COLUMN_CATEGORY = "CATEGORY";
public static final String COLUMN_DESCRIPTION = "DESCRIPTION";
public static final String COLUMN_BUY_URLS = "BUY_URLS";
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_LOCAL = "PHOTO_LOCAL";
public static final String COLUMN_PHOTO_THUMB_LOCAL = "PHOTO_THUMB_LOCAL";
public static final String COLUMN_NAME = "name";
public static final String COLUMN_CATEGORY = "category";
public static final String COLUMN_DESCRIPTION = "description";
public static final String COLUMN_BUY_URLS = "buy_urls";
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_LOCAL = "photo_local";
public static final String COLUMN_PHOTO_THUMB_LOCAL = "photo_thumb_local";
public static final String CREATE =
@ -124,17 +127,19 @@ public class Db {
}
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_NAME = "NAME";
public static final String COLUMN_ITEMS = "ITEMS";
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_LOCAL = "PHOTO_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_LOCAL = "PHOTO_THUMBNAIL_LOCAL";
public static final String COLUMN_NAME = "name";
public static final String COLUMN_ITEMS = "items";
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_LOCAL = "photo_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_LOCAL = "photo_thumbnail_local";
public static final String COLUMN_LINE_NUMBER = "line_num";
public static final String CREATE =
"CREATE TABLE " + TABLE_NAME + " (" +
@ -146,10 +151,11 @@ public class Db {
COLUMN_PHOTO_LOCAL + " TEXT, " +
COLUMN_PHOTO_THUMB_LOCAL + " TEXT, " +
COLUMN_PHOTO_THUMBNAIL_URL + " TEXT, " +
COLUMN_LINE_NUMBER + " INTEGER, " +
COLUMN_PHOTO_THUMBNAIL_LOCAL + " TEXT" +
" ); ";
public static ContentValues toContentValues(Set set) {
public static ContentValues toContentValues(Set set, int lineNumber) {
ContentValues values = new ContentValues();
values.put(COLUMN_ID, set.getId());
values.put(COLUMN_NAME, set.getName());
@ -164,6 +170,7 @@ public class Db {
values.put(COLUMN_PHOTO_URL, set.getPhoto());
values.put(COLUMN_PHOTO_THUMB_URL, set.getPhotoThumb());
values.put(COLUMN_PHOTO_THUMBNAIL_URL, set.getPhotoThumbnail());
values.put(COLUMN_LINE_NUMBER, lineNumber);
/*
values.put(COLUMN_PHOTO_LOCAL, "");
values.put(COLUMN_PHOTO_THUMB_LOCAL, "");
@ -187,9 +194,68 @@ public class Db {
set.setPhoto(cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_PHOTO_URL)));
set.setPhotoThumb(cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_PHOTO_THUMB_URL)));
set.setPhotoThumbnail(cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_PHOTO_THUMBNAIL_URL)));
set.setLineNumber(cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_LINE_NUMBER)));
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;
}
}
}

View File

@ -38,6 +38,8 @@ public class DbHelper extends SQLiteOpenHelper {
db.execSQL(Db.ItemsTable.CREATE);
db.execSQL(Db.CategoriesTable.CREATE);
db.execSQL(Db.SetsTable.CREATE);
db.execSQL(Db.LogTable.CREATE);
db.execSQL(Db.SetItemsTable.CREATE);
if (oldVersion < 2) {
// place the logic here

View File

@ -0,0 +1,51 @@
package hikapro.com.backpack.model.database;
/**
* 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_FROM_SET_DELETED = 0x14;
int ITEM_INSERTED = 0x15;
int ITEM_DELETED = 0x16;
int ITEM_PACKED = 0x17;
int ITEM_UNPACKED = 0x18;
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;
}

View File

@ -0,0 +1,15 @@
package hikapro.com.backpack.model.database;
/**
* Created by tariel on 27/04/16.
*/
public class Test {
private static Test ourInstance = new Test();
public static Test getInstance() {
return ourInstance;
}
private Test() {
}
}

View File

@ -10,7 +10,7 @@ import java.util.List;
/**
* Created by tariel on 02/04/16.
*/
public class Set implements Serializable {
public class Set implements Comparable<Set>, Serializable {
@SerializedName("id")
@Expose
@ -31,6 +31,8 @@ public class Set implements Serializable {
@Expose
private String photoThumbnail;
private int lineNumber;
public Set() {
}
@ -91,6 +93,14 @@ public class Set implements Serializable {
this.photoThumbnail = photoThumbnail;
}
public int getLineNumber() {
return lineNumber;
}
public void setLineNumber(int lineNumber) {
this.lineNumber = lineNumber;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
@ -109,4 +119,10 @@ public class Set implements Serializable {
return false;
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));
}
}

View File

@ -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() {
}
}

View File

@ -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;
}
}

View File

@ -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;
}