Refactored adding new identities

- add deterministic identities
- import existing identities
This commit is contained in:
Christian Basler 2016-10-01 10:33:11 +02:00
parent c1d5af0034
commit a18ef1ac29
22 changed files with 1249 additions and 134 deletions

View File

@ -61,9 +61,11 @@ dependencies {
compile ('com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.9.3@aar'){ compile ('com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.9.3@aar'){
transitive=true transitive=true
} }
compile 'com.github.angads25:filepicker:1.0.6'
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:1.10.19' testCompile 'org.mockito:mockito-core:1.10.19'
compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha8'
} }
idea.module { idea.module {

View File

@ -18,7 +18,8 @@
android:allowBackup="false" android:allowBackup="false"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme"
tools:replace="android:allowBackup">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:label="@string/app_name"> android:label="@string/app_name">
@ -103,6 +104,26 @@
<category android:name="android.intent.category.BROWSABLE"/> <category android:name="android.intent.category.BROWSABLE"/>
</intent-filter> </intent-filter>
</activity> </activity>
<activity
android:name=".ImportIdentityActivity"
android:label="@string/title_import_identity"
android:parentActivityName=".MainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MainActivity"/>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.dat"
android:scheme="file"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>
</activity>
<service android:name=".service.BitmessageService"/> <service android:name=".service.BitmessageService"/>
<service android:name=".service.ProofOfWorkService"/> <service android:name=".service.ProofOfWorkService"/>

View File

@ -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.share, GoogleMaterial.Icon.gmd_share);
Drawables.addIcon(getActivity(), menu, R.id.delete, GoogleMaterial.Icon.gmd_delete); Drawables.addIcon(getActivity(), menu, R.id.delete, GoogleMaterial.Icon.gmd_delete);
Drawables.addIcon(getActivity(), menu, R.id.export, Drawables.addIcon(getActivity(), menu, R.id.export,
CommunityMaterial.Icon.cmd_export) CommunityMaterial.Icon.cmd_export)
.setVisible(item != null && item.getPrivateKey() != null); .setVisible(item != null && item.getPrivateKey() != null);
super.onCreateOptionsMenu(menu, inflater); super.onCreateOptionsMenu(menu, inflater);
} }
@ -130,41 +130,45 @@ public class AddressDetailFragment extends Fragment {
else else
warning = R.string.delete_contact_warning; warning = R.string.delete_contact_warning;
new AlertDialog.Builder(ctx) new AlertDialog.Builder(ctx)
.setMessage(warning) .setMessage(warning)
.setPositiveButton(android.R.string.yes, new .setPositiveButton(android.R.string.yes, new
DialogInterface.OnClickListener() { DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
Singleton.getAddressRepository(ctx).remove(item); Singleton.getAddressRepository(ctx).remove(item);
item = null; MainActivity mainActivity = MainActivity.getInstance();
ctx.onBackPressed(); if (item.getPrivateKey() != null && mainActivity != null) {
} mainActivity.removeIdentityEntry(item);
}) }
.setNegativeButton(android.R.string.no, null) item = null;
.show(); ctx.onBackPressed();
}
})
.setNegativeButton(android.R.string.no, null)
.show();
return true; return true;
} }
case R.id.export: { case R.id.export: {
new AlertDialog.Builder(ctx) new AlertDialog.Builder(ctx)
.setMessage(R.string.confirm_export) .setMessage(R.string.confirm_export)
.setPositiveButton(android.R.string.yes, new .setPositiveButton(android.R.string.yes, new
DialogInterface.OnClickListener() { DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
Intent shareIntent = new Intent(Intent.ACTION_SEND); Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain"); shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_TITLE, item + shareIntent.putExtra(Intent.EXTRA_TITLE, item +
EXPORT_POSTFIX); EXPORT_POSTFIX);
WifExporter exporter = new WifExporter(Singleton WifExporter exporter = new WifExporter(Singleton
.getBitmessageContext(ctx)); .getBitmessageContext(ctx));
exporter.addIdentity(item); exporter.addIdentity(item);
shareIntent.putExtra(Intent.EXTRA_TEXT, exporter.toString shareIntent.putExtra(Intent.EXTRA_TEXT, exporter.toString
()); ());
startActivity(Intent.createChooser(shareIntent, null)); startActivity(Intent.createChooser(shareIntent, null));
} }
}) })
.setNegativeButton(android.R.string.no, null) .setNegativeButton(android.R.string.no, null)
.show(); .show();
return true; return true;
} }
case R.id.share: { case R.id.share: {
@ -208,7 +212,7 @@ public class AddressDetailFragment extends Fragment {
address.setText(item.getAddress()); address.setText(item.getAddress());
address.setSelected(true); address.setSelected(true);
((TextView) rootView.findViewById(R.id.stream_number)).setText(getActivity() ((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) { if (item.getPrivateKey() == null) {
Switch active = (Switch) rootView.findViewById(R.id.active); Switch active = (Switch) rootView.findViewById(R.id.active);
active.setChecked(item.isSubscribed()); active.setChecked(item.isSubscribed());
@ -220,12 +224,12 @@ public class AddressDetailFragment extends Fragment {
}); });
ImageView pubkeyAvailableImg = (ImageView) rootView.findViewById(R.id ImageView pubkeyAvailableImg = (ImageView) rootView.findViewById(R.id
.pubkey_available); .pubkey_available);
if (item.getPubkey() == null) { if (item.getPubkey() == null) {
pubkeyAvailableImg.setAlpha(0.3f); pubkeyAvailableImg.setAlpha(0.3f);
TextView pubkeyAvailableDesc = (TextView) rootView.findViewById(R.id TextView pubkeyAvailableDesc = (TextView) rootView.findViewById(R.id
.pubkey_available_desc); .pubkey_available_desc);
pubkeyAvailableDesc.setText(R.string.pubkey_not_available); pubkeyAvailableDesc.setText(R.string.pubkey_not_available);
} }
} else { } else {
@ -251,7 +255,7 @@ public class AddressDetailFragment extends Fragment {
BitMatrix result; BitMatrix result;
try { try {
result = new MultiFormatWriter().encode(link.toString(), 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) { } catch (WriterException e) {
LOG.error(e.getMessage(), e); LOG.error(e.getMessage(), e);
return null; return null;

View File

@ -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;
}
}

View File

@ -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();
}
}
}

View File

@ -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;
}
}

View File

@ -16,7 +16,6 @@
package ch.dissem.apps.abit; package ch.dissem.apps.abit;
import android.annotation.SuppressLint;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
@ -24,7 +23,6 @@ import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.graphics.Point; import android.graphics.Point;
import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
@ -34,8 +32,6 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.CompoundButton; import android.widget.CompoundButton;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.github.amlcurran.showcaseview.ShowcaseView; import com.github.amlcurran.showcaseview.ShowcaseView;
import com.github.amlcurran.showcaseview.targets.Target; import com.github.amlcurran.showcaseview.targets.Target;
@ -65,6 +61,7 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import ch.dissem.apps.abit.dialog.AddIdentityDialogFragment;
import ch.dissem.apps.abit.listener.ActionBarListener; import ch.dissem.apps.abit.listener.ActionBarListener;
import ch.dissem.apps.abit.listener.ListSelectionListener; import ch.dissem.apps.abit.listener.ListSelectionListener;
import ch.dissem.apps.abit.service.BitmessageService; 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.BitmessageContext;
import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.Plaintext; import ch.dissem.bitmessage.entity.Plaintext;
import ch.dissem.bitmessage.entity.payload.Pubkey;
import ch.dissem.bitmessage.entity.valueobject.Label; import ch.dissem.bitmessage.entity.valueobject.Label;
import static ch.dissem.apps.abit.service.BitmessageService.isRunning; import static ch.dissem.apps.abit.service.BitmessageService.isRunning;
@ -143,6 +139,7 @@ public class MainActivity extends AppCompatActivity
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
instance = new WeakReference<>(this);
bmc = Singleton.getBitmessageContext(this); bmc = Singleton.getBitmessageContext(this);
List<Label> labels = bmc.messages().getLabels(); List<Label> labels = bmc.messages().getLabels();
if (selectedLabel == null) { if (selectedLabel == null) {
@ -261,15 +258,6 @@ public class MainActivity extends AppCompatActivity
.colorRes(R.color.icons)) .colorRes(R.color.icons))
.withIdentifier(ADD_IDENTITY) .withIdentifier(ADD_IDENTITY)
); );
profiles.add(new ProfileSettingDrawerItem()
.withName(getString(R.string.add_chan))
.withDescription(getString(R.string.add_chan_summary))
.withIcon(new IconicsDrawable(this, GoogleMaterial.Icon.gmd_add)
.actionBar()
.paddingDp(5)
.colorRes(R.color.icons))
.withIdentifier(ADD_CHAN)
);
profiles.add(new ProfileSettingDrawerItem() profiles.add(new ProfileSettingDrawerItem()
.withName(getString(R.string.manage_identity)) .withName(getString(R.string.manage_identity))
.withIcon(GoogleMaterial.Icon.gmd_settings) .withIcon(GoogleMaterial.Icon.gmd_settings)
@ -288,9 +276,6 @@ public class MainActivity extends AppCompatActivity
case ADD_IDENTITY: case ADD_IDENTITY:
addIdentityDialog(); addIdentityDialog();
break; break;
case ADD_CHAN:
addChanDialog();
break;
case MANAGE_IDENTITY: case MANAGE_IDENTITY:
Intent show = new Intent(MainActivity.this, Intent show = new Intent(MainActivity.this,
AddressDetailActivity.class); AddressDetailActivity.class);
@ -423,102 +408,45 @@ public class MainActivity extends AppCompatActivity
} }
private void addIdentityDialog() { private void addIdentityDialog() {
new AlertDialog.Builder(MainActivity.this) AddIdentityDialogFragment dialog = new AddIdentityDialogFragment();
.setMessage(R.string.add_identity_warning) dialog.show(getSupportFragmentManager(), "dialog");
.setPositiveButton(android.R.string.yes, new
DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
Toast.makeText(MainActivity.this,
R.string.toast_long_running_operation,
Toast.LENGTH_SHORT).show();
new AsyncTask<Void, Void, BitmessageAddress>() {
@Override
protected BitmessageAddress doInBackground(Void... args) {
return bmc.createIdentity(false, Pubkey.Feature.DOES_ACK);
}
@Override
protected void onPostExecute(BitmessageAddress chan) {
Toast.makeText(MainActivity.this,
R.string.toast_identity_created,
Toast.LENGTH_SHORT).show();
addIdentityEntry(chan);
}
}.execute();
}
})
.setNegativeButton(android.R.string.no, null)
.show();
}
private void addChanDialog() {
@SuppressLint("InflateParams")
final View dialogView = getLayoutInflater().inflate(R.layout.dialog_input_passphrase, null);
new AlertDialog.Builder(MainActivity.this)
.setMessage(R.string.add_chan)
.setView(dialogView)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
TextView passphrase = (TextView) dialogView.findViewById(R.id.passphrase);
Toast.makeText(MainActivity.this, R.string.toast_long_running_operation,
Toast.LENGTH_SHORT).show();
new AsyncTask<String, Void, BitmessageAddress>() {
@Override
protected BitmessageAddress doInBackground(String... args) {
String pass = args[0];
BitmessageAddress chan = bmc.createChan(pass);
chan.setAlias(pass);
bmc.addresses().save(chan);
return chan;
}
@Override
protected void onPostExecute(BitmessageAddress chan) {
Toast.makeText(MainActivity.this,
R.string.toast_chan_created,
Toast.LENGTH_SHORT).show();
addIdentityEntry(chan);
}
}.execute(passphrase.getText().toString());
}
})
.setNegativeButton(R.string.cancel, null)
.show();
} }
@Override @Override
protected void onResume() { protected void onResume() {
instance = new WeakReference<>(this);
updateUnread(); updateUnread();
super.onResume(); super.onResume();
} }
private void addIdentityEntry(BitmessageAddress identity) { public void addIdentityEntry(BitmessageAddress identity) {
IProfile newProfile = new IProfile newProfile = new ProfileDrawerItem()
ProfileDrawerItem() .withIcon(new Identicon(identity))
.withName(identity.toString()) .withName(identity.toString())
.withNameShown(true)
.withEmail(identity.getAddress()) .withEmail(identity.getAddress())
.withTag(identity); .withTag(identity);
if (accountHeader.getProfiles() != null) { if (accountHeader.getProfiles() != null) {
// we know that there are 3 setting // we know that there are 2 setting
// elements. // elements.
// Set the new profile above them ;) // Set the new profile above them ;)
accountHeader.addProfile( accountHeader.addProfile(
newProfile, accountHeader newProfile, accountHeader
.getProfiles().size() .getProfiles().size()
- 3); - 2);
} else { } else {
accountHeader.addProfiles(newProfile); accountHeader.addProfiles(newProfile);
} }
} }
@Override public void removeIdentityEntry(BitmessageAddress identity) {
protected void onPause() { for (IProfile profile : accountHeader.getProfiles()) {
super.onPause(); if (profile instanceof ProfileDrawerItem) {
instance = null; if (identity.equals(((ProfileDrawerItem) profile).getTag())) {
accountHeader.removeProfile(profile);
return;
}
}
}
} }
private void checkAndStartNode(final CompoundButton buttonView) { private void checkAndStartNode(final CompoundButton buttonView) {

View File

@ -0,0 +1,109 @@
/*
* 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.adapter;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import ch.dissem.apps.abit.R;
import ch.dissem.bitmessage.entity.BitmessageAddress;
/**
* @author Christian Basler
*/
public class AddressSelectorAdapter
extends RecyclerView.Adapter<AddressSelectorAdapter.ViewHolder> {
private final List<Selectable<BitmessageAddress>> data;
public AddressSelectorAdapter(List<BitmessageAddress> identities) {
data = new ArrayList<>(identities.size());
for (BitmessageAddress identity : identities) {
data.add(new Selectable<>(identity));
}
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
final View v = inflater.inflate(R.layout.select_identity_row, parent, false);
return new ViewHolder(v);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Selectable<BitmessageAddress> selectable = data.get(position);
holder.data = selectable;
holder.checkbox.setChecked(selectable.selected);
holder.checkbox.setText(selectable.data.toString());
holder.address.setText(selectable.data.getAddress());
}
@Override
public int getItemCount() {
return data.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
public Selectable<BitmessageAddress> data;
public CheckBox checkbox;
public TextView address;
private ViewHolder(View v) {
super(v);
checkbox = (CheckBox) v.findViewById(R.id.checkbox);
address = (TextView) v.findViewById(R.id.address);
checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (data != null) {
data.selected = isChecked;
}
}
});
}
}
private static class Selectable<T> {
private final T data;
private boolean selected = false;
private Selectable(T data) {
this.data = data;
}
}
public List<BitmessageAddress> getSelected() {
List<BitmessageAddress> result = new LinkedList<>();
for (Selectable<BitmessageAddress> selectable : data) {
if (selectable.selected) {
result.add(selectable.data);
}
}
return result;
}
}

View File

@ -0,0 +1,169 @@
/*
* 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.dialog;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatDialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import ch.dissem.apps.abit.ImportIdentityActivity;
import ch.dissem.apps.abit.MainActivity;
import ch.dissem.apps.abit.R;
import ch.dissem.apps.abit.service.Singleton;
import ch.dissem.bitmessage.BitmessageContext;
import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.payload.Pubkey;
import static android.app.Activity.RESULT_OK;
/**
* @author Christian Basler
*/
public class AddIdentityDialogFragment extends AppCompatDialogFragment {
private static final int IMPORT_IDENTITY_RESULT_CODE = 1;
private BitmessageContext bmc;
@Override
public void onAttach(Context context) {
super.onAttach(context);
bmc = Singleton.getBitmessageContext(context);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
getDialog().setTitle(R.string.add_identity);
View view = inflater.inflate(R.layout.dialog_add_identity, container, false);
view.findViewById(R.id.create_identity)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
Toast.makeText(getActivity(),
R.string.toast_long_running_operation,
Toast.LENGTH_SHORT).show();
new AsyncTask<Void, Void, BitmessageAddress>() {
@Override
protected BitmessageAddress doInBackground(Void... args) {
return bmc.createIdentity(false, Pubkey.Feature.DOES_ACK);
}
@Override
protected void onPostExecute(BitmessageAddress chan) {
Toast.makeText(getActivity(),
R.string.toast_identity_created,
Toast.LENGTH_SHORT).show();
MainActivity mainActivity = MainActivity.getInstance();
if (mainActivity != null) {
mainActivity.addIdentityEntry(chan);
}
}
}.execute();
}
});
view.findViewById(R.id.import_identity)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
startActivity(new Intent(getActivity(), ImportIdentityActivity.class));
}
});
view.findViewById(R.id.add_deterministic_address)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
new DeterministicIdentityDialogFragment().show(getFragmentManager(), "dialog");
}
});
view.findViewById(R.id.add_chan)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
addChanDialog();
}
});
view.findViewById(R.id.dismiss)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
return view;
}
private void addChanDialog() {
@SuppressLint("InflateParams")
final View dialogView = getActivity().getLayoutInflater()
.inflate(R.layout.dialog_input_passphrase, null);
new AlertDialog.Builder(getActivity())
.setTitle(R.string.add_chan)
.setView(dialogView)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
TextView passphrase = (TextView) dialogView.findViewById(R.id.passphrase);
Toast.makeText(getActivity(), R.string.toast_long_running_operation,
Toast.LENGTH_SHORT).show();
new AsyncTask<String, Void, BitmessageAddress>() {
@Override
protected BitmessageAddress doInBackground(String... args) {
String pass = args[0];
BitmessageAddress chan = bmc.createChan(pass);
chan.setAlias(pass);
bmc.addresses().save(chan);
return chan;
}
@Override
protected void onPostExecute(BitmessageAddress chan) {
Toast.makeText(getActivity(),
R.string.toast_chan_created,
Toast.LENGTH_SHORT).show();
MainActivity mainActivity = MainActivity.getInstance();
if (mainActivity != null) {
mainActivity.addIdentityEntry(chan);
}
}
}.execute(passphrase.getText().toString());
}
})
.setNegativeButton(R.string.cancel, null)
.show();
}
@Override
public int getTheme() {
return R.style.FixedDialog;
}
}

View File

@ -0,0 +1,138 @@
/*
* 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.dialog;
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;
import android.view.ViewGroup;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;
import java.util.List;
import ch.dissem.apps.abit.MainActivity;
import ch.dissem.apps.abit.R;
import ch.dissem.apps.abit.service.Singleton;
import ch.dissem.bitmessage.BitmessageContext;
import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.payload.Pubkey;
/**
* @author Christian Basler
*/
public class DeterministicIdentityDialogFragment extends AppCompatDialogFragment {
private BitmessageContext bmc;
@Override
public void onAttach(Context context) {
super.onAttach(context);
bmc = Singleton.getBitmessageContext(context);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
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);
Toast.makeText(context, R.string.toast_long_running_operation,
Toast.LENGTH_SHORT).show();
new AsyncTask<Object, Void, List<BitmessageAddress>>() {
@Override
protected List<BitmessageAddress> doInBackground(Object... args) {
String label = (String) args[0];
String pass = (String) args[1];
int numberOfAddresses = (int) args[2];
boolean shorter = (boolean) args[3];
List<BitmessageAddress> 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<BitmessageAddress> 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()
);
}
});
view.findViewById(R.id.dismiss)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
return view;
}
@Override
public int getTheme() {
return R.style.FixedDialog;
}
}

View File

@ -0,0 +1,25 @@
<!--
~ 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M20,6h-8l-2,-2L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,8c0,-1.1 -0.9,-2 -2,-2zM20,18L4,18L4,8h16v10z"/>
</vector>

View File

@ -0,0 +1,118 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="18dp"
android:paddingEnd="24dp"
android:paddingStart="24dp"
android:paddingTop="18dp">
<TextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/deterministic_address_warning"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:layout_constraintLeft_creator="1"
tools:layout_constraintTop_creator="1"/>
<android.support.design.widget.TextInputLayout
android:id="@+id/label_wrapper"
android:layout_marginTop="24dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/description">
<EditText
android:id="@+id/label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/label"/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/passphrase_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/label_wrapper">
<EditText
android:id="@+id/passphrase"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/passphrase"
android:inputType="textMultiLine"/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/number_of_identities_wrapper"
android:layout_width="312dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/passphrase_wrapper">
<EditText
android:id="@+id/number_of_identities"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="@string/number_of_identities"
android:inputType="number"
android:text="1"/>
</android.support.design.widget.TextInputLayout>
<Switch
android:id="@+id/shorter"
android:layout_width="312dp"
android:layout_height="wrap_content"
android:text="@string/shorter"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/number_of_identities_wrapper"/>
<Button
android:id="@+id/ok"
style="?android:attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="@string/ok"
android:textColor="@color/colorAccent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/shorter"/>
<Button
android:id="@+id/dismiss"
style="?android:attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cancel"
android:textColor="@color/colorAccent"
app:layout_constraintBottom_toBottomOf="@id/ok"
app:layout_constraintRight_toLeftOf="@id/ok"/>
</android.support.constraint.ConstraintLayout>

View File

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:paddingEnd="24dp"
android:paddingStart="24dp"
android:paddingTop="18dp"
android:paddingBottom="18dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/add_identity_warning"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:layout_constraintLeft_creator="1"
tools:layout_constraintTop_creator="1"/>
<Button
android:id="@+id/create_identity"
style="?android:attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/create_identity"
android:textColor="@color/colorAccent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintRight_toRightOf="@+id/description"
app:layout_constraintTop_toBottomOf="@+id/description"
tools:layout_constraintLeft_creator="1"
tools:layout_constraintRight_creator="1"
tools:layout_constraintTop_creator="1"/>
<Button
android:id="@+id/import_identity"
style="?android:attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/import_identity"
android:textColor="@color/colorAccent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintRight_toRightOf="@+id/create_identity"
app:layout_constraintTop_toBottomOf="@+id/create_identity"
tools:layout_constraintLeft_creator="1"
tools:layout_constraintRight_creator="1"
tools:layout_constraintTop_creator="1"/>
<Button
android:id="@+id/add_deterministic_address"
style="?android:attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/add_deterministic_address"
android:textColor="@color/colorAccent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintRight_toRightOf="@+id/import_identity"
app:layout_constraintTop_toBottomOf="@+id/import_identity"
tools:layout_constraintLeft_creator="1"
tools:layout_constraintRight_creator="1"
tools:layout_constraintTop_creator="1"/>
<Button
android:id="@+id/add_chan"
style="?android:attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/add_chan"
android:textColor="@color/colorAccent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintRight_toRightOf="@+id/add_deterministic_address"
app:layout_constraintTop_toBottomOf="@+id/add_deterministic_address"
tools:layout_constraintLeft_creator="1"
tools:layout_constraintRight_creator="1"
tools:layout_constraintTop_creator="1"/>
<Button
android:id="@+id/dismiss"
style="?android:attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cancel"
android:textColor="@color/colorAccent"
app:layout_constraintLeft_toLeftOf="@+id/description"
app:layout_constraintTop_toBottomOf="@+id/add_deterministic_address"/>
</android.support.constraint.ConstraintLayout>

View File

@ -2,7 +2,11 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical"
android:paddingBottom="18dp"
android:paddingLeft="24dp"
android:paddingRight="24dp"
android:paddingTop="18dp">
<EditText <EditText
android:id="@+id/passphrase" android:id="@+id/passphrase"

View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="64dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp">
<TextView
android:id="@+id/description"
android:layout_width="360dp"
android:layout_height="wrap_content"
android:text="@string/import_input_description"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<EditText
android:id="@+id/wif_input"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="24dp"
android:gravity="start|top"
android:hint="@string/wif_string"
android:inputType="textMultiLine|text"
app:layout_constraintBottom_toTopOf="@+id/next"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/description"/>
<Button
android:id="@+id/next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
android:text="@string/next"
android:textColor="@color/colorAccent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
</android.support.constraint.ConstraintLayout>

View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="64dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp">
<TextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/select_identities_to_import"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="24dp"
android:inputType="textMultiLine|text"
app:layout_constraintBottom_toTopOf="@+id/finish"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/description"/>
<Button
android:id="@+id/finish"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
android:text="@string/do_import"
android:textColor="@color/colorAccent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
</android.support.constraint.ConstraintLayout>

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="64dp">
<CheckBox
android:id="@+id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:ellipsize="end"
android:paddingBottom="8dp"
android:paddingEnd="8dp"
android:paddingStart="16dp"
android:paddingTop="8dp"
android:text="CheckBox"
android:textAppearance="?android:attr/textAppearanceMedium"
tools:text="Name"/>
<TextView
android:id="@+id/address"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentBottom="true"
android:ellipsize="marquee"
android:lines="1"
android:paddingBottom="8dp"
android:paddingEnd="8dp"
android:paddingStart="48dp"
android:textAppearance="?android:attr/textAppearanceSmall"
tools:text="BM-2cW0000000000000000000000000000000"/>
</RelativeLayout>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/open_file"
android:title="@string/open_file"
android:icon="@drawable/ic_action_open_file"
app:showAsAction="ifRoom"/>
</menu>

View File

@ -81,4 +81,19 @@ Als Alternative kann in den Einstellungen ein vertrauenswürdiger Knoten konfigu
<string name="toast_chan_created">Chan erstellt</string> <string name="toast_chan_created">Chan erstellt</string>
<string name="toast_long_running_operation">Dies kann einige Minuten dauern</string> <string name="toast_long_running_operation">Dies kann einige Minuten dauern</string>
<string name="toast_identity_created">Identität erstellt</string> <string name="toast_identity_created">Identität erstellt</string>
<string name="toast_identities_created">Identitäten erstellt</string>
<string name="import_identity">Importieren</string>
<string name="create_identity">Erstellen</string>
<string name="add_deterministic_address">Deterministische Identität</string>
<string name="deterministic_address_warning">Merke dir diese Enstellungen und stelle sicher dass sie korrekt sind wenn du eine deterministische Addresse wiederherstellst.</string>
<string name="shorter">Kürzere Adressen suchen</string>
<string name="number_of_identities">Anzahl zu generierender Identitäten</string>
<string name="title_import_identity">Identität importieren</string>
<string name="wif_string">WIF / Inhalt von \'keys.dat\'</string>
<string name="select_identities_to_import">Bitte wähle die zu importierenden Identitäten:</string>
<string name="select_file_title">Datei auswählen</string>
<string name="open_file">Datei öffnen</string>
<string name="next">Weiter</string>
<string name="import_input_description">Du kannst einfach den Inhalt eines Exports oder einer \'keys.dat\'-Datei einfügen</string>
<string name="error_loading_data">Fehler beim Laden der Daten</string>
</resources> </resources>

View File

@ -14,6 +14,9 @@
<string name="manage_identity">Manage Identity</string> <string name="manage_identity">Manage Identity</string>
<string name="add_identity">Add Identity</string> <string name="add_identity">Add Identity</string>
<string name="add_identity_summary">Create new identity</string> <string name="add_identity_summary">Create new identity</string>
<string name="create_identity">Create new</string>
<string name="import_identity">Import existing</string>
<string name="add_deterministic_address">Deterministic identity</string>
<string name="add_chan">Add Chan</string> <string name="add_chan">Add Chan</string>
<string name="add_chan_summary">Add or create a chan</string> <string name="add_chan_summary">Add or create a chan</string>
<string name="title_activity_open_bitmessage_link">Import Contact</string> <string name="title_activity_open_bitmessage_link">Import Contact</string>
@ -80,8 +83,20 @@ As an alternative you could configure a trusted node in the settings, but as of
<string name="export">Export</string> <string name="export">Export</string>
<string name="confirm_export">Do you really want to export your identity? The export will contain the unencrypted private keys.</string> <string name="confirm_export">Do you really want to export your identity? The export will contain the unencrypted private keys.</string>
<string name="compose_message">Compose</string> <string name="compose_message">Compose</string>
<string name="passphrase">passphrase</string> <string name="passphrase">Passphrase</string>
<string name="toast_long_running_operation">This may take a few minutes</string> <string name="toast_long_running_operation">This may take a few minutes</string>
<string name="toast_identity_created">Identity created</string> <string name="toast_identity_created">Identity created</string>
<string name="toast_identities_created">Identities created</string>
<string name="toast_chan_created">Chan created</string> <string name="toast_chan_created">Chan created</string>
<string name="deterministic_address_warning">Be sure to remember those settings correctly when recreating a deterministic address.</string>
<string name="number_of_identities">Number of identities to create</string>
<string name="shorter">Search for shorter addresses</string>
<string name="wif_string">WIF / contents of \'keys.dat\'</string>
<string name="next">Continue</string>
<string name="title_import_identity">Import Identity</string>
<string name="open_file">Open File</string>
<string name="error_loading_data">Error loading data</string>
<string name="select_file_title">Select a File</string>
<string name="select_identities_to_import">Please select the identities you want to import:</string>
<string name="import_input_description">You can just paste the contents of an export or a \'keys.dat\' file</string>
</resources> </resources>

View File

@ -19,4 +19,7 @@
<item name="android:textColor">@color/colorAccent</item> <item name="android:textColor">@color/colorAccent</item>
</style> </style>
<style name="FixedDialog" parent="Theme.AppCompat.Light.Dialog">
<item name="windowNoTitle">false</item>
</style>
</resources> </resources>

View File

@ -9,7 +9,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:2.1.3' classpath 'com.android.tools.build:gradle:2.2.0'
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files