M src/cheogram/res/values/strings.xml => src/cheogram/res/values/strings.xml +1 -0
@@ 35,4 35,5 @@
<string name="moderate_reason">Moderation Reason</string>
<string name="unable_to_moderate">Unable to Moderate</string>
<string name="block_media">Block Media</string>
+ <string name="add_contact">New Contact or Channel</string>
</resources>
M src/main/java/eu/siacs/conversations/services/XmppConnectionService.java => src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +12 -0
@@ 136,6 136,7 @@ import eu.siacs.conversations.ui.interfaces.OnMediaLoaded;
import eu.siacs.conversations.ui.interfaces.OnSearchResultsAvailable;
import eu.siacs.conversations.utils.AccountUtils;
import eu.siacs.conversations.utils.Compatibility;
+import eu.siacs.conversations.utils.Consumer;
import eu.siacs.conversations.utils.ConversationsFileObserver;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.EasyOnboardingInvite;
@@ 3432,6 3433,17 @@ public class XmppConnectionService extends Service {
}
}
+ public void checkIfMuc(final Account account, final Jid jid, Consumer<Boolean> cb) {
+ IqPacket request = mIqGenerator.queryDiscoInfo(jid.asBareJid());
+ sendIqPacket(account, request, (acct, reply) -> {
+ ServiceDiscoveryResult result = new ServiceDiscoveryResult(reply);
+ cb.accept(
+ result.getFeatures().contains("http://jabber.org/protocol/muc") &&
+ result.hasIdentity("conference", null)
+ );
+ });
+ }
+
public void fetchConferenceConfiguration(final Conversation conversation) {
fetchConferenceConfiguration(conversation, null);
}
M src/main/java/eu/siacs/conversations/ui/BlocklistActivity.java => src/main/java/eu/siacs/conversations/ui/BlocklistActivity.java +4 -2
@@ 80,12 80,14 @@ public class BlocklistActivity extends AbstractSearchableListItemActivity implem
getString(R.string.block_jabber_id),
getString(R.string.block),
null,
+ null,
account.getJid().asBareJid().toEscapedString(),
true,
- false
+ false,
+ EnterJidDialog.SanityCheck.NO
);
- dialog.setOnEnterJidDialogPositiveListener((accountJid, contactJid) -> {
+ dialog.setOnEnterJidDialogPositiveListener((accountJid, contactJid, x, y) -> {
Blockable blockable = new RawBlockable(account, contactJid);
if (xmppConnectionService.sendBlockRequest(blockable, false)) {
Toast.makeText(BlocklistActivity.this, R.string.corresponding_conversations_closed, Toast.LENGTH_SHORT).show();
M src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java => src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java +4 -2
@@ 326,13 326,15 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
mActivatedAccounts,
getString(R.string.enter_contact),
getString(R.string.select),
+ null,
jid == null ? null : jid.asBareJid().toString(),
getIntent().getStringExtra(EXTRA_ACCOUNT),
true,
- false
+ false,
+ EnterJidDialog.SanityCheck.NO
);
- dialog.setOnEnterJidDialogPositiveListener((accountJid, contactJid) -> {
+ dialog.setOnEnterJidDialogPositiveListener((accountJid, contactJid, x, y) -> {
final Intent request = getIntent();
final Intent data = new Intent();
data.putExtra("contact", contactJid.toString());
M src/main/java/eu/siacs/conversations/ui/ConversationFragment.java => src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +3 -0
@@ 2910,6 2910,9 @@ public class ConversationFragment extends XmppFragment
attachFile(ATTACHMENT_CHOICE_RECORD_VOICE, false);
return;
}
+ if ("call".equals(postInitAction)) {
+ checkPermissionAndTriggerAudioCall();
+ }
if ("message".equals(postInitAction)) {
binding.conversationViewPager.post(() -> {
binding.conversationViewPager.setCurrentItem(0);
M src/main/java/eu/siacs/conversations/ui/EnterJidDialog.java => src/main/java/eu/siacs/conversations/ui/EnterJidDialog.java +37 -18
@@ 57,39 57,51 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
private static final String TITLE_KEY = "title";
private static final String POSITIVE_BUTTON_KEY = "positive_button";
+ private static final String SECONDARY_BUTTON_KEY = "secondary_button";
private static final String PREFILLED_JID_KEY = "prefilled_jid";
private static final String ACCOUNT_KEY = "account";
private static final String ALLOW_EDIT_JID_KEY = "allow_edit_jid";
private static final String ACCOUNTS_LIST_KEY = "activated_accounts_list";
private static final String SANITY_CHECK_JID = "sanity_check_jid";
+ private static final String SHOW_BOOKMARK_CHECKBOX = "show_bookmark_checkbox";
private KnownHostsAdapter knownHostsAdapter;
private Collection<String> whitelistedDomains = Collections.emptyList();
private EnterJidDialogBinding binding;
private AlertDialog dialog;
- private boolean sanityCheckJid = false;
+ private SanityCheck sanityCheckJid = SanityCheck.NO;
private boolean issuedWarning = false;
private GatewayListAdapter gatewayListAdapter = new GatewayListAdapter();
+ public static enum SanityCheck {
+ NO,
+ YES,
+ ALLOW_MUC
+ }
+
public static EnterJidDialog newInstance(
final List<String> activatedAccounts,
final String title,
final String positiveButton,
+ final String secondaryButton,
final String prefilledJid,
final String account,
boolean allowEditJid,
- final boolean sanity_check_jid) {
+ boolean showBookmarkCheckbox,
+ final SanityCheck sanity_check_jid) {
EnterJidDialog dialog = new EnterJidDialog();
Bundle bundle = new Bundle();
bundle.putString(TITLE_KEY, title);
bundle.putString(POSITIVE_BUTTON_KEY, positiveButton);
+ bundle.putString(SECONDARY_BUTTON_KEY, secondaryButton);
bundle.putString(PREFILLED_JID_KEY, prefilledJid);
bundle.putString(ACCOUNT_KEY, account);
bundle.putBoolean(ALLOW_EDIT_JID_KEY, allowEditJid);
bundle.putStringArrayList(ACCOUNTS_LIST_KEY, (ArrayList<String>) activatedAccounts);
- bundle.putBoolean(SANITY_CHECK_JID, sanity_check_jid);
+ bundle.putInt(SANITY_CHECK_JID, sanity_check_jid.ordinal());
+ bundle.putBoolean(SHOW_BOOKMARK_CHECKBOX, showBookmarkCheckbox);
dialog.setArguments(bundle);
return dialog;
}
@@ 131,7 143,11 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
binding.jid.setCursorVisible(false);
}
}
- sanityCheckJid = getArguments().getBoolean(SANITY_CHECK_JID, false);
+ sanityCheckJid = SanityCheck.values()[getArguments().getInt(SANITY_CHECK_JID, SanityCheck.NO.ordinal())];
+
+ if (!getArguments().getBoolean(SHOW_BOOKMARK_CHECKBOX, false)) {
+ binding.bookmark.setVisibility(View.GONE);
+ }
DelayedHintHelper.setHint(R.string.account_settings_example_jabber_id, binding.jid);
@@ 185,23 201,26 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
});
builder.setView(binding.getRoot());
- builder.setNegativeButton(R.string.cancel, null);
builder.setPositiveButton(getArguments().getString(POSITIVE_BUTTON_KEY), null);
+ if (getArguments().getString(SECONDARY_BUTTON_KEY) == null) {
+ builder.setNegativeButton(R.string.cancel, null);
+ } else {
+ builder.setNegativeButton(getArguments().getString(SECONDARY_BUTTON_KEY), null);
+ builder.setNeutralButton(R.string.cancel, null);
+ }
this.dialog = builder.create();
- View.OnClickListener dialogOnClick =
- v -> {
- handleEnter(binding, account);
- };
-
binding.jid.setOnEditorActionListener(
(v, actionId, event) -> {
- handleEnter(binding, account);
+ handleEnter(binding, account, false);
return true;
});
dialog.show();
- dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(dialogOnClick);
+ dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener((v) -> handleEnter(binding, account, false));
+ if (getArguments().getString(SECONDARY_BUTTON_KEY) != null) {
+ dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setOnClickListener((v) -> handleEnter(binding, account, true));
+ }
return dialog;
}
@@ 217,7 236,7 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
}
}
- private void handleEnter(EnterJidDialogBinding binding, String account) {
+ private void handleEnter(EnterJidDialogBinding binding, String account, boolean secondary) {
if (!binding.account.isEnabled() && account == null) {
return;
}
@@ 236,7 255,7 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
return;
}
- final Jid contactJid;
+ Jid contactJid = null;
try {
contactJid = Jid.ofEscaped(jidString);
} catch (final IllegalArgumentException e) {
@@ 244,14 263,14 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
return;
}
- if (!issuedWarning && sanityCheckJid) {
+ if (!issuedWarning && sanityCheckJid != SanityCheck.NO) {
if (contactJid.isDomainJid()) {
binding.jidLayout.setError(getActivity().getString(R.string.this_looks_like_a_domain));
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setText(R.string.add_anway);
issuedWarning = true;
return;
}
- if (suspiciousSubDomain(contactJid.getDomain().toEscapedString())) {
+ if (sanityCheckJid != SanityCheck.ALLOW_MUC && suspiciousSubDomain(contactJid.getDomain().toEscapedString())) {
binding.jidLayout.setError(getActivity().getString(R.string.this_looks_like_channel));
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setText(R.string.add_anway);
issuedWarning = true;
@@ 261,7 280,7 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
if (mListener != null) {
try {
- if (mListener.onEnterJidDialogPositive(accountJid, contactJid)) {
+ if (mListener.onEnterJidDialogPositive(accountJid, contactJid, secondary, binding.bookmark.isChecked())) {
dialog.dismiss();
}
} catch (JidError error) {
@@ 335,7 354,7 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
}
public interface OnEnterJidDialogPositiveListener {
- boolean onEnterJidDialogPositive(Jid account, Jid contact) throws EnterJidDialog.JidError;
+ boolean onEnterJidDialogPositive(Jid account, Jid contact, boolean secondary, boolean save) throws EnterJidDialog.JidError;
}
public static class JidError extends Exception {
M src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java => src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java +54 -21
@@ 339,9 339,6 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
case R.id.discover_public_channels:
startActivity(new Intent(this, ChannelDiscoveryActivity.class));
break;
- case R.id.join_public_channel:
- showJoinConferenceDialog(prefilled);
- break;
case R.id.create_private_group_chat:
showCreatePrivateGroupChatDialog();
break;
@@ 531,15 528,17 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
ft.addToBackStack(null);
EnterJidDialog dialog = EnterJidDialog.newInstance(
mActivatedAccounts,
- getString(R.string.add_contact),
- getString(R.string.add),
+ getString(R.string.start_conversation),
+ getString(R.string.message),
+ "Call",
prefilledJid,
invite == null ? null : invite.account,
invite == null || !invite.hasFingerprints(),
- true
+ true,
+ EnterJidDialog.SanityCheck.ALLOW_MUC
);
- dialog.setOnEnterJidDialogPositiveListener((accountJid, contactJid) -> {
+ dialog.setOnEnterJidDialogPositiveListener((accountJid, contactJid, call, save) -> {
if (!xmppConnectionServiceBound) {
return false;
}
@@ 548,25 547,55 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
if (account == null) {
return true;
}
-
final Contact contact = account.getRoster().getContact(contactJid);
+
if (invite != null && invite.getName() != null) {
contact.setServerName(invite.getName());
}
- if (contact.isSelf()) {
- switchToConversation(contact);
- return true;
- } else if (contact.showInRoster()) {
- throw new EnterJidDialog.JidError(getString(R.string.contact_already_exists));
- } else {
- final String preAuth = invite == null ? null : invite.getParameter(XmppUri.PARAMETER_PRE_AUTH);
- xmppConnectionService.createContact(contact, true, preAuth);
- if (invite != null && invite.hasFingerprints()) {
- xmppConnectionService.verifyFingerprints(contact, invite.getFingerprints());
- }
- switchToConversationDoNotAppend(contact, invite == null ? null : invite.getBody());
+
+ if (contact.isSelf() || contact.showInRoster()) {
+ switchToConversationDoNotAppend(contact, invite == null ? null : invite.getBody(), call ? "call" : null);
return true;
}
+
+ xmppConnectionService.checkIfMuc(account, contactJid, (isMuc) -> {
+ if (isMuc) {
+ if (save) {
+ Bookmark bookmark = account.getBookmark(contactJid);
+ if (bookmark != null) {
+ openConversationsForBookmark(bookmark);
+ } else {
+ bookmark = new Bookmark(account, contactJid.asBareJid());
+ bookmark.setAutojoin(getBooleanPreference("autojoin", R.bool.autojoin));
+ final String nick = contactJid.getResource();
+ if (nick != null && !nick.isEmpty() && !nick.equals(MucOptions.defaultNick(account))) {
+ bookmark.setNick(nick);
+ }
+ xmppConnectionService.createBookmark(account, bookmark);
+ final Conversation conversation = xmppConnectionService
+ .findOrCreateConversation(account, contactJid, true, true, true);
+ bookmark.setConversation(conversation);
+ switchToConversationDoNotAppend(conversation, invite == null ? null : invite.getBody());
+ }
+ } else {
+ final Conversation conversation = xmppConnectionService.findOrCreateConversation(account, contactJid, true, true, true);
+ switchToConversationDoNotAppend(conversation, invite == null ? null : invite.getBody());
+ }
+ } else {
+ if (save) {
+ final String preAuth = invite == null ? null : invite.getParameter(XmppUri.PARAMETER_PRE_AUTH);
+ xmppConnectionService.createContact(contact, true, preAuth);
+ if (invite != null && invite.hasFingerprints()) {
+ xmppConnectionService.verifyFingerprints(contact, invite.getFingerprints());
+ }
+ }
+ switchToConversationDoNotAppend(contact, invite == null ? null : invite.getBody(), call ? "call" : null);
+ }
+
+ dialog.dismiss();
+ });
+
+ return false;
});
dialog.show(ft, FRAGMENT_TAG_DIALOG);
}
@@ 636,8 665,12 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
}
protected void switchToConversationDoNotAppend(Contact contact, String body) {
+ switchToConversationDoNotAppend(contact, body, null);
+ }
+
+ protected void switchToConversationDoNotAppend(Contact contact, String body, String postInit) {
Conversation conversation = xmppConnectionService.findOrCreateConversation(contact.getAccount(), contact.getJid(), false, true);
- switchToConversationDoNotAppend(conversation, body);
+ switchToConversation(conversation, body, false, null, false, true, postInit);
}
@Override
M src/main/java/eu/siacs/conversations/ui/widget/DialpadView.java => src/main/java/eu/siacs/conversations/ui/widget/DialpadView.java +1 -5
@@ 26,6 26,7 @@ import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.databinding.DataBindingUtil;
import eu.siacs.conversations.databinding.DialpadBinding;
import eu.siacs.conversations.R;
+import eu.siacs.conversations.utils.Consumer;
public class DialpadView extends ConstraintLayout implements View.OnClickListener {
@@ 64,9 65,4 @@ public class DialpadView extends ConstraintLayout implements View.OnClickListene
public void onClick(View v) {
clickConsumer.accept(v.getTag().toString());
}
-
- // Based on java.util.function.Consumer to avoid Android 24 dependency
- public interface Consumer<T> {
- void accept(T t);
- }
}
A src/main/java/eu/siacs/conversations/utils/Consumer.java => src/main/java/eu/siacs/conversations/utils/Consumer.java +6 -0
@@ 0,0 1,6 @@
+package eu.siacs.conversations.utils;
+
+// Based on java.util.function.Consumer to avoid Android 24 dependency
+public interface Consumer<T> {
+ void accept(T t);
+}
M src/main/res/layout/enter_jid_dialog.xml => src/main/res/layout/enter_jid_dialog.xml +9 -0
@@ 43,5 43,14 @@
android:imeOptions="actionDone|flagNoExtractUi"
android:inputType="textEmailAddress" />
</com.google.android.material.textfield.TextInputLayout>
+
+ <CheckBox
+ android:id="@+id/bookmark"
+ style="@style/Widget.Conversations.CheckBox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:checked="true"
+ android:text="Save as Contact / Bookmark"/>
</LinearLayout>
</layout>
M src/main/res/menu/start_conversation_fab_submenu.xml => src/main/res/menu/start_conversation_fab_submenu.xml +1 -5
@@ 5,10 5,6 @@
android:icon="@drawable/ic_search_white_24dp"
android:title="@string/discover_channels" />
<item
- android:id="@+id/join_public_channel"
- android:icon="@drawable/ic_input_white_24dp"
- android:title="@string/join_public_channel" />
- <item
android:id="@+id/create_public_channel"
android:icon="@drawable/ic_public_white_24dp"
android:title="@string/create_public_channel" />
@@ 20,4 16,4 @@
android:id="@+id/create_contact"
android:icon="@drawable/ic_person_white_48dp"
android:title="@string/add_contact" />
-</menu>>
\ No newline at end of file
+</menu>