diff --git a/libs/twister-lib-android/src/main/java/net/twisterrob/android/db/DatabaseOpenHelper.java b/libs/twister-lib-android/src/main/java/net/twisterrob/android/db/DatabaseOpenHelper.java
index 57bcbd83b..8ae512780 100644
--- a/libs/twister-lib-android/src/main/java/net/twisterrob/android/db/DatabaseOpenHelper.java
+++ b/libs/twister-lib-android/src/main/java/net/twisterrob/android/db/DatabaseOpenHelper.java
@@ -113,7 +113,9 @@ public void onDestroy(SQLiteDatabase db) {
execFile(db, String.format(DB_TEST_FILE, dbName));
}
if (devMode) {
- backupDB(db, "onOpen_backup");
+ if (dumpOnOpen) {
+ backupDB(db, "onOpen_backup");
+ }
execFile(db, String.format(DB_DEVELOPMENT_FILE, dbName));
}
LOG.info("Opened database: {}", dbToString(db));
diff --git a/libs/twister-lib-android/src/main/java/net/twisterrob/android/utils/concurrent/Executable.java b/libs/twister-lib-android/src/main/java/net/twisterrob/android/utils/concurrent/Executable.java
index 9339a742d..1d3c52bf3 100644
--- a/libs/twister-lib-android/src/main/java/net/twisterrob/android/utils/concurrent/Executable.java
+++ b/libs/twister-lib-android/src/main/java/net/twisterrob/android/utils/concurrent/Executable.java
@@ -1,6 +1,8 @@
package net.twisterrob.android.utils.concurrent;
public interface Executable {
+ @SuppressWarnings("unchecked")
void executeParallel(Param... params);
+ @SuppressWarnings("unchecked")
void executeSerial(Param... params);
}
diff --git a/libs/twister-lib-android/src/main/java/net/twisterrob/android/utils/tools/DatabaseTools.java b/libs/twister-lib-android/src/main/java/net/twisterrob/android/utils/tools/DatabaseTools.java
index 649d86702..44cfb4193 100644
--- a/libs/twister-lib-android/src/main/java/net/twisterrob/android/utils/tools/DatabaseTools.java
+++ b/libs/twister-lib-android/src/main/java/net/twisterrob/android/utils/tools/DatabaseTools.java
@@ -2,6 +2,8 @@
import java.util.Locale;
+import javax.annotation.Nullable;
+
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.support.annotation.NonNull;
@@ -17,6 +19,17 @@ public static String dbToString(final SQLiteDatabase database) {
String path = database != null? database.getPath() : null;
return String.format(Locale.ROOT, "v%d@%s", version, path);
}
+ public static boolean getBoolean(Cursor cursor, String columnName) {
+ int col = cursor.getColumnIndex(columnName);
+ return cursor.getInt(col) != 0;
+ }
+ public static boolean getOptionalBoolean(Cursor cursor, String columnName, boolean defaultValue) {
+ int col = cursor.getColumnIndex(columnName);
+ if (col != DatabaseOpenHelper.CURSOR_NO_COLUMN) {
+ return cursor.getInt(col) != 0;
+ }
+ return defaultValue;
+ }
public static int getOptionalInt(Cursor cursor, String columnName, int defaultValue) {
int col = cursor.getColumnIndex(columnName);
@@ -57,41 +70,64 @@ public static String getOptionalString(Cursor cursor, String columnName, String
return defaultValue;
}
- public static Long singleResult(@NonNull Cursor cursor) {
+ public static Long singleLong(@NonNull Cursor cursor, @Nullable String columnName) {
try {
- if (cursor.getCount() == 0 || cursor.getColumnCount() == 0) {
- throw new IllegalArgumentException("Empty cursor");
- }
- if (1 < cursor.getCount()) {
- throw new IllegalArgumentException("Multiple rows returned");
- }
- if (1 < cursor.getColumnCount()) {
- throw new IllegalArgumentException("Multiple columns returned");
+ checkSingleRow(cursor);
+ int columnIndex;
+ if (columnName == null) {
+ checkSingleColumn(cursor);
+ columnIndex = 0;
+ } else {
+ columnIndex = cursor.getColumnIndexOrThrow(columnName);
}
- if (!cursor.moveToFirst()) {
- throw new IllegalArgumentException("Cannot move to first item");
- }
- return cursor.isNull(0)? null : cursor.getLong(0);
+ return cursor.isNull(columnIndex)? null : cursor.getLong(columnIndex);
} finally {
cursor.close();
}
}
- public static String singleResultFromColumn(@NonNull Cursor cursor, @NonNull String columnName) {
+ public static String singleString(@NonNull Cursor cursor, @Nullable String columnName) {
try {
- if (cursor.getCount() == 0 || cursor.getColumnCount() == 0) {
- throw new IllegalArgumentException("Empty cursor");
- }
- if (1 < cursor.getCount()) {
- throw new IllegalArgumentException("Multiple rows returned");
+ checkSingleRow(cursor);
+ if (columnName == null) {
+ checkSingleColumn(cursor);
+ return cursor.getString(0);
+ } else {
+ return cursor.getString(cursor.getColumnIndexOrThrow(columnName));
}
- if (!cursor.moveToFirst()) {
- throw new IllegalArgumentException("Cannot move to first item");
+ } finally {
+ cursor.close();
+ }
+ }
+
+ public static byte[] singleBlob(@NonNull Cursor cursor, @Nullable String columnName) {
+ try {
+ checkSingleRow(cursor);
+ if (columnName == null) {
+ checkSingleColumn(cursor);
+ return cursor.getBlob(0);
+ } else {
+ return cursor.getBlob(cursor.getColumnIndexOrThrow(columnName));
}
- int columnIndex = cursor.getColumnIndexOrThrow(columnName);
- return cursor.isNull(columnIndex)? null : cursor.getString(columnIndex);
} finally {
cursor.close();
}
}
+
+ private static void checkSingleRow(@NonNull Cursor cursor) {
+ if (cursor.getCount() == 0 || cursor.getColumnCount() == 0) {
+ throw new IllegalArgumentException("Empty cursor");
+ }
+ if (1 < cursor.getCount()) {
+ throw new IllegalArgumentException("Multiple rows returned");
+ }
+ if (!cursor.moveToFirst()) {
+ throw new IllegalArgumentException("Cannot move to first item");
+ }
+ }
+ private static void checkSingleColumn(@NonNull Cursor cursor) {
+ if (1 < cursor.getColumnCount()) {
+ throw new IllegalArgumentException("Multiple columns returned");
+ }
+ }
}
diff --git a/src/main/assets/MagicHomeInventory.schema.sql b/src/main/assets/MagicHomeInventory.schema.sql
index 3151eb588..dc45dd723 100644
--- a/src/main/assets/MagicHomeInventory.schema.sql
+++ b/src/main/assets/MagicHomeInventory.schema.sql
@@ -107,7 +107,7 @@ CREATE TABLE Item (
_id INTEGER NOT NULL,
name NVARCHAR NOT NULL, -- user entered
description TEXT NULL, -- user entered
- image VARCHAR NULL, -- relative path
+ image BLOB NULL, -- JPEG image
category INTEGER DEFAULT 0 -- uncategorized
CONSTRAINT fk_Item_category
REFERENCES Category(_id)
@@ -193,7 +193,7 @@ CREATE TABLE Property (
_id INTEGER NOT NULL,
name NVARCHAR NOT NULL, -- user entered
description TEXT NULL, -- user entered
- image VARCHAR NULL, -- relative path
+ image BLOB NULL, -- JPEG image
type INTEGER DEFAULT 0 -- other
CONSTRAINT fk_Property_type
REFERENCES PropertyType(_id)
@@ -228,7 +228,7 @@ CREATE TABLE Room (
_id INTEGER NOT NULL,
name NVARCHAR NOT NULL, -- user entered
description TEXT NULL, -- user entered
- image VARCHAR NULL, -- relative path
+ image BLOB NULL, -- JPEG image
type INTEGER DEFAULT 0 -- other
CONSTRAINT fk_Room_type
REFERENCES RoomType(_id)
diff --git a/src/main/java/net/twisterrob/inventory/android/Constants.java b/src/main/java/net/twisterrob/inventory/android/Constants.java
index 79214c1c8..02c2e41bf 100644
--- a/src/main/java/net/twisterrob/inventory/android/Constants.java
+++ b/src/main/java/net/twisterrob/inventory/android/Constants.java
@@ -8,7 +8,10 @@
import android.support.annotation.*;
import com.bumptech.glide.*;
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
+import com.bumptech.glide.load.model.ModelLoader;
+import com.bumptech.glide.load.model.stream.StreamModelLoader;
import com.bumptech.glide.load.resource.bitmap.ImageVideoBitmapDecoder;
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.load.resource.gif.GifResourceDecoder;
@@ -73,20 +76,29 @@ class Pic {
private static final LoggingListener IMAGE_LOGGING_LISTENER =
new LoggingListener<>("image");
- public static final DrawableRequestBuilder SVG_REQUEST = Glide
- .with(App.getAppContext())
- .fromResource()
+ private static DrawableRequestBuilder baseRequest(Class clazz) {
+ ModelLoader loader = Glide.buildModelLoader(clazz, InputStream.class, App.getAppContext());
+ DrawableRequestBuilder builder = Glide
+ .with(App.getAppContext())
+ .using((StreamModelLoader)loader)
+ .from(clazz)
+ .animate(android.R.anim.fade_in)
+ .error(R.drawable.image_error);
+ if (DISABLE && BuildConfig.DEBUG) {
+ builder = builder
+ .diskCacheStrategy(DiskCacheStrategy.NONE)
+ .skipMemoryCache(true)
+ ;
+ }
+ return builder;
+ }
+
+ public static final DrawableRequestBuilder SVG_REQUEST = baseRequest(Integer.class)
.listener(SVG_LOGGING_LISTENER)
- .decoder(getSvgDecoder())
- .animate(android.R.anim.fade_in)
- .error(R.drawable.image_error);
+ .decoder(getSvgDecoder());
- public static final DrawableRequestBuilder IMAGE_REQUEST = Glide
- .with(App.getAppContext())
- .fromString()
- .listener(IMAGE_LOGGING_LISTENER)
- .animate(android.R.anim.fade_in)
- .error(R.drawable.image_error);
+ public static final DrawableRequestBuilder IMAGE_REQUEST = baseRequest(String.class)
+ .listener(IMAGE_LOGGING_LISTENER);
private static GifBitmapWrapperResourceDecoder getSvgDecoder() {
Context context = App.getAppContext();
diff --git a/src/main/java/net/twisterrob/inventory/android/activity/ManageSpaceActivity.java b/src/main/java/net/twisterrob/inventory/android/activity/ManageSpaceActivity.java
index 72fc460de..8b79247f9 100644
--- a/src/main/java/net/twisterrob/inventory/android/activity/ManageSpaceActivity.java
+++ b/src/main/java/net/twisterrob/inventory/android/activity/ManageSpaceActivity.java
@@ -170,7 +170,7 @@ void recalculate() {
// sum 0 rows is NULL, count 0 rows is 0...
String sql = "select coalesce(sum(length(name) + length(location)), 0) + count() * 4 * 3 from Search";
Cursor cursor = App.db().getReadableDatabase().rawQuery(sql, null);
- return (long)DatabaseTools.singleResult(cursor);
+ return (long)DatabaseTools.singleLong(cursor, null);
}
});
}
diff --git a/src/main/java/net/twisterrob/inventory/android/content/Database.java b/src/main/java/net/twisterrob/inventory/android/content/Database.java
index 765dfe9bf..bc8ec89d1 100644
--- a/src/main/java/net/twisterrob/inventory/android/content/Database.java
+++ b/src/main/java/net/twisterrob/inventory/android/content/Database.java
@@ -33,7 +33,6 @@ public void onConfigure(SQLiteDatabase db) {
}
};
// TODO App.getPrefEditor().remove(Prefs.CURRENT_LANGUAGE).apply();
- m_helper.setDumpOnOpen(BuildConfig.DEBUG);
m_helper.setDevMode(BuildConfig.DEBUG);
}
@@ -73,6 +72,7 @@ private Cursor rawQuery(SQLiteDatabase db, int queryResource, Object... params)
try {
long start = System.nanoTime();
Cursor cursor = db.rawQuery(m_resources.getString(queryResource), StringTools.toStringArray(params));
+ cursor.moveToFirst(); // make sure the query runs now
long end = System.nanoTime();
LOG.debug("rawQuery({}, {}): {}ms", name, paramString, (end - start) / 10000000);
return cursor;
@@ -179,28 +179,40 @@ public Cursor getCategory(long itemID) {
return rawQuery(R.string.query_category, itemID);
}
- public long createProperty(long type, String name, String description, String image) {
- return rawInsert(R.string.query_property_create, type, name, description, image);
+ public long createProperty(long type, String name, String description) {
+ return rawInsert(R.string.query_property_create, type, name, description);
}
public Long findProperty(String name) {
return getID(R.string.query_property_find, name);
}
- public void updateProperty(long id, long type, String name, String description, String image) {
- execSQL(R.string.query_property_update, type, name, description, image, id);
+ public void updateProperty(long id, long type, String name, String description) {
+ execSQL(R.string.query_property_update, type, name, description, id);
+ }
+ public void addPropertyImage(long id, byte[] imageContents) {
+ execSQL(R.string.query_property_image_set, imageContents, id);
+ }
+ public Cursor getPropertyImage(long id) {
+ return rawQuery(R.string.query_property_image_get, id);
}
public void deleteProperty(long id) {
execSQL(R.string.query_property_delete, id);
}
- public long createRoom(long propertyID, long type, String name, String description, String image) {
- rawInsert(R.string.query_room_create, propertyID, type, name, description, image);
+ public long createRoom(long propertyID, long type, String name, String description) {
+ rawInsert(R.string.query_room_create, propertyID, type, name, description);
return findRoom(propertyID, name); // last_insert_rowid() doesn't work with INSTEAD OF INSERT triggers on VIEWs
}
public Long findRoom(long propertyID, String name) {
return getID(R.string.query_room_find, propertyID, name);
}
- public void updateRoom(long id, long type, String name, String description, String image) {
- execSQL(R.string.query_room_update, type, name, description, image, id);
+ public void updateRoom(long id, long type, String name, String description) {
+ execSQL(R.string.query_room_update, type, name, description, id);
+ }
+ public void addRoomImage(long id, byte[] imageContents) {
+ execSQL(R.string.query_room_image_set, imageContents, id);
+ }
+ public Cursor getRoomImage(long id) {
+ return rawQuery(R.string.query_room_image_get, id);
}
public void deleteRoom(long id) {
execSQL(R.string.query_room_delete, id);
@@ -221,17 +233,23 @@ public void moveRooms(long propertyID, long[] roomIDs) {
}
}
- private long createItem(Long parentID, long category, String name, String description, String image) {
- return rawInsert(R.string.query_item_create, parentID, category, name, description, image);
+ private long createItem(Long parentID, long category, String name, String description) {
+ return rawInsert(R.string.query_item_create, parentID, category, name, description);
}
- public long createItem(long parentID, long category, String name, String description, String image) {
- return createItem((Long)parentID, category, name, description, image);
+ public long createItem(long parentID, long category, String name, String description) {
+ return createItem((Long)parentID, category, name, description);
}
public Long findItem(long parentID, String name) {
return getID(R.string.query_item_find, parentID, name);
}
- public void updateItem(long id, long category, String name, String description, String image) {
- execSQL(R.string.query_item_update, category, name, description, image, id);
+ public void updateItem(long id, long category, String name, String description) {
+ execSQL(R.string.query_item_update, category, name, description, id);
+ }
+ public void addItemImage(long id, byte[] imageContents) {
+ execSQL(R.string.query_item_image_set, imageContents, id);
+ }
+ public Cursor getItemImage(long id) {
+ return rawQuery(R.string.query_item_image_get, id);
}
public void deleteItem(long id) {
execSQL(R.string.query_item_delete, id);
@@ -338,7 +356,7 @@ public void clearImages() {
} finally {
db.endTransaction();
}
- db.execSQL("VACUUM"); // must be outside a transaction
+ //db.execSQL("VACUUM"); // must be outside a transaction
}
public void rebuildSearch() {
@@ -351,6 +369,6 @@ public void rebuildSearch() {
} finally {
db.endTransaction();
}
- db.execSQL("VACUUM"); // must be outside a transaction
+ //db.execSQL("VACUUM"); // must be outside a transaction
}
}
diff --git a/src/main/java/net/twisterrob/inventory/android/content/InventoryProvider.java b/src/main/java/net/twisterrob/inventory/android/content/InventoryProvider.java
index 239971b91..c44ceddbe 100644
--- a/src/main/java/net/twisterrob/inventory/android/content/InventoryProvider.java
+++ b/src/main/java/net/twisterrob/inventory/android/content/InventoryProvider.java
@@ -1,6 +1,6 @@
package net.twisterrob.inventory.android.content;
-import java.io.*;
+import java.io.FileNotFoundException;
import java.lang.reflect.Field;
import java.util.*;
@@ -16,7 +16,6 @@
import net.twisterrob.android.utils.tools.*;
import net.twisterrob.inventory.android.App;
-import net.twisterrob.inventory.android.Constants.Paths;
import net.twisterrob.inventory.android.content.InventoryContract.*;
import net.twisterrob.java.annotations.DebugHelper;
import net.twisterrob.java.utils.StringTools;
@@ -124,46 +123,25 @@ private Cursor queryInternal(Uri uri, String[] projection, String[] selectionArg
if (!Arrays.asList(projection).contains(FILE_COLUMN)) {
throw new IllegalArgumentException("Property can only be queried as a file");
}
- long propertyID = Property.getID(uri);
- return buildImageCursor(propertyID, getImageFullPath(App.db().getProperty(propertyID)));
+ return App.db().getPropertyImage(Property.getID(uri));
}
case ROOM: {
if (!Arrays.asList(projection).contains(FILE_COLUMN)) {
throw new IllegalArgumentException("Room can only be queried as a file");
}
- long roomID = Room.getID(uri);
- return buildImageCursor(roomID, getImageFullPath(App.db().getRoom(roomID)));
+ return App.db().getRoomImage(Room.getID(uri));
}
case ITEM: {
if (!Arrays.asList(projection).contains(FILE_COLUMN)) {
throw new IllegalArgumentException("Item can only be queried as a file");
}
- long itemID = Item.getID(uri);
- return buildImageCursor(itemID, getImageFullPath(App.db().getItem(itemID, false)));
+ return App.db().getItemImage(Item.getID(uri));
}
default:
throw new UnsupportedOperationException("Unknown URI: " + uri);
}
}
- private Cursor buildImageCursor(long belongingID, String imagePath) throws IOException {
- byte[] imageContents = null;
- if (imagePath != null) {
- File file = new File(imagePath);
- ByteArrayOutputStream bytes = new ByteArrayOutputStream((int)file.length());
- IOTools.copyStream(new FileInputStream(file), bytes);
- imageContents = bytes.toByteArray();
- }
- MatrixCursor cursor = new MatrixCursor(new String[] {BaseColumns._ID, FILE_COLUMN}, 1);
- cursor.addRow(new Object[] {belongingID, imageContents});
- return cursor;
- }
-
- private String getImageFullPath(Cursor belonging) {
- String imageFileName = DatabaseTools.singleResultFromColumn(belonging, CommonColumns.IMAGE);
- return Paths.getImagePath(getContext(), imageFileName);
- }
-
/**
* Return a singular suggestion to display more text about what can be searched
* Tapping it would open the search activity.
@@ -206,7 +184,7 @@ private Cursor createItemSearchHelp() {
return openBlobHelper(uri, mode);
case CATEGORY:
Cursor category = App.db().getCategory(Category.getID(uri));
- String name = DatabaseTools.singleResultFromColumn(category,
+ String name = DatabaseTools.singleString(category,
net.twisterrob.inventory.android.content.contract.Category.TYPE_IMAGE);
int svgID = AndroidTools.getRawResourceID(getContext(), name);
// The following only works if the resource is uncompressed: android.aaptOptions.noCompress 'svg'
diff --git a/src/main/java/net/twisterrob/inventory/android/content/io/ExporterTask.java b/src/main/java/net/twisterrob/inventory/android/content/io/ExporterTask.java
index 3c072af35..387fafee1 100644
--- a/src/main/java/net/twisterrob/inventory/android/content/io/ExporterTask.java
+++ b/src/main/java/net/twisterrob/inventory/android/content/io/ExporterTask.java
@@ -10,7 +10,7 @@
import android.database.Cursor;
import net.twisterrob.android.utils.concurrent.SimpleAsyncTask;
-import net.twisterrob.android.utils.tools.IOTools;
+import net.twisterrob.android.utils.tools.*;
import net.twisterrob.inventory.android.*;
import net.twisterrob.inventory.android.Constants.Paths;
import net.twisterrob.inventory.android.content.contract.*;
@@ -142,7 +142,7 @@ protected void saveData() throws Throwable {
cursor.moveToPosition(-1);
publishStart();
while (cursor.moveToNext()) {
- if (!cursor.isNull(cursor.getColumnIndex(CommonColumns.IMAGE))) {
+ if (DatabaseTools.getBoolean(cursor, CommonColumns.IMAGE)) {
progress.imagesCount++;
}
exporter.writeData(cursor);
diff --git a/src/main/java/net/twisterrob/inventory/android/content/io/ImporterTask.java b/src/main/java/net/twisterrob/inventory/android/content/io/ImporterTask.java
index 4f512effb..d4fa98d32 100644
--- a/src/main/java/net/twisterrob/inventory/android/content/io/ImporterTask.java
+++ b/src/main/java/net/twisterrob/inventory/android/content/io/ImporterTask.java
@@ -155,11 +155,23 @@ public void error(String message) {
public void importImage(Type type, long id, String name, String image) throws IOException {
ZipEntry imageEntry = zip.getEntry(image);
if (imageEntry != null) {
- File imageFile = Constants.Paths.getImageFile(context, image);
- //noinspection ResultOfMethodCallIgnored FileOutputStream will fail nicely
- imageFile.getParentFile().mkdirs();
- InputStream imageStream = zip.getInputStream(imageEntry);
- IOTools.copyStream(imageStream, new FileOutputStream(imageFile));
+ InputStream zipImage = zip.getInputStream(imageEntry);
+ ByteArrayOutputStream byteOut = new ByteArrayOutputStream((int)imageEntry.getSize());
+ IOTools.copyStream(zipImage, byteOut);
+ byte[] imageContents = byteOut.toByteArray();
+ switch (type) {
+ case Property:
+ App.db().addPropertyImage(id, imageContents);
+ break;
+ case Room:
+ App.db().addRoomImage(id, imageContents);
+ break;
+ case Item:
+ App.db().addItemImage(id, imageContents);
+ break;
+ default:
+ throw new IllegalArgumentException(type + " cannot have images.");
+ }
} else {
warning(R.string.backup_import_invalid_image, name, image);
}
diff --git a/src/main/java/net/twisterrob/inventory/android/content/io/csv/CSVImporter.java b/src/main/java/net/twisterrob/inventory/android/content/io/csv/CSVImporter.java
index 549a970ae..5d6d2ee80 100644
--- a/src/main/java/net/twisterrob/inventory/android/content/io/csv/CSVImporter.java
+++ b/src/main/java/net/twisterrob/inventory/android/content/io/csv/CSVImporter.java
@@ -43,12 +43,7 @@ public void doImport(InputStream stream) throws IOException {
processor.id = Long.parseLong(record.get("id"));
}
- long dbID = processor.process();
- if (processor.imageFileName != null) {
- progress.importImage(null, dbID,
- coalesce(processor.itemName, processor.roomName, processor.propertyName),
- processor.imageFileName);
- }
+ processor.process();
progress.publishIncrement();
} catch (CancellationException ex) {
throw ex;
@@ -85,17 +80,19 @@ private class ImportProcessor {
String imageFileName;
String parentName;
long id;
+ Type type;
protected long process() throws IOException {
long dbID = processInternal();
if (imageFileName != null) {
- progress.importImage(null, dbID, coalesce(itemName, roomName, propertyName), imageFileName);
+ progress.importImage(type, dbID, coalesce(itemName, roomName, propertyName), imageFileName);
}
return dbID;
}
protected long processInternal() {
+ type = null;
if (itemName != null) { // item: property ?= null && room ?= null && item != null
if (propertyName == null) {
throw new IllegalArgumentException("Cannot process item which is not in a property");
@@ -103,13 +100,16 @@ protected long processInternal() {
if (roomName == null) {
throw new IllegalArgumentException("Cannot process item which is not in a room");
}
+ type = Type.Item;
return processItem();
} else if (roomName != null) { // room: property ?= null && room != null && item == null
if (propertyName == null) {
throw new IllegalArgumentException("Cannot process room which is not in a property");
}
+ type = Type.Room;
return processRoom();
} else if (propertyName != null) { // property: property != null && room == null && item == null
+ type = Type.Property;
return processProperty();
} else { // invalid: property: property == null && room == null && item == null
progress.warning(R.string.backup_import_invalid_belonging, belongingTypeName, imageFileName,
@@ -132,7 +132,7 @@ private Long getOrCreateProperty() {
progress.warning(R.string.backup_import_invalid_type, belongingTypeName, propertyName);
typeID = PropertyType.DEFAULT;
}
- propertyID = App.db().createProperty(typeID, propertyName, description, imageFileName);
+ propertyID = App.db().createProperty(typeID, propertyName, description);
} else {
progress.warning(R.string.backup_import_conflict_property, propertyName);
}
@@ -154,7 +154,7 @@ private Long getOrCreateRoom(long propertyID) {
progress.warning(R.string.backup_import_invalid_type, belongingTypeName, roomName);
typeID = RoomType.DEFAULT;
}
- roomID = App.db().createRoom(propertyID, typeID, roomName, description, imageFileName);
+ roomID = App.db().createRoom(propertyID, typeID, roomName, description);
} else {
progress.warning(R.string.backup_import_conflict_room, propertyName, roomName);
}
@@ -177,7 +177,7 @@ private Long getOrCreateItem(long parentID) {
progress.warning(R.string.backup_import_invalid_type, belongingTypeName, itemName);
typeID = Category.DEFAULT;
}
- itemID = App.db().createItem(parentID, typeID, itemName, description, imageFileName);
+ itemID = App.db().createItem(parentID, typeID, itemName, description);
} else {
progress.warning(R.string.backup_import_conflict_item, propertyName, roomName, itemName);
}
diff --git a/src/main/java/net/twisterrob/inventory/android/content/io/xml/XMLImporter.java b/src/main/java/net/twisterrob/inventory/android/content/io/xml/XMLImporter.java
index ee2f0a19f..dfa4e157b 100644
--- a/src/main/java/net/twisterrob/inventory/android/content/io/xml/XMLImporter.java
+++ b/src/main/java/net/twisterrob/inventory/android/content/io/xml/XMLImporter.java
@@ -199,7 +199,7 @@ public PropertyElementListener() {
progress.warning(R.string.backup_import_invalid_type, type, name);
typeID = PropertyType.DEFAULT;
}
- id = App.db().createProperty(typeID, name, description, image);
+ id = App.db().createProperty(typeID, name, description);
} else {
progress.warning(R.string.backup_import_conflict_property, name);
}
@@ -220,7 +220,7 @@ public RoomElementListener(Parent parent, TraverseFactory factory) {
progress.warning(R.string.backup_import_invalid_type, type, name);
typeID = RoomType.DEFAULT;
}
- id = App.db().createRoom(propertyID, typeID, name, description, image);
+ id = App.db().createRoom(propertyID, typeID, name, description);
} else {
progress.warning(R.string.backup_import_conflict_room, null, name);
}
@@ -273,7 +273,7 @@ public ItemElementListener(Parent parent, TraverseFactory factory) {
progress.warning(R.string.backup_import_invalid_type, type, name);
typeID = Category.DEFAULT;
}
- id = App.db().createItem(parentID, typeID, name, description, image);
+ id = App.db().createItem(parentID, typeID, name, description);
} else {
progress.warning(R.string.backup_import_conflict_item, null, null, name);
}
diff --git a/src/main/java/net/twisterrob/inventory/android/content/model/ImagedDTO.java b/src/main/java/net/twisterrob/inventory/android/content/model/ImagedDTO.java
index dbf9e13ee..e902f14ba 100644
--- a/src/main/java/net/twisterrob/inventory/android/content/model/ImagedDTO.java
+++ b/src/main/java/net/twisterrob/inventory/android/content/model/ImagedDTO.java
@@ -20,7 +20,7 @@
public abstract class ImagedDTO extends DTO {
private static final Logger LOG = LoggerFactory.getLogger(ImagedDTO.class);
- public String image;
+ public boolean image;
public String typeImage;
public long type;
@@ -29,7 +29,7 @@ protected ImagedDTO fromCursorInternal(Cursor cursor) {
super.fromCursorInternal(cursor);
typeImage = DatabaseTools.getOptionalString(cursor, CommonColumns.TYPE_IMAGE);
- image = DatabaseTools.getOptionalString(cursor, CommonColumns.IMAGE);
+ image = DatabaseTools.getOptionalBoolean(cursor, CommonColumns.IMAGE, false);
type = DatabaseTools.getOptionalLong(cursor, CommonColumns.TYPE_ID, type);
return this;
@@ -38,12 +38,12 @@ protected ImagedDTO fromCursorInternal(Cursor cursor) {
protected abstract Uri getImageUri();
public String getImage(Context context) {
- return Constants.Paths.getImagePath(context, image);
+ return Constants.Paths.getImagePath(context, null);
}
public void setImage(Context context, String fullImage) {
if (fullImage == null) {
- this.image = null;
+ this.image = false; // null
} else {
try {
String root = Paths.getImageDirectory(context).getCanonicalPath() + File.separator;
@@ -52,7 +52,7 @@ public void setImage(Context context, String fullImage) {
throw new IllegalArgumentException(String.format(Locale.ROOT,
"Image is not in internal storage (%3$s): %2$s (<- %1$s)", fullImage, image, root));
}
- this.image = image.substring(root.length());
+ this.image = true; //image.substring(root.length());
} catch (IOException e) {
LOG.error("Cannot find out the location of {}", fullImage, e);
}
@@ -68,7 +68,7 @@ public void setImage(Context context, String fullImage) {
}
public void loadInto(ImageView image, ImageView type, boolean alwaysShowType) {
- String fullImagePath = this.image != null? StringTools.toString(getImageUri(), null) : null;
+ String fullImagePath = this.image? StringTools.toString(getImageUri(), null) : null;
int typeID = AndroidTools.getRawResourceID(image.getContext(), this.typeImage);
loadInto(image, type, fullImagePath, typeID, alwaysShowType);
}
diff --git a/src/main/java/net/twisterrob/inventory/android/fragment/data/BaseGalleryFragment.java b/src/main/java/net/twisterrob/inventory/android/fragment/data/BaseGalleryFragment.java
index b68a8d210..ad0ed7d2d 100644
--- a/src/main/java/net/twisterrob/inventory/android/fragment/data/BaseGalleryFragment.java
+++ b/src/main/java/net/twisterrob/inventory/android/fragment/data/BaseGalleryFragment.java
@@ -11,7 +11,7 @@
import android.view.*;
import net.twisterrob.android.adapter.CursorRecyclerAdapter;
-import net.twisterrob.android.db.DatabaseOpenHelper;
+import net.twisterrob.android.utils.tools.DatabaseTools;
import net.twisterrob.android.view.*;
import net.twisterrob.android.view.ViewProvider.StaticViewProvider;
import net.twisterrob.inventory.android.R;
@@ -209,8 +209,7 @@ public GalleryAdapter(Cursor cursor, RecyclerViewItemEvents listener) {
private boolean isGroup(int position) {
Cursor c = getCursor();
c.moveToPosition(position);
- int groupIndex = c.getColumnIndex("group");
- return groupIndex != DatabaseOpenHelper.CURSOR_NO_COLUMN && c.getInt(groupIndex) == 1; // boolean
+ return DatabaseTools.getOptionalBoolean(c, "group", false); // boolean
}
@Override protected ViewHolder onCreateNonHeaderViewHolder(ViewGroup parent, int viewType) {
diff --git a/src/main/java/net/twisterrob/inventory/android/fragment/data/ItemEditFragment.java b/src/main/java/net/twisterrob/inventory/android/fragment/data/ItemEditFragment.java
index 29bd9f5c8..6d9106e31 100644
--- a/src/main/java/net/twisterrob/inventory/android/fragment/data/ItemEditFragment.java
+++ b/src/main/java/net/twisterrob/inventory/android/fragment/data/ItemEditFragment.java
@@ -95,9 +95,9 @@ private final class SaveTask extends SimpleSafeAsyncTask {
@Override protected Long doInBackground(ItemDTO param) throws SQLiteConstraintException {
Database db = App.db();
if (param.id == Item.ID_ADD) {
- return db.createItem(param.parentID, param.type, param.name, param.description, param.image);
+ return db.createItem(param.parentID, param.type, param.name, param.description);
} else {
- db.updateItem(param.id, param.type, param.name, param.description, param.image);
+ db.updateItem(param.id, param.type, param.name, param.description);
return param.id;
}
}
diff --git a/src/main/java/net/twisterrob/inventory/android/fragment/data/ItemViewFragment.java b/src/main/java/net/twisterrob/inventory/android/fragment/data/ItemViewFragment.java
index 6d0b8d9cc..6adaaa1c8 100644
--- a/src/main/java/net/twisterrob/inventory/android/fragment/data/ItemViewFragment.java
+++ b/src/main/java/net/twisterrob/inventory/android/fragment/data/ItemViewFragment.java
@@ -173,7 +173,7 @@ private void delete(final long itemID) {
}
@Override protected CharSequence update(ItemDTO entity, long newType, String newTypeName) {
- App.db().updateItem(entity.id, newType, entity.name, entity.description, entity.image);
+ App.db().updateItem(entity.id, newType, entity.name, entity.description);
return newTypeName;
}
diff --git a/src/main/java/net/twisterrob/inventory/android/fragment/data/PropertyEditFragment.java b/src/main/java/net/twisterrob/inventory/android/fragment/data/PropertyEditFragment.java
index 726012df5..7d8bb5bc5 100644
--- a/src/main/java/net/twisterrob/inventory/android/fragment/data/PropertyEditFragment.java
+++ b/src/main/java/net/twisterrob/inventory/android/fragment/data/PropertyEditFragment.java
@@ -96,9 +96,9 @@ private final class SaveTask extends SimpleSafeAsyncTask {
@Override protected Long doInBackground(RoomDTO param) throws SQLiteConstraintException {
Database db = App.db();
if (param.id == Room.ID_ADD) {
- return db.createRoom(param.propertyID, param.type, param.name, param.description, param.image);
+ return db.createRoom(param.propertyID, param.type, param.name, param.description);
} else {
- db.updateRoom(param.id, param.type, param.name, param.description, param.image);
+ db.updateRoom(param.id, param.type, param.name, param.description);
return param.id;
}
}
diff --git a/src/main/java/net/twisterrob/inventory/android/fragment/data/RoomViewFragment.java b/src/main/java/net/twisterrob/inventory/android/fragment/data/RoomViewFragment.java
index a448b12b2..b390ee54a 100644
--- a/src/main/java/net/twisterrob/inventory/android/fragment/data/RoomViewFragment.java
+++ b/src/main/java/net/twisterrob/inventory/android/fragment/data/RoomViewFragment.java
@@ -137,7 +137,7 @@ private void delete(final long roomID) {
}
@Override protected CharSequence update(RoomDTO entity, long newType, String newTypeName) {
- App.db().updateRoom(entity.id, newType, entity.name, entity.description, entity.image);
+ App.db().updateRoom(entity.id, newType, entity.name, entity.description);
return newTypeName;
}
diff --git a/src/main/java/net/twisterrob/inventory/android/view/adapters/BaseImagedAdapter.java b/src/main/java/net/twisterrob/inventory/android/view/adapters/BaseImagedAdapter.java
index 84b44f36f..6f59a7127 100644
--- a/src/main/java/net/twisterrob/inventory/android/view/adapters/BaseImagedAdapter.java
+++ b/src/main/java/net/twisterrob/inventory/android/view/adapters/BaseImagedAdapter.java
@@ -7,7 +7,7 @@
import android.widget.*;
import net.twisterrob.android.adapter.CursorRecyclerAdapter;
-import net.twisterrob.android.utils.tools.AndroidTools;
+import net.twisterrob.android.utils.tools.*;
import net.twisterrob.inventory.android.R;
import net.twisterrob.inventory.android.content.contract.*;
import net.twisterrob.inventory.android.content.model.ImagedDTO;
@@ -61,7 +61,7 @@ protected View inflateView(ViewGroup parent, int layoutResource) {
long id = cursor.getLong(cursor.getColumnIndexOrThrow(CommonColumns.ID));
Type type = Type.from(cursor, CommonColumns.TYPE);
String name = cursor.getString(cursor.getColumnIndexOrThrow(CommonColumns.NAME));
- boolean hasImage = cursor.getString(cursor.getColumnIndexOrThrow(CommonColumns.IMAGE)) != null;
+ boolean hasImage = DatabaseTools.getBoolean(cursor, CommonColumns.IMAGE);
String typeImage = cursor.getString(cursor.getColumnIndexOrThrow(CommonColumns.TYPE_IMAGE));
holder.title.setText(name);
diff --git a/src/main/java/net/twisterrob/inventory/android/view/adapters/GalleryGroupViewHolder.java b/src/main/java/net/twisterrob/inventory/android/view/adapters/GalleryGroupViewHolder.java
index cc8cb9a47..a2615bc91 100644
--- a/src/main/java/net/twisterrob/inventory/android/view/adapters/GalleryGroupViewHolder.java
+++ b/src/main/java/net/twisterrob/inventory/android/view/adapters/GalleryGroupViewHolder.java
@@ -6,6 +6,7 @@
import android.view.View.*;
import android.widget.*;
+import net.twisterrob.android.utils.tools.DatabaseTools;
import net.twisterrob.inventory.android.R;
import net.twisterrob.inventory.android.content.contract.*;
import net.twisterrob.inventory.android.content.model.ImagedDTO;
@@ -38,7 +39,7 @@ public void bind(Cursor cursor) {
count.setText(getCountText(cursor));
String typeImage = cursor.getString(cursor.getColumnIndexOrThrow(CommonColumns.TYPE_IMAGE));
- boolean hasImage = cursor.getString(cursor.getColumnIndexOrThrow(CommonColumns.IMAGE)) != null;
+ boolean hasImage = DatabaseTools.getBoolean(cursor, CommonColumns.IMAGE);
Type type = Type.from(cursor, CommonColumns.TYPE);
long id = cursor.getLong(cursor.getColumnIndexOrThrow(CommonColumns.ID));
ImagedDTO.loadInto(image, hasImage? type : null, id, typeImage);
diff --git a/src/main/java/net/twisterrob/inventory/android/view/adapters/GalleryViewHolder.java b/src/main/java/net/twisterrob/inventory/android/view/adapters/GalleryViewHolder.java
index 989cb9040..122f0a181 100644
--- a/src/main/java/net/twisterrob/inventory/android/view/adapters/GalleryViewHolder.java
+++ b/src/main/java/net/twisterrob/inventory/android/view/adapters/GalleryViewHolder.java
@@ -7,6 +7,7 @@
import android.widget.*;
import net.twisterrob.android.db.DatabaseOpenHelper;
+import net.twisterrob.android.utils.tools.DatabaseTools;
import net.twisterrob.inventory.android.R;
import net.twisterrob.inventory.android.content.contract.*;
import net.twisterrob.inventory.android.content.model.ImagedDTO;
@@ -43,7 +44,7 @@ public void bind(Cursor cursor) {
count.setVisibility(countText != null? View.VISIBLE : View.GONE);
String typeImage = cursor.getString(cursor.getColumnIndexOrThrow(CommonColumns.TYPE_IMAGE));
- ImagedDTO.loadInto(image, type, getImage(cursor) != null? getType(cursor) : null, getID(cursor), typeImage,
+ ImagedDTO.loadInto(image, type, hasImage(cursor)? getType(cursor) : null, getID(cursor), typeImage,
false);
}
private static Type getType(Cursor cursor) {
@@ -55,8 +56,8 @@ private static long getID(Cursor cursor) {
private static String getName(Cursor cursor) {
return cursor.getString(cursor.getColumnIndexOrThrow(CommonColumns.NAME));
}
- private static String getImage(Cursor cursor) {
- return cursor.getString(cursor.getColumnIndexOrThrow(CommonColumns.IMAGE));
+ private static boolean hasImage(Cursor cursor) {
+ return DatabaseTools.getBoolean(cursor, CommonColumns.IMAGE);
}
private static String getCountText(Cursor cursor) {
diff --git a/src/main/res/values/queries.xml b/src/main/res/values/queries.xml
index 431d58039..6c43b4191 100644
--- a/src/main/res/values/queries.xml
+++ b/src/main/res/values/queries.xml
@@ -6,7 +6,7 @@
'property' as type,
p._id as _id,
p.name as name,
- p.image as image,
+ p.image IS NOT NULL as image,
pt.image as typeImage,
(select count() from Room where property = p._id) as countChildren
from Property p
@@ -20,7 +20,7 @@
p.name as name,
p.description as description,
p.type as typeID,
- p.image as image,
+ p.image IS NOT NULL as image,
pt.image as typeImage,
(select count() from Room where property = p._id) as countChildren,
(select count() from Item where parent in (select root from Room where property = p._id)) as countDirectItems,
@@ -54,7 +54,7 @@
r._id as _id,
r.root as root,
r.name as name,
- r.image as image,
+ r.image IS NOT NULL as image,
COALESCE(rt.image, rtk.image) as typeImage,
p._id as property,
p.name as propertyName,
@@ -76,7 +76,7 @@
r.root as root,
p._id as property,
p.name as propertyName,
- r.image as image,
+ r.image IS NOT NULL as image,
COALESCE(rt.image, rtk.image) as typeImage,
(select count() from Item where parent = r.root) as countDirectItems,
(select count(distinct item) from Item_Path_Node where root = r.root and root <> node) as countAllItems
@@ -107,7 +107,7 @@
--g._id as gid,
i._id = g._id as [group],
i.name as name,
- i.image as image,
+ i.image IS NOT NULL as image,
c.image as typeImage,
(select count() from Item where parent = i._id) as countChildren,
c.name as category
@@ -139,7 +139,7 @@
i._id as _id,
i.name as name,
i.description as description,
- i.image as image,
+ i.image IS NOT NULL as image,
c.image as typeImage,
ip.categoryID as typeID,
ip.categoryName as categoryName,
@@ -169,7 +169,7 @@
'item' as type,
i._id as _id,
i.name as name,
- i.image as image,
+ i.image IS NOT NULL as image,
c.image as typeImage,
(select count() from Item where parent = i._id) as countChildren,
c.name as category
@@ -182,7 +182,7 @@
'item' as type,
i._id as _id,
i.name as name,
- i.image as image,
+ i.image IS NOT NULL as image,
c.image as typeImage,
(select count() from Item where parent = i._id) as countChildren,
c.name as category
@@ -197,7 +197,7 @@
'item' as type,
i._id as _id,
i.name as name,
- i.image as image,
+ i.image IS NOT NULL as image,
c.image as typeImage,
(select count() from Item where parent = i._id) as countChildren,
c.name as category
@@ -211,7 +211,7 @@
'item' as type,
i._id as _id,
i.name as name,
- i.image as image,
+ i.image IS NOT NULL as image,
c.image as typeImage,
(select count() from Item where parent = i._id) as countChildren,
c.name as category
@@ -233,7 +233,7 @@
c._id as typeID,
c.name as typeName,
c.image as typeImage,
- i.image as image
+ i.image IS NOT NULL as image
from Item_Path_Node n
join Item i ON i._id = n.node
join Category c ON i.category = c._id
@@ -249,7 +249,7 @@
c._id as typeID,
c.name as typeName,
c.image as typeImage,
- i.image as image
+ i.image IS NOT NULL as image
from Item_Path_Node n
join Item i ON i._id = n.node
join Category c ON i.category = c._id
@@ -265,7 +265,7 @@
rt._id as typeID,
rt.name as typeName,
COALESCE(rt.image, rtk.image) as typeImage,
- r.image as image
+ r.image IS NOT NULL as image
from Item_Path_Node n
join Room r ON n.root = r.root
join RoomType rt ON r.type = rt._id
@@ -282,7 +282,7 @@
pt._id as typeID,
pt.name as typeName,
pt.image as typeImage,
- p.image as image
+ p.image IS NOT NULL as image
from Item_Path_Node n
join Room r ON n.root = r.root
join Property p ON r.property = p._id
@@ -299,7 +299,7 @@
'category' as type,
c._id as _id,
c.name as name,
- NULL as image,
+ 1 <> 2 as image,
c.image as typeImage,
(select count() from Category where parent = c._id) as countChildren,
(select count() from Item where category in (select descendant from Category_Descendant where category = c._id)) as countAllItems
@@ -376,7 +376,7 @@
'item' as type,
i._id as _id,
i.name as name,
- i.image as image,
+ i.image IS NOT NULL as image,
c.image as typeImage,
(select count() from Item where parent = i._id) as countChildren,
c.name as category
@@ -393,7 +393,7 @@
'item' as type,
i._id as _id,
i.name as name,
- i.image as image,
+ i.image IS NOT NULL as image,
c.image as typeImage,
datetime(r.visit, 'localtime') as visit,
r.recency as recency,
@@ -430,7 +430,7 @@
'item' as type,
i._id as _id,
i.name as name,
- i.image as image,
+ i.image IS NOT NULL as image,
c.image as typeImage,
(select count() from Item where parent = i._id) as countChildren,
c.name as category
@@ -503,13 +503,19 @@
+
+
+
+
+
+