Merge branch 'feature/kotlin' into develop
This commit is contained in:
commit
a23ae14f1d
@ -1,156 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 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.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.ListFragment;
|
||||
import android.view.View;
|
||||
import android.widget.ListView;
|
||||
|
||||
import ch.dissem.apps.abit.listener.ListSelectionListener;
|
||||
|
||||
/**
|
||||
* @author Christian Basler
|
||||
*/
|
||||
public abstract class AbstractItemListFragment<L, T> extends ListFragment implements ListHolder<L> {
|
||||
/**
|
||||
* The serialization (saved instance state) Bundle key representing the
|
||||
* activated item position. Only used on tablets.
|
||||
*/
|
||||
private static final String STATE_ACTIVATED_POSITION = "activated_position";
|
||||
/**
|
||||
* A dummy implementation of the {@link ListSelectionListener} interface that does
|
||||
* nothing. Used only when this fragment is not attached to an activity.
|
||||
*/
|
||||
private static final ListSelectionListener<Object> dummyCallbacks =
|
||||
new ListSelectionListener<Object>() {
|
||||
@Override
|
||||
public void onItemSelected(Object item) {
|
||||
// NO OP
|
||||
}
|
||||
};
|
||||
/**
|
||||
* The fragment's current callback object, which is notified of list item
|
||||
* clicks.
|
||||
*/
|
||||
private ListSelectionListener<? super T> callbacks = dummyCallbacks;
|
||||
/**
|
||||
* The current activated item position. Only used on tablets.
|
||||
*/
|
||||
private int activatedPosition = ListView.INVALID_POSITION;
|
||||
private boolean activateOnItemClick;
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
// Restore the previously serialized activated item position.
|
||||
if (savedInstanceState != null
|
||||
&& savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) {
|
||||
setActivatedPosition(savedInstanceState.getInt(STATE_ACTIVATED_POSITION));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
|
||||
// Activities containing this fragment must implement its callbacks.
|
||||
if (context instanceof ListSelectionListener) {
|
||||
//noinspection unchecked
|
||||
callbacks = (ListSelectionListener) context;
|
||||
} else {
|
||||
throw new IllegalStateException("Activity must implement fragment's callbacks.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
|
||||
// Reset the active callbacks interface to the dummy implementation.
|
||||
callbacks = dummyCallbacks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onListItemClick(ListView listView, View view, int position, long id) {
|
||||
super.onListItemClick(listView, view, position, id);
|
||||
|
||||
// Notify the active callbacks interface (the activity, if the
|
||||
// fragment is attached to one) that an item has been selected.
|
||||
//noinspection unchecked
|
||||
callbacks.onItemSelected((T) listView.getItemAtPosition(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
if (activatedPosition != ListView.INVALID_POSITION) {
|
||||
// Serialize and persist the activated item position.
|
||||
outState.putInt(STATE_ACTIVATED_POSITION, activatedPosition);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns on activate-on-click mode. When this mode is on, list items will be
|
||||
* given the 'activated' state when touched.
|
||||
*/
|
||||
public void setActivateOnItemClick(boolean activateOnItemClick) {
|
||||
this.activateOnItemClick = activateOnItemClick;
|
||||
|
||||
if (isVisible()) {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
private void setActivatedPosition(int position) {
|
||||
if (position == ListView.INVALID_POSITION) {
|
||||
getListView().setItemChecked(activatedPosition, false);
|
||||
} else {
|
||||
getListView().setItemChecked(position, true);
|
||||
}
|
||||
|
||||
activatedPosition = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public L getCurrentLabel() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean showPreviousList() {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 2015 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.content.Context
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.ListFragment
|
||||
import android.view.View
|
||||
import android.widget.ListView
|
||||
|
||||
import ch.dissem.apps.abit.listener.ListSelectionListener
|
||||
|
||||
/**
|
||||
* @author Christian Basler
|
||||
*/
|
||||
abstract class AbstractItemListFragment<L, T> : ListFragment(), ListHolder<L> {
|
||||
/**
|
||||
* The fragment's current callback object, which is notified of list item
|
||||
* clicks.
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private var callbacks: ListSelectionListener<T> = DummyCallback as ListSelectionListener<T>
|
||||
/**
|
||||
* The current activated item position. Only used on tablets.
|
||||
*/
|
||||
private var activatedPosition = ListView.INVALID_POSITION
|
||||
private var activateOnItemClick: Boolean = false
|
||||
|
||||
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
// Restore the previously serialized activated item position.
|
||||
if (savedInstanceState != null && savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) {
|
||||
setActivatedPosition(savedInstanceState.getInt(STATE_ACTIVATED_POSITION))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
// When setting CHOICE_MODE_SINGLE, ListView will automatically
|
||||
// give items the 'activated' state when touched.
|
||||
listView.choiceMode = if (activateOnItemClick)
|
||||
ListView.CHOICE_MODE_SINGLE
|
||||
else
|
||||
ListView.CHOICE_MODE_NONE
|
||||
}
|
||||
|
||||
override fun onAttach(context: Context?) {
|
||||
super.onAttach(context)
|
||||
|
||||
// Activities containing this fragment must implement its callbacks.
|
||||
if (context is ListSelectionListener<*>) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
callbacks = context as ListSelectionListener<T>
|
||||
} else {
|
||||
throw IllegalStateException("Activity must implement fragment's callbacks.")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onDetach() {
|
||||
super.onDetach()
|
||||
|
||||
// Reset the active callbacks interface to the dummy implementation.
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
callbacks = DummyCallback as ListSelectionListener<T>
|
||||
}
|
||||
|
||||
override fun onListItemClick(listView: ListView, view: View?, position: Int, id: Long) {
|
||||
super.onListItemClick(listView, view, position, id)
|
||||
|
||||
// Notify the active callbacks interface (the activity, if the
|
||||
// fragment is attached to one) that an item has been selected.
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
(listView.getItemAtPosition(position) as? T)?.let {
|
||||
callbacks.onItemSelected(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle?) {
|
||||
super.onSaveInstanceState(outState)
|
||||
if (activatedPosition != ListView.INVALID_POSITION) {
|
||||
// Serialize and persist the activated item position.
|
||||
outState!!.putInt(STATE_ACTIVATED_POSITION, activatedPosition)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns on activate-on-click mode. When this mode is on, list items will be
|
||||
* given the 'activated' state when touched.
|
||||
*/
|
||||
override fun setActivateOnItemClick(activateOnItemClick: Boolean) {
|
||||
this.activateOnItemClick = activateOnItemClick
|
||||
|
||||
if (isVisible) {
|
||||
// When setting CHOICE_MODE_SINGLE, ListView will automatically
|
||||
// give items the 'activated' state when touched.
|
||||
listView.choiceMode = if (activateOnItemClick)
|
||||
ListView.CHOICE_MODE_SINGLE
|
||||
else
|
||||
ListView.CHOICE_MODE_NONE
|
||||
}
|
||||
}
|
||||
|
||||
private fun setActivatedPosition(position: Int) {
|
||||
if (position == ListView.INVALID_POSITION) {
|
||||
listView.setItemChecked(activatedPosition, false)
|
||||
} else {
|
||||
listView.setItemChecked(position, true)
|
||||
}
|
||||
|
||||
activatedPosition = position
|
||||
}
|
||||
|
||||
override var currentLabel: L? = null
|
||||
|
||||
override fun showPreviousList() = false
|
||||
|
||||
/**
|
||||
* A dummy implementation of the [ListSelectionListener] interface that does
|
||||
* nothing. Used only when this fragment is not attached to an activity.
|
||||
*/
|
||||
internal object DummyCallback : ListSelectionListener<Any> {
|
||||
override fun onItemSelected(item: Any) {
|
||||
// NO OP
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* The serialization (saved instance state) Bundle key representing the
|
||||
* activated item position. Only used on tablets.
|
||||
*/
|
||||
internal const val STATE_ACTIVATED_POSITION = "activated_position"
|
||||
}
|
||||
}
|
@ -14,25 +14,25 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package ch.dissem.apps.abit;
|
||||
package ch.dissem.apps.abit
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Bundle
|
||||
|
||||
|
||||
/**
|
||||
* An activity representing a single Subscription detail screen. This
|
||||
* activity is only used on handset devices. On tablet-size devices,
|
||||
* item details are presented side-by-side with a list of items
|
||||
* in a {@link MainActivity}.
|
||||
* <p/>
|
||||
* in a [MainActivity].
|
||||
*
|
||||
*
|
||||
* This activity is mostly just a 'shell' activity containing nothing
|
||||
* more than a {@link AddressDetailFragment}.
|
||||
* more than a [AddressDetailFragment].
|
||||
*/
|
||||
public class AddressDetailActivity extends DetailActivity {
|
||||
class AddressDetailActivity : DetailActivity() {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
// savedInstanceState is non-null when there is fragment state
|
||||
// saved from previous configurations of this activity
|
||||
@ -42,18 +42,18 @@ public class AddressDetailActivity extends DetailActivity {
|
||||
// For more information, see the Fragments API guide at:
|
||||
//
|
||||
// http://developer.android.com/guide/components/fragments.html
|
||||
//
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
// Create the detail fragment and add it to the activity
|
||||
// using a fragment transaction.
|
||||
Bundle arguments = new Bundle();
|
||||
val arguments = Bundle()
|
||||
arguments.putSerializable(AddressDetailFragment.ARG_ITEM,
|
||||
getIntent().getSerializableExtra(AddressDetailFragment.ARG_ITEM));
|
||||
AddressDetailFragment fragment = new AddressDetailFragment();
|
||||
fragment.setArguments(arguments);
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
intent.getSerializableExtra(AddressDetailFragment.ARG_ITEM))
|
||||
val fragment = AddressDetailFragment()
|
||||
fragment.arguments = arguments
|
||||
supportFragmentManager.beginTransaction()
|
||||
.add(R.id.content, fragment)
|
||||
.commit();
|
||||
.commit()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,253 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 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.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
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.CompoundButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.Switch;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.mikepenz.community_material_typeface_library.CommunityMaterial;
|
||||
import com.mikepenz.google_material_typeface_library.GoogleMaterial;
|
||||
|
||||
import ch.dissem.apps.abit.service.Singleton;
|
||||
import ch.dissem.apps.abit.util.Drawables;
|
||||
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
||||
import ch.dissem.bitmessage.wif.WifExporter;
|
||||
|
||||
|
||||
/**
|
||||
* A fragment representing a single Message detail screen.
|
||||
* This fragment is either contained in a {@link MainActivity}
|
||||
* in two-pane mode (on tablets) or a {@link MessageDetailActivity}
|
||||
* on handsets.
|
||||
*/
|
||||
public class AddressDetailFragment extends Fragment {
|
||||
/**
|
||||
* The fragment argument representing the item ID that this fragment
|
||||
* represents.
|
||||
*/
|
||||
public static final String ARG_ITEM = "item";
|
||||
public static final String EXPORT_POSTFIX = ".keys.dat";
|
||||
|
||||
/**
|
||||
* The content this fragment is presenting.
|
||||
*/
|
||||
private BitmessageAddress item;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if (getArguments().containsKey(ARG_ITEM)) {
|
||||
item = (BitmessageAddress) getArguments().getSerializable(ARG_ITEM);
|
||||
}
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.address, menu);
|
||||
|
||||
FragmentActivity activity = getActivity();
|
||||
Drawables.addIcon(activity, menu, R.id.write_message, GoogleMaterial.Icon.gmd_mail);
|
||||
Drawables.addIcon(activity, menu, R.id.share, GoogleMaterial.Icon.gmd_share);
|
||||
Drawables.addIcon(activity, menu, R.id.delete, GoogleMaterial.Icon.gmd_delete);
|
||||
Drawables.addIcon(activity, menu, R.id.export,
|
||||
CommunityMaterial.Icon.cmd_export)
|
||||
.setVisible(item != null && item.getPrivateKey() != null);
|
||||
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem menuItem) {
|
||||
final Activity ctx = getActivity();
|
||||
switch (menuItem.getItemId()) {
|
||||
case R.id.write_message: {
|
||||
BitmessageAddress identity = Singleton.getIdentity(ctx);
|
||||
if (identity == null) {
|
||||
Toast.makeText(ctx, R.string.no_identity_warning, Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
Intent intent = new Intent(ctx, ComposeMessageActivity.class);
|
||||
intent.putExtra(ComposeMessageActivity.EXTRA_IDENTITY, identity);
|
||||
intent.putExtra(ComposeMessageActivity.EXTRA_RECIPIENT, item);
|
||||
startActivity(intent);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case R.id.delete: {
|
||||
int warning;
|
||||
if (item.getPrivateKey() != null)
|
||||
warning = R.string.delete_identity_warning;
|
||||
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);
|
||||
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();
|
||||
return true;
|
||||
}
|
||||
case R.id.share: {
|
||||
Intent shareIntent = new Intent(Intent.ACTION_SEND);
|
||||
shareIntent.setType("text/plain");
|
||||
shareIntent.putExtra(Intent.EXTRA_TEXT, item.getAddress());
|
||||
startActivity(Intent.createChooser(shareIntent, null));
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
View rootView = inflater.inflate(R.layout.fragment_address_detail, container, false);
|
||||
|
||||
// Show the dummy content as text in a TextView.
|
||||
if (item != null) {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (item.isChan()) {
|
||||
activity.setTitle(R.string.title_chan_detail);
|
||||
} else if (item.getPrivateKey() != null) {
|
||||
activity.setTitle(R.string.title_identity_detail);
|
||||
} else if (item.isSubscribed()) {
|
||||
activity.setTitle(R.string.title_subscription_detail);
|
||||
} else {
|
||||
activity.setTitle(R.string.title_contact_detail);
|
||||
}
|
||||
|
||||
((ImageView) rootView.findViewById(R.id.avatar)).setImageDrawable(new Identicon(item));
|
||||
TextView name = (TextView) rootView.findViewById(R.id.name);
|
||||
name.setText(item.toString());
|
||||
name.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
item.setAlias(s.toString());
|
||||
}
|
||||
});
|
||||
TextView address = (TextView) rootView.findViewById(R.id.address);
|
||||
address.setText(item.getAddress());
|
||||
address.setSelected(true);
|
||||
((TextView) rootView.findViewById(R.id.stream_number)).setText(
|
||||
getString(R.string.stream_number, item.getStream()));
|
||||
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 button, boolean checked) {
|
||||
item.setSubscribed(checked);
|
||||
}
|
||||
});
|
||||
|
||||
ImageView pubkeyAvailableImg = (ImageView) rootView.findViewById(R.id
|
||||
.pubkey_available);
|
||||
|
||||
if (item.getPubkey() == null) {
|
||||
pubkeyAvailableImg.setAlpha(0.3f);
|
||||
TextView pubkeyAvailableDesc = (TextView) rootView.findViewById(R.id
|
||||
.pubkey_available_desc);
|
||||
pubkeyAvailableDesc.setText(R.string.pubkey_not_available);
|
||||
}
|
||||
} else {
|
||||
rootView.findViewById(R.id.active).setVisibility(View.GONE);
|
||||
rootView.findViewById(R.id.pubkey_available).setVisibility(View.GONE);
|
||||
rootView.findViewById(R.id.pubkey_available_desc).setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
// QR code
|
||||
ImageView qrCode = (ImageView) rootView.findViewById(R.id.qr_code);
|
||||
qrCode.setImageBitmap(Drawables.qrCode(item));
|
||||
}
|
||||
|
||||
return rootView;
|
||||
}
|
||||
|
||||
@Override
|
||||
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();
|
||||
}
|
||||
}
|
204
app/src/main/java/ch/dissem/apps/abit/AddressDetailFragment.kt
Normal file
204
app/src/main/java/ch/dissem/apps/abit/AddressDetailFragment.kt
Normal file
@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright 2015 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.AlertDialog
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.Fragment
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.*
|
||||
import android.widget.Toast
|
||||
import ch.dissem.apps.abit.service.Singleton
|
||||
import ch.dissem.apps.abit.util.Drawables
|
||||
import ch.dissem.bitmessage.entity.BitmessageAddress
|
||||
import ch.dissem.bitmessage.wif.WifExporter
|
||||
import com.mikepenz.community_material_typeface_library.CommunityMaterial
|
||||
import com.mikepenz.google_material_typeface_library.GoogleMaterial
|
||||
import kotlinx.android.synthetic.main.fragment_address_detail.*
|
||||
|
||||
|
||||
/**
|
||||
* A fragment representing a single Message detail screen.
|
||||
* This fragment is either contained in a [MainActivity]
|
||||
* in two-pane mode (on tablets) or a [MessageDetailActivity]
|
||||
* on handsets.
|
||||
*/
|
||||
class AddressDetailFragment : Fragment() {
|
||||
|
||||
/**
|
||||
* The content this fragment is presenting.
|
||||
*/
|
||||
private var item: BitmessageAddress? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
if (arguments.containsKey(ARG_ITEM)) {
|
||||
item = arguments.getSerializable(ARG_ITEM) as BitmessageAddress
|
||||
}
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.address, menu)
|
||||
|
||||
val ctx = activity
|
||||
Drawables.addIcon(ctx, menu, R.id.write_message, GoogleMaterial.Icon.gmd_mail)
|
||||
Drawables.addIcon(ctx, menu, R.id.share, GoogleMaterial.Icon.gmd_share)
|
||||
Drawables.addIcon(ctx, menu, R.id.delete, GoogleMaterial.Icon.gmd_delete)
|
||||
Drawables.addIcon(ctx, menu, R.id.export, CommunityMaterial.Icon.cmd_export).isVisible = item?.privateKey != null
|
||||
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(menuItem: MenuItem): Boolean {
|
||||
val item = item ?: return false
|
||||
val ctx = activity
|
||||
when (menuItem.itemId) {
|
||||
R.id.write_message -> {
|
||||
val identity = Singleton.getIdentity(ctx)
|
||||
if (identity == null) {
|
||||
Toast.makeText(ctx, R.string.no_identity_warning, Toast.LENGTH_LONG).show()
|
||||
} else {
|
||||
val intent = Intent(ctx, ComposeMessageActivity::class.java)
|
||||
intent.putExtra(ComposeMessageActivity.EXTRA_IDENTITY, identity)
|
||||
intent.putExtra(ComposeMessageActivity.EXTRA_RECIPIENT, item)
|
||||
startActivity(intent)
|
||||
}
|
||||
return true
|
||||
}
|
||||
R.id.delete -> {
|
||||
val warning = if (item.privateKey != null)
|
||||
R.string.delete_identity_warning
|
||||
else
|
||||
R.string.delete_contact_warning
|
||||
AlertDialog.Builder(ctx)
|
||||
.setMessage(warning)
|
||||
.setPositiveButton(android.R.string.yes) { _, _ ->
|
||||
Singleton.getAddressRepository(ctx).remove(item)
|
||||
val mainActivity = MainActivity.getInstance()
|
||||
if (item.privateKey != null && mainActivity != null) {
|
||||
mainActivity.removeIdentityEntry(item)
|
||||
}
|
||||
this.item = null
|
||||
ctx.onBackPressed()
|
||||
}
|
||||
.setNegativeButton(android.R.string.no, null)
|
||||
.show()
|
||||
return true
|
||||
}
|
||||
R.id.export -> {
|
||||
AlertDialog.Builder(ctx)
|
||||
.setMessage(R.string.confirm_export)
|
||||
.setPositiveButton(android.R.string.yes) { _, _ ->
|
||||
val shareIntent = Intent(Intent.ACTION_SEND)
|
||||
shareIntent.type = "text/plain"
|
||||
shareIntent.putExtra(Intent.EXTRA_TITLE, item.toString() + EXPORT_POSTFIX)
|
||||
val exporter = 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
|
||||
}
|
||||
R.id.share -> {
|
||||
val shareIntent = Intent(Intent.ACTION_SEND)
|
||||
shareIntent.type = "text/plain"
|
||||
shareIntent.putExtra(Intent.EXTRA_TEXT, item.address)
|
||||
startActivity(Intent.createChooser(shareIntent, null))
|
||||
return true
|
||||
}
|
||||
else -> return false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View
|
||||
= inflater.inflate(R.layout.fragment_address_detail, container, false)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
// Show the dummy content as text in a TextView.
|
||||
item?.let { item ->
|
||||
val activity = activity
|
||||
when {
|
||||
item.isChan -> activity.setTitle(R.string.title_chan_detail)
|
||||
item.privateKey != null -> activity.setTitle(R.string.title_identity_detail)
|
||||
item.isSubscribed -> activity.setTitle(R.string.title_subscription_detail)
|
||||
else -> activity.setTitle(R.string.title_contact_detail)
|
||||
}
|
||||
|
||||
avatar.setImageDrawable(Identicon(item))
|
||||
name.setText(item.toString())
|
||||
name.addTextChangedListener(object : TextWatcher {
|
||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
override fun afterTextChanged(s: Editable) {
|
||||
item.alias = s.toString()
|
||||
}
|
||||
})
|
||||
address.text = item.address
|
||||
address.isSelected = true
|
||||
stream_number.text = getString(R.string.stream_number, item.stream)
|
||||
if (item.privateKey == null) {
|
||||
active.isChecked = item.isSubscribed
|
||||
active.setOnCheckedChangeListener { _, checked -> item.isSubscribed = checked }
|
||||
|
||||
if (item.pubkey == null) {
|
||||
pubkey_available.alpha = 0.3f
|
||||
pubkey_available_desc.setText(R.string.pubkey_not_available)
|
||||
}
|
||||
} else {
|
||||
active.visibility = View.GONE
|
||||
pubkey_available.visibility = View.GONE
|
||||
pubkey_available_desc.visibility = View.GONE
|
||||
}
|
||||
|
||||
// QR code
|
||||
qr_code.setImageBitmap(Drawables.qrCode(item))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
item?.let { item ->
|
||||
Singleton.getAddressRepository(context).save(item)
|
||||
if (item.privateKey != null) {
|
||||
MainActivity.getInstance()?.updateIdentityEntry(item)
|
||||
}
|
||||
}
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* The fragment argument representing the item ID that this fragment
|
||||
* represents.
|
||||
*/
|
||||
val ARG_ITEM = "item"
|
||||
val EXPORT_POSTFIX = ".keys.dat"
|
||||
}
|
||||
}
|
@ -1,176 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 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.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.google.zxing.integration.android.IntentIntegrator;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import ch.dissem.apps.abit.repository.AndroidAddressRepository;
|
||||
import ch.dissem.apps.abit.service.Singleton;
|
||||
import ch.dissem.apps.abit.util.FabUtils;
|
||||
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
||||
import io.github.kobakei.materialfabspeeddial.FabSpeedDial;
|
||||
import io.github.kobakei.materialfabspeeddial.FabSpeedDialMenu;
|
||||
|
||||
/**
|
||||
* Fragment that shows a list of all contacts, the ones we subscribed to first.
|
||||
*/
|
||||
public class AddressListFragment extends AbstractItemListFragment<Void, BitmessageAddress> {
|
||||
private ArrayAdapter<BitmessageAddress> adapter;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
adapter = new ArrayAdapter<BitmessageAddress>(
|
||||
getActivity(),
|
||||
R.layout.subscription_row,
|
||||
R.id.name,
|
||||
new LinkedList<BitmessageAddress>()) {
|
||||
@NonNull
|
||||
@Override
|
||||
public View getView(int position, View convertView, @NonNull ViewGroup parent) {
|
||||
ViewHolder v;
|
||||
if (convertView == null) {
|
||||
LayoutInflater inflater = LayoutInflater.from(getContext());
|
||||
convertView = inflater.inflate(R.layout.subscription_row, parent, false);
|
||||
v = new ViewHolder();
|
||||
v.ctx = getContext();
|
||||
v.avatar = (ImageView) convertView.findViewById(R.id.avatar);
|
||||
v.name = (TextView) convertView.findViewById(R.id.name);
|
||||
v.streamNumber = (TextView) convertView.findViewById(R.id.stream_number);
|
||||
v.subscribed = convertView.findViewById(R.id.subscribed);
|
||||
convertView.setTag(v);
|
||||
} else {
|
||||
v = (ViewHolder) convertView.getTag();
|
||||
}
|
||||
BitmessageAddress item = getItem(position);
|
||||
assert item != null;
|
||||
v.avatar.setImageDrawable(new Identicon(item));
|
||||
v.name.setText(item.toString());
|
||||
v.streamNumber.setText(v.ctx.getString(R.string.stream_number, item.getStream()));
|
||||
v.subscribed.setVisibility(item.isSubscribed() ? View.VISIBLE : View.INVISIBLE);
|
||||
return convertView;
|
||||
}
|
||||
};
|
||||
setListAdapter(adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
initFab((MainActivity) getActivity());
|
||||
updateList();
|
||||
}
|
||||
|
||||
public void updateList() {
|
||||
adapter.clear();
|
||||
final AndroidAddressRepository addressRepo = Singleton.getAddressRepository(getContext());
|
||||
new AsyncTask<Void, BitmessageAddress, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
List<String> ids = addressRepo.getContactIds();
|
||||
for (String id : ids) {
|
||||
BitmessageAddress address = addressRepo.getById(id);
|
||||
publishProgress(address);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(BitmessageAddress... values) {
|
||||
for (BitmessageAddress address : values) {
|
||||
adapter.add(address);
|
||||
}
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
|
||||
private void initFab(MainActivity activity){
|
||||
activity.updateTitle(getString(R.string.contacts_and_subscriptions));
|
||||
FabSpeedDialMenu menu = new FabSpeedDialMenu(activity);
|
||||
menu.add(R.string.scan_qr_code).setIcon(R.drawable.ic_action_qr_code);
|
||||
menu.add(R.string.create_contact).setIcon(R.drawable.ic_action_create_contact);
|
||||
FabUtils.initFab(activity, R.drawable.ic_action_add_contact, menu)
|
||||
.addOnMenuItemClickListener(new FabSpeedDial.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public void onMenuItemClick(FloatingActionButton floatingActionButton, @Nullable TextView textView, int itemId) {
|
||||
switch (itemId) {
|
||||
case 1:
|
||||
IntentIntegrator.forSupportFragment(AddressListFragment.this)
|
||||
.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE_TYPES)
|
||||
.initiateScan();
|
||||
break;
|
||||
case 2:
|
||||
Intent intent = new Intent(getActivity(), CreateAddressActivity.class);
|
||||
startActivity(intent);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
|
||||
savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_address_list, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (data != null && data.hasExtra("SCAN_RESULT")) {
|
||||
Uri uri = Uri.parse(data.getStringExtra("SCAN_RESULT"));
|
||||
Intent intent = new Intent(getActivity(), CreateAddressActivity.class);
|
||||
intent.setData(uri);
|
||||
startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateList(Void label) {
|
||||
updateList();
|
||||
}
|
||||
|
||||
private static class ViewHolder {
|
||||
private Context ctx;
|
||||
private ImageView avatar;
|
||||
private TextView name;
|
||||
private TextView streamNumber;
|
||||
private View subscribed;
|
||||
}
|
||||
}
|
144
app/src/main/java/ch/dissem/apps/abit/AddressListFragment.kt
Normal file
144
app/src/main/java/ch/dissem/apps/abit/AddressListFragment.kt
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright 2015 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.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import ch.dissem.apps.abit.service.Singleton
|
||||
import ch.dissem.apps.abit.util.FabUtils
|
||||
import ch.dissem.bitmessage.entity.BitmessageAddress
|
||||
import com.google.zxing.integration.android.IntentIntegrator
|
||||
import io.github.kobakei.materialfabspeeddial.FabSpeedDialMenu
|
||||
import org.jetbrains.anko.doAsync
|
||||
import org.jetbrains.anko.uiThread
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Fragment that shows a list of all contacts, the ones we subscribed to first.
|
||||
*/
|
||||
class AddressListFragment : AbstractItemListFragment<Void, BitmessageAddress>() {
|
||||
private lateinit var adapter: ArrayAdapter<BitmessageAddress>
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
adapter = object : ArrayAdapter<BitmessageAddress>(
|
||||
activity,
|
||||
R.layout.subscription_row,
|
||||
R.id.name,
|
||||
LinkedList()) {
|
||||
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||
val result: View
|
||||
val v: ViewHolder
|
||||
if (convertView == null) {
|
||||
val inflater = LayoutInflater.from(context)
|
||||
val view = inflater.inflate(R.layout.subscription_row, parent, false)
|
||||
v = ViewHolder(
|
||||
ctx = context,
|
||||
avatar = view.findViewById(R.id.avatar) as ImageView,
|
||||
name = view.findViewById(R.id.name) as TextView,
|
||||
streamNumber = view.findViewById(R.id.stream_number) as TextView,
|
||||
subscribed = view.findViewById(R.id.subscribed)
|
||||
)
|
||||
view.tag = v
|
||||
result = view
|
||||
} else {
|
||||
v = convertView.tag as ViewHolder
|
||||
result = convertView
|
||||
}
|
||||
val item = getItem(position)!!
|
||||
v.avatar.setImageDrawable(Identicon(item))
|
||||
v.name.text = item.toString()
|
||||
v.streamNumber.text = v.ctx.getString(R.string.stream_number, item.stream)
|
||||
v.subscribed.visibility = if (item.isSubscribed) View.VISIBLE else View.INVISIBLE
|
||||
return result
|
||||
}
|
||||
}
|
||||
listAdapter = adapter
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
initFab(activity as MainActivity)
|
||||
updateList()
|
||||
}
|
||||
|
||||
fun updateList() {
|
||||
adapter.clear()
|
||||
val addressRepo = Singleton.getAddressRepository(context)
|
||||
doAsync {
|
||||
addressRepo.getContactIds()
|
||||
.map { addressRepo.getAddress(it) }
|
||||
.forEach { address -> uiThread { adapter.add(address) } }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun initFab(activity: MainActivity) {
|
||||
activity.updateTitle(getString(R.string.contacts_and_subscriptions))
|
||||
val menu = FabSpeedDialMenu(activity)
|
||||
menu.add(R.string.scan_qr_code).setIcon(R.drawable.ic_action_qr_code)
|
||||
menu.add(R.string.create_contact).setIcon(R.drawable.ic_action_create_contact)
|
||||
FabUtils.initFab(activity, R.drawable.ic_action_add_contact, menu)
|
||||
.addOnMenuItemClickListener { _, _, itemId ->
|
||||
when (itemId) {
|
||||
1 -> IntentIntegrator.forSupportFragment(this@AddressListFragment)
|
||||
.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE_TYPES)
|
||||
.initiateScan()
|
||||
2 -> {
|
||||
val intent = Intent(getActivity(), CreateAddressActivity::class.java)
|
||||
startActivity(intent)
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||
inflater.inflate(R.layout.fragment_address_list, container, false)
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (data != null && data.hasExtra("SCAN_RESULT")) {
|
||||
val uri = Uri.parse(data.getStringExtra("SCAN_RESULT"))
|
||||
val intent = Intent(activity, CreateAddressActivity::class.java)
|
||||
intent.data = uri
|
||||
startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateList(label: Void) {
|
||||
updateList()
|
||||
}
|
||||
|
||||
private data class ViewHolder(
|
||||
val ctx: Context,
|
||||
val avatar: ImageView,
|
||||
val name: TextView,
|
||||
val streamNumber: TextView,
|
||||
val subscribed: View
|
||||
)
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
/*
|
||||
* 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.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
|
||||
import ch.dissem.apps.abit.service.Singleton;
|
||||
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
||||
import ch.dissem.bitmessage.entity.Plaintext;
|
||||
|
||||
import static ch.dissem.bitmessage.entity.Plaintext.Encoding.EXTENDED;
|
||||
|
||||
/**
|
||||
* Compose a new message.
|
||||
*/
|
||||
public class ComposeMessageActivity extends AppCompatActivity {
|
||||
public static final String EXTRA_IDENTITY = "ch.dissem.abit.Message.SENDER";
|
||||
public static final String EXTRA_RECIPIENT = "ch.dissem.abit.Message.RECIPIENT";
|
||||
public static final String EXTRA_SUBJECT = "ch.dissem.abit.Message.SUBJECT";
|
||||
public static final String EXTRA_CONTENT = "ch.dissem.abit.Message.CONTENT";
|
||||
public static final String EXTRA_BROADCAST = "ch.dissem.abit.Message.IS_BROADCAST";
|
||||
public static final String EXTRA_ENCODING = "ch.dissem.abit.Message.ENCODING";
|
||||
public static final String EXTRA_PARENT = "ch.dissem.abit.Message.PARENT";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.toolbar_layout);
|
||||
|
||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
//noinspection ConstantConditions
|
||||
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_action_close);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setHomeButtonEnabled(false);
|
||||
|
||||
// Display the fragment as the main content.
|
||||
ComposeMessageFragment fragment = new ComposeMessageFragment();
|
||||
fragment.setArguments(getIntent().getExtras());
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.replace(R.id.content, fragment)
|
||||
.commit();
|
||||
}
|
||||
|
||||
public static void launchReplyTo(Fragment fragment, Plaintext item) {
|
||||
fragment.startActivity(getReplyIntent(fragment.getActivity(), item));
|
||||
}
|
||||
|
||||
public static void launchReplyTo(Activity activity, Plaintext item) {
|
||||
activity.startActivity(getReplyIntent(activity, item));
|
||||
}
|
||||
|
||||
private static Intent getReplyIntent(Context ctx, Plaintext item) {
|
||||
Intent replyIntent = new Intent(ctx, ComposeMessageActivity.class);
|
||||
BitmessageAddress receivingIdentity = item.getTo();
|
||||
if (receivingIdentity.isChan()) {
|
||||
// reply to chan, not to the sender of the message
|
||||
replyIntent.putExtra(EXTRA_RECIPIENT, receivingIdentity);
|
||||
// I hate when people send as chan, so it won't be the default behaviour.
|
||||
replyIntent.putExtra(EXTRA_IDENTITY, Singleton.getIdentity(ctx));
|
||||
} else {
|
||||
replyIntent.putExtra(EXTRA_RECIPIENT, item.getFrom());
|
||||
replyIntent.putExtra(EXTRA_IDENTITY, receivingIdentity);
|
||||
}
|
||||
// if the original message was sent using extended encoding, use it as well
|
||||
// so features like threading can be supported
|
||||
if (item.getEncoding() == EXTENDED) {
|
||||
replyIntent.putExtra(EXTRA_ENCODING, EXTENDED);
|
||||
}
|
||||
replyIntent.putExtra(EXTRA_PARENT, item);
|
||||
String prefix;
|
||||
if (item.getSubject().length() >= 3 && item.getSubject().substring(0, 3)
|
||||
.equalsIgnoreCase("RE:")) {
|
||||
prefix = "";
|
||||
} else {
|
||||
prefix = "RE: ";
|
||||
}
|
||||
replyIntent.putExtra(EXTRA_SUBJECT, prefix + item.getSubject());
|
||||
replyIntent.putExtra(EXTRA_CONTENT,
|
||||
"\n\n------------------------------------------------------\n"
|
||||
+ item.getText());
|
||||
return replyIntent;
|
||||
}
|
||||
}
|
100
app/src/main/java/ch/dissem/apps/abit/ComposeMessageActivity.kt
Normal file
100
app/src/main/java/ch/dissem/apps/abit/ComposeMessageActivity.kt
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.Fragment
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import ch.dissem.apps.abit.service.Singleton
|
||||
import ch.dissem.bitmessage.entity.Plaintext
|
||||
import ch.dissem.bitmessage.entity.Plaintext.Encoding.EXTENDED
|
||||
import kotlinx.android.synthetic.main.toolbar_layout.*
|
||||
|
||||
/**
|
||||
* Compose a new message.
|
||||
*/
|
||||
class ComposeMessageActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.toolbar_layout)
|
||||
|
||||
setSupportActionBar(toolbar)
|
||||
supportActionBar!!.setHomeAsUpIndicator(R.drawable.ic_action_close)
|
||||
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
|
||||
supportActionBar!!.setHomeButtonEnabled(false)
|
||||
|
||||
// Display the fragment as the main content.
|
||||
val fragment = ComposeMessageFragment()
|
||||
fragment.arguments = intent.extras
|
||||
supportFragmentManager.beginTransaction()
|
||||
.replace(R.id.content, fragment)
|
||||
.commit()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val EXTRA_IDENTITY = "ch.dissem.abit.Message.SENDER"
|
||||
const val EXTRA_RECIPIENT = "ch.dissem.abit.Message.RECIPIENT"
|
||||
const val EXTRA_SUBJECT = "ch.dissem.abit.Message.SUBJECT"
|
||||
const val EXTRA_CONTENT = "ch.dissem.abit.Message.CONTENT"
|
||||
const val EXTRA_BROADCAST = "ch.dissem.abit.Message.IS_BROADCAST"
|
||||
const val EXTRA_ENCODING = "ch.dissem.abit.Message.ENCODING"
|
||||
const val EXTRA_PARENT = "ch.dissem.abit.Message.PARENT"
|
||||
|
||||
fun launchReplyTo(fragment: Fragment, item: Plaintext) {
|
||||
fragment.startActivity(getReplyIntent(fragment.activity, item))
|
||||
}
|
||||
|
||||
fun launchReplyTo(activity: Activity, item: Plaintext) {
|
||||
activity.startActivity(getReplyIntent(activity, item))
|
||||
}
|
||||
|
||||
private fun getReplyIntent(ctx: Context, item: Plaintext): Intent {
|
||||
val replyIntent = Intent(ctx, ComposeMessageActivity::class.java)
|
||||
val receivingIdentity = item.to
|
||||
if (receivingIdentity!!.isChan) {
|
||||
// reply to chan, not to the sender of the message
|
||||
replyIntent.putExtra(EXTRA_RECIPIENT, receivingIdentity)
|
||||
// I hate when people send as chan, so it won't be the default behaviour.
|
||||
replyIntent.putExtra(EXTRA_IDENTITY, Singleton.getIdentity(ctx))
|
||||
} else {
|
||||
replyIntent.putExtra(EXTRA_RECIPIENT, item.from)
|
||||
replyIntent.putExtra(EXTRA_IDENTITY, receivingIdentity)
|
||||
}
|
||||
// if the original message was sent using extended encoding, use it as well
|
||||
// so features like threading can be supported
|
||||
if (item.encoding == EXTENDED) {
|
||||