Merge remote-tracking branch 'origin/master'

This commit is contained in:
12aw 2024-03-12 15:31:47 +01:00
commit d09b12e5f4
8 changed files with 252 additions and 72 deletions

View file

@ -0,0 +1,44 @@
package de.monocles.chat;
import android.util.Log;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import de.monocles.chat.services.ProviderService;
import eu.siacs.conversations.BuildConfig;
public class Config {
public static final String LOGTAG = BuildConfig.LOGTAG;
public static final String PROVIDER_URL = "https://data.xmpp.net/providers/v2/providers-B.json"; // https://invent.kde.org/melvo/xmpp-providers
//or https://invent.kde.org/melvo/xmpp-providers/-/raw/master/providers.json
public static class DOMAIN {
// use this fallback server if provider list can't be updated automatically
public static final List<String> DOMAINS = Arrays.asList(
"monocles.de",
"monocles.eu",
"conversations.im"
);
// don't use these servers in provider list
public static final List<String> BLACKLISTED_DOMAINS = Arrays.asList(
"blabber.im"
);
// choose a random server for registration
public static String getRandomServer() {
try {
new ProviderService().execute();
final String domain = ProviderService.getProviders().get(new Random().nextInt(ProviderService.getProviders().size()));
Log.d(LOGTAG, "MagicCreate account on domain: " + domain);
return domain;
} catch (Exception e) {
Log.d(LOGTAG, "Error getting random server ", e);
}
return "conversations.im";
}
}
}

View file

@ -7,17 +7,20 @@ import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
public class KeyboardHeightProvider extends PopupWindow {
LinearLayout popupView;
ViewTreeObserver.OnGlobalLayoutListener globalLayoutListener;
public KeyboardHeightProvider(Context context, WindowManager windowManager, View parentView, KeyboardHeightListener listener) {
super(context);
LinearLayout popupView = new LinearLayout(context);
popupView = new LinearLayout(context);
popupView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
popupView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
globalLayoutListener = () -> {
DisplayMetrics metrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(metrics);
@ -37,7 +40,8 @@ public class KeyboardHeightProvider extends PopupWindow {
if (listener != null) {
listener.onKeyboardHeightChanged(keyboardHeight, keyboardOpen, isLandscape);
}
});
};
popupView.getViewTreeObserver().addOnGlobalLayoutListener(globalLayoutListener);
setContentView(popupView);
@ -50,6 +54,15 @@ public class KeyboardHeightProvider extends PopupWindow {
parentView.post(() -> showAtLocation(parentView, Gravity.NO_GRAVITY, 0, 0));
}
@Override
public void dismiss() {
if (globalLayoutListener != null) {
popupView.getViewTreeObserver().removeOnGlobalLayoutListener(globalLayoutListener);
globalLayoutListener = null;
}
super.dismiss();
}
public interface KeyboardHeightListener {
void onKeyboardHeightChanged(int keyboardHeight, boolean keyboardOpen, boolean isLandscape);
}

View file

@ -0,0 +1,92 @@
package de.monocles.chat.services;
import android.os.AsyncTask;
import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import de.monocles.chat.Config;
import eu.siacs.conversations.http.HttpConnectionManager;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.ProviderHelper;
public class ProviderService extends AsyncTask<String, Object, Boolean> {
public static List<String> providers = new ArrayList<>();
XmppConnectionService xmppConnectionService;
private boolean mUseTor;
private boolean mUseI2P;
public ProviderService() {
}
public static List<String> getProviders() {
final HashSet<String> provider = new HashSet<>(Config.DOMAIN.DOMAINS);
if (!providers.isEmpty()) {
provider.addAll(providers);
}
return new ArrayList<>(provider);
}
@Override
protected Boolean doInBackground(String... params) {
StringBuilder jsonString = new StringBuilder();
boolean isError = false;
mUseTor = xmppConnectionService != null && xmppConnectionService.useTorToConnect();
mUseI2P = xmppConnectionService != null && xmppConnectionService.useI2PToConnect();
if (!mUseTor && mUseI2P) {
// Do not update providers if all connections tunneled to I2P (via settings checkbox) without Tor
return true;
}
try {
Log.d(Config.LOGTAG, "ProviderService: Updating provider list from " + Config.PROVIDER_URL);
final InputStream is = HttpConnectionManager.open(Config.PROVIDER_URL, mUseTor, false);
final BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = reader.readLine()) != null) {
jsonString.append(line);
}
is.close();
reader.close();
} catch (Exception e) {
e.printStackTrace();
isError = true;
}
try {
getProviderFromJSON(jsonString.toString());
} catch (Exception e) {
e.printStackTrace();
isError = true;
}
if (isError) {
Log.d(Config.LOGTAG, "ProviderService: Updating provider list failed");
}
return !isError;
}
private void getProviderFromJSON(String json) {
List<ProviderHelper> providersList = new Gson().fromJson(json, new TypeToken<List<ProviderHelper>>() {
}.getType());
for (int i = 0; i < providersList.size(); i++) {
final String provider = providersList.get(i).get_jid();
if (provider.length() > 0) {
if (!Config.DOMAIN.BLACKLISTED_DOMAINS.contains(provider)) {
Log.d(Config.LOGTAG, "ProviderService: Updating provider list. Adding " + provider);
providers.add(provider);
}
}
}
}
}

View file

@ -78,14 +78,10 @@ public final class Config {
public static final String CHANGELOG_URL = "https://codeberg.org/monocles/monocles_chat/releases";
public static final String GIT_URL = "https://codeberg.org/Arne/monocles_chat";
public static final String PROVIDER_URL = "";// "https://data.xmpp.net/providers/v1/providers-A.json"; // https://invent.kde.org/melvo/xmpp-providers
//or https://invent.kde.org/melvo/xmpp-providers/-/raw/master/providers.json
public static final String XMPP_IP = null; //BuildConfig.XMPP_IP; // set to null means disable
public static final Integer[] XMPP_Ports = null; //BuildConfig.XMPP_Ports; // set to null means disable
public static final String DOMAIN_LOCK = BuildConfig.DOMAIN_LOCK; //only allow account creation for this domain
public static final String MAGIC_CREATE_DOMAIN = BuildConfig.MAGIC_CREATE_DOMAIN; //"monocles.eu";
public static final Jid QUICKSY_DOMAIN = Jid.of("cheogram.com");
public static final String CHANNEL_DISCOVERY = "https://search.jabber.network";
public static final boolean DISALLOW_REGISTRATION_IN_UI = false; //hide the register checkbox

View file

@ -384,6 +384,9 @@ public class ConversationFragment extends XmppFragment
private File savingAsSticker = null;
private EmojiSearch emojiSearch = null;
private MediaPreviewAdapter mediaPreviewAdapter;
private KeyboardHeightProvider.KeyboardHeightListener keyboardHeightListener = null;
private KeyboardHeightProvider keyboardHeightProvider = null;
private final OnClickListener clickToMuc = new OnClickListener() {
@Override
@ -1742,7 +1745,9 @@ public class ConversationFragment extends XmppFragment
final MenuItem menuManageAccounts = menu.findItem(R.id.action_accounts);
final MenuItem menuSettings = menu.findItem(R.id.action_settings);
final MenuItem menuInviteToChat = menu.findItem(R.id.action_invite_user);
if (activity == null) {
return;
}
if (conversation != null) {
if (conversation.getMode() == Conversation.MODE_MULTI || (activity.xmppConnectionService != null && !activity.xmppConnectionService.hasInternetConnection())) {
menuInviteContact.setVisible(conversation.getMucOptions().canInvite());
@ -1852,7 +1857,6 @@ public class ConversationFragment extends XmppFragment
DisplayMetrics displayMetrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
if (displayMetrics.heightPixels > 0) binding.textinput.setMaxHeight(displayMetrics.heightPixels / 4);
binding.textSendButton.setOnClickListener(this.mSendButtonListener);
binding.cancelButton.setOnClickListener(this.mCancelVoiceRecord);
binding.shareButton.setOnClickListener(this.mShareVoiceRecord);
@ -1981,6 +1985,17 @@ public class ConversationFragment extends XmppFragment
public void onDestroyView() {
super.onDestroyView();
Log.d(Config.LOGTAG, "ConversationFragment.onDestroyView()");
if (activity != null &&
activity.getWindow() != null &&
activity.getWindow().getDecorView() != null) {
ViewCompat.setOnApplyWindowInsetsListener(activity.getWindow().getDecorView(), null);
}
if (keyboardHeightProvider != null) {
keyboardHeightProvider.dismiss();
}
if (messageListAdapter == null) {
return;
}
messageListAdapter.setOnContactPictureClicked(null);
messageListAdapter.setOnContactPictureLongClicked(null);
messageListAdapter.setOnInlineImageLongClicked(null);
@ -4083,6 +4098,9 @@ public class ConversationFragment extends XmppFragment
hideSoftKeyboard(activity);
}
final Activity activity = getActivity();
if (messageListAdapter == null) {
return;
}
messageListAdapter.unregisterListenerInAudioPlayer();
if (activity == null || !activity.isChangingConfigurations()) {
hideSoftKeyboard(activity);
@ -4186,6 +4204,9 @@ public class ConversationFragment extends XmppFragment
}
this.binding.textinput.setKeyboardListener(this);
this.binding.textinputSubject.setKeyboardListener(this);
if (messageListAdapter == null) {
return true;
}
messageListAdapter.updatePreferences();
refresh(false);
activity.invalidateOptionsMenu();
@ -4241,30 +4262,29 @@ public class ConversationFragment extends XmppFragment
private void hasWriteAccessInMUC() {
if ((conversation != null && conversation.getMode() == Conversation.MODE_MULTI && !conversation.getMucOptions().participating()) && !activity.xmppConnectionService.hideYouAreNotParticipating()) {
activity.runOnUiThread(() -> {
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(getString(R.string.you_are_not_participating));
builder.setMessage(getString(R.string.no_write_access_in_public_muc));
builder.setNegativeButton(getString(R.string.hide_warning),
(dialog, which) -> {
SharedPreferences preferences = activity.getPreferences();
preferences.edit().putBoolean(HIDE_YOU_ARE_NOT_PARTICIPATING, true).apply();
hideSnackbar();
});
builder.setPositiveButton(getString(R.string.ok),
(dialog, which) -> {
try {
Intent intent = new Intent(getActivity(), ConferenceDetailsActivity.class);
intent.setAction(ConferenceDetailsActivity.ACTION_VIEW_MUC);
intent.putExtra("uuid", conversation.getUuid());
startActivity(intent);
activity.overridePendingTransition(R.animator.fade_in, R.animator.fade_out);
} catch (Exception e) {
e.printStackTrace();
}
});
builder.create().show();
});
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(getString(R.string.you_are_not_participating));
builder.setMessage(getString(R.string.no_write_access_in_public_muc));
builder.setNegativeButton(getString(R.string.hide_warning),
(dialog, which) -> {
SharedPreferences preferences = activity.getPreferences();
preferences.edit().putBoolean(HIDE_YOU_ARE_NOT_PARTICIPATING, true).apply();
hideSnackbar();
});
builder.setPositiveButton(getString(R.string.ok),
(dialog, which) -> {
try {
Intent intent = new Intent(getActivity(), ConferenceDetailsActivity.class);
intent.setAction(ConferenceDetailsActivity.ACTION_VIEW_MUC);
intent.putExtra("uuid", conversation.getUuid());
startActivity(intent);
activity.overridePendingTransition(R.animator.fade_in, R.animator.fade_out);
} catch (Exception e) {
e.printStackTrace();
}
});
AlertDialog alertDialog = builder.create();
activity.runOnUiThread(alertDialog::show);
showSnackbar(R.string.no_write_access_in_public_muc, R.string.ok, clickToMuc);
}
}
@ -4750,7 +4770,10 @@ public class ConversationFragment extends XmppFragment
private boolean storeNextMessage(String msg) {
final boolean participating = conversation.getMode() == Conversational.MODE_SINGLE || conversation.getMucOptions().participating();
if (this.conversation.getStatus() != Conversation.STATUS_ARCHIVED && participating && this.conversation.setNextMessage(msg)) {
if (this.conversation.getStatus() != Conversation.STATUS_ARCHIVED &&
participating &&
this.conversation.setNextMessage(msg) &&
Objects.nonNull(activity.xmppConnectionService)) {
this.activity.xmppConnectionService.updateConversation(this.conversation);
return true;
}
@ -4862,41 +4885,42 @@ public class ConversationFragment extends XmppFragment
return ViewCompat.onApplyWindowInsets(v, insets);
});
} else {
if (keyboardHeightProvider != null) {
return;
}
RelativeLayout llRoot = binding.conversationsFragment; //The root layout (Linear, Relative, Contraint, etc...)
new KeyboardHeightProvider(activity, activity.getWindowManager(), llRoot, new KeyboardHeightProvider.KeyboardHeightListener() {
@Override
public void onKeyboardHeightChanged(int keyboardHeight, boolean keyboardOpen, boolean isLandscape) {
Log.i("keyboard listener", "keyboardHeight: " + keyboardHeight + " keyboardOpen: " + keyboardOpen + " isLandscape: " + isLandscape);
if (keyboardOpen && !(secondaryFragment instanceof ConversationFragment)) {
binding.keyboardButton.setVisibility(GONE);
binding.emojiButton.setVisibility(VISIBLE);
params.height = keyboardHeight - 25;
emojipickerview.setLayoutParams(params);
} else if (keyboardOpen) {
binding.keyboardButton.setVisibility(GONE);
binding.emojiButton.setVisibility(VISIBLE);
params.height = keyboardHeight - 150;
emojipickerview.setLayoutParams(params);
} else if (binding.emojiButton.getVisibility() == VISIBLE) {
binding.keyboardButton.setVisibility(GONE);
params.height = 0;
emojipickerview.setLayoutParams(params);
} else if (binding.keyboardButton.getVisibility() == VISIBLE && keyboardHeight == 0) {
binding.emojiButton.setVisibility(GONE);
params.height = 600;
emojipickerview.setLayoutParams(params);
} else if (binding.keyboardButton.getVisibility() == VISIBLE && keyboardHeight > 70) {
binding.emojiButton.setVisibility(GONE);
params.height = keyboardHeight;
emojipickerview.setLayoutParams(params);
}
if (activity != null && activity.xmppConnectionService != null && keyboardOpen && activity.xmppConnectionService.showTextFormatting()) {
showTextFormat(me);
} else {
hideTextFormat();
}
keyboardHeightListener = (int keyboardHeight, boolean keyboardOpen, boolean isLandscape) -> {
Log.i("keyboard listener", "keyboardHeight: " + keyboardHeight + " keyboardOpen: " + keyboardOpen + " isLandscape: " + isLandscape);
if (keyboardOpen && !(secondaryFragment instanceof ConversationFragment)) {
binding.keyboardButton.setVisibility(GONE);
binding.emojiButton.setVisibility(VISIBLE);
params.height = keyboardHeight - 25;
emojipickerview.setLayoutParams(params);
} else if (keyboardOpen) {
binding.keyboardButton.setVisibility(GONE);
binding.emojiButton.setVisibility(VISIBLE);
params.height = keyboardHeight - 150;
emojipickerview.setLayoutParams(params);
} else if (binding.emojiButton.getVisibility() == VISIBLE) {
binding.keyboardButton.setVisibility(GONE);
params.height = 0;
emojipickerview.setLayoutParams(params);
} else if (binding.keyboardButton.getVisibility() == VISIBLE && keyboardHeight == 0) {
binding.emojiButton.setVisibility(GONE);
params.height = 600;
emojipickerview.setLayoutParams(params);
} else if (binding.keyboardButton.getVisibility() == VISIBLE && keyboardHeight > 70) {
binding.emojiButton.setVisibility(GONE);
params.height = keyboardHeight;
emojipickerview.setLayoutParams(params);
}
});
if (activity != null && activity.xmppConnectionService != null && keyboardOpen && activity.xmppConnectionService.showTextFormatting()) {
showTextFormat(me);
} else {
hideTextFormat();
}
};
keyboardHeightProvider = new KeyboardHeightProvider(activity, activity.getWindowManager(), llRoot, keyboardHeightListener);
}
}

View file

@ -23,8 +23,10 @@ import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import de.monocles.chat.SignUpPage;
import de.monocles.chat.services.ProviderService;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ActivityMagicCreateBinding;
@ -88,10 +90,19 @@ public class MagicCreateActivity extends XmppActivity implements TextWatcher, Ad
}
super.onCreate(savedInstanceState);
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_magic_create);
final List<String> domains = Arrays.asList(getResources().getStringArray(R.array.domains));
// Try fetching current providers list
final List<String> domains = ProviderService.getProviders();
Collections.sort(domains, String::compareToIgnoreCase);
final ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_selectable_list_item, domains);
int defaultServer = adapter.getPosition("conversations.im");
try {
if (new ProviderService().execute().get()) {
adapter.notifyDataSetChanged();
}
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
// final List<String> domains = Arrays.asList(getResources().getStringArray(R.array.domains));
int defaultServer = adapter.getPosition(de.monocles.chat.Config.DOMAIN.getRandomServer());
if (registerFromUri && !useOwnProvider && (this.preAuth != null || domain != null)) {
binding.server.setEnabled(false);
binding.server.setVisibility(View.GONE);
@ -238,7 +249,7 @@ public class MagicCreateActivity extends XmppActivity implements TextWatcher, Ad
private void updateFullJidInformation(String username) {
if (useOwnProvider && !registerFromUri) {
this.domain = updateDomain();
} else if (!registerFromUri){
} else if (!registerFromUri && !binding.server.getSelectedItem().toString().isEmpty()) {
this.domain = binding.server.getSelectedItem().toString();
}
if (username.trim().isEmpty()) {

View file

@ -3019,11 +3019,13 @@ public class JingleRtpConnection extends AbstractJingleConnection
this.webRTCWrapper.verifyClosed();
this.jingleConnectionManager.setTerminalSessionState(id, getEndUserState(), getMedia());
this.jingleConnectionManager.finishConnectionOrThrow(this);
/* // Disable call log files for now
try {
File log = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS) + File.separator + APP_DIRECTORY + File.separator + "calls/" + id.getWith().asBareJid() + "." + id.getSessionId() + "." + created + ".log");
log.getParentFile().mkdirs();
Runtime.getRuntime().exec(new String[]{"logcat", "-dT", "" + created + ".0", "-f", log.getAbsolutePath()});
} catch (final IOException e) { }
*/
} else {
throw new IllegalStateException(
String.format("Unable to call finish from %s", this.state));

View file

@ -116,12 +116,10 @@
<string-array name="support_domains">
<item>monocles.eu</item>
<item>monocles.de</item>
<item>conversations.im</item>
</string-array>
<string-array name="support_site">
<item>https://monocles.wiki</item>
<item>https://monocles.wiki</item>
<item>https://conversations.im/#support</item>
</string-array>