From 2b1fb436a9ac62acbc493a0ebf76ddda72568073 Mon Sep 17 00:00:00 2001 From: Christian Basler Date: Sun, 16 Oct 2016 23:16:38 +0200 Subject: [PATCH] Fixed the 'full node' switch, activated the jack tools to support some Java 8 features, and fixed some lint issues --- app/build.gradle | 17 +- .../apps/abit/AbstractItemListFragment.java | 17 +- .../apps/abit/AddressDetailFragment.java | 60 ++---- .../dissem/apps/abit/AddressListFragment.java | 72 +++---- .../apps/abit/ComposeMessageFragment.java | 10 +- .../apps/abit/ImportIdentitiesFragment.java | 27 +-- .../ch/dissem/apps/abit/MainActivity.java | 201 +++++++++--------- .../ch/dissem/apps/abit/SettingsActivity.java | 2 - .../DeterministicIdentityDialogFragment.java | 118 +++++----- .../notification/NetworkNotification.java | 47 ++-- .../notification/NewMessageNotification.java | 3 +- .../repository/AndroidAddressRepository.java | 8 +- .../AndroidProofOfWorkRepository.java | 1 - .../apps/abit/service/BitmessageService.java | 30 +-- .../apps/abit/service/ProofOfWorkService.java | 45 ++-- .../dissem/apps/abit/service/Singleton.java | 38 ++-- .../ch/dissem/apps/abit/util/Preferences.java | 3 - .../layout-w720dp/activity_message_list.xml | 3 +- .../res/layout/fragment_compose_message.xml | 4 +- app/src/main/res/layout/showcase_button.xml | 11 +- app/src/main/res/layout/subscription_row.xml | 6 +- app/src/main/res/values-de/strings.xml | 15 +- app/src/main/res/values/colors.xml | 2 +- .../values/library_fab_speed_dial_strings.xml | 2 +- .../res/values/library_filepicker_strings.xml | 34 +-- .../main/res/values/library_jabit_strings.xml | 2 +- .../main/res/values/library_zxing_strings.xml | 2 +- .../library_zxingandroidembedded_strings.xml | 2 +- app/src/main/res/values/strings.xml | 19 +- build.gradle | 2 +- 30 files changed, 367 insertions(+), 436 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index da62874..81387e4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,10 +5,11 @@ ext { appName = "Abit" } if (project.hasProperty("project.configs") - && new File(project.property("project.configs") + appName + ".gradle").exists()) { + && new File(project.property("project.configs") + appName + ".gradle").exists()) { apply from: project.property("project.configs") + appName + ".gradle"; } +//noinspection GroovyMissingReturnStatement android { compileSdkVersion 24 buildToolsVersion "24.0.3" @@ -19,17 +20,23 @@ android { targetSdkVersion 24 versionCode 9 versionName "1.0-beta9" + jackOptions.enabled = true + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 } buildTypes { release { - minifyEnabled false + minifyEnabled true + shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' signingConfig signingConfigs.release } } } -ext.jabitVersion = '2.0.1' +ext.jabitVersion = '2.0.2' dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:24.2.1' @@ -58,8 +65,8 @@ dependencies { compile 'com.google.zxing:core:3.3.0' compile 'io.github.yavski:fab-speed-dial:1.0.4' compile 'com.github.amlcurran.showcaseview:library:5.4.3' - compile ('com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.9.3@aar'){ - transitive=true + compile('com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.9.3@aar') { + transitive = true } compile 'com.github.angads25:filepicker:1.0.6' 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 3cb1e07..5432210 100644 --- a/app/src/main/java/ch/dissem/apps/abit/AbstractItemListFragment.java +++ b/app/src/main/java/ch/dissem/apps/abit/AbstractItemListFragment.java @@ -23,7 +23,6 @@ import android.view.View; import android.widget.ListView; import ch.dissem.apps.abit.listener.ListSelectionListener; -import ch.dissem.bitmessage.entity.valueobject.Label; /** * @author Christian Basler @@ -38,11 +37,7 @@ public abstract class AbstractItemListFragment extends ListFragment implement * A dummy implementation of the {@link ListSelectionListener} interface that does * nothing. Used only when this fragment is not attached to an activity. */ - private static ListSelectionListener dummyCallbacks = new - ListSelectionListener() { - @Override - public void onItemSelected(Object plaintext) { - } + private static ListSelectionListener dummyCallbacks = plaintext -> { }; /** * The fragment's current callback object, which is notified of list item @@ -61,7 +56,7 @@ public abstract class AbstractItemListFragment extends ListFragment implement // Restore the previously serialized activated item position. if (savedInstanceState != null - && savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) { + && savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) { setActivatedPosition(savedInstanceState.getInt(STATE_ACTIVATED_POSITION)); } } @@ -73,8 +68,8 @@ public abstract class AbstractItemListFragment extends ListFragment implement // When setting CHOICE_MODE_SINGLE, ListView will automatically // give items the 'activated' state when touched. getListView().setChoiceMode(activateOnItemClick - ? ListView.CHOICE_MODE_SINGLE - : ListView.CHOICE_MODE_NONE); + ? ListView.CHOICE_MODE_SINGLE + : ListView.CHOICE_MODE_NONE); } @Override @@ -129,8 +124,8 @@ public abstract class AbstractItemListFragment extends ListFragment implement // When setting CHOICE_MODE_SINGLE, ListView will automatically // give items the 'activated' state when touched. getListView().setChoiceMode(activateOnItemClick - ? ListView.CHOICE_MODE_SINGLE - : ListView.CHOICE_MODE_NONE); + ? ListView.CHOICE_MODE_SINGLE + : ListView.CHOICE_MODE_NONE); } } 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 d4b8b39..439823f 100644 --- a/app/src/main/java/ch/dissem/apps/abit/AddressDetailFragment.java +++ b/app/src/main/java/ch/dissem/apps/abit/AddressDetailFragment.java @@ -18,7 +18,6 @@ package ch.dissem.apps.abit; import android.app.Activity; import android.app.AlertDialog; -import android.content.DialogInterface; import android.content.Intent; import android.graphics.Bitmap; import android.os.Bundle; @@ -31,7 +30,6 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.widget.CompoundButton; import android.widget.ImageView; import android.widget.Switch; import android.widget.TextView; @@ -131,19 +129,15 @@ public class AddressDetailFragment extends Fragment { warning = R.string.delete_contact_warning; new AlertDialog.Builder(ctx) .setMessage(warning) - .setPositiveButton(android.R.string.yes, new - DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - Singleton.getAddressRepository(ctx).remove(item); - MainActivity mainActivity = MainActivity.getInstance(); - if (item.getPrivateKey() != null && mainActivity != null) { - mainActivity.removeIdentityEntry(item); - } - item = null; - ctx.onBackPressed(); - } - }) + .setPositiveButton(android.R.string.yes, (dialog, which) -> { + Singleton.getAddressRepository(ctx).remove(item); + MainActivity mainActivity = MainActivity.getInstance(); + if (item.getPrivateKey() != null && mainActivity != null) { + mainActivity.removeIdentityEntry(item); + } + item = null; + ctx.onBackPressed(); + }) .setNegativeButton(android.R.string.no, null) .show(); return true; @@ -151,22 +145,18 @@ public class AddressDetailFragment extends Fragment { case R.id.export: { new AlertDialog.Builder(ctx) .setMessage(R.string.confirm_export) - .setPositiveButton(android.R.string.yes, new - DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - Intent shareIntent = new Intent(Intent.ACTION_SEND); - shareIntent.setType("text/plain"); - shareIntent.putExtra(Intent.EXTRA_TITLE, item + - EXPORT_POSTFIX); - WifExporter exporter = new WifExporter(Singleton - .getBitmessageContext(ctx)); - exporter.addIdentity(item); - shareIntent.putExtra(Intent.EXTRA_TEXT, exporter.toString - ()); - startActivity(Intent.createChooser(shareIntent, null)); - } - }) + .setPositiveButton(android.R.string.yes, (dialog, which) -> { + Intent shareIntent = new Intent(Intent.ACTION_SEND); + shareIntent.setType("text/plain"); + shareIntent.putExtra(Intent.EXTRA_TITLE, item + + EXPORT_POSTFIX); + WifExporter exporter = new WifExporter(Singleton + .getBitmessageContext(ctx)); + exporter.addIdentity(item); + shareIntent.putExtra(Intent.EXTRA_TEXT, exporter.toString + ()); + startActivity(Intent.createChooser(shareIntent, null)); + }) .setNegativeButton(android.R.string.no, null) .show(); return true; @@ -216,12 +206,8 @@ public class AddressDetailFragment extends Fragment { if (item.getPrivateKey() == null) { Switch active = (Switch) rootView.findViewById(R.id.active); active.setChecked(item.isSubscribed()); - active.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - item.setSubscribed(isChecked); - } - }); + active.setOnCheckedChangeListener((buttonView, isChecked) -> + item.setSubscribed(isChecked)); ImageView pubkeyAvailableImg = (ImageView) rootView.findViewById(R.id .pubkey_available); 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 66a52aa..5168422 100644 --- a/app/src/main/java/ch/dissem/apps/abit/AddressListFragment.java +++ b/app/src/main/java/ch/dissem/apps/abit/AddressListFragment.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.view.LayoutInflater; import android.view.MenuItem; @@ -32,7 +33,6 @@ import android.widget.TextView; import com.google.zxing.integration.android.IntentIntegrator; import java.util.Collections; -import java.util.Comparator; import java.util.List; import ch.dissem.apps.abit.listener.ActionBarListener; @@ -55,59 +55,53 @@ public class AddressListFragment extends AbstractItemListFragment addresses = Singleton.getAddressRepository(getContext()) - .getContacts(); - Collections.sort(addresses, new Comparator() { - /** - * Yields the following order: - *
    - *
  1. Subscribed addresses come first
  2. - *
  3. Addresses with Aliases (alphabetically)
  4. - *
  5. Addresses (alphabetically)
  6. - *
- */ - @Override - public int compare(BitmessageAddress lhs, BitmessageAddress rhs) { - 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; + .getContacts(); + Collections.sort(addresses, (lhs, 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 lhs.getAddress().compareTo(rhs.getAddress()); + return -1; } - } - if (lhs.isSubscribed()) { - return -1; - } else { + } else if (rhs.getAlias() != null) { return 1; + } else { + return lhs.getAddress().compareTo(rhs.getAddress()); } } + if (lhs.isSubscribed()) { + return -1; + } else { + return 1; + } }); setListAdapter(new ArrayAdapter( - getActivity(), - android.R.layout.simple_list_item_activated_1, - android.R.id.text1, - addresses) { + getActivity(), + android.R.layout.simple_list_item_activated_1, + android.R.id.text1, + addresses) { + @NonNull @Override - public View getView(int position, View convertView, ViewGroup parent) { + 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, null, false); + convertView = inflater.inflate(R.layout.subscription_row, parent, false); } BitmessageAddress item = getItem(position); ((ImageView) convertView.findViewById(R.id.avatar)).setImageDrawable(new - Identicon(item)); + 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())); + .getStream())); convertView.findViewById(R.id.subscribed).setVisibility(item.isSubscribed() ? - View.VISIBLE : View.INVISIBLE); + View.VISIBLE : View.INVISIBLE); return convertView; } }); @@ -124,7 +118,7 @@ public class AddressListFragment extends AbstractItemListFragment parent, View view, int position, long id) { - recipient = adapter.getItem(position); - } - }); + recipientInput.setOnItemClickListener( + (parent, view, position, id) -> recipient = adapter.getItem(position) + ); recipientInput.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView parent, View view, int position, long id) { diff --git a/app/src/main/java/ch/dissem/apps/abit/ImportIdentitiesFragment.java b/app/src/main/java/ch/dissem/apps/abit/ImportIdentitiesFragment.java index f3e91a3..4d335b0 100644 --- a/app/src/main/java/ch/dissem/apps/abit/ImportIdentitiesFragment.java +++ b/app/src/main/java/ch/dissem/apps/abit/ImportIdentitiesFragment.java @@ -42,9 +42,6 @@ import ch.dissem.bitmessage.wif.WifImporter; public class ImportIdentitiesFragment extends Fragment { public static final String WIF_DATA = "wif_data"; - private BitmessageContext bmc; - private RecyclerView recyclerView; - private LinearLayoutManager layoutManager; private AddressSelectorAdapter adapter; private WifImporter importer; @@ -53,14 +50,15 @@ public class ImportIdentitiesFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { String wifData = getArguments().getString(WIF_DATA); - bmc = Singleton.getBitmessageContext(getActivity()); + BitmessageContext bmc = Singleton.getBitmessageContext(getActivity()); View view = inflater.inflate(R.layout.fragment_import_select_identities, container, false); try { importer = new WifImporter(bmc, wifData); adapter = new AddressSelectorAdapter(importer.getIdentities()); - layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, + LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), + LinearLayoutManager.VERTICAL, false); - recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view); + RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view); recyclerView.setLayoutManager(layoutManager); recyclerView.setAdapter(adapter); @@ -69,18 +67,15 @@ public class ImportIdentitiesFragment extends Fragment { } catch (IOException e) { return super.onCreateView(inflater, container, savedInstanceState); } - view.findViewById(R.id.finish).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - importer.importAll(adapter.getSelected()); - MainActivity mainActivity = MainActivity.getInstance(); - if (mainActivity != null) { - for (BitmessageAddress selected : adapter.getSelected()) { - mainActivity.addIdentityEntry(selected); - } + view.findViewById(R.id.finish).setOnClickListener(v -> { + importer.importAll(adapter.getSelected()); + MainActivity mainActivity = MainActivity.getInstance(); + if (mainActivity != null) { + for (BitmessageAddress selected : adapter.getSelected()) { + mainActivity.addIdentityEntry(selected); } - getActivity().finish(); } + getActivity().finish(); }); return view; } 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 0c347fd..10dc12f 100644 --- a/app/src/main/java/ch/dissem/apps/abit/MainActivity.java +++ b/app/src/main/java/ch/dissem/apps/abit/MainActivity.java @@ -19,7 +19,6 @@ package ch.dissem.apps.abit; import android.app.AlertDialog; import android.content.ComponentName; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.ServiceConnection; import android.graphics.Point; @@ -34,7 +33,6 @@ import android.widget.CompoundButton; import android.widget.RelativeLayout; import com.github.amlcurran.showcaseview.ShowcaseView; -import com.github.amlcurran.showcaseview.targets.Target; import com.mikepenz.community_material_typeface_library.CommunityMaterial; import com.mikepenz.google_material_typeface_library.GoogleMaterial; import com.mikepenz.iconics.IconicsDrawable; @@ -42,7 +40,6 @@ import com.mikepenz.materialdrawer.AccountHeader; import com.mikepenz.materialdrawer.AccountHeaderBuilder; import com.mikepenz.materialdrawer.Drawer; import com.mikepenz.materialdrawer.DrawerBuilder; -import com.mikepenz.materialdrawer.interfaces.OnCheckedChangeListener; import com.mikepenz.materialdrawer.model.DividerDrawerItem; import com.mikepenz.materialdrawer.model.PrimaryDrawerItem; import com.mikepenz.materialdrawer.model.ProfileDrawerItem; @@ -102,7 +99,8 @@ public class MainActivity extends AppCompatActivity private static final Logger LOG = LoggerFactory.getLogger(MainActivity.class); private static final int ADD_IDENTITY = 1; private static final int MANAGE_IDENTITY = 2; - private static final int ADD_CHAN = 3; + + private static final long ID_NODE_SWITCH = 1; private static WeakReference instance; @@ -134,7 +132,7 @@ public class MainActivity extends AppCompatActivity private AccountHeader accountHeader; private Drawer drawer; - private ShowcaseView showcaseView; + private SwitchDrawerItem nodeSwitch; @Override protected void onCreate(Bundle savedInstanceState) { @@ -152,7 +150,9 @@ public class MainActivity extends AppCompatActivity setSupportActionBar(toolbar); MessageListFragment listFragment = new MessageListFragment(); - getSupportFragmentManager().beginTransaction().replace(R.id.item_list, listFragment) + getSupportFragmentManager() + .beginTransaction() + .replace(R.id.item_list, listFragment) .commit(); if (findViewById(R.id.message_detail_container) != null) { @@ -189,27 +189,23 @@ public class MainActivity extends AppCompatActivity int margin = ((Number) (getResources().getDisplayMetrics().density * 12)).intValue(); lps.setMargins(margin, margin, margin, margin); - showcaseView = new ShowcaseView.Builder(this) + new ShowcaseView.Builder(this) .withMaterialShowcase() .setStyle(R.style.CustomShowcaseTheme) .setContentTitle(R.string.full_node) .setContentText(R.string.full_node_description) - .setTarget(new Target() { - @Override - public Point getPoint() { - View view = drawer.getStickyFooter(); - int[] location = new int[2]; - view.getLocationInWindow(location); - int x = location[0] + 7 * view.getWidth() / 8; - int y = location[1] + view.getHeight() / 2; - return new Point(x, y); - } - } - ) + .setTarget(() -> { + View view = drawer.getStickyFooter(); + int[] location = new int[2]; + view.getLocationInWindow(location); + int x = location[0] + 7 * view.getWidth() / 8; + int y = location[1] + view.getHeight() / 2; + return new Point(x, y); + }) .replaceEndButton(R.layout.showcase_button) .hideOnTouchOutside() - .build(); - showcaseView.setButtonPosition(lps); + .build() + .setButtonPosition(lps); } } @@ -268,32 +264,28 @@ public class MainActivity extends AppCompatActivity .withActivity(this) .withHeaderBackground(R.drawable.header) .withProfiles(profiles) - .withOnAccountHeaderListener(new AccountHeader.OnAccountHeaderListener() { - @Override - public boolean onProfileChanged(View view, IProfile profile, boolean - currentProfile) { - switch ((int) profile.getIdentifier()) { - case ADD_IDENTITY: - addIdentityDialog(); - break; - case MANAGE_IDENTITY: - Intent show = new Intent(MainActivity.this, - AddressDetailActivity.class); - show.putExtra(AddressDetailFragment.ARG_ITEM, - Singleton.getIdentity(getApplicationContext())); - startActivity(show); - break; - default: - if (profile instanceof ProfileDrawerItem) { - Object tag = ((ProfileDrawerItem) profile).getTag(); - if (tag instanceof BitmessageAddress) { - Singleton.setIdentity((BitmessageAddress) tag); - } + .withOnAccountHeaderListener((view, profile, currentProfile) -> { + switch ((int) profile.getIdentifier()) { + case ADD_IDENTITY: + addIdentityDialog(); + break; + case MANAGE_IDENTITY: + Intent show = new Intent(MainActivity.this, + AddressDetailActivity.class); + show.putExtra(AddressDetailFragment.ARG_ITEM, + Singleton.getIdentity(getApplicationContext())); + 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; + } } + // false if it should close the drawer + return false; }) .build(); if (profiles.size() > 2) { // There's always the add and manage identity items @@ -346,62 +338,55 @@ public class MainActivity extends AppCompatActivity .withName(R.string.settings) .withIcon(GoogleMaterial.Icon.gmd_settings)); + nodeSwitch = new SwitchDrawerItem() + .withIdentifier(ID_NODE_SWITCH) + .withName(R.string.full_node) + .withIcon(CommunityMaterial.Icon.cmd_cloud_outline) + .withChecked(isRunning()) + .withOnCheckedChangeListener((drawerItem, buttonView, isChecked) -> { + if (isChecked) { + checkAndStartNode(buttonView); + } else { + service.shutdownNode(); + } + }); + drawer = new DrawerBuilder() .withActivity(this) .withToolbar(toolbar) .withAccountHeader(accountHeader) .withDrawerItems(drawerItems) - .addStickyDrawerItems( - new SwitchDrawerItem() - .withName(R.string.full_node) - .withIcon(CommunityMaterial.Icon.cmd_cloud_outline) - .withChecked(isRunning()) - .withOnCheckedChangeListener(new OnCheckedChangeListener() { - @Override - public void onCheckedChanged(IDrawerItem drawerItem, - CompoundButton buttonView, - boolean isChecked) { - if (isChecked) { - checkAndStartNode(buttonView); - } else { - service.shutdownNode(); - } - } - }) - ) - .withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() { - @Override - public boolean onItemClick(View view, int position, IDrawerItem item) { - if (item.getTag() instanceof Label) { - selectedLabel = (Label) item.getTag(); - showSelectedLabel(); - 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.archive: - selectedLabel = null; - showSelectedLabel(); - break; - case R.string.full_node: - return true; - } - } + .addStickyDrawerItems(nodeSwitch) + .withOnDrawerItemClickListener((view, position, item) -> { + if (item.getTag() instanceof Label) { + selectedLabel = (Label) item.getTag(); + showSelectedLabel(); 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.archive: + selectedLabel = null; + showSelectedLabel(); + break; + case R.string.full_node: + return true; + } } + return false; }) .withShowDrawerOnFirstLaunch(true) .build(); @@ -415,6 +400,7 @@ public class MainActivity extends AppCompatActivity @Override protected void onResume() { updateUnread(); + updateNodeSwitch(); super.onResume(); } @@ -470,18 +456,14 @@ public class MainActivity extends AppCompatActivity } else { new AlertDialog.Builder(MainActivity.this) .setMessage(R.string.full_node_warning) - .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - service.startupNode(); - } - }) - .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - buttonView.setChecked(false); - } - }) + .setPositiveButton( + android.R.string.yes, + (dialog, which) -> service.startupNode() + ) + .setNegativeButton( + android.R.string.no, + (dialog, which) -> updateNodeSwitch() + ) .show(); } } @@ -501,6 +483,13 @@ public class MainActivity extends AppCompatActivity } } + public void updateNodeSwitch() { + runOnUiThread(() -> { + nodeSwitch.withChecked(bmc.isRunning()); + drawer.updateStickyFooterItem(nodeSwitch); + }); + } + private void showSelectedLabel() { if (getSupportFragmentManager().findFragmentById(R.id.item_list) instanceof MessageListFragment) { diff --git a/app/src/main/java/ch/dissem/apps/abit/SettingsActivity.java b/app/src/main/java/ch/dissem/apps/abit/SettingsActivity.java index 07f4cc7..8997349 100644 --- a/app/src/main/java/ch/dissem/apps/abit/SettingsActivity.java +++ b/app/src/main/java/ch/dissem/apps/abit/SettingsActivity.java @@ -1,8 +1,6 @@ package ch.dissem.apps.abit; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; /** * @author Christian Basler diff --git a/app/src/main/java/ch/dissem/apps/abit/dialog/DeterministicIdentityDialogFragment.java b/app/src/main/java/ch/dissem/apps/abit/dialog/DeterministicIdentityDialogFragment.java index 9cad6ba..a31b84b 100644 --- a/app/src/main/java/ch/dissem/apps/abit/dialog/DeterministicIdentityDialogFragment.java +++ b/app/src/main/java/ch/dissem/apps/abit/dialog/DeterministicIdentityDialogFragment.java @@ -20,7 +20,6 @@ import android.content.Context; import android.os.AsyncTask; import android.os.Bundle; import android.support.annotation.Nullable; -import android.support.v4.app.FragmentActivity; import android.support.v7.app.AppCompatDialogFragment; import android.view.LayoutInflater; import android.view.View; @@ -41,7 +40,6 @@ import ch.dissem.bitmessage.entity.payload.Pubkey; /** * @author Christian Basler */ - public class DeterministicIdentityDialogFragment extends AppCompatDialogFragment { private BitmessageContext bmc; @@ -58,76 +56,68 @@ public class DeterministicIdentityDialogFragment extends AppCompatDialogFragment getDialog().setTitle(R.string.add_deterministic_address); View view = inflater.inflate(R.layout.dialog_add_deterministic_identity, container, false); view.findViewById(R.id.ok) - .setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - dismiss(); - final Context context = getActivity().getBaseContext(); - View dialogView = getView(); - TextView label = (TextView) dialogView.findViewById(R.id.label); - TextView passphrase = (TextView) dialogView.findViewById(R.id.passphrase); - TextView numberOfAddresses = (TextView) dialogView.findViewById(R.id - .number_of_identities); - Switch shorter = (Switch) dialogView.findViewById(R.id.shorter); + .setOnClickListener(v -> { + dismiss(); + final Context context = getActivity().getBaseContext(); + View dialogView = getView(); + TextView label = (TextView) dialogView.findViewById(R.id.label); + TextView passphrase = (TextView) dialogView.findViewById(R.id.passphrase); + TextView numberOfAddresses = (TextView) dialogView.findViewById(R.id + .number_of_identities); + Switch shorter = (Switch) dialogView.findViewById(R.id.shorter); - Toast.makeText(context, R.string.toast_long_running_operation, - Toast.LENGTH_SHORT).show(); - new AsyncTask>() { - @Override - protected List doInBackground(Object... args) { - String label = (String) args[0]; - String pass = (String) args[1]; - int numberOfAddresses = (int) args[2]; - boolean shorter = (boolean) args[3]; - List identities = bmc.createDeterministicAddresses - (pass, - numberOfAddresses, Pubkey.LATEST_VERSION, 1L, shorter); - int i = 0; - for (BitmessageAddress identity : identities) { - i++; - if (identities.size() == 1) { - identity.setAlias(label); - } else { - identity.setAlias(label + " (" + i + ")"); - } - bmc.addresses().save(identity); - } - return identities; - } - - @Override - protected void onPostExecute(List identities) { - int messageRes; + Toast.makeText(context, R.string.toast_long_running_operation, + Toast.LENGTH_SHORT).show(); + new AsyncTask>() { + @Override + protected List doInBackground(Object... args) { + String label = (String) args[0]; + String pass = (String) args[1]; + int numberOfAddresses = (int) args[2]; + boolean shorter = (boolean) args[3]; + List identities = bmc.createDeterministicAddresses + (pass, + numberOfAddresses, Pubkey.LATEST_VERSION, 1L, shorter); + int i = 0; + for (BitmessageAddress identity : identities) { + i++; if (identities.size() == 1) { - messageRes = R.string.toast_identity_created; + identity.setAlias(label); } else { - messageRes = R.string.toast_identities_created; + identity.setAlias(label + " (" + i + ")"); } - Toast.makeText(context, - messageRes, - Toast.LENGTH_SHORT).show(); - MainActivity mainActivity = MainActivity.getInstance(); - if (mainActivity != null) { - for (BitmessageAddress identity : identities) { - mainActivity.addIdentityEntry(identity); - } + bmc.addresses().save(identity); + } + return identities; + } + + @Override + protected void onPostExecute(List identities) { + int messageRes; + if (identities.size() == 1) { + messageRes = R.string.toast_identity_created; + } else { + messageRes = R.string.toast_identities_created; + } + Toast.makeText(context, + messageRes, + Toast.LENGTH_SHORT).show(); + MainActivity mainActivity = MainActivity.getInstance(); + if (mainActivity != null) { + for (BitmessageAddress identity : identities) { + mainActivity.addIdentityEntry(identity); } } - }.execute( - label.getText().toString(), - passphrase.getText().toString(), - Integer.valueOf(numberOfAddresses.getText().toString()), - shorter.isChecked() - ); - } + } + }.execute( + label.getText().toString(), + passphrase.getText().toString(), + Integer.valueOf(numberOfAddresses.getText().toString()), + shorter.isChecked() + ); }); view.findViewById(R.id.dismiss) - .setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - dismiss(); - } - }); + .setOnClickListener(v -> dismiss()); return view; } 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 d11c0c9..1377e1f 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 @@ -17,7 +17,6 @@ package ch.dissem.apps.abit.notification; import android.annotation.SuppressLint; -import android.app.Notification; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; @@ -28,7 +27,7 @@ import java.util.TimerTask; import ch.dissem.apps.abit.MainActivity; import ch.dissem.apps.abit.R; -import ch.dissem.bitmessage.BitmessageContext; +import ch.dissem.apps.abit.service.BitmessageService; import ch.dissem.bitmessage.utils.Property; /** @@ -37,31 +36,32 @@ import ch.dissem.bitmessage.utils.Property; public class NetworkNotification extends AbstractNotification { public static final int ONGOING_NOTIFICATION_ID = 2; - private final BitmessageContext bmc; private NotificationCompat.Builder builder; - public NetworkNotification(Context ctx, BitmessageContext bmc) { + public NetworkNotification(Context ctx) { super(ctx); - this.bmc = bmc; + Intent showMessageIntent = new Intent(ctx, MainActivity.class); + PendingIntent pendingIntent = PendingIntent.getActivity(ctx, 1, showMessageIntent, 0); builder = new NotificationCompat.Builder(ctx); builder.setSmallIcon(R.drawable.ic_notification_full_node) - .setContentTitle(ctx.getString(R.string.bitmessage_full_node)) - .setVisibility(NotificationCompat.VISIBILITY_PUBLIC); - } - - @Override - public Notification getNotification() { - update(); - return notification; + .setContentTitle(ctx.getString(R.string.bitmessage_full_node)) + .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + .setShowWhen(false) + .setContentIntent(pendingIntent); } @SuppressLint("StringFormatMatches") + @SuppressWarnings("BooleanMethodIsAlwaysInverted") private boolean update() { - boolean running = bmc.isRunning(); + boolean running = BitmessageService.isRunning(); builder.setOngoing(running); - Property connections = bmc.status().getProperty("network").getProperty("connections"); + Property connections = BitmessageService.getStatus().getProperty("network", "connections"); if (!running) { builder.setContentText(ctx.getString(R.string.connection_info_disconnected)); + MainActivity mainActivity = MainActivity.getInstance(); + if (mainActivity != null) { + mainActivity.updateNodeSwitch(); + } } else if (connections.getProperties().length == 0) { builder.setContentText(ctx.getString(R.string.connection_info_pending)); } else { @@ -71,29 +71,24 @@ public class NetworkNotification extends AbstractNotification { Integer nodeCount = (Integer) stream.getProperty("nodes").getValue(); if (nodeCount == 1) { info.append(ctx.getString(R.string.connection_info_1, - streamNumber)); + streamNumber)); } else { info.append(ctx.getString(R.string.connection_info_n, - streamNumber, nodeCount)); + streamNumber, nodeCount)); } info.append('\n'); } builder.setContentText(info); } - Intent showMessageIntent = new Intent(ctx, MainActivity.class); - PendingIntent pendingIntent = PendingIntent.getActivity(ctx, 1, showMessageIntent, 0); - builder.setContentIntent(pendingIntent); notification = builder.build(); return running; } @Override public void show() { - update(); super.show(); - final Timer timer = new Timer(); - timer.schedule(new TimerTask() { + new Timer().schedule(new TimerTask() { @Override public void run() { if (!update()) { @@ -108,4 +103,10 @@ public class NetworkNotification extends AbstractNotification { protected int getNotificationId() { return ONGOING_NOTIFICATION_ID; } + + public void connecting() { + builder.setOngoing(true); + builder.setContentText(ctx.getString(R.string.connection_info_pending)); + notification = builder.build(); + } } diff --git a/app/src/main/java/ch/dissem/apps/abit/notification/NewMessageNotification.java b/app/src/main/java/ch/dissem/apps/abit/notification/NewMessageNotification.java index 246ea6d..80ff371 100644 --- a/app/src/main/java/ch/dissem/apps/abit/notification/NewMessageNotification.java +++ b/app/src/main/java/ch/dissem/apps/abit/notification/NewMessageNotification.java @@ -36,7 +36,7 @@ import ch.dissem.bitmessage.entity.Plaintext; import static ch.dissem.apps.abit.util.Drawables.toBitmap; public class NewMessageNotification extends AbstractNotification { - public static final int NEW_MESSAGE_NOTIFICATION_ID = 1; + private static final int NEW_MESSAGE_NOTIFICATION_ID = 1; private static final StyleSpan SPAN_EMPHASIS = new StyleSpan(Typeface.BOLD); public NewMessageNotification(Context ctx) { @@ -62,6 +62,7 @@ public class NewMessageNotification extends AbstractNotification { PendingIntent.FLAG_UPDATE_CURRENT); builder.setContentIntent(pendingIntent); + // TODO: add proper intents to reply/delete builder.addAction(R.drawable.ic_action_reply, ctx.getString(R.string.reply), pendingIntent); builder.addAction(R.drawable.ic_action_delete, ctx.getString(R.string.delete), pendingIntent); 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 4eb3374..b585aeb 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 @@ -196,7 +196,9 @@ public class AndroidAddressRepository implements AddressRepository { SQLiteDatabase db = sql.getWritableDatabase(); // Create a new map of values, where column names are the keys ContentValues values = new ContentValues(); - values.put(COLUMN_ALIAS, address.getAlias()); + if (address.getAlias() != null) { + values.put(COLUMN_ALIAS, address.getAlias()); + } if (address.getPubkey() != null) { ByteArrayOutputStream out = new ByteArrayOutputStream(); address.getPubkey().writeUnencrypted(out); @@ -207,7 +209,9 @@ public class AndroidAddressRepository implements AddressRepository { if (address.getPrivateKey() != null) { values.put(COLUMN_PRIVATE_KEY, Encode.bytes(address.getPrivateKey())); } - values.put(COLUMN_CHAN, address.isChan()); + if (address.isChan()) { + values.put(COLUMN_CHAN, true); + } values.put(COLUMN_SUBSCRIBED, address.isSubscribed()); int update = db.update(TABLE_NAME, values, "address=?", diff --git a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidProofOfWorkRepository.java b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidProofOfWorkRepository.java index d27a821..6b944d2 100644 --- a/app/src/main/java/ch/dissem/apps/abit/repository/AndroidProofOfWorkRepository.java +++ b/app/src/main/java/ch/dissem/apps/abit/repository/AndroidProofOfWorkRepository.java @@ -33,7 +33,6 @@ import ch.dissem.bitmessage.entity.ObjectMessage; import ch.dissem.bitmessage.factory.Factory; import ch.dissem.bitmessage.ports.ProofOfWorkRepository; import ch.dissem.bitmessage.utils.Encode; -import ch.dissem.bitmessage.utils.Strings; import static ch.dissem.bitmessage.utils.Singleton.cryptography; import static ch.dissem.bitmessage.utils.Strings.hex; diff --git a/app/src/main/java/ch/dissem/apps/abit/service/BitmessageService.java b/app/src/main/java/ch/dissem/apps/abit/service/BitmessageService.java index d2e04d8..799aa07 100644 --- a/app/src/main/java/ch/dissem/apps/abit/service/BitmessageService.java +++ b/app/src/main/java/ch/dissem/apps/abit/service/BitmessageService.java @@ -21,11 +21,9 @@ import android.content.Intent; import android.os.Binder; import android.os.IBinder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import ch.dissem.apps.abit.notification.NetworkNotification; import ch.dissem.bitmessage.BitmessageContext; +import ch.dissem.bitmessage.utils.Property; import static ch.dissem.apps.abit.notification.NetworkNotification.ONGOING_NOTIFICATION_ID; @@ -35,12 +33,7 @@ import static ch.dissem.apps.abit.notification.NetworkNotification.ONGOING_NOTIF * onPerformSync(). */ public class BitmessageService extends Service { - public static final Logger LOG = LoggerFactory.getLogger(BitmessageService.class); - - // Object to use as a thread-safe lock - private static final Object lock = new Object(); - - private static NetworkNotification notification = null; + private NetworkNotification notification = null; private static BitmessageContext bmc = null; private static volatile boolean running = false; @@ -51,11 +44,11 @@ public class BitmessageService extends Service { @Override public void onCreate() { - synchronized (lock) { + synchronized (BitmessageService.class) { if (bmc == null) { bmc = Singleton.getBitmessageContext(this); - notification = new NetworkNotification(this, bmc); } + notification = new NetworkNotification(this); } } @@ -70,7 +63,6 @@ public class BitmessageService extends Service { running = false; } - /** * Return an object that allows the system to invoke * the sync adapter. @@ -84,6 +76,7 @@ public class BitmessageService extends Service { public void startupNode() { startService(new Intent(BitmessageService.this, BitmessageService.class)); running = true; + notification.connecting(); startForeground(ONGOING_NOTIFICATION_ID, notification.getNotification()); if (!bmc.isRunning()) { bmc.startup(); @@ -96,8 +89,17 @@ public class BitmessageService extends Service { bmc.shutdown(); } running = false; - stopForeground(false); + stopForeground(true); + notification.show(); stopSelf(); } } -} \ No newline at end of file + + public static Property getStatus() { + if (bmc != null) { + return bmc.status(); + } else { + return new Property("bitmessage context", null); + } + } +} diff --git a/app/src/main/java/ch/dissem/apps/abit/service/ProofOfWorkService.java b/app/src/main/java/ch/dissem/apps/abit/service/ProofOfWorkService.java index cb61cf3..c01f5c3 100644 --- a/app/src/main/java/ch/dissem/apps/abit/service/ProofOfWorkService.java +++ b/app/src/main/java/ch/dissem/apps/abit/service/ProofOfWorkService.java @@ -40,7 +40,7 @@ public class ProofOfWorkService extends Service { private static ProofOfWorkEngine engine = new MultiThreadedPOWEngine(); private static boolean calculating; private static final Queue queue = new LinkedList<>(); - private static ProofOfWorkNotification notification; + private ProofOfWorkNotification notification; @Override public void onCreate() { @@ -55,16 +55,18 @@ public class ProofOfWorkService extends Service { public static class PowBinder extends Binder { private final ProofOfWorkService service; + private final ProofOfWorkNotification notification; private PowBinder(ProofOfWorkService service) { this.service = service; + this.notification = service.notification; } - public void process(PowItem item) { + void process(PowItem item) { synchronized (queue) { service.startService(new Intent(service, ProofOfWorkService.class)); service.startForeground(ONGOING_NOTIFICATION_ID, - notification.getNotification()); + notification.getNotification()); if (!calculating) { calculating = true; service.calculateNonce(item); @@ -90,28 +92,25 @@ public class ProofOfWorkService extends Service { } private void calculateNonce(final PowItem item) { - engine.calculateNonce(item.initialHash, item.targetValue, new ProofOfWorkEngine.Callback() { - @Override - public void onNonceCalculated(byte[] initialHash, byte[] nonce) { - try { - item.callback.onNonceCalculated(initialHash, nonce); - } finally { - PowItem item; - synchronized (queue) { - item = queue.poll(); - if (item == null) { - calculating = false; - stopForeground(true); - stopSelf(); - } else { - notification.update(queue.size()).show(); - } - } - if (item != null) { - calculateNonce(item); + engine.calculateNonce(item.initialHash, item.targetValue, (initialHash, nonce) -> { + try { + item.callback.onNonceCalculated(initialHash, nonce); + } finally { + PowItem next; + synchronized (queue) { + next = queue.poll(); + if (next == null) { + calculating = false; + stopForeground(true); + stopSelf(); + } else { + notification.update(queue.size()).show(); } } + if (next != null) { + calculateNonce(next); + } } }); } -} \ No newline at end of file +} diff --git a/app/src/main/java/ch/dissem/apps/abit/service/Singleton.java b/app/src/main/java/ch/dissem/apps/abit/service/Singleton.java index 1bc0f77..a92521d 100644 --- a/app/src/main/java/ch/dissem/apps/abit/service/Singleton.java +++ b/app/src/main/java/ch/dissem/apps/abit/service/Singleton.java @@ -46,7 +46,6 @@ import static ch.dissem.bitmessage.utils.UnixTime.DAY; * Provides singleton objects across the application. */ public class Singleton { - public static final Object lock = new Object(); private static BitmessageContext bitmessageContext; private static MessageListener messageListener; private static BitmessageAddress identity; @@ -54,28 +53,28 @@ public class Singleton { public static BitmessageContext getBitmessageContext(Context context) { if (bitmessageContext == null) { - synchronized (lock) { + synchronized (Singleton.class) { if (bitmessageContext == null) { final Context ctx = context.getApplicationContext(); SqlHelper sqlHelper = new SqlHelper(ctx); powRepo = new AndroidProofOfWorkRepository(sqlHelper); TTL.pubkey(2 * DAY); bitmessageContext = new BitmessageContext.Builder() - .proofOfWorkEngine(new SwitchingProofOfWorkEngine( - ctx, Constants.PREFERENCE_SERVER_POW, - new ServerPowEngine(ctx), - new ServicePowEngine(ctx) - )) - .cryptography(new AndroidCryptography()) - .nodeRegistry(new AndroidNodeRegistry(sqlHelper)) - .inventory(new AndroidInventory(sqlHelper)) - .addressRepo(new AndroidAddressRepository(sqlHelper)) - .messageRepo(new AndroidMessageRepository(sqlHelper, ctx)) - .powRepo(powRepo) - .networkHandler(new NioNetworkHandler()) - .listener(getMessageListener(ctx)) - .doNotSendPubkeyOnIdentityCreation() - .build(); + .proofOfWorkEngine(new SwitchingProofOfWorkEngine( + ctx, Constants.PREFERENCE_SERVER_POW, + new ServerPowEngine(ctx), + new ServicePowEngine(ctx) + )) + .cryptography(new AndroidCryptography()) + .nodeRegistry(new AndroidNodeRegistry(sqlHelper)) + .inventory(new AndroidInventory(sqlHelper)) + .addressRepo(new AndroidAddressRepository(sqlHelper)) + .messageRepo(new AndroidMessageRepository(sqlHelper, ctx)) + .powRepo(powRepo) + .networkHandler(new NioNetworkHandler()) + .listener(getMessageListener(ctx)) + .doNotSendPubkeyOnIdentityCreation() + .build(); } } } @@ -108,11 +107,12 @@ public class Singleton { public static BitmessageAddress getIdentity(Context ctx) { if (identity == null) { + BitmessageContext bmc = getBitmessageContext(ctx); synchronized (Singleton.class) { if (identity == null) { - BitmessageContext bmc = getBitmessageContext(ctx); + // FIXME: this may block the UI, there must be a better way! List identities = bmc.addresses() - .getIdentities(); + .getIdentities(); if (identities.size() > 0) { identity = identities.get(0); } else { 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 66923cd..0653559 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 @@ -25,7 +25,6 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import java.net.InetAddress; -import java.net.UnknownHostException; import ch.dissem.apps.abit.R; import ch.dissem.apps.abit.listener.WifiReceiver; @@ -39,8 +38,6 @@ import static ch.dissem.apps.abit.util.Constants.PREFERENCE_WIFI_ONLY; * @author Christian Basler */ public class Preferences { - private static Logger LOG = LoggerFactory.getLogger(Preferences.class); - public static boolean useTrustedNode(Context ctx) { String trustedNode = getPreference(ctx, PREFERENCE_TRUSTED_NODE); return trustedNode != null && !trustedNode.trim().isEmpty(); 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 4e2005b..8c402c6 100644 --- a/app/src/main/res/layout-w720dp/activity_message_list.xml +++ b/app/src/main/res/layout-w720dp/activity_message_list.xml @@ -51,7 +51,8 @@ android:layout_margin="16dp" android:background="@color/contentBackground" android:elevation="2dp" - tools:layout="@layout/fragment_message_detail"/> + tools:layout="@layout/fragment_message_detail" + tools:ignore="InconsistentLayout,UnusedAttribute"/> diff --git a/app/src/main/res/layout/fragment_compose_message.xml b/app/src/main/res/layout/fragment_compose_message.xml index 35153ca..32ae0c3 100644 --- a/app/src/main/res/layout/fragment_compose_message.xml +++ b/app/src/main/res/layout/fragment_compose_message.xml @@ -15,7 +15,7 @@ android:layout_height="wrap_content" android:hint="@string/to" android:inputType="textNoSuggestions" - android:singleLine="true"/> + android:maxLines="1"/> @@ -43,4 +43,4 @@ android:inputType="textMultiLine|textCapSentences" android:scrollbars="vertical"/> - \ No newline at end of file + diff --git a/app/src/main/res/layout/showcase_button.xml b/app/src/main/res/layout/showcase_button.xml index f8b0558..5772c83 100644 --- a/app/src/main/res/layout/showcase_button.xml +++ b/app/src/main/res/layout/showcase_button.xml @@ -1,14 +1,11 @@ \ No newline at end of file + android:textSize="13sp" + android:textStyle="bold"> + diff --git a/app/src/main/res/layout/subscription_row.xml b/app/src/main/res/layout/subscription_row.xml index c7d137d..8a40938 100644 --- a/app/src/main/res/layout/subscription_row.xml +++ b/app/src/main/res/layout/subscription_row.xml @@ -34,10 +34,11 @@ + tools:text="Stream #" + tools:ignore="RelativeOverlap"/> Nachricht Abonnement Bitmessage Netzknoten - Art der WLAN-Verbindung Einstellungen Nur WLAN Nicht mit Mobilfunknetz verbinden - Abonnements An Betreff Identität verwalten Identität hinzufügen Eine neue Identität erstellen - Erstellen Eine neue, zufällige Identität erstellen - Importieren Eine existierende Identität von PyBitmessage oder einem Export importieren Deterministische Identität Eine deterministische Identität erstellen oder wiederherstellen @@ -25,11 +21,8 @@ Einen Chan erstellen oder einem beitreten Kontakt importieren - Einstellungen Stream %1$d: eine Verbindung Stream %1$d: %2$d Verbindungen - Adresse importieren - Kontakt hinzufügen Label Abonnieren Importieren @@ -42,7 +35,6 @@ Archiv Papierkorb leeren Stream %d - Aktiv Vertrauenswürdiger Knoten Diese Adresse wird für die Synchronisation verwendet Zeitbeschränkung der Synchronisierung @@ -56,7 +48,6 @@ Arbeite am Versenden Arbeite am Versenden (%1$d in Warteschlange) Ungültiger Port in den Synchronisationseinstellungen: %s - Synchronisation fehlgeschlagen: der vertrauenswürdige Knoten konnte nicht erreicht werden. Nachricht schreiben Kontakte Abonniert @@ -78,10 +69,9 @@ Bist Du sicher dass dieser Kontakt gelöscht werden soll? QR-Code scannen Kontakt erfassen - Solange kein aktiver Knoten gestartet ist, werden keine Meldungen empfangen oder gesendet. Dies braucht jedoch viele Resourcen und Daten. + Solange kein aktiver Knoten gestartet ist, werden keine Meldungen empfangen oder gesendet. Dies braucht jedoch viele Ressourcen und Daten. Als Alternative kann in den Einstellungen ein vertrauenswürdiger Knoten konfiguriert werden, aber im Moment muss dieser selbst bereitgestellt werden. - Alles klar Bitmessage-Adresse Vielleicht hat es einen Tippfehler Exportieren @@ -95,7 +85,7 @@ Als Alternative kann in den Einstellungen ein vertrauenswürdiger Knoten konfigu Identität erstellt Identitäten erstellt Chan erstellt - Merke dir diese Enstellungen und stelle sicher dass sie korrekt sind wenn du eine deterministische Addresse wiederherstellst. + Merke dir diese Enstellungen und stelle sicher dass sie korrekt sind wenn du eine deterministische Adresse wiederherstellst. Anzahl zu generierender Identitäten Kürzere Adressen suchen WIF / Inhalt von ‘keys.dat’ @@ -106,5 +96,4 @@ Als Alternative kann in den Einstellungen ein vertrauenswürdiger Knoten konfigu Datei auswählen Bitte wähle die zu importierenden Identitäten: Du kannst einfach den Inhalt eines Exports oder einer ‘keys.dat’-Datei einfügen - Name diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index f2f59f8..ae469d9 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -1,6 +1,6 @@ - + #FFC107 #FFA000 #DEFFFFFF diff --git a/app/src/main/res/values/library_fab_speed_dial_strings.xml b/app/src/main/res/values/library_fab_speed_dial_strings.xml index bdc1c1f..976a0f6 100644 --- a/app/src/main/res/values/library_fab_speed_dial_strings.xml +++ b/app/src/main/res/values/library_fab_speed_dial_strings.xml @@ -15,7 +15,7 @@ ~ limitations under the License. --> - + Yavor Ivanov diff --git a/app/src/main/res/values/library_filepicker_strings.xml b/app/src/main/res/values/library_filepicker_strings.xml index 23ba3b6..aa3b993 100644 --- a/app/src/main/res/values/library_filepicker_strings.xml +++ b/app/src/main/res/values/library_filepicker_strings.xml @@ -1,21 +1,21 @@ - + - - Angad Singh - https://github.com/Angads25 - - FilePicker - Android Library to select files/directories from Device Storage. - https://github.com/Angads25/android-filepicker - 1.0.6 - - true - https://github.com/Angads25/android-filepicker - - com.github.angads25.filepicker.view.FilePickerDialog - - apache_2_0 - + + Angad Singh + https://github.com/Angads25 + + FilePicker + Android Library to select files/directories from Device Storage. + https://github.com/Angads25/android-filepicker + 1.0.6 + + true + https://github.com/Angads25/android-filepicker + + com.github.angads25.filepicker.view.FilePickerDialog + + apache_2_0 + diff --git a/app/src/main/res/values/library_jabit_strings.xml b/app/src/main/res/values/library_jabit_strings.xml index c12f0b6..42a2d5c 100644 --- a/app/src/main/res/values/library_jabit_strings.xml +++ b/app/src/main/res/values/library_jabit_strings.xml @@ -1,5 +1,5 @@ - + Christian Basler diff --git a/app/src/main/res/values/library_zxing_strings.xml b/app/src/main/res/values/library_zxing_strings.xml index 49e7177..14ba997 100644 --- a/app/src/main/res/values/library_zxing_strings.xml +++ b/app/src/main/res/values/library_zxing_strings.xml @@ -15,7 +15,7 @@ ~ limitations under the License. --> - + Google, Inc. diff --git a/app/src/main/res/values/library_zxingandroidembedded_strings.xml b/app/src/main/res/values/library_zxingandroidembedded_strings.xml index 3540706..d441c48 100644 --- a/app/src/main/res/values/library_zxingandroidembedded_strings.xml +++ b/app/src/main/res/values/library_zxingandroidembedded_strings.xml @@ -1,6 +1,6 @@ - + JourneyApps diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 54fdc10..dd448d9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,22 +1,18 @@ - + Abit A Bitmessage client for Android Message Detail Subscription Detail Bitmessage Node - Wi-Fi Connection Mode Settings Wi-Fi only Don\'t connect to the mobile network - Subscriptions To Subject Manage Identity Add Identity Create new identity - Create new Create a new, random identity - Import existing Import an existing identity from PyBitmessage or from an export Deterministic identity Create or recreate a deterministic identity @@ -24,24 +20,20 @@ Create or join a chan Import Contact - Settings Stream #%1$d: one connection - Stream #%1$d: %2$d connections - Import Address - Add to contacts + Stream #%1$d: %2$d connections Label Subscribe Import Cancel Broadcast - %d new messages + %d new messages Reply Delete Mark unread Archive Empty Trash Stream #%d - Enabled Trusted node Use this node for synchronization Synchronization Timeout @@ -53,9 +45,8 @@ Connecting… Proof of Work Doing work to send message - Doing work to send message (%1$d queued) + Doing work to send message (%1$d queued) Invalid port in synchronization settings: %s - Synchronization failed: Trusted node could not be reached. Write message Contacts Subscribed @@ -80,7 +71,6 @@ You can\'t receive or send messages unless you start a full node. But be aware that this uses a lot of resources and internet traffic. As an alternative you could configure a trusted node in the settings, but as of now you\'ll need to deploy your own. - Got it Bitmessage Address There might be a typo Export @@ -105,5 +95,4 @@ As an alternative you could configure a trusted node in the settings, but as of Select a File Please select the identities you want to import: You can just paste the contents of an export or a ‘keys.dat’ file - Name diff --git a/build.gradle b/build.gradle index c9dbf0f..ec2dca6 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.2.0' + classpath 'com.android.tools.build:gradle:2.2.1' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files