Bumped Jabit version to prepare for conversations
This commit is contained in:
parent
22ac1920a2
commit
42cf18445c
@ -40,9 +40,9 @@ android {
|
||||
ext.jabitVersion = 'feature-extended-encoding-SNAPSHOT'
|
||||
dependencies {
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
compile 'com.android.support:appcompat-v7:25.1.0'
|
||||
compile 'com.android.support:support-v4:25.1.0'
|
||||
compile 'com.android.support:design:25.1.0'
|
||||
compile 'com.android.support:appcompat-v7:25.3.0'
|
||||
compile 'com.android.support:support-v4:25.3.0'
|
||||
compile 'com.android.support:design:25.3.0'
|
||||
|
||||
compile "ch.dissem.jabit:jabit-core:$jabitVersion"
|
||||
compile "ch.dissem.jabit:jabit-networking:$jabitVersion"
|
||||
@ -52,25 +52,25 @@ dependencies {
|
||||
|
||||
compile 'org.slf4j:slf4j-android:1.7.12'
|
||||
|
||||
compile 'com.mikepenz:materialize:1.0.0@aar'
|
||||
compile('com.mikepenz:materialdrawer:5.6.0@aar') {
|
||||
compile 'com.mikepenz:materialize:1.0.1@aar'
|
||||
compile('com.mikepenz:materialdrawer:5.8.2@aar') {
|
||||
transitive = true
|
||||
}
|
||||
compile('com.mikepenz:aboutlibraries:5.8.1@aar') {
|
||||
compile('com.mikepenz:aboutlibraries:5.9.4@aar') {
|
||||
transitive = true
|
||||
}
|
||||
compile 'com.mikepenz:iconics:1.6.2@aar'
|
||||
compile 'com.mikepenz:community-material-typeface:1.5.54.2@aar'
|
||||
compile 'com.mikepenz:community-material-typeface:1.8.36.1@aar'
|
||||
|
||||
compile 'com.journeyapps:zxing-android-embedded:3.3.0@aar'
|
||||
compile 'com.google.zxing:core:3.3.0'
|
||||
compile 'io.github.yavski:fab-speed-dial:1.0.6'
|
||||
compile 'com.github.amlcurran.showcaseview:library:5.4.3'
|
||||
compile('com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.9.3@aar') {
|
||||
compile('com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.10.4@aar') {
|
||||
transitive = true
|
||||
}
|
||||
compile 'com.github.angads25:filepicker:1.0.6'
|
||||
compile 'com.android.support.constraint:constraint-layout:1.0.0-beta4'
|
||||
compile 'com.github.angads25:filepicker:1.0.9'
|
||||
compile 'com.android.support.constraint:constraint-layout:1.0.2'
|
||||
|
||||
testCompile 'junit:junit:4.12'
|
||||
testCompile 'org.mockito:mockito-core:1.10.19'
|
||||
|
@ -0,0 +1,11 @@
|
||||
ALTER TABLE Message ADD COLUMN conversation BINARY[16];
|
||||
|
||||
CREATE TABLE Message_Parent (
|
||||
parent BINARY(64) NOT NULL,
|
||||
child BINARY(64) NOT NULL,
|
||||
pos INT NOT NULL,
|
||||
conversation BINARY[16] NOT NULL,
|
||||
|
||||
PRIMARY KEY (parent, child),
|
||||
FOREIGN KEY (child) REFERENCES Message (iv)
|
||||
);
|
@ -55,6 +55,7 @@ import java.io.Serializable;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import ch.dissem.apps.abit.dialog.AddIdentityDialogFragment;
|
||||
import ch.dissem.apps.abit.dialog.FullNodeDialogActivity;
|
||||
@ -311,7 +312,15 @@ public class MainActivity extends AppCompatActivity
|
||||
public boolean onItemClick(View view, int position, IDrawerItem item) {
|
||||
if (item.getTag() instanceof Label) {
|
||||
selectedLabel = (Label) item.getTag();
|
||||
showSelectedLabel();
|
||||
if (getSupportFragmentManager().findFragmentById(R.id.item_list) instanceof
|
||||
MessageListFragment) {
|
||||
((MessageListFragment) getSupportFragmentManager()
|
||||
.findFragmentById(R.id.item_list)).updateList(selectedLabel);
|
||||
} else {
|
||||
MessageListFragment listFragment = new MessageListFragment();
|
||||
changeList(listFragment);
|
||||
listFragment.updateList(selectedLabel);
|
||||
}
|
||||
return false;
|
||||
} else if (item instanceof Nameable<?>) {
|
||||
Nameable<?> ni = (Nameable<?>) item;
|
||||
@ -374,7 +383,7 @@ public class MainActivity extends AppCompatActivity
|
||||
for (Label label : labels) {
|
||||
addLabelEntry(label);
|
||||
}
|
||||
showSelectedLabel();
|
||||
drawer.setSelection(drawer.getDrawerItem(selectedLabel));
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
@ -389,7 +398,9 @@ public class MainActivity extends AppCompatActivity
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||
selectedLabel = (Label) savedInstanceState.getSerializable("selectedLabel");
|
||||
showSelectedLabel();
|
||||
|
||||
drawer.setSelection(drawer.getDrawerItem(selectedLabel));
|
||||
|
||||
super.onRestoreInstanceState(savedInstanceState);
|
||||
}
|
||||
|
||||
@ -439,7 +450,7 @@ public class MainActivity extends AppCompatActivity
|
||||
item.withIcon(CommunityMaterial.Icon.cmd_file);
|
||||
break;
|
||||
case OUTBOX:
|
||||
item.withIcon(CommunityMaterial.Icon.cmd_outbox);
|
||||
item.withIcon(CommunityMaterial.Icon.cmd_inbox_arrow_up);
|
||||
break;
|
||||
case SENT:
|
||||
item.withIcon(CommunityMaterial.Icon.cmd_send);
|
||||
@ -521,18 +532,6 @@ public class MainActivity extends AppCompatActivity
|
||||
}
|
||||
}
|
||||
|
||||
private void showSelectedLabel() {
|
||||
if (getSupportFragmentManager().findFragmentById(R.id.item_list) instanceof
|
||||
MessageListFragment) {
|
||||
((MessageListFragment) getSupportFragmentManager()
|
||||
.findFragmentById(R.id.item_list)).updateList(selectedLabel);
|
||||
} else {
|
||||
MessageListFragment listFragment = new MessageListFragment();
|
||||
changeList(listFragment);
|
||||
listFragment.updateList(selectedLabel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback method from {@link ListSelectionListener}
|
||||
* indicating that the item with the given ID was selected.
|
||||
|
@ -29,8 +29,10 @@ import android.widget.Toast;
|
||||
import com.mikepenz.aboutlibraries.Libs;
|
||||
import com.mikepenz.aboutlibraries.LibsBuilder;
|
||||
|
||||
import ch.dissem.apps.abit.repository.AndroidNodeRegistry;
|
||||
import ch.dissem.apps.abit.service.Singleton;
|
||||
import ch.dissem.apps.abit.synchronization.SyncAdapter;
|
||||
import ch.dissem.bitmessage.BitmessageContext;
|
||||
|
||||
import static ch.dissem.apps.abit.util.Constants.PREFERENCE_SERVER_POW;
|
||||
import static ch.dissem.apps.abit.util.Constants.PREFERENCE_TRUSTED_NODE;
|
||||
@ -78,7 +80,9 @@ public class SettingsFragment
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
Singleton.getBitmessageContext(ctx).cleanup();
|
||||
BitmessageContext bmc = Singleton.getBitmessageContext(ctx);
|
||||
bmc.cleanup();
|
||||
bmc.internals().getNodeRegistry().clear();
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -31,8 +31,10 @@ import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import ch.dissem.apps.abit.R;
|
||||
import ch.dissem.apps.abit.util.UuidUtils;
|
||||
import ch.dissem.bitmessage.entity.Plaintext;
|
||||
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
|
||||
import ch.dissem.bitmessage.entity.valueobject.Label;
|
||||
@ -40,6 +42,8 @@ import ch.dissem.bitmessage.ports.AbstractMessageRepository;
|
||||
import ch.dissem.bitmessage.ports.MessageRepository;
|
||||
import ch.dissem.bitmessage.utils.Encode;
|
||||
|
||||
import static ch.dissem.apps.abit.util.UuidUtils.asUuid;
|
||||
import static ch.dissem.bitmessage.utils.Strings.hex;
|
||||
import static java.lang.String.valueOf;
|
||||
|
||||
/**
|
||||
@ -65,6 +69,9 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
|
||||
private static final String COLUMN_RETRIES = "retries";
|
||||
private static final String COLUMN_NEXT_TRY = "next_try";
|
||||
private static final String COLUMN_INITIAL_HASH = "initial_hash";
|
||||
private static final String COLUMN_CONVERSATION = "conversation";
|
||||
|
||||
private static final String PARENTS_TABLE_NAME = "Message_Parent";
|
||||
|
||||
private static final String JOIN_TABLE_NAME = "Message_Label";
|
||||
private static final String JT_COLUMN_MESSAGE = "message_id";
|
||||
@ -164,7 +171,7 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
|
||||
public int countUnread(Label label) {
|
||||
String[] args;
|
||||
String where;
|
||||
if (label == null){
|
||||
if (label == null) {
|
||||
return 0;
|
||||
}
|
||||
if (label == LABEL_ARCHIVE) {
|
||||
@ -187,6 +194,72 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UUID> findConversations(Label label) {
|
||||
String[] projection = {
|
||||
COLUMN_CONVERSATION,
|
||||
};
|
||||
|
||||
String where;
|
||||
if (label == null) {
|
||||
where = "id NOT IN (SELECT message_id FROM Message_Label)";
|
||||
} else {
|
||||
where = "id IN (SELECT message_id FROM Message_Label WHERE label_id=" + label.getId() + ")";
|
||||
}
|
||||
List<UUID> result = new LinkedList<>();
|
||||
SQLiteDatabase db = sql.getReadableDatabase();
|
||||
try (Cursor c = db.query(
|
||||
TABLE_NAME, projection,
|
||||
where,
|
||||
null, null, null, null
|
||||
)) {
|
||||
while (c.moveToNext()) {
|
||||
byte[] uuidBytes = c.getBlob(c.getColumnIndex(COLUMN_CONVERSATION));
|
||||
result.add(asUuid(uuidBytes));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private void updateParents(SQLiteDatabase db, Plaintext message) {
|
||||
if (message.getInventoryVector() == null || message.getParents().isEmpty()) {
|
||||
// There are no parents to save yet (they are saved in the extended data, that's enough for now)
|
||||
return;
|
||||
}
|
||||
db.delete(PARENTS_TABLE_NAME, "child=?", new String[]{hex(message.getInitialHash()).toString()});
|
||||
|
||||
byte[] childIV = message.getInventoryVector().getHash();
|
||||
// save new parents
|
||||
int order = 0;
|
||||
for (InventoryVector parentIV : message.getParents()) {
|
||||
Plaintext parent = getMessage(parentIV);
|
||||
mergeConversations(db, parent.getConversationId(), message.getConversationId());
|
||||
order++;
|
||||
ContentValues values = new ContentValues();
|
||||
values.put("parent", parentIV.getHash());
|
||||
values.put("child", childIV);
|
||||
values.put("pos", order);
|
||||
values.put("conversation", UuidUtils.asBytes(message.getConversationId()));
|
||||
db.insertOrThrow(PARENTS_TABLE_NAME, null, values);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces every occurrence of the source conversation ID with the target ID
|
||||
*
|
||||
* @param db is used to keep everything within one transaction
|
||||
* @param source ID of the conversation to be merged
|
||||
* @param target ID of the merge target
|
||||
*/
|
||||
private void mergeConversations(SQLiteDatabase db, UUID source, UUID target) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put("conversation", UuidUtils.asBytes(target));
|
||||
String[] whereArgs = {hex(UuidUtils.asBytes(source)).toString()};
|
||||
db.update(TABLE_NAME, values, "conversation=?", whereArgs);
|
||||
db.update(PARENTS_TABLE_NAME, values, "conversation=?", whereArgs);
|
||||
}
|
||||
|
||||
protected List<Plaintext> find(String where) {
|
||||
List<Plaintext> result = new LinkedList<>();
|
||||
|
||||
@ -205,7 +278,8 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
|
||||
COLUMN_STATUS,
|
||||
COLUMN_TTL,
|
||||
COLUMN_RETRIES,
|
||||
COLUMN_NEXT_TRY
|
||||
COLUMN_NEXT_TRY,
|
||||
COLUMN_CONVERSATION
|
||||
};
|
||||
|
||||
SQLiteDatabase db = sql.getReadableDatabase();
|
||||
@ -220,8 +294,8 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
|
||||
byte[] data = c.getBlob(c.getColumnIndex(COLUMN_DATA));
|
||||
Plaintext.Type type = Plaintext.Type.valueOf(c.getString(c.getColumnIndex
|
||||
(COLUMN_TYPE)));
|
||||
Plaintext.Builder builder = Plaintext.readWithoutSignature(type, new
|
||||
ByteArrayInputStream(data));
|
||||
Plaintext.Builder builder = Plaintext.readWithoutSignature(type,
|
||||
new ByteArrayInputStream(data));
|
||||
long id = c.getLong(c.getColumnIndex(COLUMN_ID));
|
||||
builder.id(id);
|
||||
builder.IV(new InventoryVector(iv));
|
||||
@ -240,6 +314,7 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
|
||||
if (!c.isNull(nextTryColumn)) {
|
||||
builder.nextTry(c.getLong(nextTryColumn));
|
||||
}
|
||||
builder.conversation(asUuid(c.getBlob(c.getColumnIndex(COLUMN_CONVERSATION))));
|
||||
builder.labels(findLabels(id));
|
||||
result.add(builder.build());
|
||||
}
|
||||
@ -268,6 +343,8 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
|
||||
update(db, message);
|
||||
}
|
||||
|
||||
updateParents(db, message);
|
||||
|
||||
// remove existing labels
|
||||
db.delete(JOIN_TABLE_NAME, "message_id=?", new String[]{valueOf(message.getId())});
|
||||
|
||||
@ -302,6 +379,7 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
|
||||
values.put(COLUMN_TTL, message.getTTL());
|
||||
values.put(COLUMN_RETRIES, message.getRetries());
|
||||
values.put(COLUMN_NEXT_TRY, message.getNextTry());
|
||||
values.put(COLUMN_CONVERSATION, UuidUtils.asBytes(message.getConversationId()));
|
||||
long id = db.insertOrThrow(TABLE_NAME, null, values);
|
||||
message.setId(id);
|
||||
}
|
||||
@ -322,6 +400,7 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
|
||||
values.put(COLUMN_TTL, message.getTTL());
|
||||
values.put(COLUMN_RETRIES, message.getRetries());
|
||||
values.put(COLUMN_NEXT_TRY, message.getNextTry());
|
||||
values.put(COLUMN_CONVERSATION, UuidUtils.asBytes(message.getConversationId()));
|
||||
db.update(TABLE_NAME, values, "id = " + message.getId(), null);
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ import android.database.sqlite.SQLiteStatement;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -56,6 +57,12 @@ public class AndroidNodeRegistry implements NodeRegistry {
|
||||
db.delete(TABLE_NAME, "time < ?", new String[]{valueOf(now(-28 * DAY))});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
SQLiteDatabase db = sql.getWritableDatabase();
|
||||
db.delete(TABLE_NAME, null, null);
|
||||
}
|
||||
|
||||
private Long loadExistingTime(NetworkAddress node) {
|
||||
SQLiteStatement statement = loadExistingStatement.get();
|
||||
if (statement == null) {
|
||||
|
@ -27,7 +27,7 @@ import ch.dissem.apps.abit.util.Assets;
|
||||
*/
|
||||
public class SqlHelper extends SQLiteOpenHelper {
|
||||
// If you change the database schema, you must increment the database version.
|
||||
private static final int DATABASE_VERSION = 6;
|
||||
private static final int DATABASE_VERSION = 7;
|
||||
private static final String DATABASE_NAME = "jabit.db";
|
||||
|
||||
private final Context ctx;
|
||||
@ -61,6 +61,8 @@ public class SqlHelper extends SQLiteOpenHelper {
|
||||
executeMigration(db, "V3.3__Create_table_node");
|
||||
case 5:
|
||||
executeMigration(db, "V3.4__Add_label_outbox");
|
||||
case 6:
|
||||
executeMigration(db, "V4.0__Create_table_message_parent");
|
||||
default:
|
||||
// Nothing to do. Let's assume we won't upgrade from a version that's newer than
|
||||
// DATABASE_VERSION.
|
||||
@ -73,7 +75,7 @@ public class SqlHelper extends SQLiteOpenHelper {
|
||||
}
|
||||
}
|
||||
|
||||
public static StringBuilder join(long... numbers) {
|
||||
static StringBuilder join(long... numbers) {
|
||||
StringBuilder streamList = new StringBuilder();
|
||||
for (int i = 0; i < numbers.length; i++) {
|
||||
if (i > 0) streamList.append(", ");
|
||||
@ -82,7 +84,7 @@ public class SqlHelper extends SQLiteOpenHelper {
|
||||
return streamList;
|
||||
}
|
||||
|
||||
public static StringBuilder join(Enum<?>... types) {
|
||||
static StringBuilder join(Enum<?>... types) {
|
||||
StringBuilder streamList = new StringBuilder();
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
if (i > 0) streamList.append(", ");
|
||||
|
37
app/src/main/java/ch/dissem/apps/abit/util/UuidUtils.java
Normal file
37
app/src/main/java/ch/dissem/apps/abit/util/UuidUtils.java
Normal file
@ -0,0 +1,37 @@
|
||||
package ch.dissem.apps.abit.util;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* SQLite has no UUID data type, and UUIDs are therefore best saved as BINARY[16]. This class
|
||||
* takes care of conversion between byte[16] and UUID.
|
||||
* <p>
|
||||
* Thanks to Brice Roncace on
|
||||
* <a href="http://stackoverflow.com/questions/17893609/convert-uuid-to-byte-that-works-when-using-uuid-nameuuidfrombytesb">
|
||||
* Stack Overflow
|
||||
* </a>
|
||||
* for providing the UUID <-> byte[] conversions.
|
||||
* </p>
|
||||
*/
|
||||
public class UuidUtils {
|
||||
public static UUID asUuid(byte[] bytes) {
|
||||
if (bytes == null) {
|
||||
return null;
|
||||
}
|
||||
ByteBuffer bb = ByteBuffer.wrap(bytes);
|
||||
long firstLong = bb.getLong();
|
||||
long secondLong = bb.getLong();
|
||||
return new UUID(firstLong, secondLong);
|
||||
}
|
||||
|
||||
public static byte[] asBytes(UUID uuid) {
|
||||
if (uuid == null) {
|
||||
return null;
|
||||
}
|
||||
ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
|
||||
bb.putLong(uuid.getMostSignificantBits());
|
||||
bb.putLong(uuid.getLeastSignificantBits());
|
||||
return bb.array();
|
||||
}
|
||||
}
|
@ -9,7 +9,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.2.3'
|
||||
classpath 'com.android.tools.build:gradle:2.3.0'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,6 @@
|
||||
#Fri Aug 12 22:10:25 CEST 2016
|
||||
#Thu Mar 09 06:38:41 CET 2017
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
|
||||
|
Loading…
Reference in New Issue
Block a user