mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-17 13:19:52 +01:00
Merge branch '41-alias-frontend' into 'master'
Add UI for changing contact aliases Closes #41 See merge request briar/briar!965
This commit is contained in:
@@ -105,6 +105,7 @@ dependencies {
|
|||||||
implementation "com.android.support:cardview-v7:$supportVersion"
|
implementation "com.android.support:cardview-v7:$supportVersion"
|
||||||
implementation "com.android.support:support-annotations:$supportVersion"
|
implementation "com.android.support:support-annotations:$supportVersion"
|
||||||
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
|
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
|
||||||
|
implementation "android.arch.lifecycle:extensions:1.1.1"
|
||||||
|
|
||||||
implementation('ch.acra:acra:4.11') {
|
implementation('ch.acra:acra:4.11') {
|
||||||
exclude module: 'support-v4'
|
exclude module: 'support-v4'
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package org.briarproject.briar.android;
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
|
import android.arch.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
import org.briarproject.bramble.BrambleAndroidModule;
|
import org.briarproject.bramble.BrambleAndroidModule;
|
||||||
import org.briarproject.bramble.BrambleCoreEagerSingletons;
|
import org.briarproject.bramble.BrambleCoreEagerSingletons;
|
||||||
import org.briarproject.bramble.BrambleCoreModule;
|
import org.briarproject.bramble.BrambleCoreModule;
|
||||||
@@ -154,6 +156,8 @@ public interface AndroidComponent
|
|||||||
|
|
||||||
CircumventionProvider circumventionProvider();
|
CircumventionProvider circumventionProvider();
|
||||||
|
|
||||||
|
ViewModelProvider.Factory viewModelFactory();
|
||||||
|
|
||||||
void inject(SignInReminderReceiver briarService);
|
void inject(SignInReminderReceiver briarService);
|
||||||
|
|
||||||
void inject(BriarService briarService);
|
void inject(BriarService briarService);
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import org.briarproject.bramble.plugin.tor.CircumventionProvider;
|
|||||||
import org.briarproject.bramble.util.AndroidUtils;
|
import org.briarproject.bramble.util.AndroidUtils;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
import org.briarproject.briar.android.account.LockManagerImpl;
|
import org.briarproject.briar.android.account.LockManagerImpl;
|
||||||
|
import org.briarproject.briar.android.viewmodel.ViewModelModule;
|
||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
import org.briarproject.briar.api.android.DozeWatchdog;
|
import org.briarproject.briar.api.android.DozeWatchdog;
|
||||||
import org.briarproject.briar.api.android.LockManager;
|
import org.briarproject.briar.api.android.LockManager;
|
||||||
@@ -57,7 +58,7 @@ import static java.util.Collections.emptyList;
|
|||||||
import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_ONION_ADDRESS;
|
import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_ONION_ADDRESS;
|
||||||
import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_PUBLIC_KEY_HEX;
|
import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_PUBLIC_KEY_HEX;
|
||||||
|
|
||||||
@Module
|
@Module(includes = ViewModelModule.class)
|
||||||
public class AppModule {
|
public class AppModule {
|
||||||
|
|
||||||
static class EagerSingletons {
|
static class EagerSingletons {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import org.briarproject.briar.android.blog.ReblogFragment;
|
|||||||
import org.briarproject.briar.android.blog.RssFeedImportActivity;
|
import org.briarproject.briar.android.blog.RssFeedImportActivity;
|
||||||
import org.briarproject.briar.android.blog.RssFeedManageActivity;
|
import org.briarproject.briar.android.blog.RssFeedManageActivity;
|
||||||
import org.briarproject.briar.android.blog.WriteBlogPostActivity;
|
import org.briarproject.briar.android.blog.WriteBlogPostActivity;
|
||||||
|
import org.briarproject.briar.android.contact.AliasDialogFragment;
|
||||||
import org.briarproject.briar.android.contact.ContactListFragment;
|
import org.briarproject.briar.android.contact.ContactListFragment;
|
||||||
import org.briarproject.briar.android.contact.ContactModule;
|
import org.briarproject.briar.android.contact.ContactModule;
|
||||||
import org.briarproject.briar.android.contact.ConversationActivity;
|
import org.briarproject.briar.android.contact.ConversationActivity;
|
||||||
@@ -211,4 +212,7 @@ public interface ActivityComponent {
|
|||||||
void inject(ScreenFilterDialogFragment fragment);
|
void inject(ScreenFilterDialogFragment fragment);
|
||||||
|
|
||||||
void inject(ContactExchangeErrorFragment fragment);
|
void inject(ContactExchangeErrorFragment fragment);
|
||||||
|
|
||||||
|
void inject(AliasDialogFragment aliasDialogFragment);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package org.briarproject.briar.android.contact;
|
||||||
|
|
||||||
|
import android.arch.lifecycle.ViewModelProvider;
|
||||||
|
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.briar.R;
|
||||||
|
import org.briarproject.briar.android.activity.BriarActivity;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
|
|
||||||
|
public class AliasDialogFragment extends AppCompatDialogFragment {
|
||||||
|
|
||||||
|
final static String TAG = AliasDialogFragment.class.getName();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ViewModelProvider.Factory viewModelFactory;
|
||||||
|
|
||||||
|
private ConversationViewModel viewModel;
|
||||||
|
private EditText aliasEditText;
|
||||||
|
|
||||||
|
public static AliasDialogFragment newInstance() {
|
||||||
|
return new AliasDialogFragment();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
setStyle(STYLE_NO_TITLE, R.style.BriarDialogTheme);
|
||||||
|
|
||||||
|
if (getActivity() == null) return;
|
||||||
|
((BriarActivity) getActivity()).getActivityComponent().inject(this);
|
||||||
|
viewModel = ViewModelProviders.of(getActivity(), viewModelFactory)
|
||||||
|
.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 = requireNonNull(viewModel.getContact().getValue());
|
||||||
|
String alias = contact.getAlias();
|
||||||
|
aliasEditText.setText(alias);
|
||||||
|
if (alias != null) aliasEditText.setSelection(alias.length());
|
||||||
|
|
||||||
|
Button setButton = v.findViewById(R.id.setButton);
|
||||||
|
setButton.setOnClickListener(v1 -> {
|
||||||
|
viewModel.setContactAlias(aliasEditText.getText().toString());
|
||||||
|
getDialog().dismiss();
|
||||||
|
});
|
||||||
|
|
||||||
|
Button cancelButton = v.findViewById(R.id.cancelButton);
|
||||||
|
cancelButton.setOnClickListener(v1 -> getDialog().cancel());
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
package org.briarproject.briar.android.contact;
|
package org.briarproject.briar.android.contact;
|
||||||
|
|
||||||
import android.arch.lifecycle.MutableLiveData;
|
|
||||||
import android.arch.lifecycle.Observer;
|
import android.arch.lifecycle.Observer;
|
||||||
|
import android.arch.lifecycle.ViewModelProvider;
|
||||||
|
import android.arch.lifecycle.ViewModelProviders;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -23,7 +24,6 @@ import android.widget.TextView;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.FormatException;
|
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.ContactId;
|
||||||
import org.briarproject.bramble.api.contact.ContactManager;
|
import org.briarproject.bramble.api.contact.ContactManager;
|
||||||
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
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.Event;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.event.EventListener;
|
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.MethodsNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.ConnectionRegistry;
|
import org.briarproject.bramble.api.plugin.ConnectionRegistry;
|
||||||
@@ -96,6 +95,7 @@ import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.PromptSt
|
|||||||
import static android.support.v4.view.ViewCompat.setTransitionName;
|
import static android.support.v4.view.ViewCompat.setTransitionName;
|
||||||
import static android.support.v7.util.SortedList.INVALID_POSITION;
|
import static android.support.v7.util.SortedList.INVALID_POSITION;
|
||||||
import static android.widget.Toast.LENGTH_SHORT;
|
import static android.widget.Toast.LENGTH_SHORT;
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||||
@@ -105,6 +105,7 @@ import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_INTRO
|
|||||||
import static org.briarproject.briar.android.settings.SettingsFragment.SETTINGS_NAMESPACE;
|
import static org.briarproject.briar.android.settings.SettingsFragment.SETTINGS_NAMESPACE;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.getAvatarTransitionName;
|
import static org.briarproject.briar.android.util.UiUtils.getAvatarTransitionName;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.getBulbTransitionName;
|
import static org.briarproject.briar.android.util.UiUtils.getBulbTransitionName;
|
||||||
|
import static org.briarproject.briar.android.util.UiUtils.observeOnce;
|
||||||
import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_TEXT_LENGTH;
|
import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_TEXT_LENGTH;
|
||||||
import static uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.STATE_DISMISSED;
|
import static uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.STATE_DISMISSED;
|
||||||
import static uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.STATE_FINISHED;
|
import static uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.STATE_FINISHED;
|
||||||
@@ -131,8 +132,8 @@ public class ConversationActivity extends BriarActivity
|
|||||||
Executor cryptoExecutor;
|
Executor cryptoExecutor;
|
||||||
|
|
||||||
private final Map<MessageId, String> textCache = new ConcurrentHashMap<>();
|
private final Map<MessageId, String> textCache = new ConcurrentHashMap<>();
|
||||||
private final MutableLiveData<String> contactName = new MutableLiveData<>();
|
|
||||||
|
|
||||||
|
private ConversationViewModel viewModel;
|
||||||
private ConversationVisitor visitor;
|
private ConversationVisitor visitor;
|
||||||
private ConversationAdapter adapter;
|
private ConversationAdapter adapter;
|
||||||
private Toolbar toolbar;
|
private Toolbar toolbar;
|
||||||
@@ -163,14 +164,18 @@ public class ConversationActivity extends BriarActivity
|
|||||||
volatile BlogSharingManager blogSharingManager;
|
volatile BlogSharingManager blogSharingManager;
|
||||||
@Inject
|
@Inject
|
||||||
volatile GroupInvitationManager groupInvitationManager;
|
volatile GroupInvitationManager groupInvitationManager;
|
||||||
|
@Inject
|
||||||
|
ViewModelProvider.Factory viewModelFactory;
|
||||||
|
|
||||||
private volatile ContactId contactId;
|
private volatile ContactId contactId;
|
||||||
@Nullable
|
@Nullable
|
||||||
private volatile AuthorId contactAuthorId;
|
|
||||||
@Nullable
|
|
||||||
private volatile GroupId messagingGroupId;
|
private volatile GroupId messagingGroupId;
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
private final Observer<String> contactNameObserver = name -> {
|
||||||
|
requireNonNull(name);
|
||||||
|
loadMessages();
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle state) {
|
public void onCreate(@Nullable Bundle state) {
|
||||||
setSceneTransitionAnimation();
|
setSceneTransitionAnimation();
|
||||||
@@ -181,20 +186,37 @@ public class ConversationActivity extends BriarActivity
|
|||||||
if (id == -1) throw new IllegalStateException();
|
if (id == -1) throw new IllegalStateException();
|
||||||
contactId = new ContactId(id);
|
contactId = new ContactId(id);
|
||||||
|
|
||||||
|
viewModel = ViewModelProviders.of(this, viewModelFactory)
|
||||||
|
.get(ConversationViewModel.class);
|
||||||
|
viewModel.setContactId(contactId);
|
||||||
|
|
||||||
setContentView(R.layout.activity_conversation);
|
setContentView(R.layout.activity_conversation);
|
||||||
|
|
||||||
// Custom Toolbar
|
// Custom Toolbar
|
||||||
toolbar = setUpCustomToolbar(true);
|
toolbar = requireNonNull(setUpCustomToolbar(true));
|
||||||
if (toolbar != null) {
|
toolbarAvatar = toolbar.findViewById(R.id.contactAvatar);
|
||||||
toolbarAvatar = toolbar.findViewById(R.id.contactAvatar);
|
toolbarStatus = toolbar.findViewById(R.id.contactStatus);
|
||||||
toolbarStatus = toolbar.findViewById(R.id.contactStatus);
|
toolbarTitle = toolbar.findViewById(R.id.contactName);
|
||||||
toolbarTitle = toolbar.findViewById(R.id.contactName);
|
|
||||||
}
|
observeOnce(viewModel.getContactAuthorId(), this, authorId -> {
|
||||||
|
requireNonNull(authorId);
|
||||||
|
toolbarAvatar.setImageDrawable(
|
||||||
|
new IdenticonDrawable(authorId.getBytes()));
|
||||||
|
});
|
||||||
|
viewModel.getContactDisplayName().observe(this, contactName -> {
|
||||||
|
requireNonNull(contactName);
|
||||||
|
toolbarTitle.setText(contactName);
|
||||||
|
});
|
||||||
|
viewModel.isContactDeleted().observe(this, deleted -> {
|
||||||
|
requireNonNull(deleted);
|
||||||
|
if (deleted) finish();
|
||||||
|
});
|
||||||
|
|
||||||
setTransitionName(toolbarAvatar, getAvatarTransitionName(contactId));
|
setTransitionName(toolbarAvatar, getAvatarTransitionName(contactId));
|
||||||
setTransitionName(toolbarStatus, getBulbTransitionName(contactId));
|
setTransitionName(toolbarStatus, getBulbTransitionName(contactId));
|
||||||
|
|
||||||
visitor = new ConversationVisitor(this, this, contactName);
|
visitor = new ConversationVisitor(this, this,
|
||||||
|
viewModel.getContactDisplayName());
|
||||||
adapter = new ConversationAdapter(this, this);
|
adapter = new ConversationAdapter(this, this);
|
||||||
list = findViewById(R.id.conversationView);
|
list = findViewById(R.id.conversationView);
|
||||||
list.setLayoutManager(new LinearLayoutManager(this));
|
list.setLayoutManager(new LinearLayoutManager(this));
|
||||||
@@ -229,7 +251,7 @@ public class ConversationActivity extends BriarActivity
|
|||||||
notificationManager.blockContactNotification(contactId);
|
notificationManager.blockContactNotification(contactId);
|
||||||
notificationManager.clearContactNotification(contactId);
|
notificationManager.clearContactNotification(contactId);
|
||||||
displayContactOnlineStatus();
|
displayContactOnlineStatus();
|
||||||
loadContactDetailsAndMessages();
|
viewModel.getContactDisplayName().observe(this, contactNameObserver);
|
||||||
list.startPeriodicUpdate();
|
list.startPeriodicUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,6 +260,7 @@ public class ConversationActivity extends BriarActivity
|
|||||||
super.onStop();
|
super.onStop();
|
||||||
eventBus.removeListener(this);
|
eventBus.removeListener(this);
|
||||||
notificationManager.unblockContactNotification(contactId);
|
notificationManager.unblockContactNotification(contactId);
|
||||||
|
viewModel.getContactDisplayName().removeObserver(contactNameObserver);
|
||||||
list.stopPeriodicUpdate();
|
list.stopPeriodicUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,6 +272,8 @@ public class ConversationActivity extends BriarActivity
|
|||||||
|
|
||||||
enableIntroductionActionIfAvailable(
|
enableIntroductionActionIfAvailable(
|
||||||
menu.findItem(R.id.action_introduction));
|
menu.findItem(R.id.action_introduction));
|
||||||
|
enableAliasActionIfAvailable(
|
||||||
|
menu.findItem(R.id.action_set_alias));
|
||||||
|
|
||||||
return super.onCreateOptionsMenu(menu);
|
return super.onCreateOptionsMenu(menu);
|
||||||
}
|
}
|
||||||
@@ -266,6 +291,10 @@ public class ConversationActivity extends BriarActivity
|
|||||||
intent.putExtra(CONTACT_ID, contactId.getInt());
|
intent.putExtra(CONTACT_ID, contactId.getInt());
|
||||||
startActivityForResult(intent, REQUEST_INTRODUCTION);
|
startActivityForResult(intent, REQUEST_INTRODUCTION);
|
||||||
return true;
|
return true;
|
||||||
|
case R.id.action_set_alias:
|
||||||
|
AliasDialogFragment.newInstance().show(
|
||||||
|
getSupportFragmentManager(), AliasDialogFragment.TAG);
|
||||||
|
return true;
|
||||||
case R.id.action_social_remove_person:
|
case R.id.action_social_remove_person:
|
||||||
askToRemoveContact();
|
askToRemoveContact();
|
||||||
return true;
|
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() {
|
private void displayContactOnlineStatus() {
|
||||||
runOnUiThreadUnlessDestroyed(() -> {
|
runOnUiThreadUnlessDestroyed(() -> {
|
||||||
if (connectionRegistry.isConnected(contactId)) {
|
if (connectionRegistry.isConnected(contactId)) {
|
||||||
@@ -453,21 +452,9 @@ public class ConversationActivity extends BriarActivity
|
|||||||
private void onNewPrivateMessage(PrivateMessageHeader h) {
|
private void onNewPrivateMessage(PrivateMessageHeader h) {
|
||||||
runOnUiThreadUnlessDestroyed(() -> {
|
runOnUiThreadUnlessDestroyed(() -> {
|
||||||
if (h instanceof PrivateRequest || h instanceof PrivateResponse) {
|
if (h instanceof PrivateRequest || h instanceof PrivateResponse) {
|
||||||
String cName = contactName.getValue();
|
// contact name might not have been loaded
|
||||||
if (cName == null) {
|
observeOnce(viewModel.getContactDisplayName(), this,
|
||||||
// Wait for the contact name to be loaded
|
name -> addConversationItem(h.accept(visitor)));
|
||||||
contactName.observe(this, new Observer<String>() {
|
|
||||||
@Override
|
|
||||||
public void onChanged(@Nullable String cName) {
|
|
||||||
if (cName != null) {
|
|
||||||
addConversationItem(h.accept(visitor));
|
|
||||||
contactName.removeObserver(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
addConversationItem(h.accept(visitor));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
addConversationItem(h.accept(visitor));
|
addConversationItem(h.accept(visitor));
|
||||||
loadMessageText(h.getId());
|
loadMessageText(h.getId());
|
||||||
@@ -605,6 +592,10 @@ public class ConversationActivity extends BriarActivity
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void enableAliasActionIfAvailable(MenuItem item) {
|
||||||
|
observeOnce(viewModel.getContact(), this, c -> item.setEnabled(true));
|
||||||
|
}
|
||||||
|
|
||||||
private void enableIntroductionAction(MenuItem item) {
|
private void enableIntroductionAction(MenuItem item) {
|
||||||
runOnUiThreadUnlessDestroyed(() -> item.setEnabled(true));
|
runOnUiThreadUnlessDestroyed(() -> item.setEnabled(true));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,115 @@
|
|||||||
|
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.Nullable;
|
||||||
|
|
||||||
|
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.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
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.Objects.requireNonNull;
|
||||||
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
public class ConversationViewModel extends AndroidViewModel {
|
||||||
|
|
||||||
|
private static Logger LOG =
|
||||||
|
getLogger(ConversationViewModel.class.getName());
|
||||||
|
|
||||||
|
@DatabaseExecutor
|
||||||
|
private final Executor dbExecutor;
|
||||||
|
private final ContactManager contactManager;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private ContactId contactId = null;
|
||||||
|
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<>();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ConversationViewModel(Application application,
|
||||||
|
@DatabaseExecutor Executor dbExecutor,
|
||||||
|
ContactManager contactManager) {
|
||||||
|
super(application);
|
||||||
|
this.dbExecutor = dbExecutor;
|
||||||
|
this.contactManager = contactManager;
|
||||||
|
contactDeleted.setValue(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setContactId(ContactId contactId) {
|
||||||
|
if (this.contactId == null) {
|
||||||
|
this.contactId = contactId;
|
||||||
|
loadContact();
|
||||||
|
} else if (!contactId.equals(this.contactId)) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadContact() {
|
||||||
|
dbExecutor.execute(() -> {
|
||||||
|
try {
|
||||||
|
long start = now();
|
||||||
|
Contact c =
|
||||||
|
contactManager.getContact(requireNonNull(contactId));
|
||||||
|
contact.postValue(c);
|
||||||
|
logDuration(LOG, "Loading contact", start);
|
||||||
|
} catch (NoSuchContactException e) {
|
||||||
|
contactDeleted.postValue(true);
|
||||||
|
} catch (DbException e) {
|
||||||
|
logException(LOG, WARNING, e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void setContactAlias(String alias) {
|
||||||
|
dbExecutor.execute(() -> {
|
||||||
|
try {
|
||||||
|
contactManager.setContactAlias(requireNonNull(contactId),
|
||||||
|
alias.isEmpty() ? null : alias);
|
||||||
|
loadContact();
|
||||||
|
} 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -3,6 +3,9 @@ package org.briarproject.briar.android.util;
|
|||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.app.KeyguardManager;
|
import android.app.KeyguardManager;
|
||||||
|
import android.arch.lifecycle.LifecycleOwner;
|
||||||
|
import android.arch.lifecycle.LiveData;
|
||||||
|
import android.arch.lifecycle.Observer;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface.OnClickListener;
|
import android.content.DialogInterface.OnClickListener;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -11,6 +14,7 @@ import android.os.PowerManager;
|
|||||||
import android.support.annotation.AttrRes;
|
import android.support.annotation.AttrRes;
|
||||||
import android.support.annotation.ColorInt;
|
import android.support.annotation.ColorInt;
|
||||||
import android.support.annotation.ColorRes;
|
import android.support.annotation.ColorRes;
|
||||||
|
import android.support.annotation.MainThread;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.design.widget.TextInputLayout;
|
import android.support.design.widget.TextInputLayout;
|
||||||
import android.support.v4.app.FragmentManager;
|
import android.support.v4.app.FragmentManager;
|
||||||
@@ -314,4 +318,21 @@ public class UiUtils {
|
|||||||
keyEvent.getKeyCode() == KEYCODE_ENTER;
|
keyEvent.getKeyCode() == KEYCODE_ENTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Observes the given {@link LiveData} until the first change.
|
||||||
|
* If the LiveData's value is available, the {@link Observer} will be
|
||||||
|
* called right away.
|
||||||
|
*/
|
||||||
|
@MainThread
|
||||||
|
public static <T> void observeOnce(LiveData<T> liveData,
|
||||||
|
LifecycleOwner owner, Observer<T> observer) {
|
||||||
|
liveData.observe(owner, new Observer<T>() {
|
||||||
|
@Override
|
||||||
|
public void onChanged(@Nullable T t) {
|
||||||
|
observer.onChanged(t);
|
||||||
|
liveData.removeObserver(this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* 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 org.briarproject.briar.android.viewmodel;
|
||||||
|
|
||||||
|
import android.arch.lifecycle.ViewModel;
|
||||||
|
import android.arch.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Provider;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@NotNullByDefault
|
||||||
|
class ViewModelFactory implements ViewModelProvider.Factory {
|
||||||
|
|
||||||
|
private final Map<Class<? extends ViewModel>, Provider<ViewModel>> creators;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ViewModelFactory(Map<Class<? extends ViewModel>,
|
||||||
|
Provider<ViewModel>> creators) {
|
||||||
|
this.creators = creators;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends ViewModel> T create(Class<T> modelClass) {
|
||||||
|
Provider<? extends ViewModel> creator = creators.get(modelClass);
|
||||||
|
if (creator == null) {
|
||||||
|
for (Entry<Class<? extends ViewModel>, Provider<ViewModel>> entry :
|
||||||
|
creators.entrySet()) {
|
||||||
|
if (modelClass.isAssignableFrom(entry.getKey())) {
|
||||||
|
creator = entry.getValue();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (creator == null) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"unknown model class " + modelClass);
|
||||||
|
}
|
||||||
|
//noinspection unchecked
|
||||||
|
return (T) creator.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package org.briarproject.briar.android.viewmodel;
|
||||||
|
|
||||||
|
import android.arch.lifecycle.ViewModel;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import dagger.MapKey;
|
||||||
|
|
||||||
|
@Documented
|
||||||
|
@Target({ElementType.METHOD})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@MapKey
|
||||||
|
@interface ViewModelKey {
|
||||||
|
Class<? extends ViewModel> value();
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package org.briarproject.briar.android.viewmodel;
|
||||||
|
|
||||||
|
import android.arch.lifecycle.ViewModel;
|
||||||
|
import android.arch.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
|
import org.briarproject.briar.android.contact.ConversationViewModel;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import dagger.Binds;
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.multibindings.IntoMap;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public abstract class ViewModelModule {
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@ViewModelKey(ConversationViewModel.class)
|
||||||
|
abstract ViewModel bindConversationViewModel(
|
||||||
|
ConversationViewModel conversationViewModel);
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@Singleton
|
||||||
|
abstract ViewModelProvider.Factory bindViewModelFactory(
|
||||||
|
ViewModelFactory viewModelFactory);
|
||||||
|
|
||||||
|
}
|
||||||
54
briar-android/src/main/res/layout/fragment_alias_dialog.xml
Normal file
54
briar-android/src/main/res/layout/fragment_alias_dialog.xml
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<?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:paddingLeft="16dp"
|
||||||
|
android:paddingRight="16dp"
|
||||||
|
android:paddingTop="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>
|
||||||
@@ -1,75 +1,69 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
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"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
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
|
<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_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
|
<Button
|
||||||
android:id="@+id/cancelButton"
|
android:id="@+id/cancelButton"
|
||||||
style="@style/BriarButtonFlat.Positive"
|
style="@style/BriarButtonFlat.Positive"
|
||||||
android:layout_width="0dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/cancel"
|
android:text="@string/cancel"/>
|
||||||
app:layout_constraintEnd_toStartOf="@+id/openButton"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"/>
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/openButton"
|
android:id="@+id/openButton"
|
||||||
style="@style/BriarButtonFlat.Negative"
|
style="@style/BriarButtonFlat.Negative"
|
||||||
android:layout_width="0dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/link_warning_open_link"
|
android:text="@string/link_warning_open_link"/>
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/cancelButton"/>
|
|
||||||
|
|
||||||
</android.support.constraint.ConstraintLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
@@ -10,6 +10,12 @@
|
|||||||
android:enabled="false"
|
android:enabled="false"
|
||||||
app:showAsAction="never"/>
|
app:showAsAction="never"/>
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_set_alias"
|
||||||
|
android:title="@string/set_contact_alias"
|
||||||
|
android:enabled="false"
|
||||||
|
app:showAsAction="never"/>
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_social_remove_person"
|
android:id="@+id/action_social_remove_person"
|
||||||
android:icon="@drawable/action_delete_white"
|
android:icon="@drawable/action_delete_white"
|
||||||
|
|||||||
@@ -127,6 +127,9 @@
|
|||||||
<string name="date_no_private_messages">No messages.</string>
|
<string name="date_no_private_messages">No messages.</string>
|
||||||
<string name="no_private_messages">No messages to show</string>
|
<string name="no_private_messages">No messages to show</string>
|
||||||
<string name="message_hint">Type message</string>
|
<string name="message_hint">Type message</string>
|
||||||
|
<string name="set_contact_alias">Change contact name</string>
|
||||||
|
<string name="set_contact_alias_hint">Contact name</string>
|
||||||
|
<string name="set_alias">Set</string>
|
||||||
<string name="delete_contact">Delete contact</string>
|
<string name="delete_contact">Delete contact</string>
|
||||||
<string name="dialog_title_delete_contact">Confirm Contact Deletion</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>
|
<string name="dialog_message_delete_contact">Are you sure that you want to remove this contact and all messages exchanged with this contact?</string>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ dependencyVerification {
|
|||||||
'android.arch.core:common:1.1.1:common-1.1.1.jar:3a616a32f433e9e23f556b38575c31b013613d3ae85206263b7625fe1f4c151a',
|
'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.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: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-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:livedata:1.1.1:livedata-1.1.1.aar:50ab0490c1ff1a7cfb4e554032998b080888946d0dd424f39900efc4a1bcd750',
|
||||||
'android.arch.lifecycle:runtime:1.1.1:runtime-1.1.1.aar:c4e4be66c1b2f0abec593571454e1de14013f7e0f96bf2a9f212931a48cae550',
|
'android.arch.lifecycle:runtime:1.1.1:runtime-1.1.1.aar:c4e4be66c1b2f0abec593571454e1de14013f7e0f96bf2a9f212931a48cae550',
|
||||||
|
|||||||
Reference in New Issue
Block a user