From c7200d06bc5725d5cf285e244fc79e5e837c7fb1 Mon Sep 17 00:00:00 2001
From: Christian Basler
Date: Tue, 25 Apr 2017 23:00:31 +0200
Subject: [PATCH 01/53] Some improvements suggested by Codacy
---
.../apps/abit/ComposeMessageFragment.java | 18 +-
.../ch/dissem/apps/abit/MainActivity.java | 188 +++++-------------
.../abit/drawer/ProfileImageListener.java | 69 +++++++
.../abit/drawer/ProfileSelectionListener.java | 65 ++++++
4 files changed, 192 insertions(+), 148 deletions(-)
create mode 100644 app/src/main/java/ch/dissem/apps/abit/drawer/ProfileImageListener.java
create mode 100644 app/src/main/java/ch/dissem/apps/abit/drawer/ProfileSelectionListener.java
diff --git a/app/src/main/java/ch/dissem/apps/abit/ComposeMessageFragment.java b/app/src/main/java/ch/dissem/apps/abit/ComposeMessageFragment.java
index 142e8f8..13833c8 100644
--- a/app/src/main/java/ch/dissem/apps/abit/ComposeMessageFragment.java
+++ b/app/src/main/java/ch/dissem/apps/abit/ComposeMessageFragment.java
@@ -67,26 +67,17 @@ public class ComposeMessageFragment extends Fragment {
private Plaintext.Encoding encoding;
private Plaintext parent;
- /**
- * Mandatory empty constructor for the fragment manager to instantiate the
- * fragment (e.g. upon screen orientation changes).
- */
- public ComposeMessageFragment() {
- }
-
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
if (getArguments().containsKey(EXTRA_IDENTITY)) {
identity = (BitmessageAddress) getArguments().getSerializable(EXTRA_IDENTITY);
- if (getActivity() != null) {
- if (identity == null || identity.getPrivateKey() == null) {
- identity = Singleton.getIdentity(getActivity());
- }
+ if (getActivity() != null && (identity == null || identity.getPrivateKey() == null)) {
+ identity = Singleton.getIdentity(getActivity());
}
} else {
- throw new RuntimeException("No identity set for ComposeMessageFragment");
+ throw new IllegalStateException("No identity set for ComposeMessageFragment");
}
broadcast = getArguments().getBoolean(EXTRA_BROADCAST, false);
if (getArguments().containsKey(EXTRA_RECIPIENT)) {
@@ -107,7 +98,7 @@ public class ComposeMessageFragment extends Fragment {
parent = (Plaintext) getArguments().getSerializable(EXTRA_PARENT);
}
} else {
- throw new RuntimeException("No identity set for ComposeMessageFragment");
+ throw new IllegalStateException("No identity set for ComposeMessageFragment");
}
setHasOptionsMenu(true);
}
@@ -139,6 +130,7 @@ public class ComposeMessageFragment extends Fragment {
@Override
public void onNothingSelected(AdapterView> parent) {
+ // leave current selection
}
});
if (recipient != null) {
diff --git a/app/src/main/java/ch/dissem/apps/abit/MainActivity.java b/app/src/main/java/ch/dissem/apps/abit/MainActivity.java
index f7d2c07..20e238a 100644
--- a/app/src/main/java/ch/dissem/apps/abit/MainActivity.java
+++ b/app/src/main/java/ch/dissem/apps/abit/MainActivity.java
@@ -16,25 +16,17 @@
package ch.dissem.apps.abit;
-import android.app.Dialog;
-import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Point;
-import android.graphics.drawable.ColorDrawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
-import android.view.Display;
import android.view.View;
import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
import android.widget.CompoundButton;
-import android.widget.ImageView;
import android.widget.RelativeLayout;
-import android.widget.Toast;
import com.github.amlcurran.showcaseview.ShowcaseView;
import com.github.amlcurran.showcaseview.targets.Target;
@@ -60,15 +52,14 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
-import ch.dissem.apps.abit.dialog.AddIdentityDialogFragment;
import ch.dissem.apps.abit.dialog.FullNodeDialogActivity;
+import ch.dissem.apps.abit.drawer.ProfileImageListener;
+import ch.dissem.apps.abit.drawer.ProfileSelectionListener;
import ch.dissem.apps.abit.listener.ActionBarListener;
import ch.dissem.apps.abit.listener.ListSelectionListener;
-import ch.dissem.apps.abit.repository.AndroidMessageRepository;
import ch.dissem.apps.abit.service.BitmessageService;
import ch.dissem.apps.abit.service.Singleton;
import ch.dissem.apps.abit.synchronization.SyncAdapter;
-import ch.dissem.apps.abit.util.Drawables;
import ch.dissem.apps.abit.util.Labels;
import ch.dissem.apps.abit.util.Preferences;
import ch.dissem.bitmessage.BitmessageContext;
@@ -76,7 +67,6 @@ import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.Plaintext;
import ch.dissem.bitmessage.entity.valueobject.Label;
-import static android.widget.Toast.LENGTH_LONG;
import static ch.dissem.apps.abit.ComposeMessageActivity.launchReplyTo;
import static ch.dissem.apps.abit.repository.AndroidMessageRepository.LABEL_ARCHIVE;
import static ch.dissem.apps.abit.service.BitmessageService.isRunning;
@@ -106,8 +96,8 @@ public class MainActivity extends AppCompatActivity
public static final String EXTRA_REPLY_TO_MESSAGE = "ch.dissem.abit.ReplyToMessage";
public static final String ACTION_SHOW_INBOX = "ch.dissem.abit.ShowInbox";
- private static final int ADD_IDENTITY = 1;
- private static final int MANAGE_IDENTITY = 2;
+ public static final int ADD_IDENTITY = 1;
+ public static final int MANAGE_IDENTITY = 2;
private static final long ID_NODE_SWITCH = 1;
@@ -239,81 +229,8 @@ public class MainActivity extends AppCompatActivity
.withActivity(this)
.withHeaderBackground(R.drawable.header)
.withProfiles(profiles)
- .withOnAccountHeaderProfileImageListener(new AccountHeader.OnAccountHeaderProfileImageListener() {
- @Override
- public boolean onProfileImageClick(View view, IProfile profile, boolean current) {
- if (current) {
- // Show QR code in modal dialog
- final Dialog dialog = new Dialog(MainActivity.this);
- dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
-
- ImageView imageView = new ImageView(MainActivity.this);
- imageView.setImageBitmap(Drawables.qrCode(Singleton.getIdentity(MainActivity.this)));
- imageView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- dialog.dismiss();
- }
- });
- dialog.addContentView(imageView, new RelativeLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
- Window window = dialog.getWindow();
- if (window != null) {
- Display display = window.getWindowManager().getDefaultDisplay();
- Point size = new Point();
- display.getSize(size);
- int dim = size.x < size.y ? size.x : size.y;
-
- WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
- lp.copyFrom(window.getAttributes());
- lp.width = dim;
- lp.height = dim;
-
- window.setAttributes(lp);
- }
- dialog.show();
- return true;
- }
- return false;
- }
-
- @Override
- public boolean onProfileImageLongClick(View view, IProfile iProfile, boolean b) {
- return false;
- }
- })
- .withOnAccountHeaderListener(new AccountHeader.OnAccountHeaderListener() {
- @Override
- public boolean onProfileChanged(View view, IProfile profile, boolean current) {
- switch ((int) profile.getIdentifier()) {
- case ADD_IDENTITY:
- addIdentityDialog();
- break;
- case MANAGE_IDENTITY:
- BitmessageAddress identity = Singleton.getIdentity(MainActivity.this);
- if (identity == null) {
- Toast.makeText(MainActivity.this,
- R.string.no_identity_warning, LENGTH_LONG).show();
- } else {
- Intent show = new Intent(MainActivity.this,
- AddressDetailActivity.class);
- show.putExtra(AddressDetailFragment.ARG_ITEM, identity);
- startActivity(show);
- }
- break;
- default:
- if (profile instanceof ProfileDrawerItem) {
- Object tag = ((ProfileDrawerItem) profile).getTag();
- if (tag instanceof BitmessageAddress) {
- Singleton.setIdentity((BitmessageAddress) tag);
- }
- }
- }
- // false if it should close the drawer
- return false;
- }
- })
+ .withOnAccountHeaderProfileImageListener(new ProfileImageListener(this))
+ .withOnAccountHeaderListener(new ProfileSelectionListener(MainActivity.this, getSupportFragmentManager()))
.build();
if (profiles.size() > 2) { // There's always the add and manage identity items
accountHeader.setActiveProfile(profiles.get(0), true);
@@ -356,44 +273,7 @@ public class MainActivity extends AppCompatActivity
.withAccountHeader(accountHeader)
.withDrawerItems(drawerItems)
.addStickyDrawerItems(nodeSwitch)
- .withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() {
- @Override
- public boolean onItemClick(View view, int position, IDrawerItem item) {
- if (item.getTag() instanceof Label) {
- selectedLabel = (Label) item.getTag();
- 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;
- switch (ni.getName().getTextRes()) {
- case R.string.contacts_and_subscriptions:
- if (!(getSupportFragmentManager().findFragmentById(R.id
- .item_list) instanceof AddressListFragment)) {
- changeList(new AddressListFragment());
- } else {
- ((AddressListFragment) getSupportFragmentManager()
- .findFragmentById(R.id.item_list)).updateList();
- }
- break;
- case R.string.settings:
- startActivity(new Intent(MainActivity.this, SettingsActivity
- .class));
- break;
- case R.string.full_node:
- return true;
- }
- }
- return false;
- }
- })
+ .withOnDrawerItemClickListener(new DrawerItemClickListener())
.withShowDrawerOnFirstLaunch(true)
.build();
@@ -440,6 +320,47 @@ public class MainActivity extends AppCompatActivity
}.execute();
}
+ private class DrawerItemClickListener implements Drawer.OnDrawerItemClickListener {
+ @Override
+ public boolean onItemClick(View view, int position, IDrawerItem item) {
+ if (item.getTag() instanceof Label) {
+ selectedLabel = (Label) item.getTag();
+ 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;
+ switch (ni.getName().getTextRes()) {
+ case R.string.contacts_and_subscriptions:
+ if (!(getSupportFragmentManager().findFragmentById(R.id
+ .item_list) instanceof AddressListFragment)) {
+ changeList(new AddressListFragment());
+ } else {
+ ((AddressListFragment) getSupportFragmentManager()
+ .findFragmentById(R.id.item_list)).updateList();
+ }
+ return false;
+ case R.string.settings:
+ startActivity(new Intent(MainActivity.this, SettingsActivity
+ .class));
+ return false;
+ case R.string.full_node:
+ return true;
+ default:
+ return false;
+ }
+ }
+ return false;
+ }
+ }
+
@Override
protected void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
@@ -458,11 +379,6 @@ public class MainActivity extends AppCompatActivity
super.onRestoreInstanceState(savedInstanceState);
}
- private void addIdentityDialog() {
- AddIdentityDialogFragment dialog = new AddIdentityDialogFragment();
- dialog.show(getSupportFragmentManager(), "dialog");
- }
-
@Override
protected void onResume() {
updateUnread();
@@ -500,8 +416,9 @@ public class MainActivity extends AppCompatActivity
public void updateIdentityEntry(BitmessageAddress identity) {
for (IProfile profile : accountHeader.getProfiles()) {
if (profile instanceof ProfileDrawerItem) {
- if (identity.equals(((ProfileDrawerItem) profile).getTag())) {
- ((ProfileDrawerItem) profile)
+ ProfileDrawerItem profileDrawerItem = (ProfileDrawerItem) profile;
+ if (identity.equals(profileDrawerItem.getTag())) {
+ profileDrawerItem
.withName(identity.toString())
.withTag(identity);
return;
@@ -513,7 +430,8 @@ public class MainActivity extends AppCompatActivity
public void removeIdentityEntry(BitmessageAddress identity) {
for (IProfile profile : accountHeader.getProfiles()) {
if (profile instanceof ProfileDrawerItem) {
- if (identity.equals(((ProfileDrawerItem) profile).getTag())) {
+ ProfileDrawerItem profileDrawerItem = (ProfileDrawerItem) profile;
+ if (identity.equals(profileDrawerItem.getTag())) {
accountHeader.removeProfile(profile);
return;
}
diff --git a/app/src/main/java/ch/dissem/apps/abit/drawer/ProfileImageListener.java b/app/src/main/java/ch/dissem/apps/abit/drawer/ProfileImageListener.java
new file mode 100644
index 0000000..20539b4
--- /dev/null
+++ b/app/src/main/java/ch/dissem/apps/abit/drawer/ProfileImageListener.java
@@ -0,0 +1,69 @@
+package ch.dissem.apps.abit.drawer;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.graphics.Point;
+import android.view.Display;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+
+import com.mikepenz.materialdrawer.AccountHeader;
+import com.mikepenz.materialdrawer.model.interfaces.IProfile;
+
+import ch.dissem.apps.abit.service.Singleton;
+import ch.dissem.apps.abit.util.Drawables;
+
+public class ProfileImageListener implements AccountHeader.OnAccountHeaderProfileImageListener {
+ private final Context ctx;
+
+ public ProfileImageListener(Context ctx) {
+ this.ctx = ctx;
+ }
+
+ @Override
+ public boolean onProfileImageClick(View view, IProfile profile, boolean current) {
+ if (current) {
+ // Show QR code in modal dialog
+ final Dialog dialog = new Dialog(ctx);
+ dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
+
+ ImageView imageView = new ImageView(ctx);
+ imageView.setImageBitmap(Drawables.qrCode(Singleton.getIdentity(ctx)));
+ imageView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ dialog.dismiss();
+ }
+ });
+ dialog.addContentView(imageView, new RelativeLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ Window window = dialog.getWindow();
+ if (window != null) {
+ Display display = window.getWindowManager().getDefaultDisplay();
+ Point size = new Point();
+ display.getSize(size);
+ int dim = size.x < size.y ? size.x : size.y;
+
+ WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
+ lp.copyFrom(window.getAttributes());
+ lp.width = dim;
+ lp.height = dim;
+
+ window.setAttributes(lp);
+ }
+ dialog.show();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onProfileImageLongClick(View view, IProfile iProfile, boolean b) {
+ return false;
+ }
+}
diff --git a/app/src/main/java/ch/dissem/apps/abit/drawer/ProfileSelectionListener.java b/app/src/main/java/ch/dissem/apps/abit/drawer/ProfileSelectionListener.java
new file mode 100644
index 0000000..1b4d66d
--- /dev/null
+++ b/app/src/main/java/ch/dissem/apps/abit/drawer/ProfileSelectionListener.java
@@ -0,0 +1,65 @@
+package ch.dissem.apps.abit.drawer;
+
+import android.content.Context;
+import android.content.Intent;
+import android.support.v4.app.FragmentManager;
+import android.view.View;
+import android.widget.Toast;
+
+import com.mikepenz.materialdrawer.AccountHeader;
+import com.mikepenz.materialdrawer.model.ProfileDrawerItem;
+import com.mikepenz.materialdrawer.model.interfaces.IProfile;
+
+import ch.dissem.apps.abit.AddressDetailActivity;
+import ch.dissem.apps.abit.AddressDetailFragment;
+import ch.dissem.apps.abit.MainActivity;
+import ch.dissem.apps.abit.R;
+import ch.dissem.apps.abit.dialog.AddIdentityDialogFragment;
+import ch.dissem.apps.abit.service.Singleton;
+import ch.dissem.bitmessage.entity.BitmessageAddress;
+
+import static android.widget.Toast.LENGTH_LONG;
+
+public class ProfileSelectionListener implements AccountHeader.OnAccountHeaderListener {
+ private final Context ctx;
+ private final FragmentManager fragmentManager;
+
+ public ProfileSelectionListener(Context ctx, FragmentManager fragmentManager) {
+ this.ctx = ctx;
+ this.fragmentManager = fragmentManager;
+ }
+
+ @Override
+ public boolean onProfileChanged(View view, IProfile profile, boolean current) {
+ switch ((int) profile.getIdentifier()) {
+ case MainActivity.ADD_IDENTITY:
+ addIdentityDialog();
+ break;
+ case MainActivity.MANAGE_IDENTITY:
+ BitmessageAddress identity = Singleton.getIdentity(ctx);
+ if (identity == null) {
+ Toast.makeText(ctx, R.string.no_identity_warning, LENGTH_LONG).show();
+ } else {
+ Intent show = new Intent(ctx, AddressDetailActivity.class);
+ show.putExtra(AddressDetailFragment.ARG_ITEM, identity);
+ ctx.startActivity(show);
+ }
+ break;
+ default:
+ if (profile instanceof ProfileDrawerItem) {
+ Object tag = ((ProfileDrawerItem) profile).getTag();
+ if (tag instanceof BitmessageAddress) {
+ Singleton.setIdentity((BitmessageAddress) tag);
+ }
+ }
+ break;
+ }
+ // false if it should close the drawer
+ return false;
+ }
+
+ private void addIdentityDialog() {
+ AddIdentityDialogFragment dialog = new AddIdentityDialogFragment();
+ dialog.show(fragmentManager, "dialog");
+ }
+}
From 5bc1bc2a4746074dd7fdfe670225c1f3f742d694 Mon Sep 17 00:00:00 2001
From: Christian Basler
Date: Fri, 5 May 2017 07:27:24 +0200
Subject: [PATCH 02/53] Some improvements suggested by Codacy
---
.../apps/abit/CreateAddressActivity.java | 99 +++++++++++--------
.../ch/dissem/apps/abit/MainActivity.java | 4 +
.../apps/abit/MessageDetailFragment.java | 4 +-
.../dissem/apps/abit/MessageListFragment.java | 7 --
.../ch/dissem/apps/abit/SettingsFragment.java | 17 ++--
.../abit/adapter/SwipeableMessageAdapter.java | 6 +-
.../ch/dissem/apps/abit/util/Strings.java | 17 +++-
7 files changed, 90 insertions(+), 64 deletions(-)
diff --git a/app/src/main/java/ch/dissem/apps/abit/CreateAddressActivity.java b/app/src/main/java/ch/dissem/apps/abit/CreateAddressActivity.java
index 6ed8060..c493a0c 100644
--- a/app/src/main/java/ch/dissem/apps/abit/CreateAddressActivity.java
+++ b/app/src/main/java/ch/dissem/apps/abit/CreateAddressActivity.java
@@ -27,6 +27,9 @@ import android.widget.EditText;
import android.widget.Switch;
import android.widget.TextView;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.regex.Matcher;
@@ -43,6 +46,8 @@ import ch.dissem.bitmessage.entity.payload.V4Pubkey;
import static android.util.Base64.URL_SAFE;
public class CreateAddressActivity extends AppCompatActivity {
+ private static final Logger LOG = LoggerFactory.getLogger(CreateAddressActivity.class);
+
private static final Pattern KEY_VALUE_PATTERN = Pattern.compile("^([a-zA-Z]+)=(.*)$");
private byte[] pubkeyBytes;
@@ -77,6 +82,9 @@ public class CreateAddressActivity extends AppCompatActivity {
case "pubkey":
pubkeyBytes = Base64.decode(value, URL_SAFE);
break;
+ default:
+ LOG.debug("Unknown attribute: " + key + "=" + value);
+ break;
}
}
}
@@ -92,55 +100,60 @@ public class CreateAddressActivity extends AppCompatActivity {
finish();
}
});
- final Button ok = (Button) findViewById(R.id.do_import);
- ok.setOnClickListener(new View.OnClickListener() {
+ findViewById(R.id.do_import).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
- String addressText = String.valueOf(address.getText()).trim();
- try {
- BitmessageAddress bmAddress = new BitmessageAddress(addressText);
- bmAddress.setAlias(label.getText().toString());
-
- BitmessageContext bmc = Singleton.getBitmessageContext
- (CreateAddressActivity.this);
- bmc.addContact(bmAddress);
- if (subscribe.isChecked()) {
- bmc.addSubscribtion(bmAddress);
- }
- if (pubkeyBytes != null) {
- try {
- final Pubkey pubkey;
- InputStream pubkeyStream = new ByteArrayInputStream(pubkeyBytes);
- long stream = bmAddress.getStream();
- switch ((int) bmAddress.getVersion()) {
- case 2:
- pubkey = V2Pubkey.read(pubkeyStream, stream);
- break;
- case 3:
- pubkey = V3Pubkey.read(pubkeyStream, stream);
- break;
- case 4:
- pubkey = new V4Pubkey(V3Pubkey.read(pubkeyStream, stream));
- break;
- default:
- pubkey = null;
- }
- if (pubkey != null) {
- bmAddress.setPubkey(pubkey);
- }
- } catch (Exception ignore) {
- }
- }
-
- setResult(Activity.RESULT_OK);
- finish();
- } catch (RuntimeException e) {
- address.setError(getString(R.string.error_illegal_address));
- }
+ onOK(address, label, subscribe);
}
});
}
+
+ private void onOK(TextView address, EditText label, Switch subscribe) {
+ String addressText = String.valueOf(address.getText()).trim();
+ try {
+ BitmessageAddress bmAddress = new BitmessageAddress(addressText);
+ bmAddress.setAlias(label.getText().toString());
+
+ BitmessageContext bmc = Singleton.getBitmessageContext
+ (CreateAddressActivity.this);
+ bmc.addContact(bmAddress);
+ if (subscribe.isChecked()) {
+ bmc.addSubscribtion(bmAddress);
+ }
+ if (pubkeyBytes != null) {
+ try {
+ final Pubkey pubkey;
+ InputStream pubkeyStream = new ByteArrayInputStream(pubkeyBytes);
+ long stream = bmAddress.getStream();
+ switch ((int) bmAddress.getVersion()) {
+ case 2:
+ pubkey = V2Pubkey.read(pubkeyStream, stream);
+ break;
+ case 3:
+ pubkey = V3Pubkey.read(pubkeyStream, stream);
+ break;
+ case 4:
+ pubkey = new V4Pubkey(V3Pubkey.read(pubkeyStream, stream));
+ break;
+ default:
+ pubkey = null;
+ break;
+ }
+ if (pubkey != null) {
+ bmAddress.setPubkey(pubkey);
+ }
+ } catch (Exception ignore) {
+ }
+ }
+
+ setResult(Activity.RESULT_OK);
+ finish();
+ } catch (RuntimeException e) {
+ address.setError(getString(R.string.error_illegal_address));
+ }
+ }
+
private String getAddress(Uri uri) {
StringBuilder result = new StringBuilder();
String schemeSpecificPart = uri.getSchemeSpecificPart();
diff --git a/app/src/main/java/ch/dissem/apps/abit/MainActivity.java b/app/src/main/java/ch/dissem/apps/abit/MainActivity.java
index 20e238a..590e983 100644
--- a/app/src/main/java/ch/dissem/apps/abit/MainActivity.java
+++ b/app/src/main/java/ch/dissem/apps/abit/MainActivity.java
@@ -277,6 +277,10 @@ public class MainActivity extends AppCompatActivity
.withShowDrawerOnFirstLaunch(true)
.build();
+ loadDrawerItemsAsynchronously();
+ }
+
+ private void loadDrawerItemsAsynchronously() {
new AsyncTask>() {
@Override
protected List doInBackground(Void... params) {
diff --git a/app/src/main/java/ch/dissem/apps/abit/MessageDetailFragment.java b/app/src/main/java/ch/dissem/apps/abit/MessageDetailFragment.java
index ab851a9..4d31cb0 100644
--- a/app/src/main/java/ch/dissem/apps/abit/MessageDetailFragment.java
+++ b/app/src/main/java/ch/dissem/apps/abit/MessageDetailFragment.java
@@ -57,7 +57,7 @@ import ch.dissem.bitmessage.ports.MessageRepository;
import static android.text.util.Linkify.WEB_URLS;
import static ch.dissem.apps.abit.util.Constants.BITMESSAGE_ADDRESS_PATTERN;
import static ch.dissem.apps.abit.util.Constants.BITMESSAGE_URL_SCHEMA;
-import static ch.dissem.apps.abit.util.Strings.normalizeWhitespaces;
+import static ch.dissem.apps.abit.util.Strings.prepareMessageExtract;
/**
@@ -263,7 +263,7 @@ public class MessageDetailFragment extends Fragment {
viewHolder.avatar.setImageDrawable(new Identicon(message.getFrom()));
viewHolder.status.setImageResource(Assets.getStatusDrawable(message.getStatus()));
viewHolder.sender.setText(message.getFrom().toString());
- viewHolder.extract.setText(normalizeWhitespaces(message.getText()));
+ viewHolder.extract.setText(prepareMessageExtract(message.getText()));
viewHolder.item = message;
}
diff --git a/app/src/main/java/ch/dissem/apps/abit/MessageListFragment.java b/app/src/main/java/ch/dissem/apps/abit/MessageListFragment.java
index f2bc0fb..5d43314 100644
--- a/app/src/main/java/ch/dissem/apps/abit/MessageListFragment.java
+++ b/app/src/main/java/ch/dissem/apps/abit/MessageListFragment.java
@@ -80,13 +80,6 @@ public class MessageListFragment extends Fragment implements ListHolder {
private MessageRepository messageRepo;
private boolean activateOnItemClick;
- /**
- * Mandatory empty constructor for the fragment manager to instantiate the
- * fragment (e.g. upon screen orientation changes).
- */
- public MessageListFragment() {
- }
-
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
diff --git a/app/src/main/java/ch/dissem/apps/abit/SettingsFragment.java b/app/src/main/java/ch/dissem/apps/abit/SettingsFragment.java
index 111bf08..a92cc47 100644
--- a/app/src/main/java/ch/dissem/apps/abit/SettingsFragment.java
+++ b/app/src/main/java/ch/dissem/apps/abit/SettingsFragment.java
@@ -120,7 +120,7 @@ public class SettingsFragment
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
switch (key) {
- case PREFERENCE_TRUSTED_NODE:
+ case PREFERENCE_TRUSTED_NODE: {
String node = sharedPreferences.getString(PREFERENCE_TRUSTED_NODE, null);
if (node != null) {
SyncAdapter.startSync(getActivity());
@@ -128,13 +128,18 @@ public class SettingsFragment
SyncAdapter.stopSync(getActivity());
}
break;
- case PREFERENCE_SERVER_POW:
- if (sharedPreferences.getBoolean(PREFERENCE_SERVER_POW, false)) {
- SyncAdapter.startPowSync(getActivity());
- } else {
- SyncAdapter.stopPowSync(getActivity());
+ }
+ case PREFERENCE_SERVER_POW: {
+ String node = sharedPreferences.getString(PREFERENCE_TRUSTED_NODE, null);
+ if (node != null) {
+ if (sharedPreferences.getBoolean(PREFERENCE_SERVER_POW, false)) {
+ SyncAdapter.startPowSync(getActivity());
+ } else {
+ SyncAdapter.stopPowSync(getActivity());
+ }
}
break;
+ }
}
}
}
diff --git a/app/src/main/java/ch/dissem/apps/abit/adapter/SwipeableMessageAdapter.java b/app/src/main/java/ch/dissem/apps/abit/adapter/SwipeableMessageAdapter.java
index 7990c62..070092f 100644
--- a/app/src/main/java/ch/dissem/apps/abit/adapter/SwipeableMessageAdapter.java
+++ b/app/src/main/java/ch/dissem/apps/abit/adapter/SwipeableMessageAdapter.java
@@ -46,7 +46,7 @@ import ch.dissem.bitmessage.entity.Plaintext;
import ch.dissem.bitmessage.entity.valueobject.Label;
import static ch.dissem.apps.abit.repository.AndroidMessageRepository.LABEL_ARCHIVE;
-import static ch.dissem.apps.abit.util.Strings.normalizeWhitespaces;
+import static ch.dissem.apps.abit.util.Strings.prepareMessageExtract;
/**
* Adapted from the basic swipeable example by Haruki Hasegawa. See
@@ -182,8 +182,8 @@ public class SwipeableMessageAdapter
holder.status.setContentDescription(
holder.status.getContext().getString(Assets.getStatusString(item.getStatus())));
holder.sender.setText(item.getFrom().toString());
- holder.subject.setText(normalizeWhitespaces(item.getSubject()));
- holder.extract.setText(normalizeWhitespaces(item.getText()));
+ holder.subject.setText(prepareMessageExtract(item.getSubject()));
+ holder.extract.setText(prepareMessageExtract(item.getText()));
if (item.isUnread()) {
holder.sender.setTypeface(Typeface.DEFAULT_BOLD);
holder.subject.setTypeface(Typeface.DEFAULT_BOLD);
diff --git a/app/src/main/java/ch/dissem/apps/abit/util/Strings.java b/app/src/main/java/ch/dissem/apps/abit/util/Strings.java
index 7fef838..cc1f809 100644
--- a/app/src/main/java/ch/dissem/apps/abit/util/Strings.java
+++ b/app/src/main/java/ch/dissem/apps/abit/util/Strings.java
@@ -24,8 +24,19 @@ import java.util.regex.Pattern;
public class Strings {
private final static Pattern WHITESPACES = Pattern.compile("\\s+");
- public static String normalizeWhitespaces(CharSequence string) {
- string = string.subSequence(0, Math.min(string.length(), 200));
- return WHITESPACES.matcher(string).replaceAll(" ");
+ private static CharSequence trim(CharSequence string, int length) {
+ if (string.length() <= length) {
+ return string;
+ } else {
+ return string.subSequence(0, length);
+ }
+ }
+
+ /**
+ * Trime the string to 200 characters and normalizes all whitespaces by replacing any sequence
+ * of whitespace characters with a single space character.
+ */
+ public static String prepareMessageExtract(CharSequence string) {
+ return WHITESPACES.matcher(trim(string, 200)).replaceAll(" ");
}
}
From 422c7ac803d5fcf570718e78d5071e5ac391da21 Mon Sep 17 00:00:00 2001
From: Christian Basler
Date: Sun, 7 May 2017 13:39:30 +0200
Subject: [PATCH 03/53] Remember connection state (so you don't have to start a
full node whenever you lost your WiFi connection)
---
.../apps/abit/AddressDetailFragment.java | 8 -------
.../ch/dissem/apps/abit/MainActivity.java | 4 ++++
.../abit/dialog/FullNodeDialogActivity.java | 8 ++-----
.../apps/abit/listener/WifiReceiver.java | 13 ++++++-----
.../notification/NetworkNotification.java | 2 --
.../abit/service/BitmessageIntentService.java | 2 ++
.../abit/synchronization/SyncAdapter.java | 4 ++--
.../ch/dissem/apps/abit/util/Constants.java | 1 +
.../ch/dissem/apps/abit/util/Preferences.java | 22 ++++++++++++++++---
9 files changed, 37 insertions(+), 27 deletions(-)
diff --git a/app/src/main/java/ch/dissem/apps/abit/AddressDetailFragment.java b/app/src/main/java/ch/dissem/apps/abit/AddressDetailFragment.java
index 704726d..dae54bb 100644
--- a/app/src/main/java/ch/dissem/apps/abit/AddressDetailFragment.java
+++ b/app/src/main/java/ch/dissem/apps/abit/AddressDetailFragment.java
@@ -65,14 +65,6 @@ public class AddressDetailFragment extends Fragment {
*/
private BitmessageAddress item;
-
- /**
- * Mandatory empty constructor for the fragment manager to instantiate the
- * fragment (e.g. upon screen orientation changes).
- */
- public AddressDetailFragment() {
- }
-
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
diff --git a/app/src/main/java/ch/dissem/apps/abit/MainActivity.java b/app/src/main/java/ch/dissem/apps/abit/MainActivity.java
index 590e983..5970b60 100644
--- a/app/src/main/java/ch/dissem/apps/abit/MainActivity.java
+++ b/app/src/main/java/ch/dissem/apps/abit/MainActivity.java
@@ -259,6 +259,7 @@ public class MainActivity extends AppCompatActivity
@Override
public void onCheckedChanged(IDrawerItem drawerItem, CompoundButton buttonView,
boolean isChecked) {
+ Preferences.setFullNodeActive(MainActivity.this, isChecked);
if (isChecked) {
checkAndStartNode();
} else {
@@ -386,6 +387,9 @@ public class MainActivity extends AppCompatActivity
@Override
protected void onResume() {
updateUnread();
+ if (Preferences.isFullNodeActive(this)){
+ checkAndStartNode();
+ }
updateNodeSwitch();
Singleton.getMessageListener(this).resetNotification();
super.onResume();
diff --git a/app/src/main/java/ch/dissem/apps/abit/dialog/FullNodeDialogActivity.java b/app/src/main/java/ch/dissem/apps/abit/dialog/FullNodeDialogActivity.java
index a0f48f5..015dbfd 100644
--- a/app/src/main/java/ch/dissem/apps/abit/dialog/FullNodeDialogActivity.java
+++ b/app/src/main/java/ch/dissem/apps/abit/dialog/FullNodeDialogActivity.java
@@ -17,14 +17,11 @@
package ch.dissem.apps.abit.dialog;
import android.app.Activity;
-import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import ch.dissem.apps.abit.R;
-import ch.dissem.apps.abit.service.BitmessageService;
-
-import static ch.dissem.apps.abit.MainActivity.updateNodeSwitch;
+import ch.dissem.apps.abit.util.Preferences;
/**
* @author Christian Basler
@@ -38,8 +35,7 @@ public class FullNodeDialogActivity extends Activity {
findViewById(R.id.ok).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
- startService(new Intent(FullNodeDialogActivity.this, BitmessageService.class));
- updateNodeSwitch();
+ Preferences.setWifiOnly(FullNodeDialogActivity.this, true);
finish();
}
});
diff --git a/app/src/main/java/ch/dissem/apps/abit/listener/WifiReceiver.java b/app/src/main/java/ch/dissem/apps/abit/listener/WifiReceiver.java
index 329d903..898be32 100644
--- a/app/src/main/java/ch/dissem/apps/abit/listener/WifiReceiver.java
+++ b/app/src/main/java/ch/dissem/apps/abit/listener/WifiReceiver.java
@@ -22,6 +22,7 @@ import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
+import ch.dissem.apps.abit.service.BitmessageService;
import ch.dissem.apps.abit.service.Singleton;
import ch.dissem.apps.abit.util.Preferences;
import ch.dissem.bitmessage.BitmessageContext;
@@ -30,12 +31,12 @@ public class WifiReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context ctx, Intent intent) {
if ("android.net.conn.CONNECTIVITY_CHANGE".equals(intent.getAction())) {
- if (Preferences.isWifiOnly(ctx)) {
- BitmessageContext bmc = Singleton.getBitmessageContext(ctx);
-
- if (isConnectedToMeteredNetwork(ctx) && bmc.isRunning()) {
- bmc.shutdown();
- }
+ BitmessageContext bmc = Singleton.getBitmessageContext(ctx);
+ if (Preferences.isWifiOnly(ctx) && isConnectedToMeteredNetwork(ctx) && bmc.isRunning()) {
+ bmc.shutdown();
+ }
+ if (!bmc.isRunning() && !(Preferences.isWifiOnly(ctx) && isConnectedToMeteredNetwork(ctx))) {
+ ctx.startService(new Intent(ctx, BitmessageService.class));
}
}
}
diff --git a/app/src/main/java/ch/dissem/apps/abit/notification/NetworkNotification.java b/app/src/main/java/ch/dissem/apps/abit/notification/NetworkNotification.java
index 4a11cc2..2bce79b 100644
--- a/app/src/main/java/ch/dissem/apps/abit/notification/NetworkNotification.java
+++ b/app/src/main/java/ch/dissem/apps/abit/notification/NetworkNotification.java
@@ -32,7 +32,6 @@ import ch.dissem.apps.abit.service.BitmessageService;
import ch.dissem.bitmessage.utils.Property;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
-import static ch.dissem.apps.abit.MainActivity.updateNodeSwitch;
/**
* Shows the network status (as long as the client is connected as a full node)
@@ -63,7 +62,6 @@ public class NetworkNotification extends AbstractNotification {
Property connections = BitmessageService.getStatus().getProperty("network", "connections");
if (!running) {
builder.setContentText(ctx.getString(R.string.connection_info_disconnected));
- updateNodeSwitch();
} else if (connections.getProperties().length == 0) {
builder.setContentText(ctx.getString(R.string.connection_info_pending));
} else {
diff --git a/app/src/main/java/ch/dissem/apps/abit/service/BitmessageIntentService.java b/app/src/main/java/ch/dissem/apps/abit/service/BitmessageIntentService.java
index 84a5ed8..ad17d9d 100644
--- a/app/src/main/java/ch/dissem/apps/abit/service/BitmessageIntentService.java
+++ b/app/src/main/java/ch/dissem/apps/abit/service/BitmessageIntentService.java
@@ -57,6 +57,7 @@ public class BitmessageIntentService extends IntentService {
}
if (intent.hasExtra(EXTRA_STARTUP_NODE)) {
if (Preferences.isConnectionAllowed(this)) {
+ Preferences.setFullNodeActive(this, true);
startService(new Intent(this, BitmessageService.class));
updateNodeSwitch();
} else {
@@ -67,6 +68,7 @@ public class BitmessageIntentService extends IntentService {
}
}
if (intent.hasExtra(EXTRA_SHUTDOWN_NODE)) {
+ Preferences.setFullNodeActive(this, false);
stopService(new Intent(this, BitmessageService.class));
}
}
diff --git a/app/src/main/java/ch/dissem/apps/abit/synchronization/SyncAdapter.java b/app/src/main/java/ch/dissem/apps/abit/synchronization/SyncAdapter.java
index dd8f984..770adc0 100644
--- a/app/src/main/java/ch/dissem/apps/abit/synchronization/SyncAdapter.java
+++ b/app/src/main/java/ch/dissem/apps/abit/synchronization/SyncAdapter.java
@@ -71,11 +71,11 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
public void onPerformSync(Account account, Bundle extras, String authority,
ContentProviderClient provider, SyncResult syncResult) {
try {
- if (account.equals(Authenticator.ACCOUNT_SYNC)) {
+ if (account.equals(ACCOUNT_SYNC)) {
if (Preferences.isConnectionAllowed(getContext())) {
syncData();
}
- } else if (account.equals(Authenticator.ACCOUNT_POW)) {
+ } else if (account.equals(ACCOUNT_POW)) {
syncPOW();
} else {
syncResult.stats.numAuthExceptions++;
diff --git a/app/src/main/java/ch/dissem/apps/abit/util/Constants.java b/app/src/main/java/ch/dissem/apps/abit/util/Constants.java
index bd1817d..66fa847 100644
--- a/app/src/main/java/ch/dissem/apps/abit/util/Constants.java
+++ b/app/src/main/java/ch/dissem/apps/abit/util/Constants.java
@@ -26,6 +26,7 @@ public class Constants {
public static final String PREFERENCE_TRUSTED_NODE = "trusted_node";
public static final String PREFERENCE_SYNC_TIMEOUT = "sync_timeout";
public static final String PREFERENCE_SERVER_POW = "server_pow";
+ public static final String PREFERENCE_FULL_NODE = "full_node";
public static final String BITMESSAGE_URL_SCHEMA = "bitmessage:";
public static final Pattern BITMESSAGE_ADDRESS_PATTERN = Pattern.compile("\\bBM-[a-zA-Z0-9]+\\b");
diff --git a/app/src/main/java/ch/dissem/apps/abit/util/Preferences.java b/app/src/main/java/ch/dissem/apps/abit/util/Preferences.java
index e5d52ba..ebb2dfb 100644
--- a/app/src/main/java/ch/dissem/apps/abit/util/Preferences.java
+++ b/app/src/main/java/ch/dissem/apps/abit/util/Preferences.java
@@ -27,6 +27,7 @@ import ch.dissem.apps.abit.R;
import ch.dissem.apps.abit.listener.WifiReceiver;
import ch.dissem.apps.abit.notification.ErrorNotification;
+import static ch.dissem.apps.abit.util.Constants.PREFERENCE_FULL_NODE;
import static ch.dissem.apps.abit.util.Constants.PREFERENCE_SYNC_TIMEOUT;
import static ch.dissem.apps.abit.util.Constants.PREFERENCE_TRUSTED_NODE;
import static ch.dissem.apps.abit.util.Constants.PREFERENCE_WIFI_ONLY;
@@ -54,7 +55,7 @@ public class Preferences {
int index = trustedNode.lastIndexOf(':');
trustedNode = trustedNode.substring(0, index);
}
- return InetAddress.getByName(trustedNode);
+ return InetAddress.getByName(trustedNode);
}
public static int getTrustedNodePort(Context ctx) {
@@ -69,8 +70,8 @@ public class Preferences {
return Integer.parseInt(portString);
} catch (NumberFormatException e) {
new ErrorNotification(ctx)
- .setError(R.string.error_invalid_sync_port, portString)
- .show();
+ .setError(R.string.error_invalid_sync_port, portString)
+ .show();
}
}
return 8444;
@@ -95,4 +96,19 @@ public class Preferences {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(ctx);
return preferences.getBoolean(PREFERENCE_WIFI_ONLY, true);
}
+
+ public static void setWifiOnly(Context ctx, boolean status) {
+ SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(ctx);
+ preferences.edit().putBoolean(PREFERENCE_WIFI_ONLY, status).apply();
+ }
+
+ public static boolean isFullNodeActive(Context ctx) {
+ SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(ctx);
+ return preferences.getBoolean(PREFERENCE_FULL_NODE, false);
+ }
+
+ public static void setFullNodeActive(Context ctx, boolean status) {
+ SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(ctx);
+ preferences.edit().putBoolean(PREFERENCE_FULL_NODE, status).apply();
+ }
}
From 6540df4fc9db8ad9f431079cf2eb7b8b4d7286b0 Mon Sep 17 00:00:00 2001
From: Christian Basler
Date: Sun, 7 May 2017 16:13:20 +0200
Subject: [PATCH 04/53] Some improvements suggested by Codacy
---
.../apps/abit/AddressDetailFragment.java | 1 +
.../ch/dissem/apps/abit/SettingsFragment.java | 1 -
.../repository/AndroidMessageRepository.java | 26 +++++--------------
.../abit/repository/AndroidNodeRegistry.java | 1 -
4 files changed, 8 insertions(+), 21 deletions(-)
diff --git a/app/src/main/java/ch/dissem/apps/abit/AddressDetailFragment.java b/app/src/main/java/ch/dissem/apps/abit/AddressDetailFragment.java
index dae54bb..9dec757 100644
--- a/app/src/main/java/ch/dissem/apps/abit/AddressDetailFragment.java
+++ b/app/src/main/java/ch/dissem/apps/abit/AddressDetailFragment.java
@@ -160,6 +160,7 @@ public class AddressDetailFragment extends Fragment {
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_TEXT, item.getAddress());
startActivity(Intent.createChooser(shareIntent, null));
+ return true;
}
default:
return false;
diff --git a/app/src/main/java/ch/dissem/apps/abit/SettingsFragment.java b/app/src/main/java/ch/dissem/apps/abit/SettingsFragment.java
index a92cc47..c198485 100644
--- a/app/src/main/java/ch/dissem/apps/abit/SettingsFragment.java
+++ b/app/src/main/java/ch/dissem/apps/abit/SettingsFragment.java
@@ -29,7 +29,6 @@ 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;
diff --git a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidMessageRepository.java b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidMessageRepository.java
index f305ffb..d869ee8 100644
--- a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidMessageRepository.java
+++ b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidMessageRepository.java
@@ -337,7 +337,7 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
}
}
- private void insert(SQLiteDatabase db, Plaintext message) {
+ private ContentValues getValues(Plaintext message) {
ContentValues values = new ContentValues();
values.put(COLUMN_IV, message.getInventoryVector() == null ? null : message
.getInventoryVector().getHash());
@@ -354,28 +354,16 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
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);
+ return values;
+ }
+
+ private void insert(SQLiteDatabase db, Plaintext message) {
+ long id = db.insertOrThrow(TABLE_NAME, null, getValues(message));
message.setId(id);
}
private void update(SQLiteDatabase db, Plaintext message) {
- ContentValues values = new ContentValues();
- values.put(COLUMN_IV, message.getInventoryVector() == null ? null : message
- .getInventoryVector().getHash());
- values.put(COLUMN_TYPE, message.getType().name());
- values.put(COLUMN_SENDER, message.getFrom().getAddress());
- values.put(COLUMN_RECIPIENT, message.getTo() == null ? null : message.getTo().getAddress());
- values.put(COLUMN_DATA, Encode.bytes(message));
- values.put(COLUMN_ACK_DATA, message.getAckData());
- values.put(COLUMN_SENT, message.getSent());
- values.put(COLUMN_RECEIVED, message.getReceived());
- values.put(COLUMN_STATUS, message.getStatus() == null ? null : message.getStatus().name());
- values.put(COLUMN_INITIAL_HASH, message.getInitialHash());
- 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);
+ db.update(TABLE_NAME, getValues(message), "id = " + message.getId(), null);
}
@Override
diff --git a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidNodeRegistry.java b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidNodeRegistry.java
index 2183fcb..1ab7d5c 100644
--- a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidNodeRegistry.java
+++ b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidNodeRegistry.java
@@ -10,7 +10,6 @@ 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;
From 263fc8893fd39af15f2964fe4c9e66630d96c135 Mon Sep 17 00:00:00 2001
From: Christian Basler
Date: Sun, 7 May 2017 16:17:43 +0200
Subject: [PATCH 05/53] Some improvements suggested by Codacy
---
.../java/ch/dissem/apps/abit/MessageDetailFragment.java | 8 --------
1 file changed, 8 deletions(-)
diff --git a/app/src/main/java/ch/dissem/apps/abit/MessageDetailFragment.java b/app/src/main/java/ch/dissem/apps/abit/MessageDetailFragment.java
index 4d31cb0..2ed4a13 100644
--- a/app/src/main/java/ch/dissem/apps/abit/MessageDetailFragment.java
+++ b/app/src/main/java/ch/dissem/apps/abit/MessageDetailFragment.java
@@ -78,14 +78,6 @@ public class MessageDetailFragment extends Fragment {
*/
private Plaintext item;
-
- /**
- * Mandatory empty constructor for the fragment manager to instantiate the
- * fragment (e.g. upon screen orientation changes).
- */
- public MessageDetailFragment() {
- }
-
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
From 73944b588392717da8b15054356681ca92211490 Mon Sep 17 00:00:00 2001
From: Christian Basler
Date: Mon, 8 May 2017 20:28:43 +0200
Subject: [PATCH 06/53] Fixed issues with new full node behaviour
---
app/src/main/java/ch/dissem/apps/abit/MainActivity.java | 4 ++--
.../ch/dissem/apps/abit/dialog/FullNodeDialogActivity.java | 2 +-
app/src/main/java/ch/dissem/apps/abit/util/Drawables.java | 4 +++-
3 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/app/src/main/java/ch/dissem/apps/abit/MainActivity.java b/app/src/main/java/ch/dissem/apps/abit/MainActivity.java
index 5970b60..d52afe5 100644
--- a/app/src/main/java/ch/dissem/apps/abit/MainActivity.java
+++ b/app/src/main/java/ch/dissem/apps/abit/MainActivity.java
@@ -387,8 +387,8 @@ public class MainActivity extends AppCompatActivity
@Override
protected void onResume() {
updateUnread();
- if (Preferences.isFullNodeActive(this)){
- checkAndStartNode();
+ if (Preferences.isFullNodeActive(this) && Preferences.isConnectionAllowed(MainActivity.this)) {
+ startService(new Intent(this, BitmessageService.class));
}
updateNodeSwitch();
Singleton.getMessageListener(this).resetNotification();
diff --git a/app/src/main/java/ch/dissem/apps/abit/dialog/FullNodeDialogActivity.java b/app/src/main/java/ch/dissem/apps/abit/dialog/FullNodeDialogActivity.java
index 015dbfd..bb0cf57 100644
--- a/app/src/main/java/ch/dissem/apps/abit/dialog/FullNodeDialogActivity.java
+++ b/app/src/main/java/ch/dissem/apps/abit/dialog/FullNodeDialogActivity.java
@@ -35,7 +35,7 @@ public class FullNodeDialogActivity extends Activity {
findViewById(R.id.ok).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
- Preferences.setWifiOnly(FullNodeDialogActivity.this, true);
+ Preferences.setWifiOnly(FullNodeDialogActivity.this, false);
finish();
}
});
diff --git a/app/src/main/java/ch/dissem/apps/abit/util/Drawables.java b/app/src/main/java/ch/dissem/apps/abit/util/Drawables.java
index dfda9c8..721cc87 100644
--- a/app/src/main/java/ch/dissem/apps/abit/util/Drawables.java
+++ b/app/src/main/java/ch/dissem/apps/abit/util/Drawables.java
@@ -45,6 +45,7 @@ import static android.graphics.Color.BLACK;
import static android.graphics.Color.WHITE;
import static android.util.Base64.NO_WRAP;
import static android.util.Base64.URL_SAFE;
+import static ch.dissem.apps.abit.util.Constants.BITMESSAGE_URL_SCHEMA;
/**
* Some helper methods to work with drawables.
@@ -73,7 +74,8 @@ public class Drawables {
}
public static Bitmap qrCode(BitmessageAddress address) {
- StringBuilder link = new StringBuilder("bitmessage:");
+ StringBuilder link = new StringBuilder();
+ link.append(BITMESSAGE_URL_SCHEMA);
link.append(address.getAddress());
if (address.getAlias() != null) {
link.append("?label=").append(address.getAlias());
From bf070da20a578e0a3d3f13aa3c60210fc5ffece1 Mon Sep 17 00:00:00 2001
From: Christian Basler
Date: Wed, 17 May 2017 12:24:13 +0200
Subject: [PATCH 07/53] Fixed NullPointerException when accessing outbox items
---
app/build.gradle | 2 +-
.../java/ch/dissem/apps/abit/repository/AndroidInventory.java | 2 +-
.../dissem/apps/abit/repository/AndroidMessageRepository.java | 2 +-
build.gradle | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index 76984f3..e2150b3 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -38,7 +38,7 @@ android {
}
//ext.jabitVersion = '2.0.4'
-ext.jabitVersion = 'feature-extended-encoding-SNAPSHOT'
+ext.jabitVersion = 'development-SNAPSHOT'
ext.supportVersion = '25.3.1'
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
diff --git a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidInventory.java b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidInventory.java
index 8632679..6b7720f 100644
--- a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidInventory.java
+++ b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidInventory.java
@@ -100,7 +100,7 @@ public class AndroidInventory implements Inventory {
while (c.moveToNext()) {
byte[] blob = c.getBlob(c.getColumnIndex(COLUMN_HASH));
long expires = c.getLong(c.getColumnIndex(COLUMN_EXPIRES));
- result.put(new InventoryVector(blob), expires);
+ result.put(InventoryVector.fromHash(blob), expires);
}
}
LOG.info("Stream #" + stream + " inventory size: " + result.size());
diff --git a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidMessageRepository.java b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidMessageRepository.java
index d869ee8..8d44495 100644
--- a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidMessageRepository.java
+++ b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidMessageRepository.java
@@ -272,7 +272,7 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
new ByteArrayInputStream(data));
long id = c.getLong(c.getColumnIndex(COLUMN_ID));
builder.id(id);
- builder.IV(new InventoryVector(iv));
+ builder.IV(InventoryVector.fromHash(iv));
builder.from(ctx.getAddressRepository().getAddress(c.getString(c.getColumnIndex
(COLUMN_SENDER))));
builder.to(ctx.getAddressRepository().getAddress(c.getString(c.getColumnIndex
diff --git a/build.gradle b/build.gradle
index ceae43c..51bb49b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -9,7 +9,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.3.1'
+ classpath 'com.android.tools.build:gradle:2.3.2'
classpath 'com.github.ben-manes:gradle-versions-plugin:0.14.0'
// NOTE: Do not place your application dependencies here; they belong
From a67560c28b50e0c88dece69d72ee07ac92518306 Mon Sep 17 00:00:00 2001
From: Christian Basler
Date: Thu, 18 May 2017 07:29:16 +0200
Subject: [PATCH 08/53] Fixed and improved the UI for starting a full node
---
.../java/ch/dissem/apps/abit/MainActivity.java | 2 +-
app/src/main/res/layout/dialog_full_node.xml | 15 +++++++--------
app/src/main/res/values-de/strings.xml | 3 ++-
app/src/main/res/values/strings.xml | 3 ++-
4 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/app/src/main/java/ch/dissem/apps/abit/MainActivity.java b/app/src/main/java/ch/dissem/apps/abit/MainActivity.java
index d52afe5..2384b48 100644
--- a/app/src/main/java/ch/dissem/apps/abit/MainActivity.java
+++ b/app/src/main/java/ch/dissem/apps/abit/MainActivity.java
@@ -479,7 +479,7 @@ public class MainActivity extends AppCompatActivity
i.runOnUiThread(new Runnable() {
@Override
public void run() {
- i.nodeSwitch.withChecked(i.bmc.isRunning());
+ i.nodeSwitch.withChecked(Preferences.isFullNodeActive(i));
i.drawer.updateStickyFooterItem(i.nodeSwitch);
}
});
diff --git a/app/src/main/res/layout/dialog_full_node.xml b/app/src/main/res/layout/dialog_full_node.xml
index 9c8edd9..450c969 100644
--- a/app/src/main/res/layout/dialog_full_node.xml
+++ b/app/src/main/res/layout/dialog_full_node.xml
@@ -38,12 +38,12 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="8dp"
- android:text="@string/startup_node"
+ android:text="@string/use_mobile_network"
android:textColor="@color/colorAccent"
- app:layout_constraintEnd_toEndOf="@+id/description"
+ app:layout_constraintEnd_toEndOf="@id/description"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintTop_toBottomOf="@+id/description"
- tools:layout_editor_absoluteX="184dp"/>
+ tools:layout_editor_absoluteX="8dp"/>
+ app:layout_constraintEnd_toEndOf="@id/description"
+ app:layout_constraintTop_toBottomOf="@+id/ok"
+ tools:layout_editor_absoluteX="8dp"/>
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 4d03c23..1fa2b69 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -98,7 +98,7 @@ Als Alternative kann in den Einstellungen ein vertrauenswürdiger Knoten konfigu
Du kannst einfach den Inhalt eines Exports oder einer ‘keys.dat’-Datei einfügen
Knoten starten
Knoten beenden
- Knoten starten
+ Mobilfunknetz benutzen
Nachricht
Bitte versuchs nochmals wenn eine Identität verfügbar ist.
Chan
@@ -117,4 +117,5 @@ Als Alternative kann in den Einstellungen ein vertrauenswürdiger Knoten konfigu
Aufräumarbeiten gestartet
Aufräumarbeiten beendet
Veraltete Inventareinträge werden entfernt
+ Auf W-LAN warten
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 96037f6..ac64a6d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -100,7 +100,7 @@ As an alternative you could configure a trusted node in the settings, but as of
You can just paste the contents of an export or a ‘keys.dat’ file
shutdown node
restart node
- Startup node
+ Use mobile network
Message
Please try again once an identity is available.
public key requested
@@ -116,4 +116,5 @@ As an alternative you could configure a trusted node in the settings, but as of
Remove outdated inventory entries
Cleanup started
Cleanup finished
+ Wait for Wi-Fi
From bf52d2f3de4e2eb78026cefe99b647dbf399ddeb Mon Sep 17 00:00:00 2001
From: Christian Basler
Date: Thu, 29 Jun 2017 23:29:56 +0200
Subject: [PATCH 09/53] Asynchronously load contacts to improve responsiveness
---
.../apps/abit/AddressDetailFragment.java | 3 -
.../dissem/apps/abit/AddressListFragment.java | 120 ++++++------
.../apps/abit/ImportIdentitiesFragment.java | 26 ++-
.../ch/dissem/apps/abit/MainActivity.java | 13 +-
.../repository/AndroidAddressRepository.java | 174 ++++++++++++------
.../repository/AndroidMessageRepository.java | 34 ++--
.../abit/repository/AndroidNodeRegistry.java | 8 +-
.../AndroidProofOfWorkRepository.java | 19 +-
.../apps/abit/service/BitmessageService.java | 2 +-
.../dissem/apps/abit/service/Singleton.java | 8 +-
.../abit/synchronization/SyncAdapter.java | 4 +-
.../ch/dissem/apps/abit/util/Drawables.java | 8 +-
.../ch/dissem/apps/abit/util/UuidUtils.java | 6 +-
.../main/res/drawable/avatar_placeholder.xml | 12 ++
app/src/main/res/layout/subscription_row.xml | 2 +-
app/src/main/res/values/strings.xml | 2 +-
build.gradle | 2 +-
17 files changed, 261 insertions(+), 182 deletions(-)
create mode 100644 app/src/main/res/drawable/avatar_placeholder.xml
diff --git a/app/src/main/java/ch/dissem/apps/abit/AddressDetailFragment.java b/app/src/main/java/ch/dissem/apps/abit/AddressDetailFragment.java
index 9dec757..791e1b2 100644
--- a/app/src/main/java/ch/dissem/apps/abit/AddressDetailFragment.java
+++ b/app/src/main/java/ch/dissem/apps/abit/AddressDetailFragment.java
@@ -70,9 +70,6 @@ public class AddressDetailFragment extends Fragment {
super.onCreate(savedInstanceState);
if (getArguments().containsKey(ARG_ITEM)) {
- // Load the dummy content specified by the fragment
- // arguments. In a real-world scenario, use a Loader
- // to load content from a content provider.
item = (BitmessageAddress) getArguments().getSerializable(ARG_ITEM);
}
setHasOptionsMenu(true);
diff --git a/app/src/main/java/ch/dissem/apps/abit/AddressListFragment.java b/app/src/main/java/ch/dissem/apps/abit/AddressListFragment.java
index 93e1f2e..9633cbe 100644
--- a/app/src/main/java/ch/dissem/apps/abit/AddressListFragment.java
+++ b/app/src/main/java/ch/dissem/apps/abit/AddressListFragment.java
@@ -19,6 +19,7 @@ package ch.dissem.apps.abit;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@@ -32,11 +33,11 @@ import android.widget.TextView;
import com.google.zxing.integration.android.IntentIntegrator;
-import java.util.Collections;
-import java.util.Comparator;
+import java.util.LinkedList;
import java.util.List;
import ch.dissem.apps.abit.listener.ActionBarListener;
+import ch.dissem.apps.abit.repository.AndroidAddressRepository;
import ch.dissem.apps.abit.service.Singleton;
import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.valueobject.Label;
@@ -47,6 +48,46 @@ import io.github.yavski.fabspeeddial.SimpleMenuListenerAdapter;
* Fragment that shows a list of all contacts, the ones we subscribed to first.
*/
public class AddressListFragment extends AbstractItemListFragment {
+ private ArrayAdapter adapter;
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ adapter = new ArrayAdapter(
+ getActivity(),
+ R.layout.subscription_row,
+ R.id.name,
+ new LinkedList()) {
+ @NonNull
+ @Override
+ public View getView(int position, View convertView, @NonNull ViewGroup parent) {
+ ViewHolder v;
+ if (convertView == null) {
+ LayoutInflater inflater = LayoutInflater.from(getContext());
+ convertView = inflater.inflate(R.layout.subscription_row, parent, false);
+ v = new ViewHolder();
+ v.ctx = getContext();
+ v.avatar = (ImageView) convertView.findViewById(R.id.avatar);
+ v.name = (TextView) convertView.findViewById(R.id.name);
+ v.streamNumber = (TextView) convertView.findViewById(R.id.stream_number);
+ v.subscribed = convertView.findViewById(R.id.subscribed);
+ convertView.setTag(v);
+ } else {
+ v = (ViewHolder) convertView.getTag();
+ }
+ BitmessageAddress item = getItem(position);
+ assert item != null;
+ v.avatar.setImageDrawable(new Identicon(item));
+ v.name.setText(item.toString());
+ v.streamNumber.setText(v.ctx.getString(R.string.stream_number, item.getStream()));
+ v.subscribed.setVisibility(item.isSubscribed() ? View.VISIBLE : View.INVISIBLE);
+ return convertView;
+ }
+ };
+ setListAdapter(adapter);
+ }
+
@Override
public void onResume() {
super.onResume();
@@ -55,61 +96,26 @@ public class AddressListFragment extends AbstractItemListFragment addresses = Singleton.getAddressRepository(getContext())
- .getContacts();
- Collections.sort(addresses, new Comparator() {
+ adapter.clear();
+ final AndroidAddressRepository addressRepo = Singleton.getAddressRepository(getContext());
+ new AsyncTask() {
@Override
- public int compare(BitmessageAddress lhs, BitmessageAddress rhs) {
- // Yields the following order:
- // * Subscribed addresses come first
- // * Addresses with Aliases (alphabetically)
- // * Addresses (alphabetically)
- if (lhs.isSubscribed() == rhs.isSubscribed()) {
- if (lhs.getAlias() != null) {
- if (rhs.getAlias() != null) {
- return lhs.getAlias().compareTo(rhs.getAlias());
- } else {
- return -1;
- }
- } else if (rhs.getAlias() != null) {
- return 1;
- } else {
- return lhs.getAddress().compareTo(rhs.getAddress());
- }
+ protected Void doInBackground(Void... params) {
+ List ids = addressRepo.getContactIds();
+ for (String id : ids) {
+ BitmessageAddress address = addressRepo.getById(id);
+ publishProgress(address);
}
- if (lhs.isSubscribed()) {
- return -1;
- } else {
- return 1;
+ return null;
+ }
+
+ @Override
+ protected void onProgressUpdate(BitmessageAddress... values) {
+ for (BitmessageAddress address : values) {
+ adapter.add(address);
}
}
- });
- setListAdapter(new ArrayAdapter(
- getActivity(),
- android.R.layout.simple_list_item_activated_1,
- android.R.id.text1,
- addresses) {
- @NonNull
- @Override
- public View getView(int position, View convertView, @NonNull ViewGroup parent) {
- if (convertView == null) {
- LayoutInflater inflater = LayoutInflater.from(getContext());
- convertView = inflater.inflate(R.layout.subscription_row, parent, false);
- }
- BitmessageAddress item = getItem(position);
- assert item != null;
- ((ImageView) convertView.findViewById(R.id.avatar)).setImageDrawable(new
- Identicon(item));
- TextView name = (TextView) convertView.findViewById(R.id.name);
- name.setText(item.toString());
- TextView streamNumber = (TextView) convertView.findViewById(R.id.stream_number);
- streamNumber.setText(getContext().getString(R.string.stream_number,
- item.getStream()));
- convertView.findViewById(R.id.subscribed).setVisibility(item.isSubscribed() ?
- View.VISIBLE : View.INVISIBLE);
- return convertView;
- }
- });
+ }.execute();
}
@Override
@@ -163,4 +169,12 @@ public class AddressListFragment extends AbstractItemListFragment getIdentities() {
return find("private_key IS NOT NULL");
}
+ @NonNull
@Override
public List getChans() {
return find("chan = '1'");
}
+ @NonNull
@Override
public List getSubscriptions() {
return find("subscribed = '1'");
}
+ @NonNull
@Override
public List getSubscriptions(long broadcastVersion) {
if (broadcastVersion > 4) {
@@ -108,11 +113,55 @@ public class AndroidAddressRepository implements AddressRepository {
}
}
+ @NonNull
@Override
public List getContacts() {
return find("private_key IS NULL OR chan = '1'");
}
+ /**
+ * Returns the contacts in the following order:
+ *
+ * - Subscribed addresses come first
+ *
- Addresses with Aliases (alphabetically)
+ *
- Addresses (alphabetically)
+ *
+ *
+ * @return the ordered list of ids (address strings)
+ */
+ @NonNull
+ public List getContactIds() {
+ return findIds(
+ "private_key IS NULL OR chan = '1'",
+ COLUMN_SUBSCRIBED + " DESC, " + COLUMN_ALIAS + " IS NULL, " + COLUMN_ALIAS + ", " + COLUMN_ADDRESS
+ );
+ }
+
+ @NonNull
+ private List findIds(String where, String orderBy) {
+ List result = new LinkedList<>();
+
+ // Define a projection that specifies which columns from the database
+ // you will actually use after this query.
+ String[] projection = {
+ COLUMN_ADDRESS
+ };
+
+ SQLiteDatabase db = sql.getReadableDatabase();
+ try (Cursor c = db.query(
+ TABLE_NAME, projection,
+ where,
+ null, null, null,
+ orderBy
+ )) {
+ while (c.moveToNext()) {
+ result.add(c.getString(c.getColumnIndex(COLUMN_ADDRESS)));
+ }
+ }
+ return result;
+ }
+
+ @NonNull
private List find(String where) {
List result = new LinkedList<>();
@@ -161,8 +210,6 @@ public class AndroidAddressRepository implements AddressRepository {
result.add(address);
}
- } catch (IOException e) {
- LOG.error(e.getMessage(), e);
}
return result;
}
@@ -188,61 +235,55 @@ public class AndroidAddressRepository implements AddressRepository {
}
private void update(BitmessageAddress address) {
- try {
- SQLiteDatabase db = sql.getWritableDatabase();
- // Create a new map of values, where column names are the keys
- ContentValues values = new ContentValues();
- if (address.getAlias() != null) {
- values.put(COLUMN_ALIAS, address.getAlias());
- }
- if (address.getPubkey() != null) {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- address.getPubkey().writeUnencrypted(out);
- values.put(COLUMN_PUBLIC_KEY, out.toByteArray());
- }
- if (address.getPrivateKey() != null) {
- values.put(COLUMN_PRIVATE_KEY, Encode.bytes(address.getPrivateKey()));
- }
- if (address.isChan()) {
- values.put(COLUMN_CHAN, true);
- }
- values.put(COLUMN_SUBSCRIBED, address.isSubscribed());
+ SQLiteDatabase db = sql.getWritableDatabase();
+ // Create a new map of values, where column names are the keys
+ ContentValues values = new ContentValues();
+ if (address.getAlias() != null) {
+ values.put(COLUMN_ALIAS, address.getAlias());
+ }
+ if (address.getPubkey() != null) {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ address.getPubkey().writeUnencrypted(out);
+ values.put(COLUMN_PUBLIC_KEY, out.toByteArray());
+ }
+ if (address.getPrivateKey() != null) {
+ values.put(COLUMN_PRIVATE_KEY, Encode.bytes(address.getPrivateKey()));
+ }
+ if (address.isChan()) {
+ values.put(COLUMN_CHAN, true);
+ }
+ values.put(COLUMN_SUBSCRIBED, address.isSubscribed());
- int update = db.update(TABLE_NAME, values, "address=?",
- new String[]{address.getAddress()});
- if (update < 0) {
- LOG.error("Could not update address " + address);
- }
- } catch (IOException e) {
- LOG.error(e.getMessage(), e);
+ int update = db.update(TABLE_NAME, values, "address=?",
+ new String[]{address.getAddress()});
+ if (update < 0) {
+ LOG.error("Could not update address " + address);
}
}
private void insert(BitmessageAddress address) {
- try {
- SQLiteDatabase db = sql.getWritableDatabase();
- // Create a new map of values, where column names are the keys
- ContentValues values = new ContentValues();
- values.put(COLUMN_ADDRESS, address.getAddress());
- values.put(COLUMN_VERSION, address.getVersion());
- values.put(COLUMN_ALIAS, address.getAlias());
- if (address.getPubkey() != null) {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- address.getPubkey().writeUnencrypted(out);
- values.put(COLUMN_PUBLIC_KEY, out.toByteArray());
- } else {
- values.put(COLUMN_PUBLIC_KEY, (byte[]) null);
- }
+ SQLiteDatabase db = sql.getWritableDatabase();
+ // Create a new map of values, where column names are the keys
+ ContentValues values = new ContentValues();
+ values.put(COLUMN_ADDRESS, address.getAddress());
+ values.put(COLUMN_VERSION, address.getVersion());
+ values.put(COLUMN_ALIAS, address.getAlias());
+ if (address.getPubkey() != null) {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ address.getPubkey().writeUnencrypted(out);
+ values.put(COLUMN_PUBLIC_KEY, out.toByteArray());
+ } else {
+ values.put(COLUMN_PUBLIC_KEY, (byte[]) null);
+ }
+ if (address.getPrivateKey() != null) {
values.put(COLUMN_PRIVATE_KEY, Encode.bytes(address.getPrivateKey()));
- values.put(COLUMN_CHAN, address.isChan());
- values.put(COLUMN_SUBSCRIBED, address.isSubscribed());
+ }
+ values.put(COLUMN_CHAN, address.isChan());
+ values.put(COLUMN_SUBSCRIBED, address.isSubscribed());
- long insert = db.insert(TABLE_NAME, null, values);
- if (insert < 0) {
- LOG.error("Could not insert address " + address);
- }
- } catch (IOException e) {
- LOG.error(e.getMessage(), e);
+ long insert = db.insert(TABLE_NAME, null, values);
+ if (insert < 0) {
+ LOG.error("Could not insert address " + address);
}
}
@@ -252,10 +293,21 @@ public class AndroidAddressRepository implements AddressRepository {
db.delete(TABLE_NAME, "address = ?", new String[]{address.getAddress()});
}
+ @NonNull
+ public BitmessageAddress getById(String id) {
+ List result = find("address = '" + id + "'");
+ if (result.size() > 0) {
+ return result.get(0);
+ } else {
+ throw new ApplicationException("Address with id " + id + " not found.");
+ }
+ }
+
+ @NonNull
@Override
public BitmessageAddress getAddress(String address) {
List result = find("address = '" + address + "'");
if (result.size() > 0) return result.get(0);
- return null;
+ return new BitmessageAddress(address);
}
}
diff --git a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidMessageRepository.java b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidMessageRepository.java
index 8d44495..b62e761 100644
--- a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidMessageRepository.java
+++ b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidMessageRepository.java
@@ -22,12 +22,12 @@ import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteConstraintException;
import android.database.sqlite.SQLiteDatabase;
+import android.support.annotation.NonNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
-import java.io.IOException;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
@@ -91,6 +91,7 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
this.context = ctx;
}
+ @NonNull
@Override
public List findMessages(Label label) {
if (label == LABEL_ARCHIVE) {
@@ -100,6 +101,7 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
}
}
+ @NonNull
public List
*/
public class UuidUtils {
+ /**
+ * @param bytes that represent a UUID, or null for a random UUID
+ * @return the UUID from the given bytes, or a random UUID if bytes is null.
+ */
public static UUID asUuid(byte[] bytes) {
if (bytes == null) {
- return null;
+ return UUID.randomUUID();
}
ByteBuffer bb = ByteBuffer.wrap(bytes);
long firstLong = bb.getLong();
diff --git a/app/src/main/res/drawable/avatar_placeholder.xml b/app/src/main/res/drawable/avatar_placeholder.xml
new file mode 100644
index 0000000..9b5bd5d
--- /dev/null
+++ b/app/src/main/res/drawable/avatar_placeholder.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/subscription_row.xml b/app/src/main/res/layout/subscription_row.xml
index 8a40938..83ef228 100644
--- a/app/src/main/res/layout/subscription_row.xml
+++ b/app/src/main/res/layout/subscription_row.xml
@@ -29,7 +29,7 @@
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_margin="16dp"
- android:src="@color/colorAccent"
+ android:src="@drawable/avatar_placeholder"
tools:ignore="ContentDescription"/>
Public key available
Public key not yet available
QR code
- Having more identities will reequire more resources. If you are sure you want to add an identity, please select what exactly you want to do:
+ Having more identities will require more resources. If you are sure you want to add an identity, please select what exactly you want to do:
Share
Are you sure you want to delete this identity? You won\'t be able to receive any messages sent to this address and can\'t undo this operation.
Are you sure you want to delete this contact?
diff --git a/build.gradle b/build.gradle
index 51bb49b..b06c3d3 100644
--- a/build.gradle
+++ b/build.gradle
@@ -9,7 +9,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.3.2'
+ classpath 'com.android.tools.build:gradle:2.3.3'
classpath 'com.github.ben-manes:gradle-versions-plugin:0.14.0'
// NOTE: Do not place your application dependencies here; they belong
From 1c284eba26d02404a12a973bbac7f3ac30594bc0 Mon Sep 17 00:00:00 2001
From: Christian Basler
Date: Fri, 30 Jun 2017 00:07:54 +0200
Subject: [PATCH 10/53] Asynchronously load messages to improve responsiveness
---
.../dissem/apps/abit/MessageListFragment.java | 28 ++++++-----
.../abit/adapter/SwipeableMessageAdapter.java | 15 ++++--
.../repository/AndroidMessageRepository.java | 46 +++++++++++++++++--
3 files changed, 69 insertions(+), 20 deletions(-)
diff --git a/app/src/main/java/ch/dissem/apps/abit/MessageListFragment.java b/app/src/main/java/ch/dissem/apps/abit/MessageListFragment.java
index 5d43314..e3a187a 100644
--- a/app/src/main/java/ch/dissem/apps/abit/MessageListFragment.java
+++ b/app/src/main/java/ch/dissem/apps/abit/MessageListFragment.java
@@ -39,12 +39,14 @@ import com.h6ah4i.android.widget.advrecyclerview.touchguard.RecyclerViewTouchAct
import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils;
import java.util.Collections;
+import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import ch.dissem.apps.abit.adapter.SwipeableMessageAdapter;
import ch.dissem.apps.abit.listener.ActionBarListener;
import ch.dissem.apps.abit.listener.ListSelectionListener;
+import ch.dissem.apps.abit.repository.AndroidMessageRepository;
import ch.dissem.apps.abit.service.Singleton;
import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.Plaintext;
@@ -77,7 +79,7 @@ public class MessageListFragment extends Fragment implements ListHolder {
private Label currentLabel;
private MenuItem emptyTrashMenuItem;
- private MessageRepository messageRepo;
+ private AndroidMessageRepository messageRepo;
private boolean activateOnItemClick;
@Override
@@ -103,19 +105,15 @@ public class MessageListFragment extends Fragment implements ListHolder {
return;
}
- if (!Objects.equals(currentLabel, label)) {
- adapter.setData(label, Collections.emptyList());
- adapter.notifyDataSetChanged();
- }
doUpdateList(label);
}
private void doUpdateList(final Label label) {
+ adapter.clear(label);
if (label == null) {
if (getActivity() instanceof ActionBarListener) {
((ActionBarListener) getActivity()).updateTitle(getString(R.string.app_name));
}
- adapter.setData(null, Collections.emptyList());
adapter.notifyDataSetChanged();
return;
}
@@ -131,18 +129,24 @@ public class MessageListFragment extends Fragment implements ListHolder {
actionBarListener.updateTitle(label.toString());
}
}
- new AsyncTask>() {
+ new AsyncTask() {
@Override
- protected List doInBackground(Void... params) {
- return messageRepo.findMessages(label);
+ protected Void doInBackground(Void... params) {
+ List ids = messageRepo.findMessageIds(label);
+ for (Long id : ids) {
+ Plaintext message = messageRepo.getMessage(id);
+ publishProgress(message);
+ }
+ return null;
}
@Override
- protected void onPostExecute(List messages) {
+ protected void onProgressUpdate(Plaintext... values) {
if (adapter != null) {
- adapter.setData(label, messages);
- adapter.notifyDataSetChanged();
+ for (Plaintext message : values) {
+ adapter.add(message);
+ }
}
}
}.execute();
diff --git a/app/src/main/java/ch/dissem/apps/abit/adapter/SwipeableMessageAdapter.java b/app/src/main/java/ch/dissem/apps/abit/adapter/SwipeableMessageAdapter.java
index 070092f..df3e2c0 100644
--- a/app/src/main/java/ch/dissem/apps/abit/adapter/SwipeableMessageAdapter.java
+++ b/app/src/main/java/ch/dissem/apps/abit/adapter/SwipeableMessageAdapter.java
@@ -37,6 +37,7 @@ import com.h6ah4i.android.widget.advrecyclerview.utils.AbstractSwipeableItemView
import com.h6ah4i.android.widget.advrecyclerview.utils.RecyclerViewAdapterUtils;
import java.util.Collections;
+import java.util.LinkedList;
import java.util.List;
import ch.dissem.apps.abit.Identicon;
@@ -59,7 +60,7 @@ public class SwipeableMessageAdapter
extends RecyclerView.Adapter
implements SwipeableItemAdapter, SwipeableItemConstants {
- private List data = Collections.emptyList();
+ private List data = new LinkedList<>();
private EventListener eventListener;
private final View.OnClickListener itemViewOnClickListener;
private final View.OnClickListener swipeableViewContainerOnClickListener;
@@ -124,9 +125,15 @@ public class SwipeableMessageAdapter
setHasStableIds(true);
}
- public void setData(Label label, List data) {
- this.label = label;
- this.data = data;
+ public void add(Plaintext item) {
+ data.add(item);
+ notifyDataSetChanged();
+ }
+
+ public void clear(Label newLabel) {
+ label = newLabel;
+ data.clear();
+ notifyDataSetChanged();
}
private void onItemViewClick(View v) {
diff --git a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidMessageRepository.java b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidMessageRepository.java
index b62e761..316f5f8 100644
--- a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidMessageRepository.java
+++ b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidMessageRepository.java
@@ -101,6 +101,15 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
}
}
+ @NonNull
+ public List findMessageIds(Label label) {
+ if (label == LABEL_ARCHIVE) {
+ return findIds("id NOT IN (SELECT message_id FROM Message_Label)");
+ } else {
+ return findIds("id IN (SELECT message_id FROM Message_Label WHERE label_id=" + label.getId() + ")");
+ }
+ }
+
@NonNull
public List findLabels(String where) {
List result = new LinkedList<>();
@@ -239,6 +248,31 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
db.update(PARENTS_TABLE_NAME, values, "conversation=?", whereArgs);
}
+ @NonNull
+ protected List findIds(String where) {
+ List result = new LinkedList<>();
+
+ // Define a projection that specifies which columns from the database
+ // you will actually use after this query.
+ String[] projection = {
+ COLUMN_ID
+ };
+
+ SQLiteDatabase db = sql.getReadableDatabase();
+ try (Cursor c = db.query(
+ TABLE_NAME, projection,
+ where,
+ null, null, null,
+ COLUMN_RECEIVED + " DESC, " + COLUMN_SENT + " DESC"
+ )) {
+ while (c.moveToNext()) {
+ long id = c.getLong(c.getColumnIndex(COLUMN_ID));
+ result.add(id);
+ }
+ }
+ return result;
+ }
+
@NonNull
protected List find(String where) {
List result = new LinkedList<>();
@@ -279,10 +313,14 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
long id = c.getLong(c.getColumnIndex(COLUMN_ID));
builder.id(id);
builder.IV(InventoryVector.fromHash(iv));
- builder.from(ctx.getAddressRepository().getAddress(c.getString(c.getColumnIndex
- (COLUMN_SENDER))));
- builder.to(ctx.getAddressRepository().getAddress(c.getString(c.getColumnIndex
- (COLUMN_RECIPIENT))));
+ String sender = c.getString(c.getColumnIndex(COLUMN_SENDER));
+ if (sender != null) {
+ builder.from(ctx.getAddressRepository().getAddress(sender));
+ }
+ String recipient = c.getString(c.getColumnIndex(COLUMN_RECIPIENT));
+ if (recipient != null) {
+ builder.to(ctx.getAddressRepository().getAddress(recipient));
+ }
builder.ackData(c.getBlob(c.getColumnIndex(COLUMN_ACK_DATA)));
builder.sent(c.getLong(c.getColumnIndex(COLUMN_SENT)));
builder.received(c.getLong(c.getColumnIndex(COLUMN_RECEIVED)));
From 433c7571076cd8d2a3375abcec7cc9ef3097eecf Mon Sep 17 00:00:00 2001
From: Christian Basler
Date: Mon, 10 Jul 2017 06:21:29 +0200
Subject: [PATCH 11/53] UI improvements and fixes for older Android versions
---
app/build.gradle | 3 +-
app/src/main/AndroidManifest.xml | 14 +--
.../apps/abit/AbstractItemListFragment.java | 12 ++-
.../dissem/apps/abit/AddressListFragment.java | 4 +-
.../java/ch/dissem/apps/abit/ListHolder.java | 10 +-
.../ch/dissem/apps/abit/MainActivity.java | 66 +++++++++---
.../dissem/apps/abit/MessageListFragment.java | 33 ++++--
.../ch/dissem/apps/abit/SettingsActivity.java | 18 ----
.../ch/dissem/apps/abit/SettingsFragment.java | 35 +++++--
.../ch/dissem/apps/abit/StatusFragment.java | 49 +++++++++
.../abit/adapter/SwipeableMessageAdapter.java | 6 +-
.../repository/AndroidAddressRepository.java | 3 +-
.../repository/AndroidMessageRepository.java | 62 ++++++-----
.../apps/abit/repository/SqlHelper.java | 30 ++++++
.../main/res/drawable/bg_item_selectable.xml | 12 +++
.../res/drawable/bg_item_selected_state.xml | 24 ++---
app/src/main/res/drawable/bg_white.xml | 8 ++
.../layout-w720dp/activity_message_list.xml | 96 +++++++++---------
app/src/main/res/layout/contact_row.xml | 16 +--
.../main/res/layout/fragment_address_list.xml | 11 +-
app/src/main/res/layout/fragment_status.xml | 11 ++
app/src/main/res/layout/subscription_row.xml | 3 +-
app/src/main/res/values/colors.xml | 1 +
app/src/main/res/values/styles.xml | 1 +
app/src/main/res/xml/preferences.xml | 12 +--
gradle/wrapper/gradle-wrapper.jar | Bin 54208 -> 54212 bytes
gradle/wrapper/gradle-wrapper.properties | 4 +-
27 files changed, 352 insertions(+), 192 deletions(-)
delete mode 100644 app/src/main/java/ch/dissem/apps/abit/SettingsActivity.java
create mode 100644 app/src/main/java/ch/dissem/apps/abit/StatusFragment.java
create mode 100644 app/src/main/res/drawable/bg_item_selectable.xml
create mode 100644 app/src/main/res/drawable/bg_white.xml
create mode 100644 app/src/main/res/layout/fragment_status.xml
diff --git a/app/build.gradle b/app/build.gradle
index e2150b3..f33f564 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,5 +1,5 @@
-apply plugin: 'idea'
apply plugin: 'com.android.application'
+apply plugin: 'idea'
ext {
appName = "Abit"
@@ -44,6 +44,7 @@ dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile "com.android.support:appcompat-v7:$supportVersion"
+ compile "com.android.support:preference-v7:$supportVersion"
compile "com.android.support:support-v4:$supportVersion"
compile "com.android.support:design:$supportVersion"
compile "com.android.support:multidex:1.0.1"
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d46c295..fb086cc 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -84,16 +84,6 @@
-
-
-
-
-
-
-
+ android:parentActivityName=".MainActivity">
+ android:value=".MainActivity"/>
diff --git a/app/src/main/java/ch/dissem/apps/abit/AbstractItemListFragment.java b/app/src/main/java/ch/dissem/apps/abit/AbstractItemListFragment.java
index b61de46..aeaed74 100644
--- a/app/src/main/java/ch/dissem/apps/abit/AbstractItemListFragment.java
+++ b/app/src/main/java/ch/dissem/apps/abit/AbstractItemListFragment.java
@@ -27,7 +27,7 @@ import ch.dissem.apps.abit.listener.ListSelectionListener;
/**
* @author Christian Basler
*/
-public abstract class AbstractItemListFragment extends ListFragment implements ListHolder {
+public abstract class AbstractItemListFragment extends ListFragment implements ListHolder {
/**
* The serialization (saved instance state) Bundle key representing the
* activated item position. Only used on tablets.
@@ -143,4 +143,14 @@ public abstract class AbstractItemListFragment extends ListFragment implement
activatedPosition = position;
}
+
+ @Override
+ public L getCurrentLabel() {
+ return null;
+ }
+
+ @Override
+ public boolean showPreviousList() {
+ return false;
+ }
}
diff --git a/app/src/main/java/ch/dissem/apps/abit/AddressListFragment.java b/app/src/main/java/ch/dissem/apps/abit/AddressListFragment.java
index 9633cbe..ee220a8 100644
--- a/app/src/main/java/ch/dissem/apps/abit/AddressListFragment.java
+++ b/app/src/main/java/ch/dissem/apps/abit/AddressListFragment.java
@@ -47,7 +47,7 @@ import io.github.yavski.fabspeeddial.SimpleMenuListenerAdapter;
/**
* Fragment that shows a list of all contacts, the ones we subscribed to first.
*/
-public class AddressListFragment extends AbstractItemListFragment {
+public class AddressListFragment extends AbstractItemListFragment {
private ArrayAdapter adapter;
@Override
@@ -166,7 +166,7 @@ public class AddressListFragment extends AbstractItemListFragment {
+ void updateList(L label);
void setActivateOnItemClick(boolean activateOnItemClick);
+
+ L getCurrentLabel();
+
+ boolean showPreviousList();
}
diff --git a/app/src/main/java/ch/dissem/apps/abit/MainActivity.java b/app/src/main/java/ch/dissem/apps/abit/MainActivity.java
index d8c40bf..0b6ed77 100644
--- a/app/src/main/java/ch/dissem/apps/abit/MainActivity.java
+++ b/app/src/main/java/ch/dissem/apps/abit/MainActivity.java
@@ -21,6 +21,7 @@ import android.graphics.Point;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
@@ -195,11 +196,15 @@ public class MainActivity extends AppCompatActivity
}
private void changeList(F listFragment) {
- getSupportFragmentManager()
- .beginTransaction()
- .replace(R.id.item_list, listFragment)
- .addToBackStack(null)
- .commit();
+
+ FragmentTransaction transaction = getSupportFragmentManager()
+ .beginTransaction();
+ transaction.replace(R.id.item_list, listFragment);
+ Fragment detailFragment = getSupportFragmentManager().findFragmentById(R.id.message_detail_container);
+ if (detailFragment != null) {
+ transaction.remove(detailFragment);
+ }
+ transaction.addToBackStack(null).commit();
if (twoPane) {
// In two-pane mode, list items should be given the
@@ -325,15 +330,31 @@ public class MainActivity extends AppCompatActivity
}.execute();
}
+ @Override
+ public void onBackPressed() {
+ Fragment listFragment = getSupportFragmentManager().findFragmentById(R.id.item_list);
+ if (listFragment instanceof ListHolder) {
+ ListHolder listHolder = (ListHolder) listFragment;
+ if (listHolder.showPreviousList()) {
+ IDrawerItem drawerItem = drawer.getDrawerItem(listHolder.getCurrentLabel());
+ if (drawerItem != null){
+ drawer.setSelection(drawerItem);
+ }
+ return;
+ }
+ }
+ super.onBackPressed();
+ }
+
private class DrawerItemClickListener implements Drawer.OnDrawerItemClickListener {
@Override
public boolean onItemClick(View view, int position, IDrawerItem item) {
+ Fragment itemList = getSupportFragmentManager().findFragmentById(R.id.item_list);
if (item.getTag() instanceof Label) {
selectedLabel = (Label) item.getTag();
- if (getSupportFragmentManager().findFragmentById(R.id.item_list) instanceof
+ if (itemList instanceof
MessageListFragment) {
- ((MessageListFragment) getSupportFragmentManager()
- .findFragmentById(R.id.item_list)).updateList(selectedLabel);
+ ((MessageListFragment) itemList).updateList(selectedLabel);
} else {
MessageListFragment listFragment = new MessageListFragment();
changeList(listFragment);
@@ -344,17 +365,18 @@ public class MainActivity extends AppCompatActivity
Nameable> ni = (Nameable>) item;
switch (ni.getName().getTextRes()) {
case R.string.contacts_and_subscriptions:
- if (!(getSupportFragmentManager().findFragmentById(R.id
- .item_list) instanceof AddressListFragment)) {
+ if (!(itemList instanceof AddressListFragment)) {
changeList(new AddressListFragment());
} else {
- ((AddressListFragment) getSupportFragmentManager()
- .findFragmentById(R.id.item_list)).updateList();
+ ((AddressListFragment) itemList).updateList();
}
return false;
case R.string.settings:
- startActivity(new Intent(MainActivity.this, SettingsActivity
- .class));
+ getSupportFragmentManager()
+ .beginTransaction()
+ .replace(R.id.item_list, new SettingsFragment())
+ .addToBackStack(null)
+ .commit();
return false;
case R.string.full_node:
return true;
@@ -501,7 +523,7 @@ public class MainActivity extends AppCompatActivity
Fragment fragment;
if (item instanceof Plaintext) {
fragment = new MessageDetailFragment();
- } else if (item instanceof String) {
+ } else if (item instanceof BitmessageAddress) {
fragment = new AddressDetailFragment();
} else {
throw new IllegalArgumentException("Plaintext or BitmessageAddress expected, but was " + item.getClass().getSimpleName());
@@ -517,7 +539,7 @@ public class MainActivity extends AppCompatActivity
if (item instanceof Plaintext) {
detailIntent = new Intent(this, MessageDetailActivity.class);
detailIntent.putExtra(EXTRA_SHOW_LABEL, selectedLabel);
- } else if (item instanceof String) {
+ } else if (item instanceof BitmessageAddress) {
detailIntent = new Intent(this, AddressDetailActivity.class);
} else {
throw new IllegalArgumentException("Plaintext or BitmessageAddress expected, but " +
@@ -529,6 +551,18 @@ public class MainActivity extends AppCompatActivity
}
}
+ public boolean hasDetailPane() {
+ return twoPane;
+ }
+
+ public void setDetailView(Fragment fragment) {
+ if (twoPane) {
+ getSupportFragmentManager().beginTransaction()
+ .replace(R.id.message_detail_container, fragment)
+ .commit();
+ }
+ }
+
@Override
public void updateTitle(CharSequence title) {
if (getSupportActionBar() != null) {
diff --git a/app/src/main/java/ch/dissem/apps/abit/MessageListFragment.java b/app/src/main/java/ch/dissem/apps/abit/MessageListFragment.java
index e3a187a..219436e 100644
--- a/app/src/main/java/ch/dissem/apps/abit/MessageListFragment.java
+++ b/app/src/main/java/ch/dissem/apps/abit/MessageListFragment.java
@@ -38,10 +38,8 @@ import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeMana
import com.h6ah4i.android.widget.advrecyclerview.touchguard.RecyclerViewTouchActionGuardManager;
import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils;
-import java.util.Collections;
-import java.util.LinkedList;
import java.util.List;
-import java.util.Objects;
+import java.util.Stack;
import ch.dissem.apps.abit.adapter.SwipeableMessageAdapter;
import ch.dissem.apps.abit.listener.ActionBarListener;
@@ -51,7 +49,6 @@ import ch.dissem.apps.abit.service.Singleton;
import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.Plaintext;
import ch.dissem.bitmessage.entity.valueobject.Label;
-import ch.dissem.bitmessage.ports.MessageRepository;
import io.github.yavski.fabspeeddial.FabSpeedDial;
import io.github.yavski.fabspeeddial.SimpleMenuListenerAdapter;
@@ -68,7 +65,7 @@ import static ch.dissem.apps.abit.MessageDetailFragment.isInTrash;
* Activities containing this fragment MUST implement the {@link ListSelectionListener}
* interface.
*/
-public class MessageListFragment extends Fragment implements ListHolder {
+public class MessageListFragment extends Fragment implements ListHolder {
private RecyclerView recyclerView;
private RecyclerView.LayoutManager layoutManager;
@@ -82,6 +79,8 @@ public class MessageListFragment extends Fragment implements ListHolder {
private AndroidMessageRepository messageRepo;
private boolean activateOnItemClick;
+ private Stack backStack = new Stack<>();
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -95,11 +94,18 @@ public class MessageListFragment extends Fragment implements ListHolder {
MainActivity activity = (MainActivity) getActivity();
messageRepo = Singleton.getMessageRepository(activity);
- doUpdateList(activity.getSelectedLabel());
+ if (backStack.isEmpty()) {
+ doUpdateList(activity.getSelectedLabel());
+ } else {
+ doUpdateList(backStack.peek());
+ }
}
@Override
public void updateList(Label label) {
+ if (currentLabel != null && !currentLabel.equals(label)) {
+ backStack.push(currentLabel);
+ }
if (!isResumed()) {
currentLabel = label;
return;
@@ -330,4 +336,19 @@ public class MessageListFragment extends Fragment implements ListHolder {
}
this.activateOnItemClick = activateOnItemClick;
}
+
+ @Override
+ public boolean showPreviousList() {
+ if (backStack.isEmpty()) {
+ return false;
+ } else {
+ doUpdateList(backStack.pop());
+ return true;
+ }
+ }
+
+ @Override
+ public Label getCurrentLabel() {
+ return currentLabel;
+ }
}
diff --git a/app/src/main/java/ch/dissem/apps/abit/SettingsActivity.java b/app/src/main/java/ch/dissem/apps/abit/SettingsActivity.java
deleted file mode 100644
index 8997349..0000000
--- a/app/src/main/java/ch/dissem/apps/abit/SettingsActivity.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package ch.dissem.apps.abit;
-
-import android.os.Bundle;
-
-/**
- * @author Christian Basler
- */
-public class SettingsActivity extends DetailActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // Display the fragment as the main content.
- getFragmentManager().beginTransaction()
- .replace(R.id.content, new SettingsFragment())
- .commit();
- }
-}
diff --git a/app/src/main/java/ch/dissem/apps/abit/SettingsFragment.java b/app/src/main/java/ch/dissem/apps/abit/SettingsFragment.java
index c198485..854194e 100644
--- a/app/src/main/java/ch/dissem/apps/abit/SettingsFragment.java
+++ b/app/src/main/java/ch/dissem/apps/abit/SettingsFragment.java
@@ -21,14 +21,15 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.preference.Preference;
-import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceFragmentCompat;
import android.widget.Toast;
import com.mikepenz.aboutlibraries.Libs;
import com.mikepenz.aboutlibraries.LibsBuilder;
+import ch.dissem.apps.abit.listener.ActionBarListener;
import ch.dissem.apps.abit.service.Singleton;
import ch.dissem.apps.abit.synchronization.SyncAdapter;
import ch.dissem.bitmessage.BitmessageContext;
@@ -40,26 +41,29 @@ import static ch.dissem.apps.abit.util.Constants.PREFERENCE_TRUSTED_NODE;
* @author Christian Basler
*/
public class SettingsFragment
- extends PreferenceFragment
+ extends PreferenceFragmentCompat
implements SharedPreferences.OnSharedPreferenceChangeListener {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- // Load the preferences from an XML resource
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.preferences);
Preference about = findPreference("about");
about.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
- new LibsBuilder()
+ LibsBuilder libsBuilder = new LibsBuilder()
.withActivityTitle(getActivity().getString(R.string.about))
.withActivityStyle(Libs.ActivityStyle.LIGHT_DARK_TOOLBAR)
.withAboutIconShown(true)
.withAboutVersionShown(true)
- .withAboutDescription(getString(R.string.about_app))
- .start(getActivity());
+ .withAboutDescription(getString(R.string.about_app));
+ MainActivity activity = (MainActivity) getActivity();
+ if (activity.hasDetailPane()) {
+ activity.setDetailView(libsBuilder.supportFragment());
+ } else {
+ libsBuilder.start(getActivity());
+ }
return true;
}
});
@@ -103,7 +107,12 @@ public class SettingsFragment
status.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
- startActivity(new Intent(getActivity(), StatusActivity.class));
+ MainActivity activity = (MainActivity) getActivity();
+ if (activity.hasDetailPane()) {
+ activity.setDetailView(new StatusFragment());
+ } else {
+ startActivity(new Intent(getActivity(), StatusActivity.class));
+ }
return true;
}
});
@@ -114,6 +123,10 @@ public class SettingsFragment
super.onAttach(ctx);
PreferenceManager.getDefaultSharedPreferences(ctx)
.registerOnSharedPreferenceChangeListener(this);
+
+ if (ctx instanceof ActionBarListener) {
+ ((ActionBarListener) ctx).updateTitle(getString(R.string.settings));
+ }
}
@Override
diff --git a/app/src/main/java/ch/dissem/apps/abit/StatusFragment.java b/app/src/main/java/ch/dissem/apps/abit/StatusFragment.java
new file mode 100644
index 0000000..a334f14
--- /dev/null
+++ b/app/src/main/java/ch/dissem/apps/abit/StatusFragment.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2016 Christian Basler
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.dissem.apps.abit;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import ch.dissem.apps.abit.service.Singleton;
+import ch.dissem.bitmessage.BitmessageContext;
+import ch.dissem.bitmessage.entity.BitmessageAddress;
+
+public class StatusFragment extends Fragment {
+
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.fragment_status, container, false);
+
+ BitmessageContext bmc = Singleton.getBitmessageContext(inflater.getContext());
+ StringBuilder status = new StringBuilder();
+ for (BitmessageAddress address : bmc.addresses().getIdentities()) {
+ status.append(address.getAddress()).append('\n');
+ }
+ status.append('\n');
+ status.append(bmc.status());
+ ((TextView) view.findViewById(R.id.content)).setText(status);
+ return view;
+ }
+
+}
diff --git a/app/src/main/java/ch/dissem/apps/abit/adapter/SwipeableMessageAdapter.java b/app/src/main/java/ch/dissem/apps/abit/adapter/SwipeableMessageAdapter.java
index df3e2c0..d745189 100644
--- a/app/src/main/java/ch/dissem/apps/abit/adapter/SwipeableMessageAdapter.java
+++ b/app/src/main/java/ch/dissem/apps/abit/adapter/SwipeableMessageAdapter.java
@@ -30,13 +30,11 @@ import android.widget.TextView;
import com.h6ah4i.android.widget.advrecyclerview.swipeable.SwipeableItemAdapter;
import com.h6ah4i.android.widget.advrecyclerview.swipeable.SwipeableItemConstants;
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultAction;
-import com.h6ah4i.android.widget.advrecyclerview.swipeable.action
- .SwipeResultActionMoveToSwipedDirection;
+import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultActionMoveToSwipedDirection;
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultActionRemoveItem;
import com.h6ah4i.android.widget.advrecyclerview.utils.AbstractSwipeableItemViewHolder;
import com.h6ah4i.android.widget.advrecyclerview.utils.RecyclerViewAdapterUtils;
-import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
@@ -66,7 +64,7 @@ public class SwipeableMessageAdapter
private final View.OnClickListener swipeableViewContainerOnClickListener;
private Label label;
- private int selectedPosition;
+ private int selectedPosition = -1;
private boolean activateOnItemClick;
public void setActivateOnItemClick(boolean activateOnItemClick) {
diff --git a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidAddressRepository.java b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidAddressRepository.java
index 6440ab2..a189a16 100644
--- a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidAddressRepository.java
+++ b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidAddressRepository.java
@@ -303,11 +303,10 @@ public class AndroidAddressRepository implements AddressRepository {
}
}
- @NonNull
@Override
public BitmessageAddress getAddress(String address) {
List result = find("address = '" + address + "'");
if (result.size() > 0) return result.get(0);
- return new BitmessageAddress(address);
+ return null;
}
}
diff --git a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidMessageRepository.java b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidMessageRepository.java
index 316f5f8..9c52d1c 100644
--- a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidMessageRepository.java
+++ b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidMessageRepository.java
@@ -35,6 +35,7 @@ import java.util.UUID;
import ch.dissem.apps.abit.util.Labels;
import ch.dissem.apps.abit.util.UuidUtils;
+import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.Plaintext;
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
import ch.dissem.bitmessage.entity.valueobject.Label;
@@ -154,29 +155,30 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
@Override
public int countUnread(Label label) {
- String[] args;
- String where;
- if (label == null) {
- return 0;
- }
if (label == LABEL_ARCHIVE) {
- where = "";
- args = new String[]{
- Label.Type.UNREAD.name()
- };
+ return 0;
+ } else if (label == null) {
+ return (int) DatabaseUtils.queryNumEntries(
+ sql.getReadableDatabase(),
+ TABLE_NAME,
+ "id IN (SELECT message_id FROM Message_Label WHERE label_id IN (SELECT id FROM Label WHERE type=?))",
+ new String[]{
+ String.valueOf(label.getId()),
+ Label.Type.UNREAD.name()
+ }
+ );
} else {
- where = "id IN (SELECT message_id FROM Message_Label WHERE label_id=?) AND ";
- args = new String[]{
- String.valueOf(label.getId()),
- Label.Type.UNREAD.name()
- };
+ return (int) DatabaseUtils.queryNumEntries(
+ sql.getReadableDatabase(),
+ TABLE_NAME,
+ " id IN (SELECT message_id FROM Message_Label WHERE label_id=?) " +
+ "AND id IN (SELECT message_id FROM Message_Label WHERE label_id IN (SELECT id FROM Label WHERE type=?))",
+ new String[]{
+ String.valueOf(label.getId()),
+ Label.Type.UNREAD.name()
+ }
+ );
}
- SQLiteDatabase db = sql.getReadableDatabase();
- return (int) DatabaseUtils.queryNumEntries(db, TABLE_NAME,
- where + "id IN (SELECT message_id FROM Message_Label WHERE label_id IN (" +
- "SELECT id FROM Label WHERE type=?))",
- args
- );
}
@NonNull
@@ -249,7 +251,7 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
}
@NonNull
- protected List findIds(String where) {
+ private List findIds(String where) {
List result = new LinkedList<>();
// Define a projection that specifies which columns from the database
@@ -266,7 +268,7 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
COLUMN_RECEIVED + " DESC, " + COLUMN_SENT + " DESC"
)) {
while (c.moveToNext()) {
- long id = c.getLong(c.getColumnIndex(COLUMN_ID));
+ long id = c.getLong(0);
result.add(id);
}
}
@@ -315,11 +317,21 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
builder.IV(InventoryVector.fromHash(iv));
String sender = c.getString(c.getColumnIndex(COLUMN_SENDER));
if (sender != null) {
- builder.from(ctx.getAddressRepository().getAddress(sender));
+ BitmessageAddress address = ctx.getAddressRepository().getAddress(sender);
+ if (address != null) {
+ builder.from(address);
+ } else {
+ builder.from(new BitmessageAddress(sender));
+ }
}
String recipient = c.getString(c.getColumnIndex(COLUMN_RECIPIENT));
if (recipient != null) {
- builder.to(ctx.getAddressRepository().getAddress(recipient));
+ BitmessageAddress address = ctx.getAddressRepository().getAddress(recipient);
+ if (address != null) {
+ builder.to(address);
+ } else {
+ builder.to(new BitmessageAddress(sender));
+ }
}
builder.ackData(c.getBlob(c.getColumnIndex(COLUMN_ACK_DATA)));
builder.sent(c.getLong(c.getColumnIndex(COLUMN_SENT)));
@@ -405,7 +417,7 @@ public class AndroidMessageRepository extends AbstractMessageRepository {
}
private void update(SQLiteDatabase db, Plaintext message) {
- db.update(TABLE_NAME, getValues(message), "id = " + message.getId(), null);
+ db.update(TABLE_NAME, getValues(message), "id=?", new String[]{valueOf(message.getId())});
}
@Override
diff --git a/app/src/main/java/ch/dissem/apps/abit/repository/SqlHelper.java b/app/src/main/java/ch/dissem/apps/abit/repository/SqlHelper.java
index db7d411..dd55b4f 100644
--- a/app/src/main/java/ch/dissem/apps/abit/repository/SqlHelper.java
+++ b/app/src/main/java/ch/dissem/apps/abit/repository/SqlHelper.java
@@ -16,11 +16,16 @@
package ch.dissem.apps.abit.repository;
+import android.content.ContentValues;
import android.content.Context;
+import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
+import java.util.UUID;
+
import ch.dissem.apps.abit.util.Assets;
+import ch.dissem.apps.abit.util.UuidUtils;
/**
* Handles database migration and provides access.
@@ -63,12 +68,37 @@ public class SqlHelper extends SQLiteOpenHelper {
executeMigration(db, "V3.4__Add_label_outbox");
case 6:
executeMigration(db, "V4.0__Create_table_message_parent");
+ case 7:
+ setMissingConversationIds(db);
default:
// Nothing to do. Let's assume we won't upgrade from a version that's newer than
// DATABASE_VERSION.
}
}
+ /**
+ * Set UUIDs for all messages that have no conversation ID
+ */
+ private void setMissingConversationIds(SQLiteDatabase db) {
+ try (Cursor c = db.query(
+ "Message", new String[]{"id"},
+ "conversation IS NULL",
+ null, null, null, null
+ )) {
+ while (c.moveToNext()) {
+ long id = c.getLong(0);
+ setMissingConversationId(id, db);
+ }
+ }
+
+ }
+
+ private void setMissingConversationId(long id, SQLiteDatabase db) {
+ ContentValues values = new ContentValues(1);
+ values.put("conversation", UuidUtils.asBytes(UUID.randomUUID()));
+ db.update("Message", values, "id=?", new String[]{String.valueOf(id)});
+ }
+
private void executeMigration(SQLiteDatabase db, String name) {
for (String statement : Assets.readSqlStatements(ctx, "db/migration/" + name + ".sql")) {
db.execSQL(statement);
diff --git a/app/src/main/res/drawable/bg_item_selectable.xml b/app/src/main/res/drawable/bg_item_selectable.xml
new file mode 100644
index 0000000..b7f0964
--- /dev/null
+++ b/app/src/main/res/drawable/bg_item_selectable.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/bg_item_selected_state.xml b/app/src/main/res/drawable/bg_item_selected_state.xml
index 32a0c99..8861fff 100644
--- a/app/src/main/res/drawable/bg_item_selected_state.xml
+++ b/app/src/main/res/drawable/bg_item_selected_state.xml
@@ -1,21 +1,13 @@
-
-
-
+
+
+
+
+ -
+
+
+
diff --git a/app/src/main/res/drawable/bg_white.xml b/app/src/main/res/drawable/bg_white.xml
new file mode 100644
index 0000000..9d61c42
--- /dev/null
+++ b/app/src/main/res/drawable/bg_white.xml
@@ -0,0 +1,8 @@
+
+
+ -
+
+
+
+
+
diff --git a/app/src/main/res/layout-w720dp/activity_message_list.xml b/app/src/main/res/layout-w720dp/activity_message_list.xml
index 8c402c6..a52604d 100644
--- a/app/src/main/res/layout-w720dp/activity_message_list.xml
+++ b/app/src/main/res/layout-w720dp/activity_message_list.xml
@@ -1,59 +1,61 @@
-
+
+ tools:ignore="UnusedAttribute"
+ tools:layout_editor_absoluteX="8dp" />
-
+
-
+
-
+
-
-
-
-
-
-
-
+
diff --git a/app/src/main/res/layout/contact_row.xml b/app/src/main/res/layout/contact_row.xml
index af37c4a..491f39f 100644
--- a/app/src/main/res/layout/contact_row.xml
+++ b/app/src/main/res/layout/contact_row.xml
@@ -1,5 +1,4 @@
-
-
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/bg_item_selectable">
+ tools:ignore="ContentDescription" />
+ tools:text="Name" />
+ tools:text="BM-2cW0000000000000000000000000000000" />
diff --git a/app/src/main/res/layout/fragment_address_list.xml b/app/src/main/res/layout/fragment_address_list.xml
index ad4b671..7ba2697 100644
--- a/app/src/main/res/layout/fragment_address_list.xml
+++ b/app/src/main/res/layout/fragment_address_list.xml
@@ -1,8 +1,8 @@
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ android:scrollbarStyle="outsideOverlay" />
+ app:fabMenu="@menu/fab_address" />
diff --git a/app/src/main/res/layout/fragment_status.xml b/app/src/main/res/layout/fragment_status.xml
new file mode 100644
index 0000000..ccd7a09
--- /dev/null
+++ b/app/src/main/res/layout/fragment_status.xml
@@ -0,0 +1,11 @@
+
+
diff --git a/app/src/main/res/layout/subscription_row.xml b/app/src/main/res/layout/subscription_row.xml
index 83ef228..957e22f 100644
--- a/app/src/main/res/layout/subscription_row.xml
+++ b/app/src/main/res/layout/subscription_row.xml
@@ -19,8 +19,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="?android:attr/activatedBackgroundIndicator">
+ android:layout_height="wrap_content">
#DEFFFFFF
#FFECB3
#607D8B
+ #d3e0e6
#212121
#727272
#FFFFFF
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 7d6f486..aa4baab 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -5,6 +5,7 @@
- @drawable/bg_item_activated
- @color/colorPrimaryText
- @color/colorSecondaryText
+ - @style/PreferenceThemeOverlay