provide the same fab submenu for both tabs. rename tab to bookmark
|  | @ -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); | ||||
| 	} | ||||
|  |  | |||
|  | @ -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) { | ||||
|  |  | |||
|  | @ -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<Conversation> 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<Jid> 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); | ||||
| 						} | ||||
|  |  | |||
|  | @ -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()); | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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<String> accounts) { | ||||
|         CreateConferenceDialog dialog = new CreateConferenceDialog(); | ||||
|         Bundle bundle =  new Bundle(); | ||||
|     public static CreatePrivateGroupChatDialog newInstance(List<String> accounts) { | ||||
|         CreatePrivateGroupChatDialog dialog = new CreatePrivateGroupChatDialog(); | ||||
|         Bundle bundle = new Bundle(); | ||||
|         bundle.putStringArrayList(ACCOUNTS_LIST_KEY, (ArrayList<String>) 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<String> 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); | ||||
|     } | ||||
|  | @ -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<String> accounts) { | ||||
|         CreatePublicChannelDialog dialog = new CreatePublicChannelDialog(); | ||||
|         Bundle bundle = new Bundle(); | ||||
|         bundle.putStringArrayList(ACCOUNTS_LIST_KEY, (ArrayList<String>) 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<String> 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<String> 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(); | ||||
|     } | ||||
| } | ||||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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<String> 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<Conversation>() { | ||||
| 			@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); | ||||
| 			} | ||||
|  |  | |||
|  | @ -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)]; | ||||
|  |  | |||
| Before Width: | Height: | Size: 221 B | 
| After Width: | Height: | Size: 504 B | 
| Before Width: | Height: | Size: 175 B | 
| After Width: | Height: | Size: 339 B | 
| Before Width: | Height: | Size: 257 B | 
| After Width: | Height: | Size: 661 B | 
| Before Width: | Height: | Size: 347 B | 
| After Width: | Height: | Size: 982 B | 
| Before Width: | Height: | Size: 436 B | 
| After Width: | Height: | Size: 1.3 KiB | 
|  | @ -46,10 +46,10 @@ | |||
|             app:backgroundTint="?colorPrimary" | ||||
|             android:layout_alignParentRight="true" | ||||
|             android:layout_alignParentBottom="true" | ||||
|             app:sdMainFabClosedSrc="@drawable/ic_person_add_white_24dp" | ||||
|             app:sdMainFabClosedSrc="@drawable/ic_add_white_24dp" | ||||
|             app:sdMainFabClosedBackgroundColor="?colorPrimary" | ||||
|             app:sdMainFabOpenedSrc="@drawable/ic_close_white_24dp" | ||||
|             app:sdMainFabOpenedBackgroundColor="?colorPrimaryDark" | ||||
|             app:sdUseReverseAnimationOnClose="true" | ||||
|             app:sdOverlayLayout="@id/overlay"/> | ||||
|     </RelativeLayout> | ||||
| </layout> | ||||
|  |  | |||
|  | @ -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"/> | ||||
|         </android.support.design.widget.TextInputLayout> | ||||
|     </LinearLayout> | ||||
| </layout> | ||||
|  |  | |||
|  | @ -0,0 +1,55 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <layout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|         xmlns:app="http://schemas.android.com/apk/res-auto"> | ||||
| 
 | ||||
|     <LinearLayout | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="match_parent" | ||||
|         android:orientation="vertical" | ||||
|         android:padding="?dialogPreferredPadding"> | ||||
| 
 | ||||
|         <TextView | ||||
|             style="@style/InputLabel" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:text="@string/your_account"/> | ||||
| 
 | ||||
|         <Spinner | ||||
|             android:id="@+id/account" | ||||
|             android:layout_width="fill_parent" | ||||
|             android:layout_height="wrap_content"/> | ||||
| 
 | ||||
|         <android.support.design.widget.TextInputLayout | ||||
|             android:id="@+id/name_layout" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content" | ||||
|             app:errorTextAppearance="@style/TextAppearance.Conversations.Design.Error" | ||||
|             app:hintTextAppearance="@style/TextAppearance.Conversations.Design.Hint"> | ||||
| 
 | ||||
|             <eu.siacs.conversations.ui.widget.EmojiWrapperEditText | ||||
|                 android:id="@+id/group_chat_name" | ||||
|                 style="@style/Widget.Conversations.EditText" | ||||
|                 android:layout_width="match_parent" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:hint="@string/create_dialog_channel_name" | ||||
|                 android:imeOptions="actionNext|flagNoExtractUi"/> | ||||
|         </android.support.design.widget.TextInputLayout> | ||||
|         <android.support.design.widget.TextInputLayout | ||||
|             android:id="@+id/xmpp_address_layout" | ||||
|             android:visibility="gone" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:hint="@string/xmpp_address" | ||||
|             app:errorTextAppearance="@style/TextAppearance.Conversations.Design.Error" | ||||
|             app:hintTextAppearance="@style/TextAppearance.Conversations.Design.Hint"> | ||||
| 
 | ||||
|             <AutoCompleteTextView | ||||
|                 android:id="@+id/jid" | ||||
|                 style="@style/Widget.Conversations.EditText" | ||||
|                 android:layout_width="fill_parent" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:inputType="textEmailAddress" | ||||
|                 android:imeOptions="actionDone|flagNoExtractUi"/> | ||||
|         </android.support.design.widget.TextInputLayout> | ||||
|     </LinearLayout> | ||||
| </layout> | ||||
|  | @ -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.support.design.widget.TextInputLayout> | ||||
| 
 | ||||
|         <CheckBox | ||||
|  |  | |||
|  | @ -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.support.design.widget.TextInputLayout> | ||||
|     </LinearLayout> | ||||
| </layout> | ||||
|  |  | |||
|  | @ -1,9 +1,6 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <menu xmlns:android="http://schemas.android.com/apk/res/android" > | ||||
| 
 | ||||
|     <item | ||||
|         android:id="@+id/context_join_conference" | ||||
|         android:title="@string/join_conference"/> | ||||
|     <item | ||||
|         android:id="@+id/context_delete_conference" | ||||
|         android:title="@string/delete_bookmark"/> | ||||
|  |  | |||
|  | @ -0,0 +1,19 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <menu xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
|     <item | ||||
|         android:id="@+id/join_public_channel" | ||||
|         android:title="@string/join_public_channel" | ||||
|         android:icon="@drawable/ic_input_white_24dp"/> | ||||
|     <item | ||||
|         android:id="@+id/create_public_channel" | ||||
|         android:title="@string/create_public_channel" | ||||
|         android:icon="@drawable/ic_public_white_24dp"/> | ||||
|     <item | ||||
|         android:id="@+id/create_private_group_chat" | ||||
|         android:title="@string/create_private_group_chat" | ||||
|         android:icon="@drawable/ic_group_white_24dp"/> | ||||
|     <item | ||||
|         android:id="@+id/create_contact" | ||||
|         android:title="@string/add_contact" | ||||
|         android:icon="@drawable/ic_person_white_48dp"/> | ||||
| </menu> | ||||
|  | @ -1,11 +0,0 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <menu xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
|     <item | ||||
|         android:id="@+id/enter" | ||||
|         android:title="@string/enter_jabber_id" | ||||
|         android:icon="@drawable/ic_input_white_24dp"/> | ||||
|     <item | ||||
|         android:id="@+id/create" | ||||
|         android:title="@string/create_group_chat" | ||||
|         android:icon="@drawable/ic_edit_white_24dp"/> | ||||
| </menu> | ||||
|  | @ -7,6 +7,7 @@ | |||
|     <string name="action_end_conversation">Close this conversation</string> | ||||
|     <string name="action_contact_details">Contact details</string> | ||||
|     <string name="action_muc_details">Group chat details</string> | ||||
|     <string name="channel_details">Channel details</string> | ||||
|     <string name="action_secure">Secure conversation</string> | ||||
|     <string name="action_add_account">Add account</string> | ||||
|     <string name="action_edit_contact">Edit name</string> | ||||
|  | @ -211,12 +212,9 @@ | |||
|     <string name="fetching_keys">Fetching keys…</string> | ||||
|     <string name="done">Done</string> | ||||
|     <string name="decrypt">Decrypt</string> | ||||
|     <string name="conferences">Group chats</string> | ||||
|     <string name="bookmarks">Bookmarks</string> | ||||
|     <string name="search">Search</string> | ||||
|     <string name="dialog_title_create_contact">Create Contact</string> | ||||
|     <string name="enter_contact">Enter Contact</string> | ||||
|     <string name="join_conference">Join group chat</string> | ||||
|     <string name="dialog_title_join_conference">Join Group Chat</string> | ||||
|     <string name="delete_contact">Delete contact</string> | ||||
|     <string name="view_contact_details">View contact details</string> | ||||
|     <string name="block_contact">Block contact</string> | ||||
|  | @ -225,8 +223,8 @@ | |||
|     <string name="select">Select</string> | ||||
|     <string name="contact_already_exists">The contact already exists</string> | ||||
|     <string name="join">Join</string> | ||||
|     <string name="conference_address">Group chat address</string> | ||||
|     <string name="conference_address_example">room@conference.example.com/nick</string> | ||||
|     <string name="channel_full_jid_example">channel@conference.example.com/nick</string> | ||||
|     <string name="channel_bare_jid_example">channel@conference.example.com</string> | ||||
|     <string name="save_as_bookmark">Save as bookmark</string> | ||||
|     <string name="delete_bookmark">Delete bookmark</string> | ||||
|     <string name="destroy_room">Destroy group chat</string> | ||||
|  | @ -416,7 +414,8 @@ | |||
|     <string name="no_application_found_to_display_location">No application found to display location</string> | ||||
|     <string name="location">Location</string> | ||||
|     <string name="title_undo_swipe_out_conversation">Conversation closed</string> | ||||
|     <string name="title_undo_swipe_out_muc">Left group chat</string> | ||||
|     <string name="title_undo_swipe_out_group_chat">Left private group chat</string> | ||||
|     <string name="title_undo_swipe_out_channel">Left public channel</string> | ||||
|     <string name="pref_dont_trust_system_cas_title">Don’t trust system CAs</string> | ||||
|     <string name="pref_dont_trust_system_cas_summary">All certificates must be manually approved</string> | ||||
|     <string name="pref_remove_trusted_certificates_title">Remove certificates</string> | ||||
|  | @ -541,7 +540,6 @@ | |||
|     <string name="device_does_not_support_battery_op">Your device does not support opting out of battery optimization</string> | ||||
|     <string name="registration_please_wait">Registration failed: Try again later</string> | ||||
|     <string name="registration_password_too_weak">Registration failed: Password too weak</string> | ||||
|     <string name="dialog_title_create_conference">Create Group Chat</string> | ||||
|     <string name="choose_participants">Choose participants</string> | ||||
|     <string name="creating_conference">Creating group chat…</string> | ||||
|     <string name="invite_again">Invite again</string> | ||||
|  | @ -824,4 +822,16 @@ | |||
|     <string name="backup_channel_name">Backup & Restore</string> | ||||
|     <string name="enter_jabber_id">Enter Jabber ID</string> | ||||
|     <string name="create_group_chat">Create group chat</string> | ||||
|     <string name="join_public_channel">Join public channel</string> | ||||
|     <string name="create_private_group_chat">Create private group chat</string> | ||||
|     <string name="create_public_channel">Create public channel</string> | ||||
|     <string name="create_dialog_channel_name">Channel name</string> | ||||
|     <string name="xmpp_address">XMPP address</string> | ||||
|     <string name="please_enter_name">Please provide a name for the channel</string> | ||||
|     <string name="please_enter_xmpp_address">Please provide an XMPP address</string> | ||||
|     <string name="this_is_an_xmpp_address">This is an XMPP address. Please provide a name.</string> | ||||
|     <string name="creating_channel">Creating public channel…</string> | ||||
|     <string name="channel_already_exists">This channel already exits</string> | ||||
|     <string name="joined_an_existing_channel">You’ve joined an existing channel</string> | ||||
|     <string name="unable_to_set_channel_configuration">Unable to set channel configuration</string> | ||||
| </resources> | ||||
|  |  | |||
|  | @ -10,7 +10,7 @@ | |||
|         <item name="color_background_primary">@color/grey50</item> | ||||
|         <item name="color_background_secondary">@color/grey200</item> | ||||
|         <item name="color_background_tertiary">@color/grey300</item> | ||||
|         <item name="color_background_overlay">@color/grey300_40</item> | ||||
|         <item name="color_background_overlay">@color/black12</item> | ||||
|         <item name="color_warning">@color/red_a700</item> | ||||
|         <item name="TextColorOnline">@color/green600</item> | ||||
|         <item name="TextColorError">@color/red800</item> | ||||
|  | @ -123,7 +123,7 @@ | |||
|         <item name="color_background_primary">@color/grey800</item> | ||||
|         <item name="color_background_secondary">@color/grey900</item> | ||||
|         <item name="color_background_tertiary">@color/grey700</item> | ||||
|         <item name="color_background_overlay">@color/grey700_40</item> | ||||
|         <item name="color_background_overlay">@color/black26</item> | ||||
|         <item name="activity_background_search">@drawable/search_background_dark</item> | ||||
|         <item name="activity_background_no_results">@drawable/no_results_background_dark</item> | ||||
|         <item name="list_item_background">@drawable/list_item_background_dark</item> | ||||
|  |  | |||
 Daniel Gultsch
						Daniel Gultsch