[android] finalize list of pending contacts and add test code

This commit is contained in:
Torsten Grote
2019-02-12 16:15:05 -02:00
parent 66cdf4f595
commit 4a57939b80
13 changed files with 269 additions and 95 deletions

View File

@@ -13,17 +13,12 @@ import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
import javax.inject.Inject;
import static java.util.logging.Logger.getLogger;
@NotNullByDefault
public class AddContactViewModel extends AndroidViewModel {
private static Logger LOG = getLogger(AddContactViewModel.class.getName());
private final ContactManager contactManager;
@DatabaseExecutor
private final Executor dbExecutor;

View File

@@ -0,0 +1,9 @@
package org.briarproject.briar.android.contact.add.remote;
import org.briarproject.bramble.api.contact.PendingContact;
interface PendingContactListener {
void onFailedPendingContactRemoved(PendingContact pendingContact);
}

View File

@@ -1,18 +1,13 @@
package org.briarproject.briar.android.contact.add.remote;
import android.arch.lifecycle.ViewModelProvider;
import android.arch.lifecycle.ViewModelProviders;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.support.v7.widget.LinearLayoutManager;
import android.view.MenuItem;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.contact.PendingContact;
import org.briarproject.bramble.api.contact.event.ContactAddedEvent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R;
@@ -28,13 +23,12 @@ import javax.inject.Inject;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
public class PendingRequestsActivity extends BriarActivity
implements EventListener {
implements PendingContactListener {
@Inject
ContactManager contactManager;
@Inject
EventBus eventBus;
ViewModelProvider.Factory viewModelFactory;
private PendingRequestsViewModel viewModel;
private PendingRequestsAdapter adapter;
private BriarRecyclerView list;
@@ -54,33 +48,29 @@ public class PendingRequestsActivity extends BriarActivity
ab.setDisplayHomeAsUpEnabled(true);
}
adapter = new PendingRequestsAdapter(this, PendingContact.class);
viewModel = ViewModelProviders.of(this, viewModelFactory)
.get(PendingRequestsViewModel.class);
viewModel.getPendingContacts()
.observe(this, this::onPendingContactsChanged);
adapter = new PendingRequestsAdapter(this, this, PendingContact.class);
list = findViewById(R.id.list);
list.setEmptyText(R.string.no_pending_contacts);
list.setLayoutManager(new LinearLayoutManager(this));
list.setAdapter(adapter);
list.showProgressBar();
}
@Override
public void onStart() {
super.onStart();
eventBus.addListener(this);
list.startPeriodicUpdate();
runOnDbThread(() -> {
try {
Collection<PendingContact> contacts =
contactManager.getPendingContacts();
addPendingContacts(contacts);
} catch (DbException e) {
e.printStackTrace();
}
});
}
@Override
protected void onStop() {
super.onStop();
list.stopPeriodicUpdate();
adapter.clear();
}
@Override
@@ -95,31 +85,23 @@ public class PendingRequestsActivity extends BriarActivity
}
@Override
public void eventOccurred(Event e) {
if (e instanceof ContactAddedEvent) {
runOnDbThread(() -> {
try {
Contact contact = contactManager
.getContact(((ContactAddedEvent) e).getContactId());
runOnUiThreadUnlessDestroyed(() -> {
adapter.remove(contact);
if (adapter.isEmpty()) finish();
});
} catch (DbException e1) {
e1.printStackTrace();
}
});
public void onFailedPendingContactRemoved(PendingContact pendingContact) {
adapter.remove(pendingContact);
viewModel.removePendingContact(pendingContact);
}
private void onPendingContactsChanged(Collection<PendingContact> contacts) {
if (contacts.isEmpty()) {
if (!adapter.isEmpty()) {
// all previous contacts have been removed, so we can finish
supportFinishAfterTransition();
} else {
adapter.clear();
list.showData();
}
} else {
adapter.setItems(contacts);
}
}
private void addPendingContacts(Collection<PendingContact> contacts) {
runOnUiThreadUnlessDestroyed(() -> {
if (contacts.isEmpty()) {
list.showData();
} else {
adapter.addAll(contacts);
}
});
}
}

View File

@@ -5,7 +5,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.PendingContact;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.R;
@@ -15,8 +14,12 @@ import org.briarproject.briar.android.util.BriarAdapter;
public class PendingRequestsAdapter extends
BriarAdapter<PendingContact, PendingRequestsViewHolder> {
public PendingRequestsAdapter(Context ctx, Class<PendingContact> c) {
private final PendingContactListener listener;
public PendingRequestsAdapter(Context ctx, PendingContactListener listener,
Class<PendingContact> c) {
super(ctx, c);
this.listener = listener;
}
@Override
@@ -24,7 +27,7 @@ public class PendingRequestsAdapter extends
ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(
R.layout.list_item_pending_contact, viewGroup, false);
return new PendingRequestsViewHolder(v);
return new PendingRequestsViewHolder(v, listener);
}
@Override
@@ -52,14 +55,4 @@ public class PendingRequestsAdapter extends
item1.getTimestamp() == item2.getTimestamp();
}
// TODO use PendingContactId
public void remove(Contact contact) {
for (int i = 0; i < items.size(); i++) {
if (items.get(i).getAlias().equals(contact.getAuthor().getName())) {
items.removeItemAt(i);
return;
}
}
}
}

View File

@@ -3,6 +3,7 @@ package org.briarproject.briar.android.contact.add.remote;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import org.briarproject.bramble.api.contact.PendingContact;
@@ -10,33 +11,41 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.R;
import org.briarproject.briar.android.view.TextAvatarView;
import static org.briarproject.bramble.util.StringUtils.toUtf8;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static org.briarproject.briar.android.util.UiUtils.formatDate;
@NotNullByDefault
public class PendingRequestsViewHolder extends ViewHolder {
private final PendingContactListener listener;
private final TextAvatarView avatar;
private final TextView name;
private final TextView time;
private final TextView status;
private final Button button;
public PendingRequestsViewHolder(View v) {
public PendingRequestsViewHolder(View v, PendingContactListener listener) {
super(v);
avatar = v.findViewById(R.id.avatar);
name = v.findViewById(R.id.name);
time = v.findViewById(R.id.time);
status = v.findViewById(R.id.status);
button = v.findViewById(R.id.button);
this.listener = listener;
}
public void bind(PendingContact item) {
avatar.setText(item.getAlias());
avatar.setBackgroundBytes(toUtf8(item.getAlias() + item.getTimestamp()));
avatar.setBackgroundBytes(item.getId().getBytes());
name.setText(item.getAlias());
time.setText(formatDate(time.getContext(), item.getTimestamp()));
button.setOnClickListener(
v -> listener.onFailedPendingContactRemoved(item));
int color = ContextCompat
.getColor(status.getContext(), R.color.briar_green);
int buttonVisibility = GONE;
switch (item.getState()) {
case WAITING_FOR_CONNECTION:
color = ContextCompat
@@ -50,15 +59,16 @@ public class PendingRequestsViewHolder extends ViewHolder {
status.setText(R.string.adding_contact);
break;
case FAILED:
// TODO add remove button
color = ContextCompat
.getColor(status.getContext(), R.color.briar_red);
status.setText(R.string.adding_contact_failed);
buttonVisibility = VISIBLE;
break;
default:
throw new IllegalStateException();
}
status.setTextColor(color);
button.setVisibility(buttonVisibility);
}
}

View File

@@ -0,0 +1,95 @@
package org.briarproject.briar.android.contact.add.remote;
import android.app.Application;
import android.arch.lifecycle.AndroidViewModel;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MutableLiveData;
import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.contact.PendingContact;
import org.briarproject.bramble.api.contact.event.ContactAddedRemotelyEvent;
import org.briarproject.bramble.api.contact.event.PendingContactStateChangedEvent;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.Collection;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
import javax.inject.Inject;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.LogUtils.logException;
@NotNullByDefault
public class PendingRequestsViewModel extends AndroidViewModel
implements EventListener {
private final Logger LOG =
getLogger(PendingRequestsViewModel.class.getName());
@DatabaseExecutor
private final Executor dbExecutor;
private final ContactManager contactManager;
private final EventBus eventBus;
private final MutableLiveData<Collection<PendingContact>> pendingContacts =
new MutableLiveData<>();
@Inject
public PendingRequestsViewModel(Application application,
@DatabaseExecutor Executor dbExecutor,
ContactManager contactManager, EventBus eventBus) {
super(application);
this.dbExecutor = dbExecutor;
this.contactManager = contactManager;
this.eventBus = eventBus;
this.eventBus.addListener(this);
loadPendingContacts();
}
@Override
protected void onCleared() {
super.onCleared();
eventBus.removeListener(this);
}
@Override
public void eventOccurred(Event e) {
if (e instanceof ContactAddedRemotelyEvent ||
e instanceof PendingContactStateChangedEvent) {
loadPendingContacts();
}
}
private void loadPendingContacts() {
dbExecutor.execute(() -> {
try {
pendingContacts.postValue(contactManager.getPendingContacts());
} catch (DbException e) {
logException(LOG, WARNING, e);
}
});
}
LiveData<Collection<PendingContact>> getPendingContacts() {
return pendingContacts;
}
void removePendingContact(PendingContact pendingContact) {
dbExecutor.execute(() -> {
try {
contactManager.removePendingContact(pendingContact);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
});
loadPendingContacts();
}
}

View File

@@ -4,6 +4,7 @@ import android.arch.lifecycle.ViewModel;
import android.arch.lifecycle.ViewModelProvider;
import org.briarproject.briar.android.contact.add.remote.AddContactViewModel;
import org.briarproject.briar.android.contact.add.remote.PendingRequestsViewModel;
import org.briarproject.briar.android.conversation.ConversationViewModel;
import org.briarproject.briar.android.conversation.ImageViewModel;
@@ -34,6 +35,12 @@ public abstract class ViewModelModule {
abstract ViewModel bindAddContactViewModel(
AddContactViewModel addContactViewModel);
@Binds
@IntoMap
@ViewModelKey(PendingRequestsViewModel.class)
abstract ViewModel bindPendingRequestsViewModel(
PendingRequestsViewModel pendingRequestsViewModel);
@Binds
@Singleton
abstract ViewModelProvider.Factory bindViewModelFactory(