Compare commits

...

7 Commits

Author SHA1 Message Date
akwizgran
68738a5a03 Refactor layouts for alias and link dialogs. 2018-10-31 15:28:58 +00:00
Torsten Grote
1a025d0f40 [android] Show existing alias in alias edit text view
This commit also uses LiveData Transformations to expose contact related information
2018-10-30 08:36:10 -03:00
Torsten Grote
a3593ea8ca [android] Show contact alias inside private groups and their memberlist 2018-10-29 19:41:01 -03:00
Torsten Grote
34eaedbd63 Show alias for introduction notices in private conversation 2018-10-29 19:23:22 -03:00
Torsten Grote
44e1ce32ce [android] Show alias for creator of private group in list of private groups 2018-10-29 18:38:20 -03:00
Torsten Grote
7af4b3d3ca [android] Show Author alias in AuthorView 2018-10-29 18:18:05 -03:00
Torsten Grote
1423ca7a15 [android] Add UI for changing and displaying contact alias
Note that this commit only shows the alias where the Contact is
available. In cases, where we only have the Author, only its name is
shown.

This also introduces the first ViewModel to share state between the
ConversationActivity and the AliasDialogFragment.
2018-10-29 18:18:05 -03:00
34 changed files with 520 additions and 183 deletions

View File

@@ -10,7 +10,11 @@ import javax.annotation.concurrent.Immutable;
public class AuthorInfo {
public enum Status {
NONE, ANONYMOUS, UNKNOWN, UNVERIFIED, VERIFIED, OURSELVES
NONE, ANONYMOUS, UNKNOWN, UNVERIFIED, VERIFIED, OURSELVES;
public boolean isContact() {
return this == UNVERIFIED || this == VERIFIED;
}
}
private final Status status;

View File

@@ -105,6 +105,7 @@ dependencies {
implementation "com.android.support:cardview-v7:$supportVersion"
implementation "com.android.support:support-annotations:$supportVersion"
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation "android.arch.lifecycle:extensions:1.1.1"
implementation('ch.acra:acra:4.11') {
exclude module: 'support-v4'

View File

@@ -26,6 +26,7 @@ import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.plugin.tor.CircumventionProvider;
import org.briarproject.briar.BriarCoreEagerSingletons;
import org.briarproject.briar.BriarCoreModule;
import org.briarproject.briar.android.contact.ConversationViewModel;
import org.briarproject.briar.android.login.SignInReminderReceiver;
import org.briarproject.briar.android.reporting.BriarReportSender;
import org.briarproject.briar.android.view.TextInputView;
@@ -164,6 +165,8 @@ public interface AndroidComponent
void inject(TextInputView textInputView);
void inject(ConversationViewModel conversationViewModel);
// Eager singleton load
void inject(AppModule.EagerSingletons init);
}

View File

@@ -14,7 +14,6 @@ import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.TextView;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.R;
import org.briarproject.briar.android.view.AuthorView;
@@ -98,9 +97,7 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder {
// author and date
BlogPostHeader post = item.getPostHeader();
Author a = post.getAuthor();
author.setAuthor(a);
author.setAuthorInfo(post.getAuthorInfo());
author.setAuthor(post.getAuthor(), post.getAuthorInfo());
author.setDate(post.getTimestamp());
author.setPersona(
item.isRssFeed() ? AuthorView.RSS_FEED : AuthorView.NORMAL);
@@ -143,8 +140,7 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder {
private void onBindComment(BlogCommentItem item) {
// reblogger
reblogger.setAuthor(item.getAuthor());
reblogger.setAuthorInfo(item.getAuthorInfo());
reblogger.setAuthor(item.getAuthor(), item.getAuthorInfo());
reblogger.setDate(item.getTimestamp());
if (!fullText) {
reblogger.setAuthorClickable(v -> listener.onAuthorClick(item));
@@ -165,8 +161,7 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder {
AuthorView author = v.findViewById(R.id.authorView);
TextView text = v.findViewById(R.id.textView);
author.setAuthor(c.getAuthor());
author.setAuthorInfo(c.getAuthorInfo());
author.setAuthor(c.getAuthor(), c.getAuthorInfo());
author.setDate(c.getTimestamp());
// TODO make author clickable #624

View File

@@ -0,0 +1,75 @@
package org.briarproject.briar.android.contact;
import android.arch.lifecycle.ViewModelProviders;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatDialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.briar.R;
public class AliasDialogFragment extends AppCompatDialogFragment {
final static String TAG = AliasDialogFragment.class.getName();
private ConversationViewModel viewModel;
private ContactId contactId;
private EditText aliasEditText;
public static AliasDialogFragment newInstance(ContactId id) {
AliasDialogFragment f = new AliasDialogFragment();
Bundle args = new Bundle();
args.putInt("contactId", id.getInt());
f.setArguments(args);
return f;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() == null) throw new IllegalArgumentException();
int contactIdInt = getArguments().getInt("contactId", -1);
if (contactIdInt == -1) throw new IllegalArgumentException();
contactId = new ContactId(contactIdInt);
setStyle(STYLE_NO_TITLE, R.style.BriarDialogTheme);
viewModel =
ViewModelProviders.of(getActivity()).get(ConversationViewModel.class);
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_alias_dialog, container,
false);
aliasEditText = v.findViewById(R.id.aliasEditText);
Contact contact = viewModel.getContact().getValue();
String alias = contact == null ? null : contact.getAlias();
aliasEditText.setText(alias);
if (alias != null) aliasEditText.setSelection(alias.length());
Button setButton = v.findViewById(R.id.setButton);
setButton.setOnClickListener(v1 -> {
viewModel.setContactAlias(contactId,
aliasEditText.getText().toString());
getDialog().dismiss();
});
Button cancelButton = v.findViewById(R.id.cancelButton);
cancelButton.setOnClickListener(v1 -> getDialog().cancel());
return v;
}
}

View File

@@ -1,6 +1,7 @@
package org.briarproject.briar.android.contact;
import android.content.Context;
import android.support.annotation.NonNull;
import android.view.View;
import org.briarproject.bramble.api.contact.ContactId;
@@ -9,6 +10,7 @@ import org.briarproject.briar.android.util.BriarAdapter;
import javax.annotation.Nullable;
import static android.support.v7.util.SortedList.INVALID_POSITION;
import static org.briarproject.briar.android.util.UiUtils.getContactDisplayName;
public abstract class BaseContactListAdapter<I extends ContactItem, VH extends ContactItemViewHolder<I>>
extends BriarAdapter<I, VH> {
@@ -23,15 +25,15 @@ public abstract class BaseContactListAdapter<I extends ContactItem, VH extends C
}
@Override
public void onBindViewHolder(VH ui, int position) {
public void onBindViewHolder(@NonNull VH ui, int position) {
I item = items.get(position);
ui.bind(item, listener);
}
@Override
public int compare(I c1, I c2) {
return c1.getContact().getAuthor().getName()
.compareTo(c2.getContact().getAuthor().getName());
return getContactDisplayName(c1.getContact())
.compareTo(getContactDisplayName(c2.getContact()));
}
@Override

View File

@@ -16,6 +16,8 @@ import javax.annotation.Nullable;
import im.delight.android.identicons.IdenticonDrawable;
import static org.briarproject.briar.android.util.UiUtils.getContactDisplayName;
@UiThread
@NotNullByDefault
public class ContactItemViewHolder<I extends ContactItem>
@@ -41,8 +43,7 @@ public class ContactItemViewHolder<I extends ContactItem>
Author author = item.getContact().getAuthor();
avatar.setImageDrawable(
new IdenticonDrawable(author.getId().getBytes()));
String contactName = author.getName();
name.setText(contactName);
name.setText(getContactDisplayName(item.getContact()));
if (bulb != null) {
// online/offline

View File

@@ -1,7 +1,8 @@
package org.briarproject.briar.android.contact;
import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
@@ -23,7 +24,6 @@ import android.widget.TextView;
import android.widget.Toast;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
@@ -34,7 +34,6 @@ import org.briarproject.bramble.api.db.NoSuchContactException;
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.identity.AuthorId;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.plugin.ConnectionRegistry;
@@ -131,8 +130,8 @@ public class ConversationActivity extends BriarActivity
Executor cryptoExecutor;
private final Map<MessageId, String> textCache = new ConcurrentHashMap<>();
private final MutableLiveData<String> contactName = new MutableLiveData<>();
private ConversationViewModel viewModel;
private ConversationVisitor visitor;
private ConversationAdapter adapter;
private Toolbar toolbar;
@@ -166,8 +165,6 @@ public class ConversationActivity extends BriarActivity
private volatile ContactId contactId;
@Nullable
private volatile AuthorId contactAuthorId;
@Nullable
private volatile GroupId messagingGroupId;
@SuppressWarnings("ConstantConditions")
@@ -176,6 +173,9 @@ public class ConversationActivity extends BriarActivity
setSceneTransitionAnimation();
super.onCreate(state);
viewModel =
ViewModelProviders.of(this).get(ConversationViewModel.class);
Intent i = getIntent();
int id = i.getIntExtra(CONTACT_ID, -1);
if (id == -1) throw new IllegalStateException();
@@ -185,16 +185,29 @@ public class ConversationActivity extends BriarActivity
// Custom Toolbar
toolbar = setUpCustomToolbar(true);
if (toolbar != null) {
toolbarAvatar = toolbar.findViewById(R.id.contactAvatar);
toolbarStatus = toolbar.findViewById(R.id.contactStatus);
toolbarTitle = toolbar.findViewById(R.id.contactName);
}
toolbarAvatar = toolbar.findViewById(R.id.contactAvatar);
toolbarStatus = toolbar.findViewById(R.id.contactStatus);
toolbarTitle = toolbar.findViewById(R.id.contactName);
viewModel.getContactAuthorId().observe(this, authorId -> {
toolbarAvatar.setImageDrawable(
new IdenticonDrawable(authorId.getBytes()));
// we only need this once
viewModel.getContactAuthorId().removeObservers(this);
});
viewModel.getContactDisplayName().observe(this, contactName -> {
toolbarTitle.setText(contactName);
});
viewModel.isContactDeleted().observe(this, deleted -> {
if (deleted != null && deleted) finish();
});
viewModel.loadContact(contactId);
setTransitionName(toolbarAvatar, getAvatarTransitionName(contactId));
setTransitionName(toolbarStatus, getBulbTransitionName(contactId));
visitor = new ConversationVisitor(this, this, contactName);
visitor = new ConversationVisitor(this, this,
viewModel.getContactDisplayName());
adapter = new ConversationAdapter(this, this);
list = findViewById(R.id.conversationView);
list.setLayoutManager(new LinearLayoutManager(this));
@@ -229,7 +242,19 @@ public class ConversationActivity extends BriarActivity
notificationManager.blockContactNotification(contactId);
notificationManager.clearContactNotification(contactId);
displayContactOnlineStatus();
loadContactDetailsAndMessages();
LiveData<String> contactName = viewModel.getContactDisplayName();
if (contactName.getValue() == null) {
// wait for contact name to be initialized
contactName.observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable String cName) {
if (cName != null) {
loadMessages();
contactName.removeObserver(this);
}
}
});
} else loadMessages();
list.startPeriodicUpdate();
}
@@ -266,6 +291,10 @@ public class ConversationActivity extends BriarActivity
intent.putExtra(CONTACT_ID, contactId.getInt());
startActivityForResult(intent, REQUEST_INTRODUCTION);
return true;
case R.id.action_set_alias:
AliasDialogFragment.newInstance(contactId).show(
getSupportFragmentManager(), AliasDialogFragment.TAG);
return true;
case R.id.action_social_remove_person:
askToRemoveContact();
return true;
@@ -274,36 +303,6 @@ public class ConversationActivity extends BriarActivity
}
}
private void loadContactDetailsAndMessages() {
runOnDbThread(() -> {
try {
long start = now();
if (contactAuthorId == null) {
Contact contact = contactManager.getContact(contactId);
contactName.postValue(contact.getAuthor().getName());
contactAuthorId = contact.getAuthor().getId();
}
logDuration(LOG, "Loading contact", start);
loadMessages();
displayContactDetails();
} catch (NoSuchContactException e) {
finishOnUiThread();
} catch (DbException e) {
logException(LOG, WARNING, e);
}
});
}
// contactAuthorId and contactName are expected to be set
private void displayContactDetails() {
runOnUiThreadUnlessDestroyed(() -> {
//noinspection ConstantConditions
toolbarAvatar.setImageDrawable(
new IdenticonDrawable(contactAuthorId.getBytes()));
toolbarTitle.setText(contactName.getValue());
});
}
private void displayContactOnlineStatus() {
runOnUiThreadUnlessDestroyed(() -> {
if (connectionRegistry.isConnected(contactId)) {
@@ -453,15 +452,17 @@ public class ConversationActivity extends BriarActivity
private void onNewPrivateMessage(PrivateMessageHeader h) {
runOnUiThreadUnlessDestroyed(() -> {
if (h instanceof PrivateRequest || h instanceof PrivateResponse) {
String cName = contactName.getValue();
String cName = viewModel.getContactDisplayName().getValue();
if (cName == null) {
// Wait for the contact name to be loaded
contactName.observe(this, new Observer<String>() {
viewModel.getContactDisplayName()
.observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable String cName) {
if (cName != null) {
addConversationItem(h.accept(visitor));
contactName.removeObserver(this);
viewModel.getContactDisplayName()
.removeObserver(this);
}
}
});

View File

@@ -0,0 +1,100 @@
package org.briarproject.briar.android.contact;
import android.app.Application;
import android.arch.lifecycle.AndroidViewModel;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.Transformations;
import android.support.annotation.NonNull;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.NoSuchContactException;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.briar.android.AndroidComponent;
import org.briarproject.briar.android.BriarApplication;
import org.briarproject.briar.android.util.UiUtils;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
import javax.inject.Inject;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.LogUtils.now;
public class ConversationViewModel extends AndroidViewModel {
private static Logger LOG =
Logger.getLogger(ConversationViewModel.class.getName());
@Inject
@DatabaseExecutor
Executor dbExecutor;
@Inject
ContactManager contactManager;
private final MutableLiveData<Contact> contact = new MutableLiveData<>();
private final LiveData<AuthorId> contactAuthorId =
Transformations.map(contact, c -> c.getAuthor().getId());
private final LiveData<String> contactName =
Transformations.map(contact, UiUtils::getContactDisplayName);
private final MutableLiveData<Boolean> contactDeleted =
new MutableLiveData<>();
public ConversationViewModel(@NonNull Application application) {
super(application);
AndroidComponent component =
((BriarApplication) application).getApplicationComponent();
component.inject(this);
contactDeleted.setValue(false);
}
void loadContact(ContactId contactId) {
dbExecutor.execute(() -> {
try {
long start = now();
contact.postValue(contactManager.getContact(contactId));
logDuration(LOG, "Loading contact", start);
} catch (NoSuchContactException e) {
contactDeleted.postValue(true);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
});
}
void setContactAlias(ContactId contactId, String alias) {
dbExecutor.execute(() -> {
try {
contactManager.setContactAlias(contactId,
alias.isEmpty() ? null : alias);
loadContact(contactId);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
});
}
LiveData<Contact> getContact() {
return contact;
}
LiveData<AuthorId> getContactAuthorId() {
return contactAuthorId;
}
LiveData<String> getContactDisplayName() {
return contactName;
}
LiveData<Boolean> isContactDeleted() {
return contactDeleted;
}
}

View File

@@ -24,6 +24,7 @@ import static org.briarproject.briar.android.contact.ConversationRequestItem.Req
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.FORUM;
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.GROUP;
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.INTRODUCTION;
import static org.briarproject.briar.android.util.UiUtils.getContactDisplayName;
@UiThread
@NotNullByDefault
@@ -188,33 +189,36 @@ class ConversationVisitor implements PrivateMessageVisitor<ConversationItem> {
@Override
public ConversationItem visitIntroductionRequest(IntroductionRequest r) {
String name = getContactDisplayName(r.getNameable(), r.getAlias());
if (r.isLocal()) {
String text = ctx.getString(R.string.introduction_request_sent,
contactName.getValue(), r.getName());
contactName.getValue(), name);
return new ConversationNoticeOutItem(text, r);
} else {
String text = ctx.getString(R.string.introduction_request_received,
contactName.getValue(), r.getName());
contactName.getValue(), name);
return new ConversationRequestItem(text, INTRODUCTION, r);
}
}
@Override
public ConversationItem visitIntroductionResponse(IntroductionResponse r) {
String introducedAuthor =
getContactDisplayName(r.getIntroducedAuthor(),
r.getIntroducedAuthorInfo().getAlias());
if (r.isLocal()) {
String text;
if (r.wasAccepted()) {
String introducee = r.getIntroducedAuthor().getName();
text = ctx.getString(
R.string.introduction_response_accepted_sent,
introducee)
introducedAuthor)
+ "\n\n" + ctx.getString(
R.string.introduction_response_accepted_sent_info,
introducee);
introducedAuthor);
} else {
text = ctx.getString(
R.string.introduction_response_declined_sent,
r.getIntroducedAuthor().getName());
introducedAuthor);
}
return new ConversationNoticeOutItem(text, r);
} else {
@@ -223,17 +227,17 @@ class ConversationVisitor implements PrivateMessageVisitor<ConversationItem> {
text = ctx.getString(
R.string.introduction_response_accepted_received,
contactName.getValue(),
r.getIntroducedAuthor().getName());
introducedAuthor);
} else if (r.isIntroducer()) {
text = ctx.getString(
R.string.introduction_response_declined_received,
contactName.getValue(),
r.getIntroducedAuthor().getName());
introducedAuthor);
} else {
text = ctx.getString(
R.string.introduction_response_declined_received_by_introducee,
contactName.getValue(),
r.getIntroducedAuthor().getName());
introducedAuthor);
}
return new ConversationNoticeInItem(text, r);
}

View File

@@ -38,6 +38,7 @@ import static android.view.View.VISIBLE;
import static android.widget.Toast.LENGTH_SHORT;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.briar.android.util.UiUtils.getContactDisplayName;
import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_INTRODUCTION_TEXT_LENGTH;
public class IntroductionMessageFragment extends BaseFragment
@@ -148,8 +149,8 @@ public class IntroductionMessageFragment extends BaseFragment
c2.getAuthor().getId().getBytes()));
// set contact names
ui.contactName1.setText(c1.getAuthor().getName());
ui.contactName2.setText(c2.getAuthor().getName());
ui.contactName1.setText(getContactDisplayName(c1));
ui.contactName2.setText(getContactDisplayName(c2));
// hide progress bar
ui.progressBar.setVisibility(GONE);

View File

@@ -10,6 +10,7 @@ import org.briarproject.briar.android.threaded.BaseThreadItemViewHolder;
import org.briarproject.briar.android.threaded.ThreadItemAdapter.ThreadItemListener;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.OURSELVES;
import static org.briarproject.briar.android.util.UiUtils.getContactDisplayName;
@UiThread
@NotNullByDefault
@@ -36,24 +37,27 @@ class JoinMessageItemViewHolder
if (item.isInitial()) {
textView.setText(R.string.groups_member_created_you);
} else {
textView.setText(
getContext().getString(R.string.groups_member_joined,
item.getAuthor().getName()));
String name = getContactDisplayName(item.getAuthor(),
item.getAuthorInfo().getAlias());
textView.setText(getContext()
.getString(R.string.groups_member_joined, name));
}
}
private void bind(JoinMessageItem item) {
Context ctx = getContext();
String name = getContactDisplayName(item.getAuthor(),
item.getAuthorInfo().getAlias());
if (item.isInitial()) {
textView.setText(ctx.getString(R.string.groups_member_created,
item.getAuthor().getName()));
textView.setText(
ctx.getString(R.string.groups_member_created, name));
} else {
if (item.getAuthorInfo().getStatus() == OURSELVES) {
textView.setText(R.string.groups_member_joined_you);
} else {
textView.setText(ctx.getString(R.string.groups_member_joined,
item.getAuthor().getName()));
textView.setText(
ctx.getString(R.string.groups_member_joined, name));
}
}
}

View File

@@ -9,6 +9,8 @@ import org.briarproject.briar.api.privategroup.invitation.GroupInvitationItem;
import javax.annotation.Nullable;
import static org.briarproject.briar.android.util.UiUtils.getContactDisplayName;
class GroupInvitationViewHolder
extends InvitationViewHolder<GroupInvitationItem> {
@@ -24,7 +26,7 @@ class GroupInvitationViewHolder
sharedBy.setText(
sharedBy.getContext().getString(R.string.groups_created_by,
item.getCreator().getAuthor().getName()));
getContactDisplayName(item.getCreator())));
}
}

View File

@@ -1,6 +1,7 @@
package org.briarproject.briar.android.privategroup.list;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorInfo;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.briar.api.client.MessageTracker.GroupCount;
@@ -12,12 +13,15 @@ import org.briarproject.briar.api.privategroup.PrivateGroup;
class GroupItem {
private final PrivateGroup privateGroup;
private final AuthorInfo authorInfo;
private int messageCount, unreadCount;
private long timestamp;
private boolean dissolved;
GroupItem(PrivateGroup privateGroup, GroupCount count, boolean dissolved) {
GroupItem(PrivateGroup privateGroup, AuthorInfo authorInfo,
GroupCount count, boolean dissolved) {
this.privateGroup = privateGroup;
this.authorInfo = authorInfo;
this.messageCount = count.getMsgCount();
this.unreadCount = count.getUnreadCount();
this.timestamp = count.getLatestMsgTime();
@@ -46,6 +50,10 @@ class GroupItem {
return privateGroup.getCreator();
}
AuthorInfo getCreatorInfo() {
return authorInfo;
}
String getName() {
return privateGroup.getName();
}

View File

@@ -2,12 +2,15 @@ package org.briarproject.briar.android.privategroup.list;
import android.support.annotation.CallSuper;
import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.NoSuchGroupException;
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.identity.AuthorId;
import org.briarproject.bramble.api.identity.AuthorInfo;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
@@ -30,7 +33,9 @@ import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
@@ -52,6 +57,7 @@ class GroupListControllerImpl extends DbControllerImpl
private final PrivateGroupManager groupManager;
private final GroupInvitationManager groupInvitationManager;
private final ContactManager contactManager;
private final AndroidNotificationManager notificationManager;
private final EventBus eventBus;
@@ -61,10 +67,12 @@ class GroupListControllerImpl extends DbControllerImpl
GroupListControllerImpl(@DatabaseExecutor Executor dbExecutor,
LifecycleManager lifecycleManager, PrivateGroupManager groupManager,
GroupInvitationManager groupInvitationManager,
ContactManager contactManager,
AndroidNotificationManager notificationManager, EventBus eventBus) {
super(dbExecutor, lifecycleManager);
this.groupManager = groupManager;
this.groupInvitationManager = groupInvitationManager;
this.contactManager = contactManager;
this.notificationManager = notificationManager;
this.eventBus = eventBus;
}
@@ -153,12 +161,22 @@ class GroupListControllerImpl extends DbControllerImpl
Collection<PrivateGroup> groups =
groupManager.getPrivateGroups();
List<GroupItem> items = new ArrayList<>(groups.size());
Map<AuthorId, AuthorInfo> authorInfos = new HashMap<>();
for (PrivateGroup g : groups) {
try {
GroupId id = g.getId();
AuthorId authorId = g.getCreator().getId();
AuthorInfo authorInfo;
if (authorInfos.containsKey(authorId)) {
authorInfo = authorInfos.get(authorId);
} else {
authorInfo = contactManager.getAuthorInfo(authorId);
authorInfos.put(authorId, authorInfo);
}
GroupCount count = groupManager.getGroupCount(id);
boolean dissolved = groupManager.isDissolved(id);
items.add(new GroupItem(g, count, dissolved));
items.add(
new GroupItem(g, authorInfo, count, dissolved));
} catch (NoSuchGroupException e) {
// Continue
}

View File

@@ -20,6 +20,7 @@ import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_NAME;
import static org.briarproject.briar.android.util.UiUtils.getContactDisplayName;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
@@ -60,8 +61,9 @@ class GroupViewHolder extends RecyclerView.ViewHolder {
name.setText(group.getName());
// Creator
creator.setText(ctx.getString(R.string.groups_created_by,
group.getCreator().getName()));
String creatorName = getContactDisplayName(group.getCreator(),
group.getCreatorInfo().getAlias());
creator.setText(ctx.getString(R.string.groups_created_by, creatorName));
if (!group.isDissolved()) {
// full visibility

View File

@@ -1,6 +1,7 @@
package org.briarproject.briar.android.privategroup.memberlist;
import android.content.Context;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -8,6 +9,8 @@ import android.view.ViewGroup;
import org.briarproject.briar.R;
import org.briarproject.briar.android.util.BriarAdapter;
import static org.briarproject.briar.android.util.UiUtils.getContactDisplayName;
class MemberListAdapter extends
BriarAdapter<MemberListItem, MemberListItemHolder> {
@@ -15,8 +18,9 @@ class MemberListAdapter extends
super(context, MemberListItem.class);
}
@NonNull
@Override
public MemberListItemHolder onCreateViewHolder(ViewGroup viewGroup,
public MemberListItemHolder onCreateViewHolder(@NonNull ViewGroup viewGroup,
int i) {
View v = LayoutInflater.from(ctx).inflate(
R.layout.list_item_group_member, viewGroup, false);
@@ -24,13 +28,18 @@ class MemberListAdapter extends
}
@Override
public void onBindViewHolder(MemberListItemHolder ui, int position) {
public void onBindViewHolder(@NonNull MemberListItemHolder ui,
int position) {
ui.bind(items.get(position));
}
@Override
public int compare(MemberListItem m1, MemberListItem m2) {
return m1.getMember().getName().compareTo(m2.getMember().getName());
String n1 = getContactDisplayName(m1.getMember(),
m1.getAuthorInfo().getAlias());
String n2 = getContactDisplayName(m2.getMember(),
m2.getAuthorInfo().getAlias());
return n1.compareTo(n2);
}
@Override

View File

@@ -13,6 +13,7 @@ import org.briarproject.briar.android.view.AuthorView;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.OURSELVES;
import static org.briarproject.briar.android.util.UiUtils.getContactDisplayName;
@UiThread
@NotNullByDefault
@@ -31,8 +32,7 @@ class MemberListItemHolder extends RecyclerView.ViewHolder {
protected void bind(MemberListItem item) {
// member name, avatar and status
author.setAuthor(item.getMember());
author.setAuthorInfo(item.getAuthorInfo());
author.setAuthor(item.getMember(), item.getAuthorInfo());
// online status of visible contacts
if (item.getContactId() != null) {
@@ -52,9 +52,10 @@ class MemberListItemHolder extends RecyclerView.ViewHolder {
if (item.getStatus() == OURSELVES) {
creator.setText(R.string.groups_member_created_you);
} else {
String name = getContactDisplayName(item.getMember(),
item.getAuthorInfo().getAlias());
creator.setText(creator.getContext()
.getString(R.string.groups_member_created,
item.getMember().getName()));
.getString(R.string.groups_member_created, name));
}
} else {
creator.setVisibility(GONE);

View File

@@ -14,6 +14,7 @@ import javax.annotation.Nullable;
import static org.briarproject.briar.android.privategroup.VisibilityHelper.getVisibilityIcon;
import static org.briarproject.briar.android.privategroup.VisibilityHelper.getVisibilityString;
import static org.briarproject.briar.android.util.UiUtils.GREY_OUT;
import static org.briarproject.briar.android.util.UiUtils.getContactDisplayName;
@UiThread
@NotNullByDefault
@@ -36,7 +37,7 @@ class RevealableContactViewHolder
icon.setImageResource(getVisibilityIcon(item.getVisibility()));
info.setText(
getVisibilityString(info.getContext(), item.getVisibility(),
item.getContact().getAuthor().getName()));
getContactDisplayName(item.getContact())));
}
@Override

View File

@@ -13,6 +13,8 @@ import java.util.Collection;
import javax.annotation.Nullable;
import static org.briarproject.briar.android.util.UiUtils.getContactDisplayName;
class SharingInvitationViewHolder
extends InvitationViewHolder<SharingInvitationItem> {
@@ -28,7 +30,7 @@ class SharingInvitationViewHolder
Collection<String> names = new ArrayList<>();
for (Contact c : item.getNewSharers())
names.add(c.getAuthor().getName());
names.add(getContactDisplayName(c));
sharedBy.setText(
sharedBy.getContext().getString(R.string.shared_by_format,
StringUtils.join(names, ", ")));

View File

@@ -43,9 +43,8 @@ public abstract class BaseThreadItemViewHolder<I extends ThreadItem>
public void bind(I item, ThreadItemListener<I> listener) {
textView.setText(StringUtils.trim(item.getText()));
author.setAuthor(item.getAuthor());
author.setAuthor(item.getAuthor(), item.getAuthorInfo());
author.setDate(item.getTimestamp());
author.setAuthorInfo(item.getAuthorInfo());
if (item.isHighlighted()) {
layout.setActivated(true);

View File

@@ -33,7 +33,9 @@ import android.view.View;
import android.widget.TextView;
import org.acra.ACRA;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.system.AndroidExecutor;
@@ -74,6 +76,17 @@ public class UiUtils {
public static final int TEASER_LENGTH = 320;
public static final float GREY_OUT = 0.5f;
public static String getContactDisplayName(Author author,
@Nullable String alias) {
String name = author.getName();
if (alias == null) return name;
else return String.format("%s (%s)", alias, name);
}
public static String getContactDisplayName(Contact c) {
return getContactDisplayName(c.getAuthor(), c.getAlias());
}
public static void setError(TextInputLayout til, @Nullable String error,
boolean set) {
if (set) {
@@ -127,7 +140,9 @@ public class UiUtils {
return builder;
}
public static Spanned getSpanned(String s) {
public static Spanned getSpanned(@Nullable String s) {
// TODO move to HtmlCompat
// https://commonsware.com/blog/2018/05/29/at-last-htmlcompat.html
return Html.fromHtml(s);
}

View File

@@ -26,6 +26,7 @@ import static android.graphics.Typeface.BOLD;
import static android.util.TypedValue.COMPLEX_UNIT_PX;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.NONE;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.OURSELVES;
import static org.briarproject.briar.android.util.UiUtils.getContactDisplayName;
import static org.briarproject.briar.android.util.UiUtils.resolveAttribute;
@UiThread
@@ -70,16 +71,12 @@ public class AuthorView extends ConstraintLayout {
this(context, null);
}
public void setAuthor(Author author) {
authorName.setText(author.getName());
public void setAuthor(Author author, AuthorInfo authorInfo) {
authorName
.setText(getContactDisplayName(author, authorInfo.getAlias()));
IdenticonDrawable d = new IdenticonDrawable(author.getId().getBytes());
avatar.setImageDrawable(d);
invalidate();
requestLayout();
}
public void setAuthorInfo(AuthorInfo authorInfo) {
if (authorInfo.getStatus() != NONE) {
trustIndicator.setTrustLevel(authorInfo.getStatus());
trustIndicator.setVisibility(VISIBLE);
@@ -123,7 +120,7 @@ public class AuthorView extends ConstraintLayout {
*
* Attention: RSS_FEED and RSS_FEED_REBLOGGED change the avatar
* and override the one set by
* {@link AuthorView#setAuthor(Author)}.
* {@link AuthorView#setAuthor(Author, AuthorInfo)}.
*/
public void setPersona(int persona) {
switch (persona) {

View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/titleView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/set_contact_alias"
android:textColor="?android:attr/textColorPrimary"
android:textSize="@dimen/text_size_large"
android:textStyle="bold"/>
<EditText
android:id="@+id/aliasEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:hint="@string/set_contact_alias_hint"
android:inputType="textPersonName"
android:textColor="?android:attr/textColorPrimary"
android:textSize="@dimen/text_size_medium"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_xxlarge"
android:layout_marginStart="@dimen/margin_xxlarge"
android:gravity="end"
android:orientation="horizontal">
<Button
android:id="@+id/cancelButton"
style="@style/BriarButtonFlat.Negative"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cancel"/>
<Button
android:id="@+id/setButton"
style="@style/BriarButtonFlat.Positive"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/set_alias"/>
</LinearLayout>
</LinearLayout>

View File

@@ -1,75 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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:orientation="vertical">
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/link_warning_title"
android:textColor="?android:attr/textColorPrimary"
android:textSize="@dimen/text_size_large"
android:textStyle="bold"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_large"
android:text="@string/link_warning_intro"
android:textColor="?android:attr/textColorPrimary"
android:textSize="@dimen/text_size_medium"/>
<TextView
android:id="@+id/urlView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_large"
android:textColor="?android:attr/textColorPrimary"
android:textIsSelectable="true"
android:textSize="@dimen/text_size_medium"
android:typeface="monospace"
tools:text="http://very.bad.site.com"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_large"
android:text="@string/link_warning_text"
android:textColor="?android:attr/textColorPrimary"
android:textSize="@dimen/text_size_medium"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="@dimen/margin_large">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/link_warning_title"
android:textColor="?android:attr/textColorPrimary"
android:textSize="@dimen/text_size_large"
android:textStyle="bold"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_large"
android:text="@string/link_warning_intro"
android:textColor="?android:attr/textColorPrimary"
android:textSize="@dimen/text_size_medium"/>
<TextView
android:id="@+id/urlView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_large"
android:textIsSelectable="true"
android:typeface="monospace"
tools:text="http://very.bad.site.com"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_large"
android:text="@string/link_warning_text"
android:textColor="?android:attr/textColorPrimary"
android:textSize="@dimen/text_size_medium"/>
</LinearLayout>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="@dimen/button_size">
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_xxlarge"
android:layout_marginStart="@dimen/margin_xxlarge"
android:gravity="end"
android:orientation="horizontal">
<Button
android:id="@+id/cancelButton"
style="@style/BriarButtonFlat.Positive"
android:layout_width="0dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cancel"
app:layout_constraintEnd_toStartOf="@+id/openButton"
app:layout_constraintStart_toStartOf="parent"/>
android:text="@string/cancel"/>
<Button
android:id="@+id/openButton"
style="@style/BriarButtonFlat.Negative"
android:layout_width="0dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/link_warning_open_link"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/cancelButton"/>
android:text="@string/link_warning_open_link"/>
</android.support.constraint.ConstraintLayout>
</LinearLayout>
</LinearLayout>

View File

@@ -10,6 +10,12 @@
android:enabled="false"
app:showAsAction="never"/>
<item
android:id="@+id/action_set_alias"
android:title="@string/set_contact_alias"
android:enabled="true"
app:showAsAction="never"/>
<item
android:id="@+id/action_social_remove_person"
android:icon="@drawable/action_delete_white"

View File

@@ -127,6 +127,9 @@
<string name="date_no_private_messages">No messages.</string>
<string name="no_private_messages">No messages to show</string>
<string name="message_hint">Type message</string>
<string name="set_contact_alias">Set alias name</string>
<string name="set_contact_alias_hint">Contact alias</string>
<string name="set_alias">Set Alias</string>
<string name="delete_contact">Delete contact</string>
<string name="dialog_title_delete_contact">Confirm Contact Deletion</string>
<string name="dialog_message_delete_contact">Are you sure that you want to remove this contact and all messages exchanged with this contact?</string>

View File

@@ -3,6 +3,7 @@ dependencyVerification {
'android.arch.core:common:1.1.1:common-1.1.1.jar:3a616a32f433e9e23f556b38575c31b013613d3ae85206263b7625fe1f4c151a',
'android.arch.core:runtime:1.1.1:runtime-1.1.1.aar:c3215aa5873311b3f88a6f4e4a3c25ad89971bc127de8c3e1291c57f93a05c39',
'android.arch.lifecycle:common:1.1.1:common-1.1.1.jar:8d378e88ebd5189e09eef623414812c868fd90aa519d6160e2311fb8b81cff56',
'android.arch.lifecycle:extensions:1.1.1:extensions-1.1.1.aar:429426b2feec2245ffc5e75b3b5309bedb36159cf06dc71843ae43526ac289b6',
'android.arch.lifecycle:livedata-core:1.1.1:livedata-core-1.1.1.aar:d6fdd8b985d6178d7ea2f16986a24e83f1bee936b74d43167c69e08d3cc12c50',
'android.arch.lifecycle:livedata:1.1.1:livedata-1.1.1.aar:50ab0490c1ff1a7cfb4e554032998b080888946d0dd424f39900efc4a1bcd750',
'android.arch.lifecycle:runtime:1.1.1:runtime-1.1.1.aar:c4e4be66c1b2f0abec593571454e1de14013f7e0f96bf2a9f212931a48cae550',

View File

@@ -1,6 +1,7 @@
package org.briarproject.briar.api.introduction;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorInfo;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId;
@@ -15,19 +16,24 @@ import javax.annotation.concurrent.Immutable;
@NotNullByDefault
public class IntroductionRequest extends PrivateRequest<Author> {
private final boolean contact;
private final AuthorInfo authorInfo;
public IntroductionRequest(MessageId messageId, GroupId groupId,
long time, boolean local, boolean sent, boolean seen, boolean read,
SessionId sessionId, Author author, @Nullable String text,
boolean answered, boolean contact) {
boolean answered, AuthorInfo authorInfo) {
super(messageId, groupId, time, local, sent, seen, read, sessionId,
author, text, answered);
this.contact = contact;
this.authorInfo = authorInfo;
}
@Nullable
public String getAlias() {
return authorInfo.getAlias();
}
public boolean isContact() {
return contact;
return authorInfo.getStatus().isContact();
}
@Override

View File

@@ -1,6 +1,7 @@
package org.briarproject.briar.api.introduction;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorInfo;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId;
@@ -17,14 +18,17 @@ import static org.briarproject.briar.api.introduction.Role.INTRODUCER;
public class IntroductionResponse extends PrivateResponse {
private final Author introducedAuthor;
private final AuthorInfo introducedAuthorInfo;
private final Role ourRole;
public IntroductionResponse(MessageId messageId, GroupId groupId, long time,
boolean local, boolean sent, boolean seen, boolean read,
SessionId sessionId, boolean accepted, Author author, Role role) {
SessionId sessionId, boolean accepted, Author author,
AuthorInfo introducedAuthorInfo, Role role) {
super(messageId, groupId, time, local, sent, seen, read, sessionId,
accepted);
this.introducedAuthor = author;
this.introducedAuthorInfo = introducedAuthorInfo;
this.ourRole = role;
}
@@ -32,6 +36,10 @@ public class IntroductionResponse extends PrivateResponse {
return introducedAuthor;
}
public AuthorInfo getIntroducedAuthorInfo() {
return introducedAuthorInfo;
}
public boolean isIntroducer() {
return ourRole == INTRODUCER;
}

View File

@@ -11,6 +11,7 @@ import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.AuthorInfo;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId;
@@ -149,11 +150,13 @@ abstract class AbstractProtocolEngine<S extends Session>
throws DbException {
AuthorId localAuthorId = identityManager.getLocalAuthor(txn).getId();
Contact c = contactManager.getContact(txn, sender, localAuthorId);
AuthorInfo otherAuthorInfo =
contactManager.getAuthorInfo(txn, otherAuthor.getId());
IntroductionResponse response =
new IntroductionResponse(m.getMessageId(), m.getGroupId(),
m.getTimestamp(), false, false, false, false,
s.getSessionId(), m instanceof AcceptMessage,
otherAuthor, s.getRole());
otherAuthor, otherAuthorInfo, s.getRole());
IntroductionResponseReceivedEvent e =
new IntroductionResponseReceivedEvent(response, c.getId());
txn.attach(e);

View File

@@ -12,6 +12,7 @@ import org.briarproject.bramble.api.db.ContactExistsException;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.AuthorInfo;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -251,12 +252,12 @@ class IntroduceeProtocolEngine
LocalAuthor localAuthor = identityManager.getLocalAuthor(txn);
Contact c = contactManager.getContact(txn, s.getIntroducer().getId(),
localAuthor.getId());
boolean contactExists = contactManager
.contactExists(txn, m.getAuthor().getId(), localAuthor.getId());
AuthorInfo authorInfo =
contactManager.getAuthorInfo(txn, m.getAuthor().getId());
IntroductionRequest request = new IntroductionRequest(m.getMessageId(),
m.getGroupId(), m.getTimestamp(), false, false, false, false,
s.getSessionId(), m.getAuthor(), m.getText(), false,
contactExists);
authorInfo);
IntroductionRequestReceivedEvent e =
new IntroductionRequestReceivedEvent(request, c.getId());
txn.attach(e);

View File

@@ -15,6 +15,8 @@ import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.AuthorInfo;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -39,6 +41,7 @@ import org.briarproject.briar.introduction.IntroducerSession.Introducee;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -408,6 +411,7 @@ class IntroductionManagerImpl extends ConversationClientImpl
.getMessageMetadataAsDictionary(txn, contactGroupId, query);
List<PrivateMessageHeader> messages =
new ArrayList<>(results.size());
Map<AuthorId, AuthorInfo> authorInfos = new HashMap<>();
for (Entry<MessageId, BdfDictionary> e : results.entrySet()) {
MessageId m = e.getKey();
MessageMetadata meta =
@@ -419,15 +423,17 @@ class IntroductionManagerImpl extends ConversationClientImpl
if (type == REQUEST) {
messages.add(
parseInvitationRequest(txn, contactGroupId, m,
meta, status, ss.bdfSession));
meta, status, ss.bdfSession, authorInfos));
} else if (type == ACCEPT) {
messages.add(
parseInvitationResponse(contactGroupId, m, meta,
status, ss.bdfSession, true));
parseInvitationResponse(txn, contactGroupId, m,
meta, status, ss.bdfSession, authorInfos,
true));
} else if (type == DECLINE) {
messages.add(
parseInvitationResponse(contactGroupId, m, meta,
status, ss.bdfSession, false));
parseInvitationResponse(txn, contactGroupId, m,
meta, status, ss.bdfSession, authorInfos,
false));
}
}
return messages;
@@ -438,7 +444,8 @@ class IntroductionManagerImpl extends ConversationClientImpl
private IntroductionRequest parseInvitationRequest(Transaction txn,
GroupId contactGroupId, MessageId m, MessageMetadata meta,
MessageStatus status, BdfDictionary bdfSession)
MessageStatus status, BdfDictionary bdfSession,
Map<AuthorId, AuthorInfo> authorInfos)
throws DbException, FormatException {
Role role = sessionParser.getRole(bdfSession);
SessionId sessionId;
@@ -462,19 +469,22 @@ class IntroductionManagerImpl extends ConversationClientImpl
BdfList body = clientHelper.toList(msg);
RequestMessage rm = messageParser.parseRequestMessage(msg, body);
String text = rm.getText();
LocalAuthor localAuthor = identityManager.getLocalAuthor(txn);
boolean contactExists = contactManager
.contactExists(txn, rm.getAuthor().getId(),
localAuthor.getId());
AuthorInfo authorInfo = authorInfos.get(author.getId());
if (authorInfo == null) {
authorInfo = contactManager.getAuthorInfo(txn, author.getId());
authorInfos.put(author.getId(), authorInfo);
}
return new IntroductionRequest(m, contactGroupId, meta.getTimestamp(),
meta.isLocal(), status.isSent(), status.isSeen(), meta.isRead(),
sessionId, author, text, !meta.isAvailableToAnswer(),
contactExists);
authorInfo);
}
private IntroductionResponse parseInvitationResponse(GroupId contactGroupId,
MessageId m, MessageMetadata meta, MessageStatus status,
BdfDictionary bdfSession, boolean accept) throws FormatException {
private IntroductionResponse parseInvitationResponse(Transaction txn,
GroupId contactGroupId, MessageId m, MessageMetadata meta,
MessageStatus status, BdfDictionary bdfSession,
Map<AuthorId, AuthorInfo> authorInfos, boolean accept)
throws FormatException, DbException {
Role role = sessionParser.getRole(bdfSession);
SessionId sessionId;
Author author;
@@ -493,9 +503,14 @@ class IntroductionManagerImpl extends ConversationClientImpl
sessionId = session.getSessionId();
author = session.getRemote().author;
} else throw new AssertionError();
AuthorInfo authorInfo = authorInfos.get(author.getId());
if (authorInfo == null) {
authorInfo = contactManager.getAuthorInfo(txn, author.getId());
authorInfos.put(author.getId(), authorInfo);
}
return new IntroductionResponse(m, contactGroupId, meta.getTimestamp(),
meta.isLocal(), status.isSent(), status.isSeen(), meta.isRead(),
sessionId, accept, author, role);
sessionId, accept, author, authorInfo, role);
}
private void removeSessionWithIntroducer(Transaction txn,

View File

@@ -7,6 +7,9 @@ import io.javalin.json.JavalinJson.toJson
import io.mockk.*
import org.briarproject.bramble.api.contact.ContactId
import org.briarproject.bramble.api.db.NoSuchContactException
import org.briarproject.bramble.api.identity.AuthorInfo
import org.briarproject.bramble.api.identity.AuthorInfo.Status.UNVERIFIED
import org.briarproject.bramble.api.identity.AuthorInfo.Status.VERIFIED
import org.briarproject.bramble.test.ImmediateExecutor
import org.briarproject.bramble.test.TestUtils.getRandomId
import org.briarproject.bramble.util.StringUtils.getRandomString
@@ -61,7 +64,7 @@ internal class MessagingControllerImplTest : ControllerTest() {
fun listIntroductionRequest() {
val request = IntroductionRequest(
message.id, group.id, timestamp, true, true, false, true, sessionId, author, text,
false, false
false, AuthorInfo(UNVERIFIED)
)
expectGetContact()
@@ -200,7 +203,7 @@ internal class MessagingControllerImplTest : ControllerTest() {
fun testIntroductionRequestWithNullText() {
val request = IntroductionRequest(
message.id, group.id, timestamp, true, true, false, true, sessionId, author, null,
false, false
false, AuthorInfo(VERIFIED)
)
val json = """
{