From 2b913f367d08d26b471082118d3226cc13045f83 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 6 Feb 2019 14:45:51 +0100 Subject: [PATCH] provide the same fab submenu for both tabs. rename tab to bookmark --- .../conversations/generator/IqGenerator.java | 14 +- .../conversations/parser/PresenceParser.java | 4 +- .../services/XmppConnectionService.java | 31 +- .../ui/ConferenceDetailsActivity.java | 1 + .../ui/ConversationFragment.java | 1 + .../ui/ConversationsOverviewFragment.java | 24 +- ...java => CreatePrivateGroupChatDialog.java} | 20 +- .../ui/CreatePublicChannelDialog.java | 297 ++++++++++++++++++ .../ui/JoinConferenceDialog.java | 4 +- .../ui/StartConversationActivity.java | 178 ++++++----- .../conversations/utils/CryptoHelper.java | 3 +- .../res/drawable-hdpi/ic_close_white_24dp.png | Bin 221 -> 0 bytes .../drawable-hdpi/ic_public_white_24dp.png | Bin 0 -> 504 bytes .../res/drawable-mdpi/ic_close_white_24dp.png | Bin 175 -> 0 bytes .../drawable-mdpi/ic_public_white_24dp.png | Bin 0 -> 339 bytes .../drawable-xhdpi/ic_close_white_24dp.png | Bin 257 -> 0 bytes .../drawable-xhdpi/ic_public_white_24dp.png | Bin 0 -> 661 bytes .../drawable-xxhdpi/ic_close_white_24dp.png | Bin 347 -> 0 bytes .../drawable-xxhdpi/ic_public_white_24dp.png | Bin 0 -> 982 bytes .../drawable-xxxhdpi/ic_close_white_24dp.png | Bin 436 -> 0 bytes .../drawable-xxxhdpi/ic_public_white_24dp.png | Bin 0 -> 1288 bytes .../layout/activity_start_conversation.xml | 4 +- .../res/layout/create_conference_dialog.xml | 2 +- .../layout/create_public_channel_dialog.xml | 55 ++++ .../res/layout/dialog_join_conference.xml | 4 +- src/main/res/layout/enter_jid_dialog.xml | 2 +- src/main/res/menu/conference_context.xml | 3 - .../menu/start_conversation_fab_submenu.xml | 19 ++ .../res/menu/start_conversation_group_fab.xml | 11 - src/main/res/values/strings.xml | 26 +- src/main/res/values/themes.xml | 4 +- 31 files changed, 564 insertions(+), 143 deletions(-) rename src/main/java/eu/siacs/conversations/ui/{CreateConferenceDialog.java => CreatePrivateGroupChatDialog.java} (86%) create mode 100644 src/main/java/eu/siacs/conversations/ui/CreatePublicChannelDialog.java delete mode 100644 src/main/res/drawable-hdpi/ic_close_white_24dp.png create mode 100644 src/main/res/drawable-hdpi/ic_public_white_24dp.png delete mode 100644 src/main/res/drawable-mdpi/ic_close_white_24dp.png create mode 100644 src/main/res/drawable-mdpi/ic_public_white_24dp.png delete mode 100644 src/main/res/drawable-xhdpi/ic_close_white_24dp.png create mode 100644 src/main/res/drawable-xhdpi/ic_public_white_24dp.png delete mode 100644 src/main/res/drawable-xxhdpi/ic_close_white_24dp.png create mode 100644 src/main/res/drawable-xxhdpi/ic_public_white_24dp.png delete mode 100644 src/main/res/drawable-xxxhdpi/ic_close_white_24dp.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_public_white_24dp.png create mode 100644 src/main/res/layout/create_public_channel_dialog.xml create mode 100644 src/main/res/menu/start_conversation_fab_submenu.xml delete mode 100644 src/main/res/menu/start_conversation_group_fab.xml diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java index 0552ce840..85a3e977d 100644 --- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java @@ -456,7 +456,7 @@ public class IqGenerator extends AbstractGenerator { return packet; } - public static Bundle defaultRoomConfiguration() { + public static Bundle defaultGroupChatConfiguration() { Bundle options = new Bundle(); options.putString("muc#roomconfig_persistentroom", "1"); options.putString("muc#roomconfig_membersonly", "1"); @@ -468,6 +468,18 @@ public class IqGenerator extends AbstractGenerator { return options; } + public static Bundle defaultChannelConfiguration() { + Bundle options = new Bundle(); + options.putString("muc#roomconfig_persistentroom", "1"); + options.putString("muc#roomconfig_membersonly", "0"); + options.putString("muc#roomconfig_publicroom", "1"); + options.putString("muc#roomconfig_whois", "moderators"); + options.putString("muc#roomconfig_enablearchiving", "1"); //prosody + options.putString("mam", "1"); //ejabberd community + options.putString("muc#roomconfig_mam","1"); //ejabberd saas + return options; + } + public IqPacket requestPubsubConfiguration(Jid jid, String node) { return pubsubConfiguration(jid, node, null); } diff --git a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java index 3ae3179d5..dced15c94 100644 --- a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java +++ b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java @@ -2,7 +2,6 @@ package eu.siacs.conversations.parser; import android.util.Log; -import java.text.ParseException; import java.util.ArrayList; import java.util.List; @@ -11,7 +10,6 @@ import eu.siacs.conversations.Config; import eu.siacs.conversations.crypto.PgpEngine; import eu.siacs.conversations.crypto.axolotl.AxolotlService; import eu.siacs.conversations.entities.Account; -import eu.siacs.conversations.entities.Bookmark; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Message; @@ -99,7 +97,7 @@ public class PresenceParser extends AbstractParser implements +mucOptions.getConversation().getJid().asBareJid() +"' created. pushing default configuration"); mXmppConnectionService.pushConferenceConfiguration(mucOptions.getConversation(), - IqGenerator.defaultRoomConfiguration(), + IqGenerator.defaultGroupChatConfiguration(), null); } if (mXmppConnectionService.getPgpEngine() != null) { diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 2ee0d6062..ac2aeb49b 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -2424,6 +2424,9 @@ public class XmppConnectionService extends Service { if (mucOptions.nonanonymous() && !mucOptions.membersOnly() && !conversation.getBooleanAttribute("accept_non_anonymous", false)) { mucOptions.setError(MucOptions.Error.NON_ANONYMOUS); updateConversationUi(); + if (onConferenceJoined != null) { + onConferenceJoined.onConferenceJoined(conversation); + } return; } @@ -2707,6 +2710,32 @@ public class XmppConnectionService extends Service { return null; } + + public void createPublicChannel(final Account account, final String name, final Jid address, final UiCallback callback) { + joinMuc(findOrCreateConversation(account, address, true, false, true), conversation -> { + final Bundle configuration = IqGenerator.defaultChannelConfiguration(); + if (!TextUtils.isEmpty(name)) { + configuration.putString("muc#roomconfig_roomname", name); + } + pushConferenceConfiguration(conversation, configuration, new OnConfigurationPushed() { + @Override + public void onPushSucceeded() { + saveConversationAsBookmark(conversation, name); + callback.success(conversation); + } + + @Override + public void onPushFailed() { + if (conversation.getMucOptions().getSelf().getAffiliation().ranks(MucOptions.Affiliation.OWNER)) { + callback.error(R.string.unable_to_set_channel_configuration, conversation); + } else { + callback.error(R.string.joined_an_existing_channel, conversation); + } + } + }); + }); + } + public boolean createAdhocConference(final Account account, final String name, final Iterable jids, @@ -2726,7 +2755,7 @@ public class XmppConnectionService extends Service { joinMuc(conversation, new OnConferenceJoined() { @Override public void onConferenceJoined(final Conversation conversation) { - final Bundle configuration = IqGenerator.defaultRoomConfiguration(); + final Bundle configuration = IqGenerator.defaultGroupChatConfiguration(); if (!TextUtils.isEmpty(name)) { configuration.putString("muc#roomconfig_roomname", name); } diff --git a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java index adb36981c..7ba1c37a5 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java @@ -474,6 +474,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers } else { account = mConversation.getAccount().getJid().asBareJid().toString(); } + setTitle(mucOptions.isPrivateAndNonAnonymous() ? R.string.action_muc_details : R.string.channel_details); this.binding.editMucNameButton.setVisibility((self.getAffiliation().ranks(MucOptions.Affiliation.OWNER) || mucOptions.canChangeSubject()) ? View.VISIBLE : View.GONE); this.binding.detailsAccount.setText(getString(R.string.using_account, account)); this.binding.jid.setText(mConversation.getJid().asBareJid().toEscapedString()); diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 84a1bbe53..d5bc6a2a6 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -952,6 +952,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke if (conversation.getMode() == Conversation.MODE_MULTI) { menuContactDetails.setVisible(false); menuInviteContact.setVisible(conversation.getMucOptions().canInvite()); + menuMucDetails.setTitle(conversation.getMucOptions().isPrivateAndNonAnonymous() ? R.string.action_muc_details : R.string.channel_details); } else { menuContactDetails.setVisible(!this.conversation.withSelf()); menuMucDetails.setVisible(false); diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java index f1957c6f2..5312f8212 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java @@ -55,6 +55,7 @@ import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.databinding.FragmentConversationsOverviewBinding; import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.entities.Conversational; import eu.siacs.conversations.ui.adapter.ConversationAdapter; import eu.siacs.conversations.ui.interfaces.OnConversationArchived; import eu.siacs.conversations.ui.interfaces.OnConversationSelected; @@ -133,14 +134,23 @@ public class ConversationsOverviewFragment extends XmppFragment { if (activity instanceof OnConversationArchived) { ((OnConversationArchived) activity).onConversationArchived(swipedConversation.peek()); } - boolean isMuc = swipedConversation.peek().getMode() == Conversation.MODE_MULTI; - int title = isMuc ? R.string.title_undo_swipe_out_muc : R.string.title_undo_swipe_out_conversation; + final Conversation c = swipedConversation.peek(); + final int title; + if (c.getMode() == Conversational.MODE_MULTI) { + if (c.getMucOptions().isPrivateAndNonAnonymous()) { + title = R.string.title_undo_swipe_out_group_chat; + } else { + title = R.string.title_undo_swipe_out_channel; + } + } else { + title = R.string.title_undo_swipe_out_conversation; + } final Snackbar snackbar = Snackbar.make(binding.list, title, 5000) .setAction(R.string.undo, v -> { pendingActionHelper.undo(); - Conversation c = swipedConversation.pop(); - conversationsAdapter.insert(c, position); + Conversation conversation = swipedConversation.pop(); + conversationsAdapter.insert(conversation, position); if (formerlySelected) { if (activity instanceof OnConversationSelected) { ((OnConversationSelected) activity).onConversationSelected(c); @@ -167,9 +177,9 @@ public class ConversationsOverviewFragment extends XmppFragment { if (snackbar.isShownOrQueued()) { snackbar.dismiss(); } - Conversation c = swipedConversation.pop(); - if(c != null){ - if (!c.isRead() && c.getMode() == Conversation.MODE_SINGLE) { + final Conversation conversation = swipedConversation.pop(); + if(conversation != null){ + if (!conversation.isRead() && conversation.getMode() == Conversation.MODE_SINGLE) { return; } activity.xmppConnectionService.archiveConversation(c); diff --git a/src/main/java/eu/siacs/conversations/ui/CreateConferenceDialog.java b/src/main/java/eu/siacs/conversations/ui/CreatePrivateGroupChatDialog.java similarity index 86% rename from src/main/java/eu/siacs/conversations/ui/CreateConferenceDialog.java rename to src/main/java/eu/siacs/conversations/ui/CreatePrivateGroupChatDialog.java index 21eee709e..ef2984a23 100644 --- a/src/main/java/eu/siacs/conversations/ui/CreateConferenceDialog.java +++ b/src/main/java/eu/siacs/conversations/ui/CreatePrivateGroupChatDialog.java @@ -1,18 +1,13 @@ package eu.siacs.conversations.ui; import android.app.Dialog; +import android.content.Context; import android.databinding.DataBindingUtil; +import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v4.app.DialogFragment; -import android.content.Context; -import android.content.DialogInterface; -import android.os.Bundle; import android.support.v7.app.AlertDialog; -import android.view.KeyEvent; -import android.view.View; -import android.widget.EditText; import android.widget.Spinner; -import android.widget.TextView; import java.util.ArrayList; import java.util.List; @@ -21,14 +16,14 @@ import eu.siacs.conversations.R; import eu.siacs.conversations.databinding.CreateConferenceDialogBinding; import eu.siacs.conversations.ui.util.DelayedHintHelper; -public class CreateConferenceDialog extends DialogFragment { +public class CreatePrivateGroupChatDialog extends DialogFragment { private static final String ACCOUNTS_LIST_KEY = "activated_accounts_list"; private CreateConferenceDialogListener mListener; - public static CreateConferenceDialog newInstance(List accounts) { - CreateConferenceDialog dialog = new CreateConferenceDialog(); - Bundle bundle = new Bundle(); + public static CreatePrivateGroupChatDialog newInstance(List accounts) { + CreatePrivateGroupChatDialog dialog = new CreatePrivateGroupChatDialog(); + Bundle bundle = new Bundle(); bundle.putStringArrayList(ACCOUNTS_LIST_KEY, (ArrayList) accounts); dialog.setArguments(bundle); return dialog; @@ -44,7 +39,7 @@ public class CreateConferenceDialog extends DialogFragment { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - builder.setTitle(R.string.dialog_title_create_conference); + builder.setTitle(R.string.create_private_group_chat); CreateConferenceDialogBinding binding = DataBindingUtil.inflate(getActivity().getLayoutInflater(), R.layout.create_conference_dialog, null, false); ArrayList mActivatedAccounts = getArguments().getStringArrayList(ACCOUNTS_LIST_KEY); StartConversationActivity.populateAccountSpinner(getActivity(), mActivatedAccounts, binding.account); @@ -59,6 +54,7 @@ public class CreateConferenceDialog extends DialogFragment { return builder.create(); } + public interface CreateConferenceDialogListener { void onCreateDialogPositiveClick(Spinner spinner, String subject); } diff --git a/src/main/java/eu/siacs/conversations/ui/CreatePublicChannelDialog.java b/src/main/java/eu/siacs/conversations/ui/CreatePublicChannelDialog.java new file mode 100644 index 000000000..6b8c58cf3 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/CreatePublicChannelDialog.java @@ -0,0 +1,297 @@ +package eu.siacs.conversations.ui; + +import android.app.Activity; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.databinding.DataBindingUtil; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.DialogFragment; +import android.support.v7.app.AlertDialog; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.View; +import android.widget.AdapterView; +import android.widget.Button; +import android.widget.Spinner; + +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import eu.siacs.conversations.R; +import eu.siacs.conversations.databinding.CreateConferenceDialogBinding; +import eu.siacs.conversations.databinding.CreatePublicChannelDialogBinding; +import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.services.XmppConnectionService; +import eu.siacs.conversations.ui.adapter.KnownHostsAdapter; +import eu.siacs.conversations.ui.interfaces.OnBackendConnected; +import eu.siacs.conversations.ui.util.DelayedHintHelper; +import eu.siacs.conversations.utils.CryptoHelper; +import eu.siacs.conversations.xmpp.XmppConnection; +import rocks.xmpp.addr.Jid; + +public class CreatePublicChannelDialog extends DialogFragment implements OnBackendConnected { + + private static final char[] FORBIDDEN = new char[]{'\u0022','&','\'','/',':','<','>','@'}; + + private static final String ACCOUNTS_LIST_KEY = "activated_accounts_list"; + private CreatePublicChannelDialogListener mListener; + private KnownHostsAdapter knownHostsAdapter; + private boolean jidWasModified = false; + private boolean nameEntered = false; + private boolean skipTetxWatcher = false; + private static final SecureRandom RANDOM = new SecureRandom(); + + public static CreatePublicChannelDialog newInstance(List accounts) { + CreatePublicChannelDialog dialog = new CreatePublicChannelDialog(); + Bundle bundle = new Bundle(); + bundle.putStringArrayList(ACCOUNTS_LIST_KEY, (ArrayList) accounts); + dialog.setArguments(bundle); + return dialog; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + setRetainInstance(true); + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + jidWasModified = savedInstanceState != null && savedInstanceState.getBoolean("jid_was_modified_false", false); + nameEntered = savedInstanceState != null && savedInstanceState.getBoolean("name_entered", false); + final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder.setTitle(R.string.create_public_channel); + final CreatePublicChannelDialogBinding binding = DataBindingUtil.inflate(getActivity().getLayoutInflater(), R.layout.create_public_channel_dialog, null, false); + binding.account.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + updateJidSuggestion(binding); + } + + @Override + public void onNothingSelected(AdapterView parent) { + + } + }); + binding.jid.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + if (skipTetxWatcher) { + return; + } + if (jidWasModified) { + jidWasModified = !TextUtils.isEmpty(s); + } else { + jidWasModified = !s.toString().equals(getJidSuggestion(binding)); + } + } + }); + updateInputs(binding,false); + ArrayList mActivatedAccounts = getArguments().getStringArrayList(ACCOUNTS_LIST_KEY); + StartConversationActivity.populateAccountSpinner(getActivity(), mActivatedAccounts, binding.account); + builder.setView(binding.getRoot()); + builder.setPositiveButton(nameEntered ? R.string.create : R.string.next, null); + builder.setNegativeButton(nameEntered ? R.string.back : R.string.cancel, null); + DelayedHintHelper.setHint(R.string.channel_bare_jid_example, binding.jid); + this.knownHostsAdapter = new KnownHostsAdapter(getActivity(), R.layout.simple_list_item); + binding.jid.setAdapter(knownHostsAdapter); + final AlertDialog dialog = builder.create(); + binding.groupChatName.setOnEditorActionListener((v, actionId, event) -> { + submit(dialog, binding); + return true; + }); + dialog.setOnShowListener(dialogInterface -> { + dialog.getButton(DialogInterface.BUTTON_NEGATIVE).setOnClickListener(v -> goBack(dialog, binding)); + dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(v -> submit(dialog, binding)); + }); + return dialog; + } + + private void updateJidSuggestion(CreatePublicChannelDialogBinding binding) { + if (jidWasModified) { + return; + } + String jid = getJidSuggestion(binding); + skipTetxWatcher = true; + binding.jid.setText(jid); + skipTetxWatcher = false; + } + + @Override + public void onSaveInstanceState(Bundle outState) { + outState.putBoolean("jid_was_modified",jidWasModified); + outState.putBoolean("name_entered", nameEntered); + super.onSaveInstanceState(outState); + } + + private static String getJidSuggestion(CreatePublicChannelDialogBinding binding) { + final Account account = StartConversationActivity.getSelectedAccount(binding.getRoot().getContext(), binding.account); + final XmppConnection connection = account == null ? null : account.getXmppConnection(); + if (connection == null) { + return ""; + } + final Editable nameText = binding.groupChatName.getText(); + final String name = nameText == null ? "" : nameText.toString().trim(); + final String domain = connection.getMucServer(); + if (domain == null) { + return ""; + } + final String localpart = clean(name); + if (TextUtils.isEmpty(localpart)) { + return ""; + } else { + try { + return Jid.of(localpart, domain, null).toEscapedString(); + } catch (IllegalArgumentException e) { + return Jid.of(CryptoHelper.pronounceable(RANDOM), domain, null).toEscapedString(); + } + } + } + + private static String clean(String name) { + for(char c : FORBIDDEN) { + name = name.replace(String.valueOf(c),""); + } + return name.replaceAll("\\s+","-"); + } + + private void goBack(AlertDialog dialog, CreatePublicChannelDialogBinding binding) { + if (nameEntered) { + nameEntered = false; + updateInputs(binding, true); + updateButtons(dialog); + } else { + dialog.dismiss(); + } + } + + private void submit(AlertDialog dialog, CreatePublicChannelDialogBinding binding) { + final Context context = binding.getRoot().getContext(); + final Editable nameText = binding.groupChatName.getText(); + final String name = nameText == null ? "" : nameText.toString().trim(); + final Editable addressText = binding.jid.getText(); + final String address = addressText == null ? "" : addressText.toString().trim(); + if (nameEntered) { + binding.nameLayout.setError(null); + if (address.isEmpty()) { + binding.xmppAddressLayout.setError(context.getText(R.string.please_enter_xmpp_address)); + } else { + final Jid jid; + try { + jid = Jid.ofEscaped(address); + } catch (IllegalArgumentException e) { + binding.xmppAddressLayout.setError(context.getText(R.string.invalid_jid)); + return; + } + final Account account = StartConversationActivity.getSelectedAccount(context, binding.account); + if (account == null) { + return; + } + final XmppConnectionService service = ((XmppActivity )context).xmppConnectionService; + if (service != null && service.findFirstMuc(jid) != null) { + binding.xmppAddressLayout.setError(context.getString(R.string.channel_already_exists)); + return; + } + mListener.onCreatePublicChannel(account, name, jid); + dialog.dismiss(); + } + } else { + binding.xmppAddressLayout.setError(null); + if (name.isEmpty()) { + binding.nameLayout.setError(context.getText(R.string.please_enter_name)); + } else if (StartConversationActivity.isValidJid(name)){ + binding.nameLayout.setError(context.getText(R.string.this_is_an_xmpp_address)); + } else { + binding.nameLayout.setError(null); + nameEntered = true; + updateInputs(binding, true); + updateButtons(dialog); + binding.jid.setText(""); + binding.jid.append(getJidSuggestion(binding)); + } + } + } + + + private void updateInputs(CreatePublicChannelDialogBinding binding, boolean requestFocus) { + binding.xmppAddressLayout.setVisibility(nameEntered ? View.VISIBLE : View.GONE); + binding.nameLayout.setVisibility(nameEntered ? View.GONE : View.VISIBLE); + if (!requestFocus) { + return; + } + if (nameEntered) { + binding.xmppAddressLayout.requestFocus(); + } else { + binding.nameLayout.requestFocus(); + } + } + + private void updateButtons(AlertDialog dialog) { + final Button positive = dialog.getButton(DialogInterface.BUTTON_POSITIVE); + final Button negative = dialog.getButton(DialogInterface.BUTTON_NEGATIVE); + positive.setText(nameEntered ? R.string.create : R.string.next); + negative.setText(nameEntered ? R.string.back : R.string.cancel); + } + + @Override + public void onBackendConnected() { + refreshKnownHosts(); + } + + private void refreshKnownHosts() { + Activity activity = getActivity(); + if (activity instanceof XmppActivity) { + Collection hosts = ((XmppActivity) activity).xmppConnectionService.getKnownConferenceHosts(); + this.knownHostsAdapter.refresh(hosts); + } + } + + public interface CreatePublicChannelDialogListener { + void onCreatePublicChannel(Account account, String name, Jid address); + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + try { + mListener = (CreatePublicChannelDialogListener) context; + } catch (ClassCastException e) { + throw new ClassCastException(context.toString() + + " must implement CreateConferenceDialogListener"); + } + } + + @Override + public void onStart() { + super.onStart(); + final Activity activity = getActivity(); + if (activity instanceof XmppActivity && ((XmppActivity) activity).xmppConnectionService != null) { + refreshKnownHosts(); + } + } + + @Override + public void onDestroyView() { + Dialog dialog = getDialog(); + if (dialog != null && getRetainInstance()) { + dialog.setDismissMessage(null); + } + super.onDestroyView(); + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/JoinConferenceDialog.java b/src/main/java/eu/siacs/conversations/ui/JoinConferenceDialog.java index 035e828b6..b9c9b15b1 100644 --- a/src/main/java/eu/siacs/conversations/ui/JoinConferenceDialog.java +++ b/src/main/java/eu/siacs/conversations/ui/JoinConferenceDialog.java @@ -50,9 +50,9 @@ public class JoinConferenceDialog extends DialogFragment implements OnBackendCon @Override public Dialog onCreateDialog(Bundle savedInstanceState) { final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - builder.setTitle(R.string.dialog_title_join_conference); + builder.setTitle(R.string.join_public_channel); DialogJoinConferenceBinding binding = DataBindingUtil.inflate(getActivity().getLayoutInflater(), R.layout.dialog_join_conference, null, false); - DelayedHintHelper.setHint(R.string.conference_address_example, binding.jid); + DelayedHintHelper.setHint(R.string.channel_full_jid_example, binding.jid); this.knownHostsAdapter = new KnownHostsAdapter(getActivity(), R.layout.simple_list_item); binding.jid.setAdapter(knownHostsAdapter); String prefilledJid = getArguments().getString(PREFILLED_JID_KEY); diff --git a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java index df78a6618..f0aebb573 100644 --- a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java @@ -6,7 +6,6 @@ import android.app.Dialog; import android.app.PendingIntent; import android.content.ActivityNotFoundException; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; @@ -14,27 +13,20 @@ import android.databinding.DataBindingUtil; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.support.annotation.DrawableRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; -import android.support.v4.app.ListFragment; -import android.support.v4.content.ContextCompat; import android.support.v4.view.PagerAdapter; -import android.support.v4.view.ViewPager; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.app.ActionBar; import android.support.v7.app.AlertDialog; import android.support.v7.widget.Toolbar; import android.text.Editable; import android.text.Html; -import android.text.SpannableString; -import android.text.Spanned; import android.text.TextWatcher; import android.text.method.LinkMovementMethod; -import android.text.util.Linkify; import android.util.Log; import android.util.Pair; import android.view.ContextMenu; @@ -56,9 +48,6 @@ import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; -import com.leinardi.android.speeddial.SpeedDialActionItem; -import com.leinardi.android.speeddial.SpeedDialView; - import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -78,12 +67,10 @@ import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate; import eu.siacs.conversations.ui.adapter.ListItemAdapter; import eu.siacs.conversations.ui.interfaces.OnBackendConnected; -import eu.siacs.conversations.ui.service.EmojiService; import eu.siacs.conversations.ui.util.JidDialog; import eu.siacs.conversations.ui.util.MenuDoubleTabUtil; import eu.siacs.conversations.ui.util.PendingItem; import eu.siacs.conversations.ui.util.SoftKeyboardUtils; -import eu.siacs.conversations.ui.util.StyledAttributes; import eu.siacs.conversations.ui.widget.SwipeRefreshListFragment; import eu.siacs.conversations.utils.AccountUtils; import eu.siacs.conversations.utils.XmppUri; @@ -91,7 +78,7 @@ import eu.siacs.conversations.xmpp.OnUpdateBlocklist; import eu.siacs.conversations.xmpp.XmppConnection; import rocks.xmpp.addr.Jid; -public class StartConversationActivity extends XmppActivity implements XmppConnectionService.OnConversationUpdate, OnRosterUpdate, OnUpdateBlocklist, CreateConferenceDialog.CreateConferenceDialogListener, JoinConferenceDialog.JoinConferenceDialogListener, SwipeRefreshLayout.OnRefreshListener { +public class StartConversationActivity extends XmppActivity implements XmppConnectionService.OnConversationUpdate, OnRosterUpdate, OnUpdateBlocklist, CreatePrivateGroupChatDialog.CreateConferenceDialogListener, JoinConferenceDialog.JoinConferenceDialogListener, SwipeRefreshLayout.OnRefreshListener, CreatePublicChannelDialog.CreatePublicChannelDialogListener { public static final String EXTRA_INVITE_URI = "eu.siacs.conversations.invite_uri"; @@ -216,12 +203,6 @@ public class StartConversationActivity extends XmppActivity implements XmppConne return true; } }; - private ViewPager.SimpleOnPageChangeListener mOnPageChangeListener = new ViewPager.SimpleOnPageChangeListener() { - @Override - public void onPageSelected(int position) { - onTabChanged(); - } - }; public static void populateAccountSpinner(Context context, List accounts, Spinner spinner) { if (accounts.size() > 0) { @@ -279,35 +260,10 @@ public class StartConversationActivity extends XmppActivity implements XmppConne Toolbar toolbar = (Toolbar) binding.toolbar; setSupportActionBar(toolbar); configureActionBar(getSupportActionBar()); - this.binding.speedDial.setOnChangeListener(new SpeedDialView.OnChangeListener() { - @Override - public boolean onMainActionSelected() { - if (binding.startConversationViewPager.getCurrentItem() == 0) { - String searchString = mSearchEditText != null ? mSearchEditText.getText().toString() : null; - if (searchString != null && !searchString.trim().isEmpty()) { - try { - Jid jid = Jid.of(searchString); - if (jid.getLocal() != null && jid.isBareJid() && jid.getDomain().contains(".")) { - showCreateContactDialog(jid.toString(), null); - return false; - } - } catch (IllegalArgumentException ignored) { - //ignore and fall through - } - } - showCreateContactDialog(null, null); - } - return false; - } - @Override - public void onToggleChanged(boolean isOpen) { - - } - }); + binding.speedDial.inflate(R.menu.start_conversation_fab_submenu); binding.tabLayout.setupWithViewPager(binding.startConversationViewPager); - binding.startConversationViewPager.addOnPageChangeListener(mOnPageChangeListener); mListPagerAdapter = new ListPagerAdapter(getSupportFragmentManager()); binding.startConversationViewPager.setAdapter(mListPagerAdapter); @@ -342,18 +298,40 @@ public class StartConversationActivity extends XmppActivity implements XmppConne } mRequestedContactsPermission.set(savedInstanceState != null && savedInstanceState.getBoolean("requested_contacts_permission",false)); binding.speedDial.setOnActionSelectedListener(actionItem -> { + final String searchString = mSearchEditText != null ? mSearchEditText.getText().toString() : null; + final String prefilled; + if (isValidJid(searchString)) { + prefilled = Jid.ofEscaped(searchString).toEscapedString(); + } else { + prefilled = null; + } switch (actionItem.getId()) { - case R.id.enter: - showJoinConferenceDialog(null); + case R.id.join_public_channel: + showJoinConferenceDialog(prefilled); break; - case R.id.create: - showCreateConferenceDialog(); + case R.id.create_private_group_chat: + showCreatePrivateGroupChatDialog(); + break; + case R.id.create_public_channel: + showPublicChannelDialog(); + break; + case R.id.create_contact: + showCreateContactDialog(prefilled,null); break; } return false; }); } + public static boolean isValidJid(String input) { + try { + Jid jid = Jid.ofEscaped(input); + return !jid.isDomainJid(); + } catch (IllegalArgumentException e) { + return false; + } + } + @Override public void onSaveInstanceState(Bundle savedInstanceState) { Intent pendingIntent = pendingViewIntent.peek(); @@ -402,10 +380,6 @@ public class StartConversationActivity extends XmppActivity implements XmppConne switchToConversation(conversation); } - protected void openConversationForBookmark() { - openConversationForBookmark(conference_context_id); - } - protected void openConversationForBookmark(int position) { Bookmark bookmark = (Bookmark) conferences.get(position); openConversationsForBookmark(bookmark); @@ -504,7 +478,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne ft.addToBackStack(null); EnterJidDialog dialog = EnterJidDialog.newInstance( mActivatedAccounts, - getString(R.string.dialog_title_create_contact), + getString(R.string.add_contact), getString(R.string.create), prefilledJid, null, @@ -554,32 +528,51 @@ public class StartConversationActivity extends XmppActivity implements XmppConne joinConferenceFragment.show(ft, FRAGMENT_TAG_DIALOG); } - private void showCreateConferenceDialog() { + private void showCreatePrivateGroupChatDialog() { FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); Fragment prev = getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG_DIALOG); if (prev != null) { ft.remove(prev); } ft.addToBackStack(null); - CreateConferenceDialog createConferenceFragment = CreateConferenceDialog.newInstance(mActivatedAccounts); + CreatePrivateGroupChatDialog createConferenceFragment = CreatePrivateGroupChatDialog.newInstance(mActivatedAccounts); createConferenceFragment.show(ft, FRAGMENT_TAG_DIALOG); } - private Account getSelectedAccount(Spinner spinner) { - if (!spinner.isEnabled()) { + private void showPublicChannelDialog() { + FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + Fragment prev = getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG_DIALOG); + if (prev != null) { + ft.remove(prev); + } + ft.addToBackStack(null); + CreatePublicChannelDialog dialog = CreatePublicChannelDialog.newInstance(mActivatedAccounts); + dialog.show(ft, FRAGMENT_TAG_DIALOG); + } + + public static Account getSelectedAccount(Context context, Spinner spinner) { + if (spinner == null || !spinner.isEnabled()) { return null; } - Jid jid; - try { - if (Config.DOMAIN_LOCK != null) { - jid = Jid.of((String) spinner.getSelectedItem(), Config.DOMAIN_LOCK, null); - } else { - jid = Jid.of((String) spinner.getSelectedItem()); + if (context instanceof XmppActivity) { + Jid jid; + try { + if (Config.DOMAIN_LOCK != null) { + jid = Jid.of((String) spinner.getSelectedItem(), Config.DOMAIN_LOCK, null); + } else { + jid = Jid.of((String) spinner.getSelectedItem()); + } + } catch (final IllegalArgumentException e) { + return null; } - } catch (final IllegalArgumentException e) { + final XmppConnectionService service = ((XmppActivity) context).xmppConnectionService; + if (service == null) { + return null; + } + return service.findAccountByJid(jid); + } else { return null; } - return xmppConnectionService.findAccountByJid(jid); } protected void switchToConversation(Contact contact) { @@ -944,19 +937,6 @@ public class StartConversationActivity extends XmppActivity implements XmppConne mConferenceAdapter.notifyDataSetChanged(); } - private void onTabChanged() { - @DrawableRes final int fabDrawable; - if (binding.startConversationViewPager.getCurrentItem() == 0) { - fabDrawable = R.drawable.ic_person_add_white_24dp; - binding.speedDial.clearActionItems(); - } else { - fabDrawable = R.drawable.ic_group_add_white_24dp; - binding.speedDial.inflate(R.menu.start_conversation_group_fab); - } - binding.speedDial.setMainFabClosedDrawable(ContextCompat.getDrawable(this,fabDrawable)); - invalidateOptionsMenu(); - } - @Override public void OnUpdateBlocklist(final Status status) { refreshUi(); @@ -996,7 +976,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne if (!xmppConnectionServiceBound) { return; } - final Account account = getSelectedAccount(spinner); + final Account account = getSelectedAccount(this, spinner); if (account == null) { return; } @@ -1014,7 +994,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne if (!xmppConnectionServiceBound) { return; } - final Account account = getSelectedAccount(spinner); + final Account account = getSelectedAccount(this, spinner); if (account == null) { return; } @@ -1073,6 +1053,35 @@ public class StartConversationActivity extends XmppActivity implements XmppConne } } + @Override + public void onCreatePublicChannel(Account account, String name, Jid address) { + mToast = Toast.makeText(this, R.string.creating_channel, Toast.LENGTH_LONG); + mToast.show(); + xmppConnectionService.createPublicChannel(account, name, address, new UiCallback() { + @Override + public void success(Conversation conversation) { + runOnUiThread(() -> { + hideToast(); + switchToConversation(conversation); + }); + + } + + @Override + public void error(int errorCode, Conversation conversation) { + runOnUiThread(() -> { + replaceToast(getString(errorCode)); + switchToConversation(conversation); + }); + } + + @Override + public void userInputRequried(PendingIntent pi, Conversation object) { + + } + }); + } + public static class MyListFragment extends SwipeRefreshListFragment { private AdapterView.OnItemClickListener mOnItemClickListener; private int mResContextMenu; @@ -1154,9 +1163,6 @@ public class StartConversationActivity extends XmppActivity implements XmppConne case R.id.context_delete_contact: activity.deleteContact(); break; - case R.id.context_join_conference: - activity.openConversationForBookmark(); - break; case R.id.context_share_uri: activity.shareBookmarkUri(); break; @@ -1221,7 +1227,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne case 0: return getResources().getString(R.string.contacts); case 1: - return getResources().getString(R.string.conferences); + return getResources().getString(R.string.bookmarks); default: return super.getPageTitle(position); } diff --git a/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java b/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java index dc71b328a..40b3cad65 100644 --- a/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java @@ -63,7 +63,8 @@ public final class CryptoHelper { } public static String pronounceable(SecureRandom random) { - char[] output = new char[random.nextInt(4) * 2 + 5]; + final int rand = random.nextInt(4); + char[] output = new char[rand * 2 + (5 - rand)]; boolean vowel = random.nextBoolean(); for (int i = 0; i < output.length; ++i) { output[i] = vowel ? VOWELS[random.nextInt(VOWELS.length)] : CONSONANTS[random.nextInt(CONSONANTS.length)]; diff --git a/src/main/res/drawable-hdpi/ic_close_white_24dp.png b/src/main/res/drawable-hdpi/ic_close_white_24dp.png deleted file mode 100644 index ceb1a1eebf2b2cc9a008f42010e144f4dab968de..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 221 zcmV<303!d1P)og+*{ z>6z1@lfD*AYSPav71&OL>UNCIF903&6jb+7Dw+FwfIaom(2jH#1v7R5+oPaW>Fm2C4EqYuia~R7 zv3!=vJh6De4ErARHB})S;>mUvhB?_QX0@_zSY7FO_2}lU~_P>jq-Ut(g_l uP`M2Y+76sJbLPZ>P4kgul7`a#H=w`#`fTwM$pt+C00002B5kK^|J))MUC zlz7ydwCsb8xn}W?^r?}5wtsjdmvX{3=JbT!J9sKPrYmk={m|7^>A|Z*7j^D$`>}ry Zqi^Z9GQN4ct^!@a;OXk;vd$@?2>?I&LQeny diff --git a/src/main/res/drawable-mdpi/ic_public_white_24dp.png b/src/main/res/drawable-mdpi/ic_public_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..d82023b6bbe4986cbce484844a00a11940f7f52f GIT binary patch literal 339 zcmV-Z0j&OsP)iXoQ3Q&jxHF9K4jrLDXx9N0y+q4EB3dhh1{Fk0QGzEK2HyEs zErPzE<;(-`;urq+q^7nq*ISv5iBu>TlpFf2zLP;a=z62M9a!o%LEG{KcZ3#F0QazuV1v2PAQ8O4DuM}iI>pEGdd1m%!YG2&39|xxQ{Hz^ zERabe2nINNAP64&s=OaAcv?TcWlrYB!|Hq8a^5-NqlNpbdsRK}Sl>~7S@D<%Dka9& l4lcL$Rz?z`4*t?Vf?s}_*`ZstycPfe002ovPDHLkV1j0Tk>&sZ literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xhdpi/ic_close_white_24dp.png b/src/main/res/drawable-xhdpi/ic_close_white_24dp.png deleted file mode 100644 index b7c7ffd0e795ba76ed3a062566c9016448795f7a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 257 zcmV+c0sj7pP) zOA5m<3jYBNi%A&<@ZO?$P9};P4Y5CjG5$M&YXI45J{s}~# zf|&?x1_gn4B7+hS@X!l}&!voFhmZP^sujifL@~PKMMM~{6xH}^g$q7WOzwCQ5vHTU z6`v~H@rlA8e;CUh_(b84zg=+ih`wG<)HiJjzSlQx5#CnjMR;A)R^jtaTa9;7rSy)7O%~`cm?ZjXImW?6TYRT<;U^@VKiSj`soFk00000NkvXX Hu0mjfhD&W| diff --git a/src/main/res/drawable-xhdpi/ic_public_white_24dp.png b/src/main/res/drawable-xhdpi/ic_public_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..f545c6c1bb365e7390d778cdf162a43e069885ec GIT binary patch literal 661 zcmV;G0&4w3Tq2^p+}r;UtuExkMPMZ@i||JqS6Xfj8L+kmNh2mg z&_B?s#W0(jpePEZj)i79v-z}nnT2ofoHOq(xX-gZob!S2%rNJKr};lb#Ul$ETH3n0 z+FBasJya25jV!xo#j&Cs`P|*|z_@i?v2@gpl>w%lOHJG4U_i~+22EWx6}aO^X?f2R z0PMJv0@RX^zZ6t`?1~;yjRRjv&1SaazFh$I7%(L@=Ux`Fj`;<^yZwN1eOggpBB)6Yt0a)ncFx7!?wU-v=8}3-G3pObqlPHvsPoaiS3Tu=r~_ z5BNri6NSKcfZ06o5O85QP80yoxCBh(fr=x*bZ%oRFatO+lm~(@0K00XfZO%~OM*P$ zt}fuy8(aTUoGV+|-{)t5YtQF^taZRYUKRA}2mN#IC2!~eR)r#9OdGIgTvMkH8EXyh{JTRaptiwcq@D(P;=ehLbl?EMKm*m7(@7_siS}}k zNFtnck{HL4mc!ypcyUoqJV~4rM^fS3C#iAnkyJU3biCmDy`VZLOv=LXld^HVqNkl63V*@$>34(-A&|tVXsFE-!$0pjfUZ4`~gh9dtnny7hGzE!+ax~D62ZI&}+e0Mu z%%a^60%d6twzCmHd(pPpVFn$ccWoVNoFN?nG{7d>s2Mbkwn_ISmiY$llo>RSHo@rx zK~rcK&7ftpLkOo6106E2@j zN~1OHKxq@nqQCi^!9Y;T4pc{b4sjsCY#^wBR@aSfS-6ww2p@T==mA`DiMAH%zcW41!cI2zk9q96X*u%@E{@2D*imqQg8;X zkd3@r=pey;PLOv1t+2~w`I6@roo#WRcSuD5-5~3_p2{#s_Zoc9N4$%DGo<5L;EmJ3 zwK_-RTyd88n&>^@62zrFTayoS4G-H|TxDPKeFi*XQ(R<;b!s$eQe&MZE^v}VJcC3VA=&AJ`k+4OUo(ft>!!kRa{vGU07*qoM6N<$ Ef_Tfqj{pDw literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxxhdpi/ic_close_white_24dp.png b/src/main/res/drawable-xxxhdpi/ic_close_white_24dp.png deleted file mode 100644 index 39641921925f090e33df2767a4ee5e6d5911194f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 436 zcmV;l0ZaagP)32ETvhYyB39D^lU%DgQgv&#U%8l^-CA%qY@2qA=!B5=cm zUgehujQG*l{{`@rPr!f|fEk^>KI9WteE@ilV6HEl&_rJ@p_zU*;T}RirIc{5NocNLm*7JGdV(AM zYYDFOvk5~8{Z*t_>U=!XvoehUSEh=adIga45oe)B9kGgT}7UT3Cirmr(oHPv^YQ1-p=Hlh5u;xggf zX{&yw+El-OrrKQJRl@b7x{HLmNkj95`a#LLnW{Veb2C+!`ppt#r)=g4@?c8RY{yJj~W@W|h^mU4q`i)2y~Rw@J`jIh$1%|In!~{Tb{nMqaxlgb+dq eA%qY@zJ@mriVM?qfwL0;0000s0LSr9M&)_5(rk;!W~W625!*#K+eNdG2uflJ2K@sO&6-V%2L`(ti?L2FJJ7(z zT8HhX3p?#9=GNV?nTTahm)J>v8dmyyFCt>!=XZFX-|zc8>c#K%k}@(fGBPp(LkShs za*FG;(a#8Dj4?t#ZCv9dwNx-ilM(q;a-2^5=%A5JU zUD&wGE($ae$fKUe1mPij$<_FxnjV7GO_jzA3%N=dnpvRmv7HEE8K7EWB8MLc+i|iL z4obMmc=(-S1&_sa5u|SzAdybqQ?OXheF7y>NF4*j*UK^mhsE3{SR;CcSsWosJiU}D z7|f-Mpxx3Ntf8HFIw_Vta=1zG4(fl%=SSjcAzQXMP4J?ukPDv?CDsYqVLM?sq&V2j zGh%I1`dCPW;9X;e;$j2Oa2upl>EbFui*kq=N{G!wacfq3s3u4w+~OcB$yKVT!-~>I0qwZ$QEDjU5msb@HAFEzAYZAV21~L+18zIzA5-bVlB_U` z0Zezul3!F{O_r#`tz3R_4r{VR0Rx!M$RF}~iZxl|0Hz^w7fDO7xjsa0O+$23>3 z;Sh&H#k-jLlmh+kPEpO}hi zR9+atG*d1(*m}$o`9dD1VR@k+(>%q%!PZ6j!aPiU@9+i!5!0XYfJ4gU1AkyTB0t!KTbVrI zkRo|vDQ+9&2YC!*`c|Gukv#DorU*ImhqIUlDU=6NBoDkz1XGjzVm)s4@<58@fiH3U zM1GOQT}*=%D=AW>q$ptsQzuj8AG>gCP*OZ2J)G;TYT3JQ3LDauDmg4@`L za+n! zbG9lWR&toX86hZDvcm~tMcF401mkAUg2OU;i7&!e6e$LF{$Z(tMHzQU`4LO)1^r yS7@b=VMZBcm_Ay$%rR;xr$`wY85tQFf%y-Y0z|JHf``EX0000 diff --git a/src/main/res/layout/create_conference_dialog.xml b/src/main/res/layout/create_conference_dialog.xml index 6680ce246..f0e2f19f7 100644 --- a/src/main/res/layout/create_conference_dialog.xml +++ b/src/main/res/layout/create_conference_dialog.xml @@ -34,7 +34,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/create_dialog_group_chat_name" - android:imeOptions="actionNext"/> + android:imeOptions="actionNext|flagNoExtractUi"/> diff --git a/src/main/res/layout/create_public_channel_dialog.xml b/src/main/res/layout/create_public_channel_dialog.xml new file mode 100644 index 000000000..4e458fc3c --- /dev/null +++ b/src/main/res/layout/create_public_channel_dialog.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/main/res/layout/dialog_join_conference.xml b/src/main/res/layout/dialog_join_conference.xml index ba78f2682..cb8fd313d 100644 --- a/src/main/res/layout/dialog_join_conference.xml +++ b/src/main/res/layout/dialog_join_conference.xml @@ -26,7 +26,7 @@ android:id="@+id/account_jid_layout" android:layout_width="match_parent" android:layout_height="wrap_content" - android:hint="@string/conference_address" + android:hint="@string/xmpp_address" app:errorTextAppearance="@style/TextAppearance.Conversations.Design.Error" app:hintTextAppearance="@style/TextAppearance.Conversations.Design.Hint"> @@ -36,7 +36,7 @@ android:layout_width="fill_parent" android:layout_height="wrap_content" android:inputType="textEmailAddress" - android:imeOptions="actionDone"/> + android:imeOptions="actionDone|flagNoExtractUi"/> + android:imeOptions="actionDone|flagNoExtractUi"/> diff --git a/src/main/res/menu/conference_context.xml b/src/main/res/menu/conference_context.xml index ee9517ed8..725a7590e 100644 --- a/src/main/res/menu/conference_context.xml +++ b/src/main/res/menu/conference_context.xml @@ -1,9 +1,6 @@ - diff --git a/src/main/res/menu/start_conversation_fab_submenu.xml b/src/main/res/menu/start_conversation_fab_submenu.xml new file mode 100644 index 000000000..76a576d6a --- /dev/null +++ b/src/main/res/menu/start_conversation_fab_submenu.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/src/main/res/menu/start_conversation_group_fab.xml b/src/main/res/menu/start_conversation_group_fab.xml deleted file mode 100644 index 3c1bb2a42..000000000 --- a/src/main/res/menu/start_conversation_group_fab.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index bf0c7d662..de27b1b51 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -7,6 +7,7 @@ Close this conversation Contact details Group chat details + Channel details Secure conversation Add account Edit name @@ -211,12 +212,9 @@ Fetching keys… Done Decrypt - Group chats + Bookmarks Search - Create Contact Enter Contact - Join group chat - Join Group Chat Delete contact View contact details Block contact @@ -225,8 +223,8 @@ Select The contact already exists Join - Group chat address - room@conference.example.com/nick + channel@conference.example.com/nick + channel@conference.example.com Save as bookmark Delete bookmark Destroy group chat @@ -416,7 +414,8 @@ No application found to display location Location Conversation closed - Left group chat + Left private group chat + Left public channel Don’t trust system CAs All certificates must be manually approved Remove certificates @@ -541,7 +540,6 @@ Your device does not support opting out of battery optimization Registration failed: Try again later Registration failed: Password too weak - Create Group Chat Choose participants Creating group chat… Invite again @@ -824,4 +822,16 @@ Backup & Restore Enter Jabber ID Create group chat + Join public channel + Create private group chat + Create public channel + Channel name + XMPP address + Please provide a name for the channel + Please provide an XMPP address + This is an XMPP address. Please provide a name. + Creating public channel… + This channel already exits + You’ve joined an existing channel + Unable to set channel configuration diff --git a/src/main/res/values/themes.xml b/src/main/res/values/themes.xml index f7522f284..e7bc3cd31 100644 --- a/src/main/res/values/themes.xml +++ b/src/main/res/values/themes.xml @@ -10,7 +10,7 @@ @color/grey50 @color/grey200 @color/grey300 - @color/grey300_40 + @color/black12 @color/red_a700 @color/green600 @color/red800 @@ -123,7 +123,7 @@ @color/grey800 @color/grey900 @color/grey700 - @color/grey700_40 + @color/black26 @drawable/search_background_dark @drawable/no_results_background_dark @drawable/list_item_background_dark