diff --git a/app/build.gradle b/app/build.gradle
index 6682841..893c544 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -11,14 +11,14 @@ if (project.hasProperty("project.configs")
android {
compileSdkVersion 24
- buildToolsVersion "24.0.2"
+ buildToolsVersion "24.0.3"
defaultConfig {
applicationId "ch.dissem.apps." + appName.toLowerCase()
minSdkVersion 19
targetSdkVersion 24
- versionCode 7
- versionName "1.0-beta7"
+ versionCode 8
+ versionName "1.0-beta8"
}
buildTypes {
release {
@@ -29,7 +29,7 @@ android {
}
}
-ext.jabitVersion = 'development-SNAPSHOT'
+ext.jabitVersion = '2.0.0'
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:24.2.1'
@@ -54,16 +54,18 @@ dependencies {
compile 'com.mikepenz:iconics:1.6.2@aar'
compile 'com.mikepenz:community-material-typeface:1.5.54.2@aar'
- compile 'com.journeyapps:zxing-android-embedded:3.1.0@aar'
- compile 'com.google.zxing:core:3.2.0'
- compile 'io.github.yavski:fab-speed-dial:1.0.2'
+ compile 'com.journeyapps:zxing-android-embedded:3.3.0@aar'
+ compile 'com.google.zxing:core:3.3.0'
+ compile 'io.github.yavski:fab-speed-dial:1.0.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.github.angads25:filepicker:1.0.6'
testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:1.10.19'
+ compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha9'
}
idea.module {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a868652..90f7d6f 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -18,7 +18,8 @@
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
- android:theme="@style/AppTheme">
+ android:theme="@style/AppTheme"
+ tools:replace="android:allowBackup">
@@ -103,6 +104,26 @@
+
+
+
+
+
+
+
+
+
+
+
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 5c06208..d4b8b39 100644
--- a/app/src/main/java/ch/dissem/apps/abit/AddressDetailFragment.java
+++ b/app/src/main/java/ch/dissem/apps/abit/AddressDetailFragment.java
@@ -106,8 +106,8 @@ public class AddressDetailFragment extends Fragment {
Drawables.addIcon(getActivity(), menu, R.id.share, GoogleMaterial.Icon.gmd_share);
Drawables.addIcon(getActivity(), menu, R.id.delete, GoogleMaterial.Icon.gmd_delete);
Drawables.addIcon(getActivity(), menu, R.id.export,
- CommunityMaterial.Icon.cmd_export)
- .setVisible(item != null && item.getPrivateKey() != null);
+ CommunityMaterial.Icon.cmd_export)
+ .setVisible(item != null && item.getPrivateKey() != null);
super.onCreateOptionsMenu(menu, inflater);
}
@@ -130,41 +130,45 @@ public class AddressDetailFragment extends Fragment {
else
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);
- item = null;
- ctx.onBackPressed();
- }
- })
- .setNegativeButton(android.R.string.no, null)
- .show();
+ .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();
+ }
+ })
+ .setNegativeButton(android.R.string.no, null)
+ .show();
return true;
}
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));
- }
- })
- .setNegativeButton(android.R.string.no, null)
- .show();
+ .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));
+ }
+ })
+ .setNegativeButton(android.R.string.no, null)
+ .show();
return true;
}
case R.id.share: {
@@ -208,7 +212,7 @@ public class AddressDetailFragment extends Fragment {
address.setText(item.getAddress());
address.setSelected(true);
((TextView) rootView.findViewById(R.id.stream_number)).setText(getActivity()
- .getString(R.string.stream_number, item.getStream()));
+ .getString(R.string.stream_number, item.getStream()));
if (item.getPrivateKey() == null) {
Switch active = (Switch) rootView.findViewById(R.id.active);
active.setChecked(item.isSubscribed());
@@ -220,12 +224,12 @@ public class AddressDetailFragment extends Fragment {
});
ImageView pubkeyAvailableImg = (ImageView) rootView.findViewById(R.id
- .pubkey_available);
+ .pubkey_available);
if (item.getPubkey() == null) {
pubkeyAvailableImg.setAlpha(0.3f);
TextView pubkeyAvailableDesc = (TextView) rootView.findViewById(R.id
- .pubkey_available_desc);
+ .pubkey_available_desc);
pubkeyAvailableDesc.setText(R.string.pubkey_not_available);
}
} else {
@@ -251,7 +255,7 @@ public class AddressDetailFragment extends Fragment {
BitMatrix result;
try {
result = new MultiFormatWriter().encode(link.toString(),
- BarcodeFormat.QR_CODE, QR_CODE_SIZE, QR_CODE_SIZE, null);
+ BarcodeFormat.QR_CODE, QR_CODE_SIZE, QR_CODE_SIZE, null);
} catch (WriterException e) {
LOG.error(e.getMessage(), e);
return null;
@@ -274,6 +278,10 @@ public class AddressDetailFragment extends Fragment {
public void onPause() {
if (item != null) {
Singleton.getAddressRepository(getContext()).save(item);
+ MainActivity mainActivity = MainActivity.getInstance();
+ if (mainActivity != null && item.getPrivateKey() != null) {
+ mainActivity.updateIdentityEntry(item);
+ }
}
super.onPause();
}
diff --git a/app/src/main/java/ch/dissem/apps/abit/ImportIdentitiesFragment.java b/app/src/main/java/ch/dissem/apps/abit/ImportIdentitiesFragment.java
new file mode 100644
index 0000000..f3e91a3
--- /dev/null
+++ b/app/src/main/java/ch/dissem/apps/abit/ImportIdentitiesFragment.java
@@ -0,0 +1,87 @@
+/*
+ * 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.app.Fragment;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.h6ah4i.android.widget.advrecyclerview.decoration.SimpleListDividerDecorator;
+
+import java.io.IOException;
+
+import ch.dissem.apps.abit.adapter.AddressSelectorAdapter;
+import ch.dissem.apps.abit.service.Singleton;
+import ch.dissem.bitmessage.BitmessageContext;
+import ch.dissem.bitmessage.entity.BitmessageAddress;
+import ch.dissem.bitmessage.wif.WifImporter;
+
+/**
+ * @author Christian Basler
+ */
+
+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;
+
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
+ savedInstanceState) {
+ String wifData = getArguments().getString(WIF_DATA);
+ 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,
+ false);
+ recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
+ recyclerView.setLayoutManager(layoutManager);
+ recyclerView.setAdapter(adapter);
+
+ recyclerView.addItemDecoration(new SimpleListDividerDecorator(
+ ContextCompat.getDrawable(getActivity(), R.drawable.list_divider_h), true));
+ } 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);
+ }
+ }
+ getActivity().finish();
+ }
+ });
+ return view;
+ }
+}
diff --git a/app/src/main/java/ch/dissem/apps/abit/ImportIdentityActivity.java b/app/src/main/java/ch/dissem/apps/abit/ImportIdentityActivity.java
new file mode 100644
index 0000000..725ae7d
--- /dev/null
+++ b/app/src/main/java/ch/dissem/apps/abit/ImportIdentityActivity.java
@@ -0,0 +1,56 @@
+/*
+ * 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 static ch.dissem.apps.abit.ImportIdentitiesFragment.WIF_DATA;
+
+/**
+ * @author Christian Basler
+ */
+
+public class ImportIdentityActivity extends DetailActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ String wifData;
+ if (savedInstanceState == null) {
+ wifData = null;
+ } else {
+ wifData = savedInstanceState.getString(WIF_DATA);
+ }
+ if (wifData == null) {
+ getFragmentManager().beginTransaction()
+ .replace(R.id.content, new InputWifFragment())
+ .commit();
+ } else {
+ Bundle bundle = new Bundle();
+ bundle.putString(WIF_DATA, wifData);
+
+ ImportIdentitiesFragment fragment = new ImportIdentitiesFragment();
+ fragment.setArguments(bundle);
+
+ getFragmentManager().beginTransaction()
+ .replace(R.id.content, fragment)
+ .commit();
+ }
+ }
+
+}
diff --git a/app/src/main/java/ch/dissem/apps/abit/InputWifFragment.java b/app/src/main/java/ch/dissem/apps/abit/InputWifFragment.java
new file mode 100644
index 0000000..8ccdf5d
--- /dev/null
+++ b/app/src/main/java/ch/dissem/apps/abit/InputWifFragment.java
@@ -0,0 +1,122 @@
+/*
+ * 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.app.Fragment;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.github.angads25.filepicker.controller.DialogSelectionListener;
+import com.github.angads25.filepicker.model.DialogConfigs;
+import com.github.angads25.filepicker.model.DialogProperties;
+import com.github.angads25.filepicker.view.FilePickerDialog;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import static ch.dissem.apps.abit.ImportIdentitiesFragment.WIF_DATA;
+
+/**
+ * @author Christian Basler
+ */
+
+public class InputWifFragment extends Fragment {
+ private TextView wifData;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.fragment_import_input, container, false);
+ wifData = (TextView) view.findViewById(R.id.wif_input);
+
+ view.findViewById(R.id.next).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Bundle bundle = new Bundle();
+ bundle.putString(WIF_DATA, wifData.getText().toString());
+
+ ImportIdentitiesFragment fragment = new ImportIdentitiesFragment();
+ fragment.setArguments(bundle);
+
+ getFragmentManager().beginTransaction()
+ .replace(R.id.content, fragment)
+ .commit();
+ }
+ });
+ return view;
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ inflater.inflate(R.menu.import_input_data, menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ DialogProperties properties = new DialogProperties();
+ properties.selection_mode = DialogConfigs.SINGLE_MODE;
+ properties.selection_type = DialogConfigs.FILE_SELECT;
+ properties.root = new File(DialogConfigs.DEFAULT_DIR);
+ properties.error_dir = new File(DialogConfigs.DEFAULT_DIR);
+ properties.extensions = null;
+ FilePickerDialog dialog = new FilePickerDialog(getActivity(), properties);
+ dialog.setTitle(getString(R.string.select_file_title));
+ dialog.setDialogSelectionListener(new DialogSelectionListener() {
+ @Override
+ public void onSelectedFilePaths(String[] files) {
+ if (files.length > 0) {
+ try (InputStream in = new FileInputStream(files[0])) {
+ ByteArrayOutputStream data = new ByteArrayOutputStream();
+ byte[] buffer = new byte[1024];
+ int length;
+ //noinspection ConstantConditions
+ while ((length = in.read(buffer)) != -1) {
+ data.write(buffer, 0, length);
+ }
+ wifData.setText(data.toString("UTF-8"));
+ } catch (IOException e) {
+ Toast.makeText(
+ getActivity(),
+ R.string.error_loading_data,
+ Toast.LENGTH_SHORT
+ ).show();
+ }
+ }
+ }
+ });
+ dialog.show();
+ return true;
+ }
+}
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 5233403..0c347fd 100644
--- a/app/src/main/java/ch/dissem/apps/abit/MainActivity.java
+++ b/app/src/main/java/ch/dissem/apps/abit/MainActivity.java
@@ -16,7 +16,6 @@
package ch.dissem.apps.abit;
-import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
@@ -24,7 +23,6 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.Point;
-import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v4.app.Fragment;
@@ -34,8 +32,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.RelativeLayout;
-import android.widget.TextView;
-import android.widget.Toast;
import com.github.amlcurran.showcaseview.ShowcaseView;
import com.github.amlcurran.showcaseview.targets.Target;
@@ -65,6 +61,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import ch.dissem.apps.abit.dialog.AddIdentityDialogFragment;
import ch.dissem.apps.abit.listener.ActionBarListener;
import ch.dissem.apps.abit.listener.ListSelectionListener;
import ch.dissem.apps.abit.service.BitmessageService;
@@ -75,7 +72,6 @@ import ch.dissem.apps.abit.util.Preferences;
import ch.dissem.bitmessage.BitmessageContext;
import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.Plaintext;
-import ch.dissem.bitmessage.entity.payload.Pubkey;
import ch.dissem.bitmessage.entity.valueobject.Label;
import static ch.dissem.apps.abit.service.BitmessageService.isRunning;
@@ -143,6 +139,7 @@ public class MainActivity extends AppCompatActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ instance = new WeakReference<>(this);
bmc = Singleton.getBitmessageContext(this);
List