added interface to edit nick

This commit is contained in:
Daniel Gultsch 2018-11-09 17:47:36 +01:00
parent aca4ba981f
commit 5012ff3545
18 changed files with 2332 additions and 1924 deletions

View file

@ -2,6 +2,7 @@ package eu.siacs.conversations.entities;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.text.TextUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -380,7 +381,12 @@ public class MucOptions {
} else if (!conversation.getJid().isBareJid()) { } else if (!conversation.getJid().isBareJid()) {
return conversation.getJid().getResource(); return conversation.getJid().getResource();
} else { } else {
final String displayName = account.getDisplayName();
if (TextUtils.isEmpty(displayName)) {
return JidHelper.localPartOrFallback(account.getJid()); return JidHelper.localPartOrFallback(account.getJid());
} else {
return displayName;
}
} }
} }

View file

@ -35,7 +35,7 @@ public abstract class AbstractGenerator {
"http://jabber.org/protocol/caps", "http://jabber.org/protocol/caps",
"http://jabber.org/protocol/disco#info", "http://jabber.org/protocol/disco#info",
"urn:xmpp:avatar:metadata+notify", "urn:xmpp:avatar:metadata+notify",
"http://jabber.org/protocol/nick+notify", Namespace.NICK+"+notify",
Namespace.BOOKMARKS+"+notify", Namespace.BOOKMARKS+"+notify",
"urn:xmpp:ping", "urn:xmpp:ping",
"jabber:iq:version", "jabber:iq:version",

View file

@ -127,8 +127,15 @@ public class IqGenerator extends AbstractGenerator {
public IqPacket publishNick(String nick) { public IqPacket publishNick(String nick) {
final Element item = new Element("item"); final Element item = new Element("item");
item.addChild("nick", "http://jabber.org/protocol/nick").setContent(nick); item.addChild("nick", Namespace.NICK).setContent(nick);
return publish("http://jabber.org/protocol/nick", item); return publish(Namespace.NICK, item);
}
public IqPacket deleteNode(String node) {
IqPacket packet = new IqPacket(IqPacket.TYPE.SET);
final Element pubsub = packet.addChild("pubsub", Namespace.PUBSUB_OWNER);
pubsub.addChild("delete").setAttribute("node",node);
return packet;
} }
public IqPacket publishAvatar(Avatar avatar) { public IqPacket publishAvatar(Avatar avatar) {

View file

@ -194,16 +194,11 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
mXmppConnectionService.fetchAvatar(account, avatar); mXmppConnectionService.fetchAvatar(account, avatar);
} }
} }
} else if ("http://jabber.org/protocol/nick".equals(node)) { } else if (Namespace.NICK.equals(node)) {
final Element i = items.findChild("item"); final Element i = items.findChild("item");
final String nick = i == null ? null : i.findChildContent("nick", Namespace.NICK); final String nick = i == null ? null : i.findChildContent("nick", Namespace.NICK);
if (nick != null) { if (nick != null) {
Contact contact = account.getRoster().getContact(from); setNick(account, from, nick);
if (contact.setPresenceName(nick)) {
mXmppConnectionService.getAvatarService().clear(contact);
}
mXmppConnectionService.updateConversationUi();
mXmppConnectionService.updateAccountUi();
} }
} else if (AxolotlService.PEP_DEVICE_LIST.equals(node)) { } else if (AxolotlService.PEP_DEVICE_LIST.equals(node)) {
Element item = items.findChild("item"); Element item = items.findChild("item");
@ -212,15 +207,40 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
AxolotlService axolotlService = account.getAxolotlService(); AxolotlService axolotlService = account.getAxolotlService();
axolotlService.registerDevices(from, deviceIds); axolotlService.registerDevices(from, deviceIds);
} else if (Namespace.BOOKMARKS.equals(node)) { } else if (Namespace.BOOKMARKS.equals(node)) {
Log.d(Config.LOGTAG,"received bookmarks from "+from); Log.d(Config.LOGTAG, "received bookmarks from " + from);
if (account.getJid().asBareJid().equals(from)) { if (account.getJid().asBareJid().equals(from)) {
final Element i = items.findChild("item"); final Element i = items.findChild("item");
final Element storage = i == null ? null : i.findChild("storage", Namespace.BOOKMARKS); final Element storage = i == null ? null : i.findChild("storage", Namespace.BOOKMARKS);
mXmppConnectionService.processBookmarks(account,storage); mXmppConnectionService.processBookmarks(account, storage);
} }
} }
} }
private void parseDeleteEvent(final Element event, final Jid from, final Account account) {
final Element delete = event.findChild("delete");
if (delete == null) {
return;
}
String node = delete.getAttribute("node");
if (Namespace.NICK.equals(node)) {
Log.d(Config.LOGTAG, "parsing nick delete event from " + from);
setNick(account, from, null);
}
}
private void setNick(Account account, Jid user, String nick) {
if (user.asBareJid().equals(account.getJid().asBareJid())) {
account.setDisplayName(nick);
} else {
Contact contact = account.getRoster().getContact(user);
if (contact.setPresenceName(nick)) {
mXmppConnectionService.getAvatarService().clear(contact);
}
}
mXmppConnectionService.updateConversationUi();
mXmppConnectionService.updateAccountUi();
}
private boolean handleErrorMessage(Account account, MessagePacket packet) { private boolean handleErrorMessage(Account account, MessagePacket packet) {
if (packet.getType() == MessagePacket.TYPE_ERROR) { if (packet.getType() == MessagePacket.TYPE_ERROR) {
Jid from = packet.getFrom(); Jid from = packet.getFrom();
@ -551,7 +571,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
serverMsgIdUpdated = true; serverMsgIdUpdated = true;
} else { } else {
serverMsgIdUpdated = false; serverMsgIdUpdated = false;
Log.e(Config.LOGTAG,"failed to update message"); Log.e(Config.LOGTAG, "failed to update message");
} }
} else { } else {
serverMsgIdUpdated = false; serverMsgIdUpdated = false;
@ -757,9 +777,13 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
} }
} }
Element event = original.findChild("event", "http://jabber.org/protocol/pubsub#event"); final Element event = original.findChild("event", "http://jabber.org/protocol/pubsub#event");
if (event != null && InvalidJid.hasValidFrom(original)) { if (event != null && InvalidJid.hasValidFrom(original)) {
if (event.hasChild("items")) {
parseEvent(event, original.getFrom(), account); parseEvent(event, original.getFrom(), account);
} else if (event.hasChild("delete")) {
parseDeleteEvent(event, original.getFrom(), account);
}
} }
final String nick = packet.findChildContent("nick", Namespace.NICK); final String nick = packet.findChildContent("nick", Namespace.NICK);

View file

@ -285,11 +285,19 @@ public class XmppConnectionService extends Service {
} }
} }
} }
boolean needsUpdating = account.setOption(Account.OPTION_LOGGED_IN_SUCCESSFULLY, true); boolean loggedInSuccessfully = account.setOption(Account.OPTION_LOGGED_IN_SUCCESSFULLY, true);
needsUpdating |= account.setOption(Account.OPTION_HTTP_UPLOAD_AVAILABLE, account.getXmppConnection().getFeatures().httpUpload(0)); boolean gainedFeature = account.setOption(Account.OPTION_HTTP_UPLOAD_AVAILABLE, account.getXmppConnection().getFeatures().httpUpload(0));
if (needsUpdating) { if (loggedInSuccessfully || gainedFeature) {
databaseBackend.updateAccount(account); databaseBackend.updateAccount(account);
} }
if (loggedInSuccessfully) {
if (!TextUtils.isEmpty(account.getDisplayName())) {
Log.d(Config.LOGTAG,account.getJid().asBareJid()+": display name wasn't empty on first log in. publishing");
publishDisplayName(account);
}
}
account.getRoster().clearPresences(); account.getRoster().clearPresences();
mJingleConnectionManager.cancelInTransmission(); mJingleConnectionManager.cancelInTransmission();
mQuickConversationsService.considerSyncBackground(false); mQuickConversationsService.considerSyncBackground(false);
@ -3828,15 +3836,18 @@ public class XmppConnectionService extends Service {
public void publishDisplayName(Account account) { public void publishDisplayName(Account account) {
String displayName = account.getDisplayName(); String displayName = account.getDisplayName();
if (displayName != null && !displayName.isEmpty()) { final IqPacket request;
IqPacket publish = mIqGenerator.publishNick(displayName); if (TextUtils.isEmpty(displayName)) {
sendIqPacket(account, publish, (account1, packet) -> { request = mIqGenerator.deleteNode(Namespace.NICK);
} else {
request = mIqGenerator.publishNick(displayName);
}
sendIqPacket(account, request, (account1, packet) -> {
if (packet.getType() == IqPacket.TYPE.ERROR) { if (packet.getType() == IqPacket.TYPE.ERROR) {
Log.d(Config.LOGTAG, account1.getJid().asBareJid() + ": could not publish nick"); Log.d(Config.LOGTAG, account1.getJid().asBareJid() + ": unable to modify nick name "+packet.toString());
} }
}); });
} }
}
public ServiceDiscoveryResult getCachedServiceDiscoveryResult(Pair<String, String> key) { public ServiceDiscoveryResult getCachedServiceDiscoveryResult(Pair<String, String> key) {
ServiceDiscoveryResult result = discoCache.get(key); ServiceDiscoveryResult result = discoCache.get(key);

View file

@ -80,20 +80,52 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
private static final int REQUEST_DATA_SAVER = 0xf244; private static final int REQUEST_DATA_SAVER = 0xf244;
private static final int REQUEST_CHANGE_STATUS = 0xee11; private static final int REQUEST_CHANGE_STATUS = 0xee11;
private final PendingItem<PresenceTemplate> mPendingPresenceTemplate = new PendingItem<>();
private AlertDialog mCaptchaDialog = null; private AlertDialog mCaptchaDialog = null;
private Jid jidToEdit; private Jid jidToEdit;
private boolean mInitMode = false; private boolean mInitMode = false;
private boolean mUsernameMode = Config.DOMAIN_LOCK != null; private boolean mUsernameMode = Config.DOMAIN_LOCK != null;
private boolean mShowOptions = false; private boolean mShowOptions = false;
private Account mAccount; private Account mAccount;
private final OnClickListener mCancelButtonClickListener = v -> {
deleteAccountAndReturnIfNecessary();
finish();
};
private final UiCallback<Avatar> mAvatarFetchCallback = new UiCallback<Avatar>() {
@Override
public void userInputRequried(final PendingIntent pi, final Avatar avatar) {
finishInitialSetup(avatar);
}
@Override
public void success(final Avatar avatar) {
finishInitialSetup(avatar);
}
@Override
public void error(final int errorCode, final Avatar avatar) {
finishInitialSetup(avatar);
}
};
private final OnClickListener mAvatarClickListener = new OnClickListener() {
@Override
public void onClick(final View view) {
if (mAccount != null) {
final Intent intent = new Intent(getApplicationContext(), PublishProfilePictureActivity.class);
intent.putExtra(EXTRA_ACCOUNT, mAccount.getJid().asBareJid().toString());
startActivity(intent);
}
}
};
private String messageFingerprint; private String messageFingerprint;
private final PendingItem<PresenceTemplate> mPendingPresenceTemplate = new PendingItem<>();
private boolean mFetchingAvatar = false; private boolean mFetchingAvatar = false;
private Toast mFetchingMamPrefsToast;
private String mSavedInstanceAccount;
private boolean mSavedInstanceInit = false;
private XmppUri pendingUri = null;
private boolean mUseTor;
private ActivityEditAccountBinding binding;
private final OnClickListener mSaveButtonClickListener = new OnClickListener() { private final OnClickListener mSaveButtonClickListener = new OnClickListener() {
@Override @Override
@ -236,16 +268,71 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
} }
}; };
private final OnClickListener mCancelButtonClickListener = v -> { private final TextWatcher mTextWatcher = new TextWatcher() {
deleteAccountAndReturnIfNecessary();
finish(); @Override
public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
updatePortLayout();
updateSaveButton();
}
@Override
public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {
}
@Override
public void afterTextChanged(final Editable s) {
}
}; };
private Toast mFetchingMamPrefsToast; private View.OnFocusChangeListener mEditTextFocusListener = new View.OnFocusChangeListener() {
private String mSavedInstanceAccount; @Override
private boolean mSavedInstanceInit = false; public void onFocusChange(View view, boolean b) {
private XmppUri pendingUri = null; EditText et = (EditText) view;
private boolean mUseTor; if (b) {
private ActivityEditAccountBinding binding; int resId = mUsernameMode ? R.string.username : R.string.account_settings_example_jabber_id;
if (view.getId() == R.id.hostname) {
resId = mUseTor ? R.string.hostname_or_onion : R.string.hostname_example;
}
final int res = resId;
new Handler().postDelayed(() -> et.setHint(res), 200);
} else {
et.setHint(null);
}
}
};
private static void setAvailabilityRadioButton(Presence.Status status, DialogPresenceBinding binding) {
if (status == null) {
binding.online.setChecked(true);
return;
}
switch (status) {
case DND:
binding.dnd.setChecked(true);
break;
case XA:
binding.xa.setChecked(true);
break;
case AWAY:
binding.xa.setChecked(true);
break;
default:
binding.online.setChecked(true);
}
}
private static Presence.Status getAvailabilityRadioButton(DialogPresenceBinding binding) {
if (binding.dnd.isChecked()) {
return Presence.Status.DND;
} else if (binding.xa.isChecked()) {
return Presence.Status.XA;
} else if (binding.away.isChecked()) {
return Presence.Status.AWAY;
} else {
return Presence.Status.ONLINE;
}
}
public void refreshUiReal() { public void refreshUiReal() {
invalidateOptionsMenu(); invalidateOptionsMenu();
@ -296,70 +383,6 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
refreshUi(); refreshUi();
} }
private final UiCallback<Avatar> mAvatarFetchCallback = new UiCallback<Avatar>() {
@Override
public void userInputRequried(final PendingIntent pi, final Avatar avatar) {
finishInitialSetup(avatar);
}
@Override
public void success(final Avatar avatar) {
finishInitialSetup(avatar);
}
@Override
public void error(final int errorCode, final Avatar avatar) {
finishInitialSetup(avatar);
}
};
private final TextWatcher mTextWatcher = new TextWatcher() {
@Override
public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
updatePortLayout();
updateSaveButton();
}
@Override
public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {
}
@Override
public void afterTextChanged(final Editable s) {
}
};
private View.OnFocusChangeListener mEditTextFocusListener = new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean b) {
EditText et = (EditText) view;
if (b) {
int resId = mUsernameMode ? R.string.username : R.string.account_settings_example_jabber_id;
if (view.getId() == R.id.hostname) {
resId = mUseTor ? R.string.hostname_or_onion : R.string.hostname_example;
}
final int res = resId;
new Handler().postDelayed(() -> et.setHint(res), 200);
} else {
et.setHint(null);
}
}
};
private final OnClickListener mAvatarClickListener = new OnClickListener() {
@Override
public void onClick(final View view) {
if (mAccount != null) {
final Intent intent = new Intent(getApplicationContext(), PublishProfilePictureActivity.class);
intent.putExtra(EXTRA_ACCOUNT, mAccount.getJid().asBareJid().toString());
startActivity(intent);
}
}
};
protected void finishInitialSetup(final Avatar avatar) { protected void finishInitialSetup(final Avatar avatar) {
runOnUiThread(() -> { runOnUiThread(() -> {
SoftKeyboardUtils.hideSoftKeyboard(EditAccountActivity.this); SoftKeyboardUtils.hideSoftKeyboard(EditAccountActivity.this);
@ -406,7 +429,6 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
processFingerprintVerification(uri, true); processFingerprintVerification(uri, true);
} }
protected void processFingerprintVerification(XmppUri uri, boolean showWarningToast) { protected void processFingerprintVerification(XmppUri uri, boolean showWarningToast) {
if (mAccount != null && mAccount.getJid().asBareJid().equals(uri.getJid()) && uri.hasFingerprints()) { if (mAccount != null && mAccount.getJid().asBareJid().equals(uri.getJid()) && uri.hasFingerprints()) {
if (xmppConnectionService.verifyFingerprints(mAccount, uri.getFingerprints())) { if (xmppConnectionService.verifyFingerprints(mAccount, uri.getFingerprints())) {
@ -534,6 +556,17 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
if (Config.DISALLOW_REGISTRATION_IN_UI) { if (Config.DISALLOW_REGISTRATION_IN_UI) {
this.binding.accountRegisterNew.setVisibility(View.GONE); this.binding.accountRegisterNew.setVisibility(View.GONE);
} }
this.binding.actionEditYourName.setOnClickListener(this::onEditYourNameClicked);
}
private void onEditYourNameClicked(View view) {
quickEdit(mAccount.getDisplayName(), R.string.your_name, value -> {
final String displayName = value.trim();
updateDisplayName(displayName);
mAccount.setDisplayName(displayName);
xmppConnectionService.publishDisplayName(mAccount);
return null;
}, true);
} }
@Override @Override
@ -824,38 +857,6 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
}); });
} }
private static void setAvailabilityRadioButton(Presence.Status status, DialogPresenceBinding binding) {
if (status == null) {
binding.online.setChecked(true);
return;
}
switch (status) {
case DND:
binding.dnd.setChecked(true);
break;
case XA:
binding.xa.setChecked(true);
break;
case AWAY:
binding.xa.setChecked(true);
break;
default:
binding.online.setChecked(true);
}
}
private static Presence.Status getAvailabilityRadioButton(DialogPresenceBinding binding) {
if (binding.dnd.isChecked()) {
return Presence.Status.DND;
} else if (binding.xa.isChecked()) {
return Presence.Status.XA;
} else if (binding.away.isChecked()) {
return Presence.Status.AWAY;
} else {
return Presence.Status.ONLINE;
}
}
@Override @Override
public void alias(String alias) { public void alias(String alias) {
if (alias != null) { if (alias != null) {
@ -887,6 +888,10 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
this.binding.accountJid.setFocusableInTouchMode(editable); this.binding.accountJid.setFocusableInTouchMode(editable);
final String displayName = mAccount.getDisplayName();
updateDisplayName(displayName);
if (mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE) || !mAccount.isOptionSet(Account.OPTION_LOGGED_IN_SUCCESSFULLY)) { if (mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE) || !mAccount.isOptionSet(Account.OPTION_LOGGED_IN_SUCCESSFULLY)) {
this.binding.accountPasswordLayout.setPasswordVisibilityToggleEnabled(true); this.binding.accountPasswordLayout.setPasswordVisibilityToggleEnabled(true);
} else { } else {
@ -1055,6 +1060,16 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
} }
} }
private void updateDisplayName(String displayName) {
if (TextUtils.isEmpty(displayName)) {
this.binding.yourName.setText(R.string.no_name_set_instructions);
this.binding.yourName.setTextAppearance(this, R.style.TextAppearance_Conversations_Body1_Tertiary);
} else {
this.binding.yourName.setText(displayName);
this.binding.yourName.setTextAppearance(this, R.style.TextAppearance_Conversations_Body1);
}
}
private void removeErrorsOnAllBut(TextInputLayout exception) { private void removeErrorsOnAllBut(TextInputLayout exception) {
if (this.binding.accountJidLayout != exception) { if (this.binding.accountJidLayout != exception) {
this.binding.accountJidLayout.setErrorEnabled(false); this.binding.accountJidLayout.setErrorEnabled(false);

View file

@ -16,6 +16,7 @@ public final class Namespace {
public static final String PUBSUB = "http://jabber.org/protocol/pubsub"; public static final String PUBSUB = "http://jabber.org/protocol/pubsub";
public static final String PUBSUB_PUBLISH_OPTIONS = PUBSUB+"#publish-options"; public static final String PUBSUB_PUBLISH_OPTIONS = PUBSUB+"#publish-options";
public static final String PUBSUB_ERROR = PUBSUB+"#errors"; public static final String PUBSUB_ERROR = PUBSUB+"#errors";
public static final String PUBSUB_OWNER = PUBSUB+"#owner";
public static final String NICK = "http://jabber.org/protocol/nick"; public static final String NICK = "http://jabber.org/protocol/nick";
public static final String FLEXIBLE_OFFLINE_MESSAGE_RETRIEVAL = "http://jabber.org/protocol/offline"; public static final String FLEXIBLE_OFFLINE_MESSAGE_RETRIEVAL = "http://jabber.org/protocol/offline";
public static final String BIND = "urn:ietf:params:xml:ns:xmpp-bind"; public static final String BIND = "urn:ietf:params:xml:ns:xmpp-bind";

View file

@ -470,11 +470,53 @@
</TableLayout> </TableLayout>
<RelativeLayout <RelativeLayout
android:id="@+id/pgp_fingerprint_box" android:id="@+id/your_name_box"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginTop="32dp"> android:layout_marginTop="32dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_toLeftOf="@+id/action_edit_your_name"
android:orientation="vertical">
<TextView
android:id="@+id/your_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/no_name_set_instructions"
android:textAppearance="@style/TextAppearance.Conversations.Body1.Tertiary"/>
<TextView
android:id="@+id/your_name_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/your_name"
android:textAppearance="@style/TextAppearance.Conversations.Caption"/>
</LinearLayout>
<ImageButton
android:id="@+id/action_edit_your_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:alpha="?attr/icon_alpha"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="@dimen/image_button_padding"
android:src="?attr/icon_edit_body"
android:visibility="visible"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/pgp_fingerprint_box"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginTop="16dp">
<LinearLayout <LinearLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -514,7 +556,7 @@
android:id="@+id/axolotl_fingerprint_box" android:id="@+id/axolotl_fingerprint_box"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginTop="24dp"> android:layout_marginTop="16dp">
<LinearLayout <LinearLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"

View file

@ -515,6 +515,9 @@
<string name="share_uri_with">Share URI with…</string> <string name="share_uri_with">Share URI with…</string>
<string name="welcome_header" translatable="false">Join the Conversation</string> <string name="welcome_header" translatable="false">Join the Conversation</string>
<string name="welcome_text">Jabber is a provider independent instant messaging network. You can use this client with what ever Jabber server you choose.\nHowever for your convenience we made it easy to create an account on conversations.im¹; a provider specially suited for the use with Conversations.</string> <string name="welcome_text">Jabber is a provider independent instant messaging network. You can use this client with what ever Jabber server you choose.\nHowever for your convenience we made it easy to create an account on conversations.im¹; a provider specially suited for the use with Conversations.</string>
<string name="welcome_header_quicksy" translatable="false">Have some Quick Conversations</string>
<string name="welcome_text_quicksy"><![CDATA[Quicksy is a spin off of the popular Jabber/XMPP client Conversations with automatic contact discovery.<br><br>You sign up with your phone number and Quicksy will automatically—based on the phone numbers in your address book—suggest possible contacts to you.<br><br>By signing up you agree to our <a href="https://quicksy.im/#privacy">privacy policy</a>.]]></string>
<string name="agree_and_continue">Agree &amp; continue</string>
<string name="magic_create_text">We will guide you through the process of creating an account on conversations.im.¹\nWhen picking conversations.im as a provider you will be able to communicate with users of other providers by giving them your full Jabber ID.</string> <string name="magic_create_text">We will guide you through the process of creating an account on conversations.im.¹\nWhen picking conversations.im as a provider you will be able to communicate with users of other providers by giving them your full Jabber ID.</string>
<string name="your_full_jid_will_be">Your full Jabber ID will be: %s</string> <string name="your_full_jid_will_be">Your full Jabber ID will be: %s</string>
<string name="create_account">Create Account</string> <string name="create_account">Create Account</string>
@ -789,4 +792,9 @@
<string name="too_many_attempts">Too many attempts</string> <string name="too_many_attempts">Too many attempts</string>
<string name="the_app_is_out_of_date">You are using an out of date version of this app.</string> <string name="the_app_is_out_of_date">You are using an out of date version of this app.</string>
<string name="update">Update</string> <string name="update">Update</string>
<string name="logged_in_with_another_device">This phone number is currently logged in with another device.</string>
<string name="enter_your_name_instructions">Please enter your name to let people, who dont have you in their address books, know who you are.</string>
<string name="your_name">Your name</string>
<string name="enter_your_name">Enter your name</string>
<string name="no_name_set_instructions">Use the edit button to set your name.</string>
</resources> </resources>

View file

@ -80,6 +80,10 @@
<item name="android:textColor">?android:textColorSecondary</item> <item name="android:textColor">?android:textColorSecondary</item>
</style> </style>
<style name="TextAppearance.Conversations.Body1.Tertiary" parent="TextAppearance.Conversations.Body1">
<item name="android:textColor">?android:textColorTertiary</item>
</style>
<style name="TextAppearance.Conversations.Fingerprint" parent="TextAppearance.Conversations.Body1"> <style name="TextAppearance.Conversations.Fingerprint" parent="TextAppearance.Conversations.Body1">
<item name="android:fontFamily" tools:targetApi="jelly_bean">monospace</item> <item name="android:fontFamily" tools:targetApi="jelly_bean">monospace</item>
<item name="android:typeface">monospace</item> <item name="android:typeface">monospace</item>

View file

@ -19,5 +19,15 @@
android:launchMode="singleTask" android:launchMode="singleTask"
android:label="@string/verify_your_phone_number"/> android:label="@string/verify_your_phone_number"/>
<activity
android:name=".ui.TosActivity"
android:launchMode="singleTask"
android:label="@string/app_name"/>
<activity
android:name=".ui.EnterNameActivity"
android:launchMode="singleTask"
android:label="@string/enter_your_name"/>
</application> </application>
</manifest> </manifest>

View file

@ -0,0 +1,54 @@
package eu.siacs.conversations.ui;
import android.content.Intent;
import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.View;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ActivityEnterNameBinding;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.utils.AccountUtils;
public class EnterNameActivity extends XmppActivity {
private ActivityEnterNameBinding binding;
private Account account;
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_enter_name);
setSupportActionBar((Toolbar) this.binding.toolbar);
this.binding.next.setOnClickListener(this::next);
}
private void next(View view) {
if (account != null) {
String name = this.binding.name.getText().toString().trim();
account.setDisplayName(name);
xmppConnectionService.publishDisplayName(account);
Intent intent = new Intent(this, PublishProfilePictureActivity.class);
intent.putExtra(PublishProfilePictureActivity.EXTRA_ACCOUNT, account.getJid().asBareJid().toEscapedString());
intent.putExtra("setup", true);
startActivity(intent);
}
finish();
}
@Override
protected void refreshUiReal() {
}
@Override
void onBackendConnected() {
this.account = AccountUtils.getFirst(xmppConnectionService);
}
}

View file

@ -0,0 +1,80 @@
package eu.siacs.conversations.ui;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.widget.Button;
import android.widget.TextView;
import java.util.List;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.utils.XmppUri;
public class TosActivity extends XmppActivity {
@Override
protected void refreshUiReal() {
}
@Override
void onBackendConnected() {
}
@Override
public void onStart() {
super.onStart();
final int theme = findTheme();
if (this.mTheme != theme) {
recreate();
}
}
@Override
public void onNewIntent(Intent intent) {
if (intent != null) {
setIntent(intent);
}
}
@Override
protected void onCreate(final Bundle savedInstanceState) {
if (getResources().getBoolean(R.bool.portrait_only)) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tos);
setSupportActionBar(findViewById(R.id.toolbar));
final ActionBar ab = getSupportActionBar();
if (ab != null) {
ab.setDisplayShowHomeEnabled(false);
ab.setDisplayHomeAsUpEnabled(false);
}
final Button agreeButton = findViewById(R.id.agree);
final TextView welcomeText = findViewById(R.id.welcome_text);
agreeButton.setOnClickListener(v -> {
final Intent intent = new Intent(this, EnterPhoneNumberActivity.class);
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
preferences.edit().putBoolean("tos", true).apply();
addInviteUri(intent);
startActivity(intent);
finish();
});
welcomeText.setText(Html.fromHtml(getString(R.string.welcome_text_quicksy)));
welcomeText.setMovementMethod(LinkMovementMethod.getInstance());
}
public void addInviteUri(Intent intent) {
StartConversationActivity.addInviteUri(intent, getIntent());
}
}

View file

@ -269,9 +269,7 @@ public class VerifyActivity extends XmppActivity implements ClipboardManager.OnP
private void performPostVerificationRedirect() { private void performPostVerificationRedirect() {
if (redirectInProgress.compareAndSet(false, true)) { if (redirectInProgress.compareAndSet(false, true)) {
Intent intent = new Intent(this, PublishProfilePictureActivity.class); Intent intent = new Intent(this, EnterNameActivity.class);
intent.putExtra(PublishProfilePictureActivity.EXTRA_ACCOUNT, account.getJid().asBareJid().toEscapedString());
intent.putExtra("setup", true);
startActivity(intent); startActivity(intent);
finish(); finish();
} }

View file

@ -39,6 +39,9 @@ public class ApiDialogHelper {
case 403: case 403:
res = R.string.the_app_is_out_of_date; res = R.string.the_app_is_out_of_date;
break; break;
case 409:
res = R.string.logged_in_with_another_device;
break;
case 500: case 500:
res = R.string.something_went_wrong_processing_your_request; res = R.string.something_went_wrong_processing_your_request;
break; break;

View file

@ -2,6 +2,8 @@ package eu.siacs.conversations.utils;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log; import android.util.Log;
import eu.siacs.conversations.Config; import eu.siacs.conversations.Config;
@ -9,6 +11,7 @@ import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.ui.ConversationsActivity; import eu.siacs.conversations.ui.ConversationsActivity;
import eu.siacs.conversations.ui.EnterPhoneNumberActivity; import eu.siacs.conversations.ui.EnterPhoneNumberActivity;
import eu.siacs.conversations.ui.StartConversationActivity; import eu.siacs.conversations.ui.StartConversationActivity;
import eu.siacs.conversations.ui.TosActivity;
import eu.siacs.conversations.ui.VerifyActivity; import eu.siacs.conversations.ui.VerifyActivity;
public class SignupUtils { public class SignupUtils {
@ -28,7 +31,12 @@ public class SignupUtils {
intent = new Intent(activity, StartConversationActivity.class); intent = new Intent(activity, StartConversationActivity.class);
} }
} else { } else {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
if (preferences.getBoolean("tos",false)) {
intent = getSignUpIntent(activity); intent = getSignUpIntent(activity);
} else {
intent = new Intent(activity, TosActivity.class);
}
} }
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

View file

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include android:id="@+id/toolbar" layout="@layout/toolbar" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/instructions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:gravity="center_horizontal"
android:textAppearance="@style/TextAppearance.Conversations.Body1"
android:text="@string/enter_your_name_instructions"/>
<LinearLayout
android:id="@+id/name_box"
android:layout_width="256dp"
android:layout_height="wrap_content"
android:layout_above="@+id/next"
android:layout_below="@+id/instructions"
android:layout_centerHorizontal="true"
android:orientation="vertical">
<EditText
android:imeOptions="flagNoExtractUi"
android:id="@+id/name"
style="@style/Widget.Conversations.EditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/your_name"
android:longClickable="false" />
</LinearLayout>
<Button
android:id="@+id/next"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
style="@style/Widget.Conversations.Button.Borderless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/next"
android:textColor="?colorAccent"/>
</RelativeLayout>
</ScrollView>
</LinearLayout>
</layout>

View file

@ -0,0 +1,77 @@
<?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="match_parent"
android:orientation="vertical">
<include layout="@layout/toolbar" />
<ScrollView android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/color_background_primary">
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:minHeight="256dp"
android:orientation="vertical">
<Space
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingBottom="16dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/welcome_header_quicksy"
android:textAppearance="@style/TextAppearance.Conversations.Title"/>
<TextView
android:id="@+id/welcome_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/welcome_text_quicksy"
android:textAppearance="@style/TextAppearance.Conversations.Body1"/>
</LinearLayout>
<Button
android:id="@+id/agree"
style="@style/Widget.Conversations.Button.Borderless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:text="@string/agree_and_continue"
android:textColor="?colorAccent"/>
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/linearLayout"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:padding="8dp"
android:src="@drawable/main_logo"/>
</RelativeLayout>
</RelativeLayout>
</ScrollView>
</LinearLayout>