diff --git a/build.gradle b/build.gradle index 2540a7836..3f6c3ec6b 100644 --- a/build.gradle +++ b/build.gradle @@ -47,6 +47,7 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.exifinterface:exifinterface:1.3.7' implementation 'androidx.cardview:cardview:1.0.0' + implementation "androidx.preference:preference:1.2.1" implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' implementation 'com.google.android.material:material:1.11.0' diff --git a/src/conversations/java/eu/siacs/conversations/ui/EasyOnboardingInviteActivity.java b/src/conversations/java/eu/siacs/conversations/ui/EasyOnboardingInviteActivity.java index d09005593..9228a5170 100644 --- a/src/conversations/java/eu/siacs/conversations/ui/EasyOnboardingInviteActivity.java +++ b/src/conversations/java/eu/siacs/conversations/ui/EasyOnboardingInviteActivity.java @@ -147,7 +147,7 @@ public class EasyOnboardingInviteActivity extends XmppActivity } @Override - void onBackendConnected() { + protected void onBackendConnected() { if (easyOnboardingInvite != null) { return; } diff --git a/src/conversations/java/eu/siacs/conversations/ui/MagicCreateActivity.java b/src/conversations/java/eu/siacs/conversations/ui/MagicCreateActivity.java index 5a301f769..b6d4d452e 100644 --- a/src/conversations/java/eu/siacs/conversations/ui/MagicCreateActivity.java +++ b/src/conversations/java/eu/siacs/conversations/ui/MagicCreateActivity.java @@ -35,7 +35,7 @@ public class MagicCreateActivity extends XmppActivity implements TextWatcher { protected void refreshUiReal() {} @Override - void onBackendConnected() {} + protected void onBackendConnected() {} @Override protected void onCreate(final Bundle savedInstanceState) { diff --git a/src/conversations/java/eu/siacs/conversations/ui/ManageAccountActivity.java b/src/conversations/java/eu/siacs/conversations/ui/ManageAccountActivity.java index 1a04210dd..2f4c81671 100644 --- a/src/conversations/java/eu/siacs/conversations/ui/ManageAccountActivity.java +++ b/src/conversations/java/eu/siacs/conversations/ui/ManageAccountActivity.java @@ -137,7 +137,7 @@ public class ManageAccountActivity extends XmppActivity } @Override - void onBackendConnected() { + protected void onBackendConnected() { if (selectedAccountJid != null) { this.selectedAccount = xmppConnectionService.findAccountByJid(selectedAccountJid); } diff --git a/src/conversations/java/eu/siacs/conversations/ui/PickServerActivity.java b/src/conversations/java/eu/siacs/conversations/ui/PickServerActivity.java index cbdd21b36..f96a17ffc 100644 --- a/src/conversations/java/eu/siacs/conversations/ui/PickServerActivity.java +++ b/src/conversations/java/eu/siacs/conversations/ui/PickServerActivity.java @@ -22,7 +22,7 @@ public class PickServerActivity extends XmppActivity { } @Override - void onBackendConnected() { + protected void onBackendConnected() { } diff --git a/src/conversations/java/eu/siacs/conversations/ui/ShareViaAccountActivity.java b/src/conversations/java/eu/siacs/conversations/ui/ShareViaAccountActivity.java index 66ed355c4..0b20e26c5 100644 --- a/src/conversations/java/eu/siacs/conversations/ui/ShareViaAccountActivity.java +++ b/src/conversations/java/eu/siacs/conversations/ui/ShareViaAccountActivity.java @@ -57,7 +57,7 @@ public class ShareViaAccountActivity extends XmppActivity { } @Override - void onBackendConnected() { + protected void onBackendConnected() { final int numAccounts = xmppConnectionService.getAccounts().size(); if (numAccounts == 1) { diff --git a/src/conversations/java/eu/siacs/conversations/ui/WelcomeActivity.java b/src/conversations/java/eu/siacs/conversations/ui/WelcomeActivity.java index 24528fc16..b2a40976c 100644 --- a/src/conversations/java/eu/siacs/conversations/ui/WelcomeActivity.java +++ b/src/conversations/java/eu/siacs/conversations/ui/WelcomeActivity.java @@ -88,7 +88,7 @@ public class WelcomeActivity extends XmppActivity protected void refreshUiReal() {} @Override - void onBackendConnected() {} + protected void onBackendConnected() {} @Override public void onStart() { diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index f0d982561..fa89034ae 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -255,7 +255,7 @@ @@ -265,10 +265,10 @@ + android:label="@string/title_activity_choose_contact" /> + android:label="@string/title_activity_block_list" /> @@ -353,7 +353,7 @@ + android:label="@string/media_browser" /> + android:label="@string/group_chat_members" /> + android:label="@string/discover_channels" /> = Build.VERSION_CODES.M) { - scheduleNextIdlePing(); - } + scheduleNextIdlePing(); break; case ACTION_FCM_MESSAGE_RECEIVED: Log.d(Config.LOGTAG, "push message arrived in service. account"); @@ -1119,19 +1117,19 @@ public class XmppConnectionService extends Service { } private boolean dndOnSilentMode() { - return getBooleanPreference(SettingsActivity.DND_ON_SILENT_MODE, R.bool.dnd_on_silent_mode); + return getBooleanPreference(AppSettings.DND_ON_SILENT_MODE, R.bool.dnd_on_silent_mode); } private boolean manuallyChangePresence() { - return getBooleanPreference(SettingsActivity.MANUALLY_CHANGE_PRESENCE, R.bool.manually_change_presence); + return getBooleanPreference(AppSettings.MANUALLY_CHANGE_PRESENCE, R.bool.manually_change_presence); } private boolean treatVibrateAsSilent() { - return getBooleanPreference(SettingsActivity.TREAT_VIBRATE_AS_SILENT, R.bool.treat_vibrate_as_silent); + return getBooleanPreference(AppSettings.TREAT_VIBRATE_AS_SILENT, R.bool.treat_vibrate_as_silent); } private boolean awayWhenScreenLocked() { - return getBooleanPreference(SettingsActivity.AWAY_WHEN_SCREEN_IS_OFF, R.bool.away_when_screen_off); + return getBooleanPreference(AppSettings.AWAY_WHEN_SCREEN_IS_OFF, R.bool.away_when_screen_off); } private String getCompressPicturesPreference() { @@ -1287,10 +1285,6 @@ public class XmppConnectionService extends Service { Log.d(Config.LOGTAG, "restoring accounts..."); this.accounts = databaseBackend.getAccounts(); final SharedPreferences.Editor editor = getPreferences().edit(); - if (this.accounts.size() == 0 && Arrays.asList("Sony", "Sony Ericsson").contains(Build.MANUFACTURER)) { - editor.putBoolean(SettingsActivity.KEEP_FOREGROUND_SERVICE, true); - Log.d(Config.LOGTAG, Build.MANUFACTURER + " is on blacklist. enabling foreground service"); - } final boolean hasEnabledAccounts = hasEnabledAccounts(); editor.putBoolean(EventReceiver.SETTING_ENABLED_ACCOUNTS, hasEnabledAccounts).apply(); editor.apply(); @@ -1334,20 +1328,18 @@ public class XmppConnectionService extends Service { this.pgpServiceConnection.bindToService(); } - final PowerManager pm = ContextCompat.getSystemService(this, PowerManager.class); - this.wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Conversations:Service"); + final PowerManager powerManager = getSystemService(PowerManager.class); + this.wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Conversations:Service"); toggleForegroundService(); updateUnreadCountBadge(); toggleScreenEventReceiver(); final IntentFilter systemBroadcastFilter = new IntentFilter(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - scheduleNextIdlePing(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - systemBroadcastFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - } - systemBroadcastFilter.addAction(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED); + scheduleNextIdlePing(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + systemBroadcastFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); } + systemBroadcastFilter.addAction(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED); ContextCompat.registerReceiver( this, this.mInternalEventReceiver, @@ -1363,6 +1355,17 @@ public class XmppConnectionService extends Service { mForceDuringOnCreate.set(false); toggleForegroundService(); internalPingExecutor.scheduleAtFixedRate(this::manageAccountConnectionStatesInternal,10,10,TimeUnit.SECONDS); + final SharedPreferences sharedPreferences = + androidx.preference.PreferenceManager.getDefaultSharedPreferences(this); + sharedPreferences.registerOnSharedPreferenceChangeListener(new SharedPreferences.OnSharedPreferenceChangeListener() { + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, @Nullable String key) { + Log.d(Config.LOGTAG,"preference '"+key+"' has changed"); + if (AppSettings.KEEP_FOREGROUND_SERVICE.equals(key)) { + toggleForegroundService(); + } + } + }); } @@ -4421,7 +4424,7 @@ public class XmppConnectionService extends Service { } public long getAutomaticMessageDeletionDate() { - final long timeout = getLongPreference(SettingsActivity.AUTOMATIC_MESSAGE_DELETION, R.integer.automatic_message_deletion); + final long timeout = getLongPreference(AppSettings.AUTOMATIC_MESSAGE_DELETION, R.integer.automatic_message_deletion); return timeout == 0 ? timeout : (System.currentTimeMillis() - (timeout * 1000)); } @@ -4459,11 +4462,11 @@ public class XmppConnectionService extends Service { } public boolean showExtendedConnectionOptions() { - return QuickConversationsService.isConversations() && getBooleanPreference("show_connection_options", R.bool.show_connection_options); + return QuickConversationsService.isConversations() && getBooleanPreference(AppSettings.SHOW_CONNECTION_OPTIONS, R.bool.show_connection_options); } public boolean broadcastLastActivity() { - return getBooleanPreference(SettingsActivity.BROADCAST_LAST_ACTIVITY, R.bool.last_activity); + return getBooleanPreference(AppSettings.BROADCAST_LAST_ACTIVITY, R.bool.last_activity); } public int unreadCount() { @@ -4477,7 +4480,7 @@ public class XmppConnectionService extends Service { private List threadSafeList(Set set) { synchronized (LISTENER_LOCK) { - return set.size() == 0 ? Collections.emptyList() : new ArrayList<>(set); + return set.isEmpty() ? Collections.emptyList() : new ArrayList<>(set); } } @@ -5208,7 +5211,7 @@ public class XmppConnectionService extends Service { } public boolean blindTrustBeforeVerification() { - return getBooleanPreference(SettingsActivity.BLIND_TRUST_BEFORE_VERIFICATION, R.bool.btbv); + return getBooleanPreference(AppSettings.BLIND_TRUST_BEFORE_VERIFICATION, R.bool.btbv); } public ShortcutService getShortcutService() { diff --git a/src/main/java/eu/siacs/conversations/ui/AbstractSearchableListItemActivity.java b/src/main/java/eu/siacs/conversations/ui/AbstractSearchableListItemActivity.java index d57737f61..2aa9421fd 100644 --- a/src/main/java/eu/siacs/conversations/ui/AbstractSearchableListItemActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/AbstractSearchableListItemActivity.java @@ -126,7 +126,7 @@ public abstract class AbstractSearchableListItemActivity extends XmppActivity im protected abstract void filterContacts(final String needle); @Override - void onBackendConnected() { + protected void onBackendConnected() { filterContacts(); } diff --git a/src/main/java/eu/siacs/conversations/ui/BaseActivity.java b/src/main/java/eu/siacs/conversations/ui/BaseActivity.java index 9c8871131..cea58c15e 100644 --- a/src/main/java/eu/siacs/conversations/ui/BaseActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/BaseActivity.java @@ -25,7 +25,7 @@ public abstract class BaseActivity extends AppCompatActivity { @Override protected void onResume(){ super.onResume(); - SettingsUtils.applyScreenshotPreventionSetting(this); + SettingsUtils.applyScreenshotSetting(this); } public void setDynamicColors(final boolean isDynamicColors) { diff --git a/src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java b/src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java index cf48a1259..fba273b0a 100644 --- a/src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java @@ -51,7 +51,7 @@ public class ChangePasswordActivity extends XmppActivity implements XmppConnecti private Account mAccount; @Override - void onBackendConnected() { + protected void onBackendConnected() { this.mAccount = extractAccount(getIntent()); if (this.mAccount != null && this.mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE)) { this.binding.currentPasswordLayout.setVisibility(View.GONE); diff --git a/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java b/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java index 8d780d0d7..5a9c31d20 100644 --- a/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java @@ -65,7 +65,7 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O } @Override - void onBackendConnected() { + protected void onBackendConnected() { if (optedIn || method == ChannelDiscoveryService.Method.LOCAL_SERVER) { final String query; if (mMenuSearchView != null && mMenuSearchView.isActionViewExpanded()) { diff --git a/src/main/java/eu/siacs/conversations/ui/ChooseAccountForProfilePictureActivity.java b/src/main/java/eu/siacs/conversations/ui/ChooseAccountForProfilePictureActivity.java index 41a894403..71662589c 100644 --- a/src/main/java/eu/siacs/conversations/ui/ChooseAccountForProfilePictureActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ChooseAccountForProfilePictureActivity.java @@ -47,7 +47,7 @@ public class ChooseAccountForProfilePictureActivity extends XmppActivity { } @Override - void onBackendConnected() { + protected void onBackendConnected() { loadEnabledAccounts(); if (accountList.size() == 1) { goToProfilePictureActivity(accountList.get(0)); diff --git a/src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java b/src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java index 2aacf8927..b9ebb413d 100644 --- a/src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java @@ -362,7 +362,7 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im } @Override - void onBackendConnected() { + protected void onBackendConnected() { filterContacts(); this.mActivatedAccounts.clear(); for (final Account account : xmppConnectionService.getAccounts()) { diff --git a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java index 6d0bc7928..5ed83219d 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java @@ -396,7 +396,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers } @Override - void onBackendConnected() { + protected void onBackendConnected() { if (mPendingConferenceInvite != null) { mPendingConferenceInvite.execute(this); mPendingConferenceInvite = null; diff --git a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java index 24dd3cafd..dc038ce37 100644 --- a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java @@ -39,6 +39,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import eu.siacs.conversations.AppSettings; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.axolotl.AxolotlService; @@ -243,7 +244,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp public void onStart() { super.onStart(); final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); - this.showDynamicTags = preferences.getBoolean(SettingsActivity.SHOW_DYNAMIC_TAGS, false); + this.showDynamicTags = preferences.getBoolean(AppSettings.SHOW_DYNAMIC_TAGS, false); this.showLastSeen = preferences.getBoolean("last_activity", false); binding.mediaWrapper.setVisibility(Compatibility.hasStoragePermission(this) ? View.VISIBLE : View.GONE); mMediaAdapter.setAttachments(Collections.emptyList()); diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java index 92329c666..7d3846ebe 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java @@ -144,7 +144,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio } @Override - void onBackendConnected() { + protected void onBackendConnected() { if (performRedirectIfNecessary(true)) { return; } diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index be8caa986..bc4fab2cc 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -47,6 +47,7 @@ import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; +import eu.siacs.conversations.AppSettings; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.axolotl.AxolotlService; @@ -938,7 +939,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat private void changePresence() { SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); - boolean manualStatus = sharedPreferences.getBoolean(SettingsActivity.MANUALLY_CHANGE_PRESENCE, getResources().getBoolean(R.bool.manually_change_presence)); + boolean manualStatus = sharedPreferences.getBoolean(AppSettings.MANUALLY_CHANGE_PRESENCE, getResources().getBoolean(R.bool.manually_change_presence)); final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this); final DialogPresenceBinding binding = DataBindingUtil.inflate(getLayoutInflater(), R.layout.dialog_presence, null, false); String current = mAccount.getPresenceStatusMessage(); diff --git a/src/main/java/eu/siacs/conversations/ui/MediaBrowserActivity.java b/src/main/java/eu/siacs/conversations/ui/MediaBrowserActivity.java index f8d60d557..ac5b07e77 100644 --- a/src/main/java/eu/siacs/conversations/ui/MediaBrowserActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/MediaBrowserActivity.java @@ -44,7 +44,7 @@ public class MediaBrowserActivity extends XmppActivity implements OnMediaLoaded } @Override - void onBackendConnected() { + protected void onBackendConnected() { Intent intent = getIntent(); String account = intent == null ? null : intent.getStringExtra("account"); String jid = intent == null ? null : intent.getStringExtra("jid"); diff --git a/src/main/java/eu/siacs/conversations/ui/MemorizingActivity.java b/src/main/java/eu/siacs/conversations/ui/MemorizingActivity.java index 56913b2a1..bfce03860 100644 --- a/src/main/java/eu/siacs/conversations/ui/MemorizingActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/MemorizingActivity.java @@ -60,7 +60,7 @@ public class MemorizingActivity extends AppCompatActivity implements OnClickList @Override public void onResume() { super.onResume(); - SettingsUtils.applyScreenshotPreventionSetting(this); + SettingsUtils.applyScreenshotSetting(this); Intent i = getIntent(); decisionId = i.getIntExtra(MemorizingTrustManager.DECISION_INTENT_ID, MTMDecision.DECISION_INVALID); diff --git a/src/main/java/eu/siacs/conversations/ui/MucUsersActivity.java b/src/main/java/eu/siacs/conversations/ui/MucUsersActivity.java index f6eae81cf..72cad4cd0 100644 --- a/src/main/java/eu/siacs/conversations/ui/MucUsersActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/MucUsersActivity.java @@ -49,7 +49,7 @@ public class MucUsersActivity extends XmppActivity implements XmppConnectionServ } @Override - void onBackendConnected() { + protected void onBackendConnected() { final Intent intent = getIntent(); final String uuid = intent == null ? null : intent.getStringExtra("uuid"); if (uuid != null) { diff --git a/src/main/java/eu/siacs/conversations/ui/PublishGroupChatProfilePictureActivity.java b/src/main/java/eu/siacs/conversations/ui/PublishGroupChatProfilePictureActivity.java index aaef09978..8d686c36f 100644 --- a/src/main/java/eu/siacs/conversations/ui/PublishGroupChatProfilePictureActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/PublishGroupChatProfilePictureActivity.java @@ -63,7 +63,7 @@ public class PublishGroupChatProfilePictureActivity extends XmppActivity impleme } @Override - void onBackendConnected() { + protected void onBackendConnected() { String uuid = pendingConversationUuid.pop(); if (uuid != null) { this.conversation = xmppConnectionService.findConversationByUuid(uuid); diff --git a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java index 75c9468f9..7a2bb0938 100644 --- a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java @@ -475,7 +475,7 @@ public class RtpSessionActivity extends XmppActivity } @Override - void onBackendConnected() { + protected void onBackendConnected() { final var intent = getIntent(); if (intent == null) { return; diff --git a/src/main/java/eu/siacs/conversations/ui/SearchActivity.java b/src/main/java/eu/siacs/conversations/ui/SearchActivity.java index d49d7d23d..5803a20e5 100644 --- a/src/main/java/eu/siacs/conversations/ui/SearchActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/SearchActivity.java @@ -215,7 +215,7 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc } @Override - void onBackendConnected() { + protected void onBackendConnected() { final List searchTerm = pendingSearch.pop(); if (searchTerm != null && currentSearch.watch(searchTerm)) { xmppConnectionService.search(searchTerm, uuid,this); diff --git a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java deleted file mode 100644 index 0e80fa1d5..000000000 --- a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java +++ /dev/null @@ -1,568 +0,0 @@ -package eu.siacs.conversations.ui; - -import android.app.FragmentManager; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.SharedPreferences.OnSharedPreferenceChangeListener; -import android.content.pm.PackageManager; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.preference.CheckBoxPreference; -import android.preference.ListPreference; -import android.preference.Preference; -import android.preference.PreferenceCategory; -import android.preference.PreferenceManager; -import android.preference.PreferenceScreen; -import android.provider.MediaStore; -import android.util.Log; -import android.widget.Toast; - -import androidx.annotation.NonNull; -import androidx.appcompat.app.AlertDialog; -import androidx.core.content.ContextCompat; -import androidx.databinding.DataBindingUtil; - -import com.google.android.material.color.DynamicColors; -import com.google.android.material.dialog.MaterialAlertDialogBuilder; -import com.google.common.base.Strings; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; - -import java.io.File; -import java.net.URI; -import java.net.URISyntaxException; -import java.security.KeyStoreException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import eu.siacs.conversations.Config; -import eu.siacs.conversations.Conversations; -import eu.siacs.conversations.R; -import eu.siacs.conversations.crypto.OmemoSetting; -import eu.siacs.conversations.databinding.ActivitySettingsBinding; -import eu.siacs.conversations.entities.Account; -import eu.siacs.conversations.persistance.FileBackend; -import eu.siacs.conversations.services.ExportBackupService; -import eu.siacs.conversations.services.MemorizingTrustManager; -import eu.siacs.conversations.services.QuickConversationsService; -import eu.siacs.conversations.services.UnifiedPushDistributor; -import eu.siacs.conversations.ui.util.SettingsUtils; -import eu.siacs.conversations.utils.GeoHelper; -import eu.siacs.conversations.utils.TimeFrameUtils; -import eu.siacs.conversations.xmpp.Jid; - -public class SettingsActivity extends XmppActivity implements OnSharedPreferenceChangeListener { - - public static final String KEEP_FOREGROUND_SERVICE = "enable_foreground_service"; - public static final String AWAY_WHEN_SCREEN_IS_OFF = "away_when_screen_off"; - public static final String TREAT_VIBRATE_AS_SILENT = "treat_vibrate_as_silent"; - public static final String DND_ON_SILENT_MODE = "dnd_on_silent_mode"; - public static final String MANUALLY_CHANGE_PRESENCE = "manually_change_presence"; - public static final String BLIND_TRUST_BEFORE_VERIFICATION = "btbv"; - public static final String AUTOMATIC_MESSAGE_DELETION = "automatic_message_deletion"; - public static final String BROADCAST_LAST_ACTIVITY = "last_activity"; - public static final String THEME = "theme"; - public static final String SHOW_DYNAMIC_TAGS = "show_dynamic_tags"; - public static final String OMEMO_SETTING = "omemo"; - public static final String PREVENT_SCREENSHOTS = "prevent_screenshots"; - - public static final int REQUEST_CREATE_BACKUP = 0xbf8701; - - private SettingsFragment mSettingsFragment; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - final ActivitySettingsBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_settings); - FragmentManager fm = getFragmentManager(); - mSettingsFragment = (SettingsFragment) fm.findFragmentById(R.id.settings_content); - if (mSettingsFragment == null - || !mSettingsFragment.getClass().equals(SettingsFragment.class)) { - mSettingsFragment = new SettingsFragment(); - fm.beginTransaction().replace(R.id.settings_content, mSettingsFragment).commit(); - } - mSettingsFragment.setActivityIntent(getIntent()); - Activities.setStatusAndNavigationBarColors(this, binding.getRoot()); - setSupportActionBar(binding.toolbar); - configureActionBar(getSupportActionBar()); - } - - @Override - void onBackendConnected() { - final Preference accountPreference = - mSettingsFragment.findPreference(UnifiedPushDistributor.PREFERENCE_ACCOUNT); - reconfigureUpAccountPreference(accountPreference); - } - - private void reconfigureUpAccountPreference(final Preference preference) { - final ListPreference listPreference; - if (preference instanceof ListPreference) { - listPreference = (ListPreference) preference; - } else { - return; - } - final List accounts = - ImmutableList.copyOf( - Lists.transform( - xmppConnectionService.getAccounts(), - a -> a.getJid().asBareJid().toEscapedString())); - final ImmutableList.Builder entries = new ImmutableList.Builder<>(); - final ImmutableList.Builder entryValues = new ImmutableList.Builder<>(); - entries.add(getString(R.string.no_account_deactivated)); - entryValues.add("none"); - entries.addAll(accounts); - entryValues.addAll(accounts); - listPreference.setEntries(entries.build().toArray(new CharSequence[0])); - listPreference.setEntryValues(entryValues.build().toArray(new CharSequence[0])); - if (!accounts.contains(listPreference.getValue())) { - listPreference.setValue("none"); - } - } - - @Override - public void onStart() { - super.onStart(); - PreferenceManager.getDefaultSharedPreferences(this) - .registerOnSharedPreferenceChangeListener(this); - - changeOmemoSettingSummary(); - - if (QuickConversationsService.isQuicksy() - || QuickConversationsService.isPlayStoreFlavor() - || Strings.isNullOrEmpty(Config.CHANNEL_DISCOVERY)) { - final PreferenceCategory groupChats = - (PreferenceCategory) mSettingsFragment.findPreference("group_chats"); - final Preference channelDiscoveryMethod = - mSettingsFragment.findPreference("channel_discovery_method"); - if (groupChats != null && channelDiscoveryMethod != null) { - groupChats.removePreference(channelDiscoveryMethod); - } - } - - if (QuickConversationsService.isQuicksy()) { - final PreferenceCategory connectionOptions = - (PreferenceCategory) mSettingsFragment.findPreference("connection_options"); - PreferenceScreen expert = (PreferenceScreen) mSettingsFragment.findPreference("expert"); - if (connectionOptions != null) { - expert.removePreference(connectionOptions); - } - } - - PreferenceScreen mainPreferenceScreen = - (PreferenceScreen) mSettingsFragment.findPreference("main_screen"); - - PreferenceCategory attachmentsCategory = - (PreferenceCategory) mSettingsFragment.findPreference("attachments"); - CheckBoxPreference locationPlugin = - (CheckBoxPreference) mSettingsFragment.findPreference("use_share_location_plugin"); - if (attachmentsCategory != null && locationPlugin != null) { - if (!GeoHelper.isLocationPluginInstalled(this)) { - attachmentsCategory.removePreference(locationPlugin); - } - } - - // this feature is only available on Huawei Android 6. - PreferenceScreen huaweiPreferenceScreen = - (PreferenceScreen) mSettingsFragment.findPreference("huawei"); - if (huaweiPreferenceScreen != null) { - Intent intent = huaweiPreferenceScreen.getIntent(); - // remove when Api version is above M (Version 6.0) or if the intent is not callable - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M || !isCallable(intent)) { - PreferenceCategory generalCategory = - (PreferenceCategory) mSettingsFragment.findPreference("general"); - generalCategory.removePreference(huaweiPreferenceScreen); - if (generalCategory.getPreferenceCount() == 0) { - if (mainPreferenceScreen != null) { - mainPreferenceScreen.removePreference(generalCategory); - } - } - } - } - - final PreferenceCategory uiPreferenceCategory = (PreferenceCategory) mSettingsFragment.findPreference("ui"); - final Preference dynamicColorsPreference = mSettingsFragment.findPreference("dynamic_colors"); - if (dynamicColorsPreference != null && !DynamicColors.isDynamicColorAvailable()) { - uiPreferenceCategory.removePreference(dynamicColorsPreference); - } - - ListPreference automaticMessageDeletionList = - (ListPreference) mSettingsFragment.findPreference(AUTOMATIC_MESSAGE_DELETION); - if (automaticMessageDeletionList != null) { - final int[] choices = - getResources().getIntArray(R.array.automatic_message_deletion_values); - CharSequence[] entries = new CharSequence[choices.length]; - CharSequence[] entryValues = new CharSequence[choices.length]; - for (int i = 0; i < choices.length; ++i) { - entryValues[i] = String.valueOf(choices[i]); - if (choices[i] == 0) { - entries[i] = getString(R.string.never); - } else { - entries[i] = TimeFrameUtils.resolve(this, 1000L * choices[i]); - } - } - automaticMessageDeletionList.setEntries(entries); - automaticMessageDeletionList.setEntryValues(entryValues); - } - - final Preference removeCertsPreference = - mSettingsFragment.findPreference("remove_trusted_certificates"); - if (removeCertsPreference != null) { - removeCertsPreference.setOnPreferenceClickListener( - preference -> { - final MemorizingTrustManager mtm = - xmppConnectionService.getMemorizingTrustManager(); - final ArrayList aliases = Collections.list(mtm.getCertificates()); - if (aliases.isEmpty()) { - displayToast(getString(R.string.toast_no_trusted_certs)); - return true; - } - final ArrayList selectedItems = new ArrayList<>(); - final MaterialAlertDialogBuilder dialogBuilder = new MaterialAlertDialogBuilder(SettingsActivity.this); - dialogBuilder.setTitle( - getResources().getString(R.string.dialog_manage_certs_title)); - dialogBuilder.setMultiChoiceItems( - aliases.toArray(new CharSequence[0]), - null, - (dialog, indexSelected, isChecked) -> { - if (isChecked) { - selectedItems.add(indexSelected); - } else if (selectedItems.contains(indexSelected)) { - selectedItems.remove(Integer.valueOf(indexSelected)); - } - ((AlertDialog) dialog) - .getButton(DialogInterface.BUTTON_POSITIVE) - .setEnabled(!selectedItems.isEmpty()); - }); - - dialogBuilder.setPositiveButton( - getResources() - .getString(R.string.dialog_manage_certs_positivebutton), - (dialog, which) -> { - int count = selectedItems.size(); - if (count > 0) { - for (int i = 0; i < count; i++) { - try { - final int item = - Integer.parseInt( - selectedItems.get(i).toString()); - String alias = aliases.get(item); - mtm.deleteCertificate(alias); - } catch (final KeyStoreException e) { - displayToast("Error: " + e.getLocalizedMessage()); - } - } - if (xmppConnectionServiceBound) { - reconnectAccounts(); - } - displayToast( - getResources() - .getQuantityString( - R.plurals.toast_delete_certificates, - count, - count)); - } - }); - dialogBuilder.setNegativeButton( - getResources() - .getString(R.string.dialog_manage_certs_negativebutton), - null); - AlertDialog removeCertsDialog = dialogBuilder.create(); - removeCertsDialog.show(); - removeCertsDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false); - return true; - }); - } - - final Preference createBackupPreference = mSettingsFragment.findPreference("create_backup"); - if (createBackupPreference != null) { - createBackupPreference.setSummary( - getString( - R.string.pref_create_backup_summary, - FileBackend.getBackupDirectory(this).getAbsolutePath())); - createBackupPreference.setOnPreferenceClickListener( - preference -> { - if (hasStoragePermission(REQUEST_CREATE_BACKUP)) { - createBackup(); - } - return true; - }); - } - - if (Config.ONLY_INTERNAL_STORAGE) { - final Preference cleanCachePreference = mSettingsFragment.findPreference("clean_cache"); - if (cleanCachePreference != null) { - cleanCachePreference.setOnPreferenceClickListener(preference -> cleanCache()); - } - - final Preference cleanPrivateStoragePreference = - mSettingsFragment.findPreference("clean_private_storage"); - if (cleanPrivateStoragePreference != null) { - cleanPrivateStoragePreference.setOnPreferenceClickListener( - preference -> cleanPrivateStorage()); - } - } - - final Preference deleteOmemoPreference = - mSettingsFragment.findPreference("delete_omemo_identities"); - if (deleteOmemoPreference != null) { - deleteOmemoPreference.setOnPreferenceClickListener( - preference -> deleteOmemoIdentities()); - } - if (Config.omemoOnly()) { - final PreferenceCategory privacyCategory = - (PreferenceCategory) mSettingsFragment.findPreference("privacy"); - final Preference omemoPreference =mSettingsFragment.findPreference(OMEMO_SETTING); - if (omemoPreference != null) { - privacyCategory.removePreference(omemoPreference); - } - } - } - - private void changeOmemoSettingSummary() { - final ListPreference omemoPreference = - (ListPreference) mSettingsFragment.findPreference(OMEMO_SETTING); - if (omemoPreference == null) { - return; - } - final String value = omemoPreference.getValue(); - switch (value) { - case "always": - omemoPreference.setSummary(R.string.pref_omemo_setting_summary_always); - break; - case "default_on": - omemoPreference.setSummary(R.string.pref_omemo_setting_summary_default_on); - break; - case "default_off": - omemoPreference.setSummary(R.string.pref_omemo_setting_summary_default_off); - break; - } - } - - private boolean isCallable(final Intent i) { - return i != null - && !getPackageManager() - .queryIntentActivities(i, PackageManager.MATCH_DEFAULT_ONLY).isEmpty(); - } - - private boolean cleanCache() { - Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - intent.setData(Uri.parse("package:" + getPackageName())); - startActivity(intent); - return true; - } - - private boolean cleanPrivateStorage() { - for (String type : Arrays.asList("Images", "Videos", "Files", "Recordings")) { - cleanPrivateFiles(type); - } - return true; - } - - private void cleanPrivateFiles(final String type) { - try { - File dir = new File(getFilesDir().getAbsolutePath(), "/" + type + "/"); - File[] array = dir.listFiles(); - if (array != null) { - for (int b = 0; b < array.length; b++) { - String name = array[b].getName().toLowerCase(); - if (name.equals(".nomedia")) { - continue; - } - if (array[b].isFile()) { - array[b].delete(); - } - } - } - } catch (Throwable e) { - Log.e("CleanCache", e.toString()); - } - } - - private boolean deleteOmemoIdentities() { - final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this); - builder.setTitle(R.string.pref_delete_omemo_identities); - final List accounts = new ArrayList<>(); - for (Account account : xmppConnectionService.getAccounts()) { - if (account.isEnabled()) { - accounts.add(account.getJid().asBareJid().toString()); - } - } - final boolean[] checkedItems = new boolean[accounts.size()]; - builder.setMultiChoiceItems( - accounts.toArray(new CharSequence[accounts.size()]), - checkedItems, - (dialog, which, isChecked) -> { - checkedItems[which] = isChecked; - final AlertDialog alertDialog = (AlertDialog) dialog; - for (boolean item : checkedItems) { - if (item) { - alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(true); - return; - } - } - alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(false); - }); - builder.setNegativeButton(R.string.cancel, null); - builder.setPositiveButton( - R.string.delete_selected_keys, - (dialog, which) -> { - for (int i = 0; i < checkedItems.length; ++i) { - if (checkedItems[i]) { - try { - Jid jid = Jid.of(accounts.get(i).toString()); - Account account = xmppConnectionService.findAccountByJid(jid); - if (account != null) { - account.getAxolotlService().regenerateKeys(true); - } - } catch (IllegalArgumentException e) { - // - } - } - } - }); - AlertDialog dialog = builder.create(); - dialog.show(); - dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false); - return true; - } - - @Override - public void onStop() { - super.onStop(); - PreferenceManager.getDefaultSharedPreferences(this) - .unregisterOnSharedPreferenceChangeListener(this); - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences preferences, String name) { - final List resendPresence = - Arrays.asList( - "confirm_messages", - DND_ON_SILENT_MODE, - AWAY_WHEN_SCREEN_IS_OFF, - "allow_message_correction", - TREAT_VIBRATE_AS_SILENT, - MANUALLY_CHANGE_PRESENCE, - BROADCAST_LAST_ACTIVITY); - if (name.equals(OMEMO_SETTING)) { - OmemoSetting.load(this, preferences); - changeOmemoSettingSummary(); - } else if (name.equals(KEEP_FOREGROUND_SERVICE)) { - xmppConnectionService.toggleForegroundService(); - } else if (resendPresence.contains(name)) { - if (xmppConnectionServiceBound) { - if (name.equals(AWAY_WHEN_SCREEN_IS_OFF) || name.equals(MANUALLY_CHANGE_PRESENCE)) { - xmppConnectionService.toggleScreenEventReceiver(); - } - xmppConnectionService.refreshAllPresences(); - } - } else if (name.equals("dont_trust_system_cas")) { - xmppConnectionService.updateMemorizingTrustmanager(); - reconnectAccounts(); - } else if (name.equals("use_tor")) { - if (preferences.getBoolean(name, false)) { - displayToast(getString(R.string.audio_video_disabled_tor)); - } - reconnectAccounts(); - xmppConnectionService.reinitializeMuclumbusService(); - } else if (name.equals(AUTOMATIC_MESSAGE_DELETION)) { - xmppConnectionService.expireOldMessages(true); - } else if (name.equals(THEME)) { - final var value = preferences.getString(THEME,getString(R.string.theme)); - final int desiredNightMode = Conversations.getDesiredNightMode(value); - setDesiredNightMode(desiredNightMode); - } else if (name.equals("dynamic_colors")) { - final var value = preferences.getBoolean("dynamic_colors",false); - setDynamicColors(value); - } else if (name.equals(PREVENT_SCREENSHOTS)) { - SettingsUtils.applyScreenshotPreventionSetting(this); - } else if (UnifiedPushDistributor.PREFERENCES.contains(name)) { - final String pushServerPreference = - Strings.nullToEmpty(preferences.getString( - UnifiedPushDistributor.PREFERENCE_PUSH_SERVER, - getString(R.string.default_push_server))).trim(); - if (isJidInvalid(pushServerPreference) || isHttpUri(pushServerPreference)) { - Toast.makeText(this,R.string.invalid_jid,Toast.LENGTH_LONG).show(); - } - if (xmppConnectionService.reconfigurePushDistributor()) { - xmppConnectionService.renewUnifiedPushEndpoints(); - } - } - } - - private static boolean isJidInvalid(final String input) { - if (Strings.isNullOrEmpty(input)) { - return true; - } - try { - Jid.ofEscaped(input); - return false; - } catch (final IllegalArgumentException e) { - return true; - } - } - - private static boolean isHttpUri(final String input) { - final URI uri; - try { - uri = new URI(input); - } catch (final URISyntaxException e) { - return false; - } - return Arrays.asList("http","https").contains(uri.getScheme()); - } - - @Override - public void onResume() { - super.onResume(); - SettingsUtils.applyScreenshotPreventionSetting(this); - } - - @Override - public void onRequestPermissionsResult( - int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - if (grantResults.length > 0) - if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { - if (requestCode == REQUEST_CREATE_BACKUP) { - createBackup(); - } - } else { - Toast.makeText( - this, - getString( - R.string.no_storage_permission, - getString(R.string.app_name)), - Toast.LENGTH_SHORT) - .show(); - } - } - - private void createBackup() { - ContextCompat.startForegroundService(this, new Intent(this, ExportBackupService.class)); - final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this); - builder.setMessage(R.string.backup_started_message); - builder.setPositiveButton(R.string.ok, null); - builder.create().show(); - } - - private void displayToast(final String msg) { - runOnUiThread(() -> Toast.makeText(SettingsActivity.this, msg, Toast.LENGTH_LONG).show()); - } - - private void reconnectAccounts() { - for (Account account : xmppConnectionService.getAccounts()) { - if (account.isEnabled()) { - xmppConnectionService.reconnectAccountInBackground(account); - } - } - } - - public void refreshUiReal() { - // nothing to do. This Activity doesn't implement any listeners - } -} diff --git a/src/main/java/eu/siacs/conversations/ui/SettingsFragment.java b/src/main/java/eu/siacs/conversations/ui/SettingsFragment.java deleted file mode 100644 index 9378d82b7..000000000 --- a/src/main/java/eu/siacs/conversations/ui/SettingsFragment.java +++ /dev/null @@ -1,77 +0,0 @@ -package eu.siacs.conversations.ui; - -import android.content.Intent; -import android.os.Bundle; -import android.preference.Preference; -import android.preference.PreferenceCategory; -import android.preference.PreferenceFragment; -import android.preference.PreferenceScreen; -import android.text.TextUtils; -import android.widget.ListView; - -import eu.siacs.conversations.Config; -import eu.siacs.conversations.R; -import eu.siacs.conversations.utils.Compatibility; - -public class SettingsFragment extends PreferenceFragment { - - private String page = null; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.preferences); - - // Remove from standard preferences if the flag ONLY_INTERNAL_STORAGE is false - if (!Config.ONLY_INTERNAL_STORAGE) { - PreferenceCategory mCategory = (PreferenceCategory) findPreference("security_options"); - if (mCategory != null) { - Preference cleanCache = findPreference("clean_cache"); - Preference cleanPrivateStorage = findPreference("clean_private_storage"); - mCategory.removePreference(cleanCache); - mCategory.removePreference(cleanPrivateStorage); - } - } - Compatibility.removeUnusedPreferences(this); - - if (!TextUtils.isEmpty(page)) { - openPreferenceScreen(page); - } - - } - - @Override - public void onActivityCreated(Bundle bundle) { - super.onActivityCreated(bundle); - - final ListView listView = getActivity().findViewById(android.R.id.list); - if (listView != null) { - listView.setDivider(null); - } - } - - public void setActivityIntent(final Intent intent) { - boolean wasEmpty = TextUtils.isEmpty(page); - if (intent != null) { - if (Intent.ACTION_VIEW.equals(intent.getAction())) { - if (intent.getExtras() != null) { - this.page = intent.getExtras().getString("page"); - if (wasEmpty) { - openPreferenceScreen(page); - } - } - } - } - } - - private void openPreferenceScreen(final String screenName) { - final Preference pref = findPreference(screenName); - if (pref instanceof PreferenceScreen) { - final PreferenceScreen preferenceScreen = (PreferenceScreen) pref; - getActivity().setTitle(preferenceScreen.getTitle()); - preferenceScreen.setDependency(""); - setPreferenceScreen((PreferenceScreen) pref); - } - } -} diff --git a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java index 0f1cb4f68..c33c3e6bd 100644 --- a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java @@ -172,7 +172,7 @@ public class ShareWithActivity extends XmppActivity } @Override - void onBackendConnected() { + protected void onBackendConnected() { if (xmppConnectionServiceBound && share != null && ((share.contact != null && share.account != null))) { diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java index c7302ae2e..b9b09d0e0 100644 --- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java @@ -18,7 +18,6 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Configuration; import android.content.res.Resources; -import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Point; import android.graphics.drawable.BitmapDrawable; @@ -56,6 +55,7 @@ import com.google.android.material.color.MaterialColors; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.common.base.Strings; +import eu.siacs.conversations.AppSettings; import eu.siacs.conversations.BuildConfig; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; @@ -348,7 +348,7 @@ public abstract class XmppActivity extends ActionBarActivity { dialog.show(); } - abstract void onBackendConnected(); + protected abstract void onBackendConnected(); protected void registerListeners() { if (this instanceof XmppConnectionService.OnConversationUpdate) { @@ -414,7 +414,7 @@ public abstract class XmppActivity extends ActionBarActivity { public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { case R.id.action_settings: - startActivity(new Intent(this, SettingsActivity.class)); + startActivity(new Intent(this, eu.siacs.conversations.ui.activity.SettingsActivity.class)); break; case R.id.action_privacy_policy: openPrivacyPolicy(); @@ -832,7 +832,7 @@ public abstract class XmppActivity extends ActionBarActivity { } protected boolean manuallyChangePresence() { - return getBooleanPreference(SettingsActivity.MANUALLY_CHANGE_PRESENCE, R.bool.manually_change_presence); + return getBooleanPreference(AppSettings.MANUALLY_CHANGE_PRESENCE, R.bool.manually_change_presence); } protected String getShareableUri() { @@ -873,7 +873,7 @@ public abstract class XmppActivity extends ActionBarActivity { @Override protected void onResume(){ super.onResume(); - SettingsUtils.applyScreenshotPreventionSetting(this); + SettingsUtils.applyScreenshotSetting(this); } @Override diff --git a/src/main/java/eu/siacs/conversations/ui/activity/SettingsActivity.java b/src/main/java/eu/siacs/conversations/ui/activity/SettingsActivity.java new file mode 100644 index 000000000..7ac855534 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/activity/SettingsActivity.java @@ -0,0 +1,70 @@ +package eu.siacs.conversations.ui.activity; + +import android.app.Notification; +import android.os.Bundle; + +import androidx.databinding.DataBindingUtil; +import androidx.preference.PreferenceFragmentCompat; + +import com.google.common.collect.ImmutableSet; + +import eu.siacs.conversations.R; +import eu.siacs.conversations.databinding.ActivitySettingsBinding; +import eu.siacs.conversations.ui.Activities; +import eu.siacs.conversations.ui.XmppActivity; +import eu.siacs.conversations.ui.fragment.settings.MainSettingsFragment; +import eu.siacs.conversations.ui.fragment.settings.NotificationsSettingsFragment; +import eu.siacs.conversations.ui.fragment.settings.XmppPreferenceFragment; + +import java.util.Collections; + +public class SettingsActivity extends XmppActivity { + + @Override + protected void refreshUiReal() {} + + @Override + protected void onBackendConnected() { + final var fragmentManager = getSupportFragmentManager(); + final var currentFragment = fragmentManager.findFragmentById(R.id.fragment_container); + if (currentFragment instanceof XmppPreferenceFragment xmppPreferenceFragment) { + xmppPreferenceFragment.onBackendConnected(); + } + } + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + final ActivitySettingsBinding binding = + DataBindingUtil.setContentView(this, R.layout.activity_settings); + setSupportActionBar(binding.materialToolbar); + Activities.setStatusAndNavigationBarColors(this, binding.getRoot()); + + final var intent = getIntent(); + final var categories = intent == null ? Collections.emptySet() : intent.getCategories(); + final PreferenceFragmentCompat preferenceFragment; + if (ImmutableSet.of(Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCES) + .equals(categories)) { + preferenceFragment = new NotificationsSettingsFragment(); + } else { + preferenceFragment = new MainSettingsFragment(); + } + + final var fragmentManager = getSupportFragmentManager(); + final var currentFragment = fragmentManager.findFragmentById(R.id.fragment_container); + if (currentFragment == null) { + fragmentManager + .beginTransaction() + .replace(R.id.fragment_container, preferenceFragment) + .commit(); + } + binding.materialToolbar.setNavigationOnClickListener( + view -> { + if (fragmentManager.getBackStackEntryCount() == 0) { + finish(); + } else { + fragmentManager.popBackStack(); + } + }); + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/activity/result/PickRingtone.java b/src/main/java/eu/siacs/conversations/ui/activity/result/PickRingtone.java new file mode 100644 index 000000000..b58a7f398 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/activity/result/PickRingtone.java @@ -0,0 +1,47 @@ +package eu.siacs.conversations.ui.activity.result; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.media.RingtoneManager; +import android.net.Uri; +import androidx.activity.result.contract.ActivityResultContract; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +public class PickRingtone extends ActivityResultContract { + + private static final Uri NONE = Uri.parse("about:blank"); + + private final int ringToneType; + + public PickRingtone(final int ringToneType) { + this.ringToneType = ringToneType; + } + + @NonNull + @Override + public Intent createIntent(@NonNull final Context context, final Uri existing) { + final Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER); + intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, ringToneType); + intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true); + intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true); + if (existing != null) { + intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, existing); + } + return intent; + } + + @Override + public Uri parseResult(int resultCode, @Nullable Intent data) { + if (resultCode != Activity.RESULT_OK || data == null) { + return null; + } + final Uri pickedUri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI); + return pickedUri == null ? NONE : pickedUri; + } + + public static Uri noneToNull(final Uri uri) { + return uri == null || NONE.equals(uri) ? null : uri; + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java index 2ecf230d9..a30d25c00 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java @@ -15,11 +15,11 @@ import androidx.databinding.DataBindingUtil; import com.wefika.flowlayout.FlowLayout; +import eu.siacs.conversations.AppSettings; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.databinding.ItemContactBinding; import eu.siacs.conversations.entities.ListItem; -import eu.siacs.conversations.ui.SettingsActivity; import eu.siacs.conversations.ui.XmppActivity; import eu.siacs.conversations.ui.util.AvatarWorkerTask; import eu.siacs.conversations.utils.IrregularUnicodeDetector; @@ -47,7 +47,7 @@ public class ListItemAdapter extends ArrayAdapter { public void refreshSettings() { SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity); - this.showDynamicTags = preferences.getBoolean(SettingsActivity.SHOW_DYNAMIC_TAGS, false); + this.showDynamicTags = preferences.getBoolean(AppSettings.SHOW_DYNAMIC_TAGS, false); } @NonNull diff --git a/src/main/java/eu/siacs/conversations/ui/fragment/settings/AttachmentsSettingsFragment.java b/src/main/java/eu/siacs/conversations/ui/fragment/settings/AttachmentsSettingsFragment.java new file mode 100644 index 000000000..6b05c18c5 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/fragment/settings/AttachmentsSettingsFragment.java @@ -0,0 +1,22 @@ +package eu.siacs.conversations.ui.fragment.settings; + +import android.os.Bundle; + +import androidx.annotation.Nullable; +import androidx.preference.PreferenceFragmentCompat; + +import eu.siacs.conversations.R; + +public class AttachmentsSettingsFragment extends PreferenceFragmentCompat { + + @Override + public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) { + setPreferencesFromResource(R.xml.preferences_attachments, rootKey); + } + + @Override + public void onStart() { + super.onStart(); + requireActivity().setTitle(R.string.pref_attachments); + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/fragment/settings/ConnectionSettingsFragment.java b/src/main/java/eu/siacs/conversations/ui/fragment/settings/ConnectionSettingsFragment.java new file mode 100644 index 000000000..26bb27dc9 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/fragment/settings/ConnectionSettingsFragment.java @@ -0,0 +1,69 @@ +package eu.siacs.conversations.ui.fragment.settings; + +import android.os.Bundle; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.google.common.base.Strings; + +import eu.siacs.conversations.AppSettings; +import eu.siacs.conversations.Config; +import eu.siacs.conversations.R; +import eu.siacs.conversations.services.QuickConversationsService; + +public class ConnectionSettingsFragment extends XmppPreferenceFragment { + + private static final String GROUPS_AND_CONFERENCES = "groups_and_conferences"; + + public static boolean hideChannelDiscovery() { + return QuickConversationsService.isQuicksy() + || QuickConversationsService.isPlayStoreFlavor() + || Strings.isNullOrEmpty(Config.CHANNEL_DISCOVERY); + } + + @Override + public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) { + setPreferencesFromResource(R.xml.preferences_connection, rootKey); + final var channelDiscovery = findPreference(AppSettings.CHANNEL_DISCOVERY_METHOD); + final var groupsAndConferences = findPreference(GROUPS_AND_CONFERENCES); + if (channelDiscovery == null || groupsAndConferences == null) { + throw new IllegalStateException(); + } + if (hideChannelDiscovery()) { + groupsAndConferences.setVisible(false); + channelDiscovery.setVisible(false); + } + } + + @Override + protected void onSharedPreferenceChanged(@NonNull String key) { + super.onSharedPreferenceChanged(key); + switch (key) { + case AppSettings.USE_TOR -> { + final var appSettings = new AppSettings(requireContext()); + if (appSettings.isUseTor()) { + runOnUiThread( + () -> + Toast.makeText( + requireActivity(), + R.string.audio_video_disabled_tor, + Toast.LENGTH_LONG) + .show()); + } + reconnectAccounts(); + requireService().reinitializeMuclumbusService(); + } + case AppSettings.SHOW_CONNECTION_OPTIONS -> { + reconnectAccounts(); + } + } + } + + @Override + public void onStart() { + super.onStart(); + requireActivity().setTitle(R.string.pref_connection_options); + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/fragment/settings/InterfaceSettingsFragment.java b/src/main/java/eu/siacs/conversations/ui/fragment/settings/InterfaceSettingsFragment.java new file mode 100644 index 000000000..59ca1484e --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/fragment/settings/InterfaceSettingsFragment.java @@ -0,0 +1,67 @@ +package eu.siacs.conversations.ui.fragment.settings; + +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.google.android.material.color.DynamicColors; + +import eu.siacs.conversations.AppSettings; +import eu.siacs.conversations.Conversations; +import eu.siacs.conversations.R; +import eu.siacs.conversations.ui.activity.SettingsActivity; +import eu.siacs.conversations.ui.util.SettingsUtils; + +public class InterfaceSettingsFragment extends XmppPreferenceFragment { + + @Override + public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) { + setPreferencesFromResource(R.xml.preferences_interface, rootKey); + final var themePreference = findPreference("theme"); + final var dynamicColors = findPreference("dynamic_colors"); + if (themePreference == null || dynamicColors == null) { + throw new IllegalStateException( + "The preference resource file did not contain theme or color preferences"); + } + themePreference.setOnPreferenceChangeListener( + (preference, newValue) -> { + if (newValue instanceof final String theme) { + final int desiredNightMode = Conversations.getDesiredNightMode(theme); + requireSettingsActivity().setDesiredNightMode(desiredNightMode); + } + return true; + }); + dynamicColors.setVisible(DynamicColors.isDynamicColorAvailable()); + dynamicColors.setOnPreferenceChangeListener( + (preference, newValue) -> { + requireSettingsActivity().setDynamicColors(Boolean.TRUE.equals(newValue)); + return true; + }); + } + + @Override + protected void onSharedPreferenceChanged(@NonNull String key) { + super.onSharedPreferenceChanged(key); + if (key.equals(AppSettings.ALLOW_SCREENSHOTS)) { + SettingsUtils.applyScreenshotSetting(requireActivity()); + } + } + + @Override + public void onStart() { + super.onStart(); + requireActivity().setTitle(R.string.pref_title_interface); + } + + public SettingsActivity requireSettingsActivity() { + final var activity = requireActivity(); + if (activity instanceof SettingsActivity settingsActivity) { + return settingsActivity; + } + throw new IllegalStateException( + String.format( + "%s is not %s", + activity.getClass().getName(), SettingsActivity.class.getName())); + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/fragment/settings/MainSettingsFragment.java b/src/main/java/eu/siacs/conversations/ui/fragment/settings/MainSettingsFragment.java new file mode 100644 index 000000000..045275f95 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/fragment/settings/MainSettingsFragment.java @@ -0,0 +1,36 @@ +package eu.siacs.conversations.ui.fragment.settings; + +import android.os.Build; +import android.os.Bundle; + +import androidx.annotation.Nullable; +import androidx.preference.PreferenceFragmentCompat; + +import com.google.common.base.Strings; + +import eu.siacs.conversations.BuildConfig; +import eu.siacs.conversations.R; + +public class MainSettingsFragment extends PreferenceFragmentCompat { + + @Override + public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) { + setPreferencesFromResource(R.xml.preferences_main, rootKey); + final var about = findPreference("about"); + final var connection = findPreference("connection"); + if (about == null || connection == null) { + throw new IllegalStateException("The preference resource file is missing some preferences"); + } + about.setTitle(getString(R.string.title_activity_about_x, BuildConfig.APP_NAME)); + about.setSummary(String.format("%s %s %s (%s)", BuildConfig.APP_NAME, BuildConfig.VERSION_NAME, im.conversations.webrtc.BuildConfig.WEBRTC_VERSION, Strings.nullToEmpty(Build.DEVICE))); + if (ConnectionSettingsFragment.hideChannelDiscovery()) { + connection.setSummary(R.string.pref_connection_summary); + } + } + + @Override + public void onStart() { + super.onStart(); + requireActivity().setTitle(R.string.title_activity_settings); + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/fragment/settings/NotificationsSettingsFragment.java b/src/main/java/eu/siacs/conversations/ui/fragment/settings/NotificationsSettingsFragment.java new file mode 100644 index 000000000..81df3da18 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/fragment/settings/NotificationsSettingsFragment.java @@ -0,0 +1,102 @@ +package eu.siacs.conversations.ui.fragment.settings; + +import android.content.SharedPreferences; +import android.media.RingtoneManager; +import android.net.Uri; +import android.os.Bundle; +import android.util.Log; + +import androidx.activity.result.ActivityResultLauncher; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.preference.ListPreference; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; + +import eu.siacs.conversations.AppSettings; +import eu.siacs.conversations.Config; +import eu.siacs.conversations.R; +import eu.siacs.conversations.ui.activity.result.PickRingtone; +import eu.siacs.conversations.utils.Compatibility; + +public class NotificationsSettingsFragment extends XmppPreferenceFragment { + + private final ActivityResultLauncher pickRingtoneLauncher = + registerForActivityResult( + new PickRingtone(RingtoneManager.TYPE_RINGTONE), + result -> { + if (result == null) { + // do nothing. user aborted + return; + } + final Uri uri = PickRingtone.noneToNull(result); + setRingtone(uri); + Log.i(Config.LOGTAG, "User set ringtone to " + uri); + }); + + @Override + public void onCreatePreferences( + @Nullable final Bundle savedInstanceState, final @Nullable String rootKey) { + setPreferencesFromResource(R.xml.preferences_notifications, rootKey); + final var messageNotificationSettings = findPreference("message_notification_settings"); + final var notificationRingtone = findPreference(AppSettings.NOTIFICATION_RINGTONE); + final var notificationHeadsUp = findPreference(AppSettings.NOTIFICATION_HEADS_UP); + final var notificationVibrate = findPreference(AppSettings.NOTIFICATION_VIBRATE); + final var notificationLed = findPreference(AppSettings.NOTIFICATION_LED); + final var foregroundService = findPreference(AppSettings.KEEP_FOREGROUND_SERVICE); + if (messageNotificationSettings == null + || notificationRingtone == null + || notificationHeadsUp == null + || notificationVibrate == null + || notificationLed == null + || foregroundService == null) { + throw new IllegalStateException("The preference resource file is missing preferences"); + } + if (Compatibility.runsTwentySix()) { + notificationRingtone.setVisible(false); + notificationHeadsUp.setVisible(false); + notificationVibrate.setVisible(false); + notificationLed.setVisible(false); + foregroundService.setVisible(false); + } else { + messageNotificationSettings.setVisible(false); + } + } + + @Override + protected void onSharedPreferenceChanged(@NonNull String key) { + super.onSharedPreferenceChanged(key); + if (key.equals(AppSettings.KEEP_FOREGROUND_SERVICE)) { + requireService().toggleForegroundService(); + } + } + + @Override + public void onStart() { + super.onStart(); + requireActivity().setTitle(R.string.notifications); + } + + @Override + public boolean onPreferenceTreeClick(final Preference preference) { + if (AppSettings.RINGTONE.equals(preference.getKey())) { + pickRingtone(); + return true; + } + return super.onPreferenceTreeClick(preference); + } + + private void pickRingtone() { + final Uri uri = appSettings().getRingtone(); + Log.i(Config.LOGTAG, "current ringtone: " + uri); + this.pickRingtoneLauncher.launch(uri); + } + + private void setRingtone(final Uri uri) { + appSettings().setRingtone(uri); + } + + private AppSettings appSettings() { + return new AppSettings(requireContext()); + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/fragment/settings/PrivacySettingsFragment.java b/src/main/java/eu/siacs/conversations/ui/fragment/settings/PrivacySettingsFragment.java new file mode 100644 index 000000000..6f0c4f56c --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/fragment/settings/PrivacySettingsFragment.java @@ -0,0 +1,41 @@ +package eu.siacs.conversations.ui.fragment.settings; + +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import eu.siacs.conversations.AppSettings; +import eu.siacs.conversations.R; + +public class PrivacySettingsFragment extends XmppPreferenceFragment { + + @Override + public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) { + setPreferencesFromResource(R.xml.preferences_privacy, rootKey); + } + + @Override + protected void onSharedPreferenceChanged(@NonNull String key) { + super.onSharedPreferenceChanged(key); + switch (key) { + case AppSettings.AWAY_WHEN_SCREEN_IS_OFF, AppSettings.MANUALLY_CHANGE_PRESENCE -> { + requireService().toggleScreenEventReceiver(); + requireService().refreshAllPresences(); + } + case AppSettings.CONFIRM_MESSAGES, + AppSettings.BROADCAST_LAST_ACTIVITY, + AppSettings.ALLOW_MESSAGE_CORRECTION, + AppSettings.DND_ON_SILENT_MODE, + AppSettings.TREAT_VIBRATE_AS_SILENT -> { + requireService().refreshAllPresences(); + } + } + } + + @Override + public void onStart() { + super.onStart(); + requireActivity().setTitle(R.string.pref_privacy); + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/fragment/settings/SecuritySettingsFragment.java b/src/main/java/eu/siacs/conversations/ui/fragment/settings/SecuritySettingsFragment.java new file mode 100644 index 000000000..ba64c5fc3 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/fragment/settings/SecuritySettingsFragment.java @@ -0,0 +1,195 @@ +package eu.siacs.conversations.ui.fragment.settings; + +import android.content.Context; +import android.content.DialogInterface; +import android.os.Bundle; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; +import androidx.preference.ListPreference; +import androidx.preference.Preference; + +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.google.common.base.Strings; +import com.google.common.primitives.Ints; + +import eu.siacs.conversations.AppSettings; +import eu.siacs.conversations.R; +import eu.siacs.conversations.crypto.OmemoSetting; +import eu.siacs.conversations.services.MemorizingTrustManager; +import eu.siacs.conversations.utils.TimeFrameUtils; + +import java.security.KeyStoreException; +import java.util.ArrayList; +import java.util.Collections; + +public class SecuritySettingsFragment extends XmppPreferenceFragment { + + private static final String REMOVE_TRUSTED_CERTIFICATES = "remove_trusted_certificates"; + + @Override + public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) { + setPreferencesFromResource(R.xml.preferences_security, rootKey); + final ListPreference omemo = findPreference(AppSettings.OMEMO); + final ListPreference automaticMessageDeletion = + findPreference(AppSettings.AUTOMATIC_MESSAGE_DELETION); + if (omemo == null || automaticMessageDeletion == null) { + throw new IllegalStateException("The preference resource file is missing preferences"); + } + omemo.setSummaryProvider(new OmemoSummaryProvider()); + final int[] choices = getResources().getIntArray(R.array.automatic_message_deletion_values); + final CharSequence[] entries = new CharSequence[choices.length]; + final CharSequence[] entryValues = new CharSequence[choices.length]; + for (int i = 0; i < choices.length; ++i) { + entryValues[i] = String.valueOf(choices[i]); + entries[i] = messageDeletionValueToName(requireContext(), choices[i]); + } + automaticMessageDeletion.setEntries(entries); + automaticMessageDeletion.setEntryValues(entryValues); + automaticMessageDeletion.setSummaryProvider(new MessageDeletionSummaryProvider()); + } + + private static String messageDeletionValueToName(final Context context, final int value) { + if (value == 0) { + return context.getString(R.string.never); + } else { + return TimeFrameUtils.resolve(context, 1000L * value); + } + } + + @Override + protected void onSharedPreferenceChanged(@NonNull String key) { + super.onSharedPreferenceChanged(key); + switch (key) { + case AppSettings.OMEMO -> { + OmemoSetting.load(requireContext()); + } + case AppSettings.TRUST_SYSTEM_CA_STORE -> { + requireService().updateMemorizingTrustmanager(); + reconnectAccounts(); + } + case AppSettings.REQUIRE_CHANNEL_BINDING -> {} + } + } + + @Override + public void onStart() { + super.onStart(); + requireActivity().setTitle(R.string.pref_title_security); + } + + @Override + public boolean onPreferenceTreeClick(final Preference preference) { + if (REMOVE_TRUSTED_CERTIFICATES.equals(preference.getKey())) { + showRemoveCertificatesDialog(); + return true; + } + return super.onPreferenceTreeClick(preference); + } + + private void showRemoveCertificatesDialog() { + final MemorizingTrustManager mtm = requireService().getMemorizingTrustManager(); + final ArrayList aliases = Collections.list(mtm.getCertificates()); + if (aliases.isEmpty()) { + Toast.makeText(requireActivity(), R.string.toast_no_trusted_certs, Toast.LENGTH_LONG) + .show(); + return; + } + final ArrayList selectedItems = new ArrayList<>(); + final MaterialAlertDialogBuilder dialogBuilder = + new MaterialAlertDialogBuilder(requireActivity()); + dialogBuilder.setTitle(getString(R.string.dialog_manage_certs_title)); + dialogBuilder.setMultiChoiceItems( + aliases.toArray(new CharSequence[0]), + null, + (dialog, indexSelected, isChecked) -> { + if (isChecked) { + selectedItems.add(indexSelected); + } else if (selectedItems.contains(indexSelected)) { + selectedItems.remove(Integer.valueOf(indexSelected)); + } + if (dialog instanceof AlertDialog alertDialog) { + alertDialog + .getButton(DialogInterface.BUTTON_POSITIVE) + .setEnabled(!selectedItems.isEmpty()); + } + }); + + dialogBuilder.setPositiveButton( + getString(R.string.dialog_manage_certs_positivebutton), + (dialog, which) -> confirmCertificateDeletion(aliases, selectedItems)); + dialogBuilder.setNegativeButton(R.string.cancel, null); + final AlertDialog removeCertsDialog = dialogBuilder.create(); + removeCertsDialog.show(); + removeCertsDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false); + } + + private void confirmCertificateDeletion( + final ArrayList aliases, final ArrayList selectedItems) { + final int count = selectedItems.size(); + if (count == 0) { + return; + } + final MemorizingTrustManager mtm = requireService().getMemorizingTrustManager(); + for (int i = 0; i < count; i++) { + try { + final int item = Integer.parseInt(selectedItems.get(i).toString()); + final String alias = aliases.get(item); + mtm.deleteCertificate(alias); + } catch (final KeyStoreException e) { + Toast.makeText( + requireActivity(), + "Error: " + e.getLocalizedMessage(), + Toast.LENGTH_LONG) + .show(); + } + } + reconnectAccounts(); + Toast.makeText( + requireActivity(), + getResources() + .getQuantityString( + R.plurals.toast_delete_certificates, count, count), + Toast.LENGTH_LONG) + .show(); + } + + private static class MessageDeletionSummaryProvider + implements Preference.SummaryProvider { + + @Nullable + @Override + public CharSequence provideSummary(@NonNull ListPreference preference) { + final Integer value = Ints.tryParse(Strings.nullToEmpty(preference.getValue())); + return messageDeletionValueToName(preference.getContext(), value == null ? 0 : value); + } + } + + private static class OmemoSummaryProvider + implements Preference.SummaryProvider { + + @Nullable + @Override + public CharSequence provideSummary(@NonNull ListPreference preference) { + final var context = preference.getContext(); + final var sharedPreferences = preference.getSharedPreferences(); + final String value; + if (sharedPreferences == null) { + value = null; + } else { + value = + sharedPreferences.getString( + preference.getKey(), + context.getString(R.string.omemo_setting_default)); + } + return switch (Strings.nullToEmpty(value)) { + case "always" -> context.getString(R.string.pref_omemo_setting_summary_always); + case "default_off" -> context.getString( + R.string.pref_omemo_setting_summary_default_off); + default -> context.getString(R.string.pref_omemo_setting_summary_default_on); + }; + } + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/fragment/settings/UpSettingsFragment.java b/src/main/java/eu/siacs/conversations/ui/fragment/settings/UpSettingsFragment.java new file mode 100644 index 000000000..3470e98c3 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/fragment/settings/UpSettingsFragment.java @@ -0,0 +1,99 @@ +package eu.siacs.conversations.ui.fragment.settings; + +import android.os.Bundle; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.preference.EditTextPreference; +import androidx.preference.ListPreference; +import androidx.preference.Preference; + +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; + +import eu.siacs.conversations.R; +import eu.siacs.conversations.services.UnifiedPushDistributor; +import eu.siacs.conversations.xmpp.Jid; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.List; + +public class UpSettingsFragment extends XmppPreferenceFragment { + + @Override + public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) { + setPreferencesFromResource(R.xml.preferences_up, rootKey); + } + + @Override + public void onBackendConnected() { + final ListPreference upAccounts = findPreference(UnifiedPushDistributor.PREFERENCE_ACCOUNT); + final EditTextPreference pushServer = findPreference(UnifiedPushDistributor.PREFERENCE_PUSH_SERVER); + if (upAccounts == null || pushServer == null) { + throw new IllegalStateException(); + } + pushServer.setOnPreferenceChangeListener((preference, newValue) -> { + if (newValue instanceof String string) { + if (Strings.isNullOrEmpty(string) || isJidInvalid(string) || isHttpUri(string)) { + Toast.makeText(requireActivity(),R.string.invalid_jid,Toast.LENGTH_LONG).show(); + return false; + } else { + return true; + } + } else { + Toast.makeText(requireActivity(),R.string.invalid_jid,Toast.LENGTH_LONG).show(); + return false; + } + }); + reconfigureUpAccountPreference(upAccounts); + } + + private static boolean isJidInvalid(final String input) { + try { + final var jid = Jid.ofEscaped(input); + return !jid.isBareJid(); + } catch (final IllegalArgumentException e) { + return true; + } + } + + private static boolean isHttpUri(final String input) { + final URI uri; + try { + uri = new URI(input); + } catch (final URISyntaxException e) { + return false; + } + return Arrays.asList("http","https").contains(uri.getScheme()); + } + + + private void reconfigureUpAccountPreference(final ListPreference listPreference) { + final List accounts = + ImmutableList.copyOf( + Lists.transform( + requireService().getAccounts(), + a -> a.getJid().asBareJid().toEscapedString())); + final ImmutableList.Builder entries = new ImmutableList.Builder<>(); + final ImmutableList.Builder entryValues = new ImmutableList.Builder<>(); + entries.add(getString(R.string.no_account_deactivated)); + entryValues.add("none"); + entries.addAll(accounts); + entryValues.addAll(accounts); + listPreference.setEntries(entries.build().toArray(new CharSequence[0])); + listPreference.setEntryValues(entryValues.build().toArray(new CharSequence[0])); + if (!accounts.contains(listPreference.getValue())) { + listPreference.setValue("none"); + } + } + + @Override + public void onStart() { + super.onStart(); + requireActivity().setTitle(R.string.unified_push_distributor); + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/fragment/settings/XmppPreferenceFragment.java b/src/main/java/eu/siacs/conversations/ui/fragment/settings/XmppPreferenceFragment.java new file mode 100644 index 000000000..631ecb6c4 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/fragment/settings/XmppPreferenceFragment.java @@ -0,0 +1,80 @@ +package eu.siacs.conversations.ui.fragment.settings; + +import android.content.SharedPreferences; + +import androidx.annotation.NonNull; +import androidx.preference.PreferenceFragmentCompat; + +import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.services.XmppConnectionService; +import eu.siacs.conversations.ui.XmppActivity; + +public abstract class XmppPreferenceFragment extends PreferenceFragmentCompat { + + private final SharedPreferences.OnSharedPreferenceChangeListener + sharedPreferenceChangeListener = + (sharedPreferences, key) -> { + if (key == null) { + return; + } + onSharedPreferenceChanged(key); + }; + + protected void onSharedPreferenceChanged(@NonNull String key) {} + + public void onBackendConnected() {} + + @Override + public void onResume() { + super.onResume(); + final var sharedPreferences = getPreferenceManager().getSharedPreferences(); + if (sharedPreferences != null) { + sharedPreferences.registerOnSharedPreferenceChangeListener( + this.sharedPreferenceChangeListener); + } + final var xmppActivity = requireXmppActivity(); + if (xmppActivity.xmppConnectionService != null) { + this.onBackendConnected(); + } + } + + @Override + public void onPause() { + super.onPause(); + final var sharedPreferences = getPreferenceManager().getSharedPreferences(); + if (sharedPreferences != null) { + sharedPreferences.registerOnSharedPreferenceChangeListener( + this.sharedPreferenceChangeListener); + } + } + + protected void reconnectAccounts() { + final var service = requireService(); + for (final Account account : service.getAccounts()) { + if (account.isEnabled()) { + service.reconnectAccountInBackground(account); + } + } + } + + protected XmppActivity requireXmppActivity() { + final var activity = requireActivity(); + if (activity instanceof XmppActivity xmppActivity) { + return xmppActivity; + } + throw new IllegalStateException(); + } + + protected XmppConnectionService requireService() { + final var xmppActivity = requireXmppActivity(); + final var service = xmppActivity.xmppConnectionService; + if (service != null) { + return service; + } + throw new IllegalStateException(); + } + + protected void runOnUiThread(final Runnable runnable) { + requireActivity().runOnUiThread(runnable); + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/util/SettingsUtils.java b/src/main/java/eu/siacs/conversations/ui/util/SettingsUtils.java index ae99e0943..7d194ba95 100644 --- a/src/main/java/eu/siacs/conversations/ui/util/SettingsUtils.java +++ b/src/main/java/eu/siacs/conversations/ui/util/SettingsUtils.java @@ -1,20 +1,19 @@ package eu.siacs.conversations.ui.util; import android.app.Activity; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; import android.view.Window; import android.view.WindowManager; +import eu.siacs.conversations.AppSettings; + public class SettingsUtils { - public static void applyScreenshotPreventionSetting(Activity activity){ - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity); - boolean preventScreenshots = preferences.getBoolean("prevent_screenshots", false); - Window activityWindow = activity.getWindow(); - if(preventScreenshots){ - activityWindow.addFlags(WindowManager.LayoutParams.FLAG_SECURE); - } else { + public static void applyScreenshotSetting(final Activity activity) { + final var appSettings = new AppSettings(activity); + final Window activityWindow = activity.getWindow(); + if (appSettings.isAllowScreenshots()) { activityWindow.clearFlags(WindowManager.LayoutParams.FLAG_SECURE); + } else { + activityWindow.addFlags(WindowManager.LayoutParams.FLAG_SECURE); } } } diff --git a/src/main/java/eu/siacs/conversations/utils/Compatibility.java b/src/main/java/eu/siacs/conversations/utils/Compatibility.java index 6d3ba6224..a6e91593e 100644 --- a/src/main/java/eu/siacs/conversations/utils/Compatibility.java +++ b/src/main/java/eu/siacs/conversations/utils/Compatibility.java @@ -22,10 +22,9 @@ import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; import androidx.core.content.ContextCompat; +import eu.siacs.conversations.AppSettings; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; -import eu.siacs.conversations.ui.SettingsActivity; -import eu.siacs.conversations.ui.SettingsFragment; import java.util.Arrays; import java.util.Collections; @@ -33,15 +32,6 @@ import java.util.List; public class Compatibility { - private static final List UNUSED_SETTINGS_POST_TWENTYSIX = - Arrays.asList( - "led", - "notification_ringtone", - "notification_headsup", - "vibrate_on_notification"); - private static final List UNUSED_SETTINGS_PRE_TWENTYSIX = - Collections.singletonList("message_notification_settings"); - public static boolean hasStoragePermission(final Context context) { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU || ContextCompat.checkSelfPermission( context, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED; @@ -76,7 +66,7 @@ public class Compatibility { final PackageManager packageManager = context.getPackageManager(); final ApplicationInfo applicationInfo = packageManager.getApplicationInfo(context.getPackageName(), 0); - return applicationInfo == null || applicationInfo.targetSdkVersion >= 26; + return applicationInfo.targetSdkVersion >= 26; } catch (PackageManager.NameNotFoundException | RuntimeException e) { return true; // when in doubt… } @@ -87,7 +77,7 @@ public class Compatibility { final PackageManager packageManager = context.getPackageManager(); final ApplicationInfo applicationInfo = packageManager.getApplicationInfo(context.getPackageName(), 0); - return applicationInfo == null || applicationInfo.targetSdkVersion >= 24; + return applicationInfo.targetSdkVersion >= 24; } catch (PackageManager.NameNotFoundException | RuntimeException e) { return true; // when in doubt… } @@ -105,43 +95,10 @@ public class Compatibility { return runsAndTargetsTwentySix(context) || getBooleanPreference( context, - SettingsActivity.KEEP_FOREGROUND_SERVICE, + AppSettings.KEEP_FOREGROUND_SERVICE, R.bool.enable_foreground_service); } - public static void removeUnusedPreferences(SettingsFragment settingsFragment) { - List categories = - Arrays.asList( - (PreferenceCategory) - settingsFragment.findPreference("notification_category"), - (PreferenceCategory) settingsFragment.findPreference("advanced")); - for (String key : - (runsTwentySix() - ? UNUSED_SETTINGS_POST_TWENTYSIX - : UNUSED_SETTINGS_PRE_TWENTYSIX)) { - Preference preference = settingsFragment.findPreference(key); - if (preference != null) { - for (PreferenceCategory category : categories) { - if (category != null) { - category.removePreference(preference); - } - } - } - } - if (Compatibility.runsTwentySix()) { - if (targetsTwentySix(settingsFragment.getContext())) { - Preference preference = - settingsFragment.findPreference(SettingsActivity.KEEP_FOREGROUND_SERVICE); - if (preference != null) { - for (PreferenceCategory category : categories) { - if (category != null) { - category.removePreference(preference); - } - } - } - } - } - } public static void startService(Context context, Intent intent) { try { diff --git a/src/main/res/drawable/ic_arrow_back_24dp.xml b/src/main/res/drawable/ic_arrow_back_24dp.xml new file mode 100644 index 000000000..8ed427d74 --- /dev/null +++ b/src/main/res/drawable/ic_arrow_back_24dp.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/src/main/res/drawable/ic_assured_workload_24dp.xml b/src/main/res/drawable/ic_assured_workload_24dp.xml new file mode 100644 index 000000000..c508dbe35 --- /dev/null +++ b/src/main/res/drawable/ic_assured_workload_24dp.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + diff --git a/src/main/res/drawable/ic_attachment_24dp.xml b/src/main/res/drawable/ic_attachment_24dp.xml new file mode 100644 index 000000000..25fed9d25 --- /dev/null +++ b/src/main/res/drawable/ic_attachment_24dp.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/src/main/res/drawable/ic_auto_delete_24dp.xml b/src/main/res/drawable/ic_auto_delete_24dp.xml new file mode 100644 index 000000000..2c7ffc3ac --- /dev/null +++ b/src/main/res/drawable/ic_auto_delete_24dp.xml @@ -0,0 +1,20 @@ + + + + + + + + + diff --git a/src/main/res/drawable/ic_cloud_sync_24dp.xml b/src/main/res/drawable/ic_cloud_sync_24dp.xml new file mode 100644 index 000000000..c87b654c9 --- /dev/null +++ b/src/main/res/drawable/ic_cloud_sync_24dp.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/src/main/res/drawable/ic_dark_mode_24dp.xml b/src/main/res/drawable/ic_dark_mode_24dp.xml new file mode 100644 index 000000000..9e3255316 --- /dev/null +++ b/src/main/res/drawable/ic_dark_mode_24dp.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/src/main/res/drawable/ic_do_not_disturb_on_24dp.xml b/src/main/res/drawable/ic_do_not_disturb_on_24dp.xml new file mode 100644 index 000000000..50a7239ac --- /dev/null +++ b/src/main/res/drawable/ic_do_not_disturb_on_24dp.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/src/main/res/drawable/ic_domino_mask_24dp.xml b/src/main/res/drawable/ic_domino_mask_24dp.xml new file mode 100644 index 000000000..849d7b1c2 --- /dev/null +++ b/src/main/res/drawable/ic_domino_mask_24dp.xml @@ -0,0 +1,10 @@ + + + diff --git a/src/main/res/drawable/ic_done_all_24dp.xml b/src/main/res/drawable/ic_done_all_24dp.xml new file mode 100644 index 000000000..63a35fe64 --- /dev/null +++ b/src/main/res/drawable/ic_done_all_24dp.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/src/main/res/drawable/ic_download_24dp.xml b/src/main/res/drawable/ic_download_24dp.xml index 0a16f1635..ae2803609 100644 --- a/src/main/res/drawable/ic_download_24dp.xml +++ b/src/main/res/drawable/ic_download_24dp.xml @@ -1,5 +1,12 @@ - - - - + + + + diff --git a/src/main/res/drawable/ic_keyboard_24dp.xml b/src/main/res/drawable/ic_keyboard_24dp.xml new file mode 100644 index 000000000..2406aac48 --- /dev/null +++ b/src/main/res/drawable/ic_keyboard_24dp.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/src/main/res/drawable/ic_keyboard_return_24dp.xml b/src/main/res/drawable/ic_keyboard_return_24dp.xml new file mode 100644 index 000000000..c543e3f64 --- /dev/null +++ b/src/main/res/drawable/ic_keyboard_return_24dp.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/src/main/res/drawable/ic_label_24dp.xml b/src/main/res/drawable/ic_label_24dp.xml new file mode 100644 index 000000000..51e84c112 --- /dev/null +++ b/src/main/res/drawable/ic_label_24dp.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/src/main/res/drawable/ic_mediation_24dp.xml b/src/main/res/drawable/ic_mediation_24dp.xml new file mode 100644 index 000000000..3ce75f00f --- /dev/null +++ b/src/main/res/drawable/ic_mediation_24dp.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/src/main/res/drawable/ic_movie_24dp.xml b/src/main/res/drawable/ic_movie_24dp.xml new file mode 100644 index 000000000..915537e46 --- /dev/null +++ b/src/main/res/drawable/ic_movie_24dp.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/src/main/res/drawable/ic_network_node_24dp.xml b/src/main/res/drawable/ic_network_node_24dp.xml new file mode 100644 index 000000000..267173b5e --- /dev/null +++ b/src/main/res/drawable/ic_network_node_24dp.xml @@ -0,0 +1,10 @@ + + + diff --git a/src/main/res/drawable/ic_palette_24dp.xml b/src/main/res/drawable/ic_palette_24dp.xml new file mode 100644 index 000000000..db78749e5 --- /dev/null +++ b/src/main/res/drawable/ic_palette_24dp.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/src/main/res/drawable/ic_person_24dp.xml b/src/main/res/drawable/ic_person_24dp.xml index ddc83227b..098f18274 100644 --- a/src/main/res/drawable/ic_person_24dp.xml +++ b/src/main/res/drawable/ic_person_24dp.xml @@ -1,5 +1,12 @@ - - - - + + + + diff --git a/src/main/res/drawable/ic_phone_24dp.xml b/src/main/res/drawable/ic_phone_24dp.xml new file mode 100644 index 000000000..326fb50b8 --- /dev/null +++ b/src/main/res/drawable/ic_phone_24dp.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/src/main/res/drawable/ic_photo_24dp.xml b/src/main/res/drawable/ic_photo_24dp.xml new file mode 100644 index 000000000..4f9fd480e --- /dev/null +++ b/src/main/res/drawable/ic_photo_24dp.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/src/main/res/drawable/ic_privacy_tip_24dp.xml b/src/main/res/drawable/ic_privacy_tip_24dp.xml new file mode 100644 index 000000000..c13176ba2 --- /dev/null +++ b/src/main/res/drawable/ic_privacy_tip_24dp.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/src/main/res/drawable/ic_private_connectivity_24dp.xml b/src/main/res/drawable/ic_private_connectivity_24dp.xml new file mode 100644 index 000000000..00d17f2cc --- /dev/null +++ b/src/main/res/drawable/ic_private_connectivity_24dp.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/src/main/res/drawable/ic_report_24dp.xml b/src/main/res/drawable/ic_report_24dp.xml new file mode 100644 index 000000000..72c154915 --- /dev/null +++ b/src/main/res/drawable/ic_report_24dp.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/src/main/res/drawable/ic_screen_lock_portrait_24dp.xml b/src/main/res/drawable/ic_screen_lock_portrait_24dp.xml new file mode 100644 index 000000000..f7f199198 --- /dev/null +++ b/src/main/res/drawable/ic_screen_lock_portrait_24dp.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/src/main/res/drawable/ic_screenshot_24dp.xml b/src/main/res/drawable/ic_screenshot_24dp.xml new file mode 100644 index 000000000..be4bb2924 --- /dev/null +++ b/src/main/res/drawable/ic_screenshot_24dp.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/src/main/res/drawable/ic_security_24dp.xml b/src/main/res/drawable/ic_security_24dp.xml new file mode 100644 index 000000000..f434507bf --- /dev/null +++ b/src/main/res/drawable/ic_security_24dp.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/src/main/res/drawable/ic_send_time_extension_24dp.xml b/src/main/res/drawable/ic_send_time_extension_24dp.xml new file mode 100644 index 000000000..e9449cf1b --- /dev/null +++ b/src/main/res/drawable/ic_send_time_extension_24dp.xml @@ -0,0 +1,16 @@ + + + + + + + diff --git a/src/main/res/drawable/ic_settings_ethernet_24dp.xml b/src/main/res/drawable/ic_settings_ethernet_24dp.xml new file mode 100644 index 000000000..fad20c2fe --- /dev/null +++ b/src/main/res/drawable/ic_settings_ethernet_24dp.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/src/main/res/drawable/ic_touch_app_24dp.xml b/src/main/res/drawable/ic_touch_app_24dp.xml new file mode 100644 index 000000000..45d230a83 --- /dev/null +++ b/src/main/res/drawable/ic_touch_app_24dp.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/src/main/res/drawable/ic_travel_explore_24dp.xml b/src/main/res/drawable/ic_travel_explore_24dp.xml index 0e7c701d4..7b697eb44 100644 --- a/src/main/res/drawable/ic_travel_explore_24dp.xml +++ b/src/main/res/drawable/ic_travel_explore_24dp.xml @@ -1,5 +1,12 @@ - - - - + + + + diff --git a/src/main/res/drawable/ic_vertical_align_bottom_24dp.xml b/src/main/res/drawable/ic_vertical_align_bottom_24dp.xml new file mode 100644 index 000000000..1535646f2 --- /dev/null +++ b/src/main/res/drawable/ic_vertical_align_bottom_24dp.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/src/main/res/drawable/ic_vibration_24dp.xml b/src/main/res/drawable/ic_vibration_24dp.xml new file mode 100644 index 000000000..bdde86c2b --- /dev/null +++ b/src/main/res/drawable/ic_vibration_24dp.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/src/main/res/drawable/ic_visibility.xml b/src/main/res/drawable/ic_visibility_24dp.xml similarity index 61% rename from src/main/res/drawable/ic_visibility.xml rename to src/main/res/drawable/ic_visibility_24dp.xml index e02f1d191..ddcefe053 100644 --- a/src/main/res/drawable/ic_visibility.xml +++ b/src/main/res/drawable/ic_visibility_24dp.xml @@ -1,9 +1,12 @@ + android:width="24dp" + android:height="24dp" + android:tint="?colorControlNormal" + android:viewportWidth="24" + android:viewportHeight="24"> + + android:fillColor="@android:color/white" + android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z" /> + diff --git a/src/main/res/layout/activity_settings.xml b/src/main/res/layout/activity_settings.xml index a5865f2fa..53d84da4f 100644 --- a/src/main/res/layout/activity_settings.xml +++ b/src/main/res/layout/activity_settings.xml @@ -1,26 +1,29 @@ - + - + android:layout_height="match_parent"> + android:layout_height="wrap_content" + app:liftOnScroll="false"> - + android:layout_height="?attr/actionBarSize" + app:navigationIcon="@drawable/ic_arrow_back_24dp" /> - - + android:layout_height="match_parent" + android:fillViewport="true" + app:layout_behavior="@string/appbar_scrolling_view_behavior" /> + \ No newline at end of file diff --git a/src/main/res/values-ar/strings.xml b/src/main/res/values-ar/strings.xml index 87ddfcbcf..eda500ac6 100644 --- a/src/main/res/values-ar/strings.xml +++ b/src/main/res/values-ar/strings.xml @@ -344,7 +344,6 @@ إحذف الشهادات التي تقبلتها يدويا إحذف الشهادات قم بحذف المختارة - الغاء حركة سريعة لا شيء التي تم استعمالها كثيرا مؤخرا diff --git a/src/main/res/values-bg/strings.xml b/src/main/res/values-bg/strings.xml index 95b3b85e4..6b831f788 100644 --- a/src/main/res/values-bg/strings.xml +++ b/src/main/res/values-bg/strings.xml @@ -430,7 +430,6 @@ Няма сертификати, одобрени на ръка Премахване на сертификатите Изтриване на избраните - Отказ %d сертификат е изтрит %d сертификата са изтрити diff --git a/src/main/res/values-bn-rIN/strings.xml b/src/main/res/values-bn-rIN/strings.xml index 3944bd33d..cffaa14ae 100644 --- a/src/main/res/values-bn-rIN/strings.xml +++ b/src/main/res/values-bn-rIN/strings.xml @@ -99,7 +99,6 @@ এই ব্যক্তিকে ব্লক্ করা যাক ব্লকটা সরিয়ে ফেলা যাক পরিচিত ব্যক্তি - না, থাক। পরিচিত ব্যক্তিদের মধ্যে খোঁজা যাক বার্তাগুলির মধ্যে খোঁজা যাক সরাসরিভাবেই খোঁজা যাক diff --git a/src/main/res/values-ca/strings.xml b/src/main/res/values-ca/strings.xml index ade65234e..3ec310f85 100644 --- a/src/main/res/values-ca/strings.xml +++ b/src/main/res/values-ca/strings.xml @@ -429,7 +429,6 @@ No hi ha certificats aprovats manualment Esborrar certificats Esborrar selecció - Cancel·lar %d certificat esborrat %d certificats esborrats diff --git a/src/main/res/values-cs/strings.xml b/src/main/res/values-cs/strings.xml index d1e7487bb..090ea644e 100644 --- a/src/main/res/values-cs/strings.xml +++ b/src/main/res/values-cs/strings.xml @@ -432,7 +432,6 @@ Žádné ručně povolené certifikáty Odstranit certifikáty Smazat výběr - Zrušit %d certifikát smazán %d certifikáty smazány diff --git a/src/main/res/values-da-rDK/strings.xml b/src/main/res/values-da-rDK/strings.xml index 02b250f1f..f23495dad 100644 --- a/src/main/res/values-da-rDK/strings.xml +++ b/src/main/res/values-da-rDK/strings.xml @@ -438,7 +438,6 @@ Ingen manuelt godkendt certifikater Fjern certifikater Slet valgt - Annuller %d certifikat slettet %d certifikater slettet @@ -990,5 +989,4 @@ Udgående opkald (%s) · %s Indkommende opkald (%s) · %s Fjern konto fra server - En brugervalgt push-server til at videresende push-meddelelser via XMPP til din enhed. \ No newline at end of file diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml index aa1811da0..a97cd7176 100644 --- a/src/main/res/values-de/strings.xml +++ b/src/main/res/values-de/strings.xml @@ -440,7 +440,6 @@ Keine manuell bestätigten Zertifikate Zertifikate löschen Auswahl löschen - Abbrechen %d Zertifikat gelöscht %d Zertifikate gelöscht @@ -982,7 +981,6 @@ Umschalten auf Video ablehnen XMPP-Konto Push-Server - Ein selbst gewählter Push-Server, der Push-Nachrichten über XMPP an dein Gerät weiterleitet. Kein (deaktiviert) UnifiedPush Verteiler Das Konto, über das Push-Nachrichten empfangen werden sollen. @@ -1018,7 +1016,6 @@ Möchtest du das Lesezeichen für %s entfernen und die Unterhaltung schließen? Löschen & Schließen Willst du das Lesezeichen für %s entfernen? - Die Channelsuche verwendet einen Drittanbieterservice namens <a href=https://search.jabber.network>search.jabber.network</a>.<br><br>Wenn du diese Funktion verwendest, werden deine IP-Adresse und deine Suchbegriffe an diesen Dienst übertragen. Weitere Informationen findest du in der <a href=https://search.jabber.network/privacy>Datenschutzerklärung</a>. Teilen mit… Farbige Chatblasen helfen, gesendete und empfangene Nachrichten zu unterscheiden Farbige Chatblasen diff --git a/src/main/res/values-el/strings.xml b/src/main/res/values-el/strings.xml index b7701fa26..f6aeb830d 100644 --- a/src/main/res/values-el/strings.xml +++ b/src/main/res/values-el/strings.xml @@ -431,7 +431,6 @@ Δεν υπάρχουν χειροκίνητα επιβεβαιωμένα πιστοποιητικα Αφαίρεση πιστοποιητικών Διαγραφή επιλογής - Ακύρωση %d πιστοποιητικό διαγράφηκε %d πιστοποιητικά διαγράφηκαν diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml index 8dfe057e8..807416223 100644 --- a/src/main/res/values-es/strings.xml +++ b/src/main/res/values-es/strings.xml @@ -441,7 +441,6 @@ No aceptar certificados manualmente Eliminar certificados Eliminar seleccionados - Cancelar %d certificado eliminado %d certificados eliminados @@ -998,7 +997,6 @@ Cuenta XMPP La cuenta a través de la cual se recibirán los mensajes push. Servidor push - Un servidor push elegido por el usuario para transmitir mensajes push a través de XMPP a su dispositivo. Ninguno (desactivado) Llamada entrante (%s) · %s Llamada saliente (%s) · %s diff --git a/src/main/res/values-eu/strings.xml b/src/main/res/values-eu/strings.xml index e2d7eb852..5cf081f34 100644 --- a/src/main/res/values-eu/strings.xml +++ b/src/main/res/values-eu/strings.xml @@ -362,7 +362,6 @@ Ez dago eskuz onartutako ziurtagiririk Ziurtagiriak kendu Aukeratutakoak ezabatu - Utzi Ziurtagiri %d ezabatua %d ziurtagiri ezabatuak diff --git a/src/main/res/values-fa-rIR/strings.xml b/src/main/res/values-fa-rIR/strings.xml index f8a682dd9..dc163cc9e 100644 --- a/src/main/res/values-fa-rIR/strings.xml +++ b/src/main/res/values-fa-rIR/strings.xml @@ -139,7 +139,6 @@ آفلاین مخاطب نمایش موقعیت مکانی - لغو آنلاین متوسط تأییدیهٔ امنیتی ناشناخته پذیرفته شود؟ @@ -157,7 +156,6 @@ دیدن گفتگو اثر انگشت OMEMO کپی شد نمایش مسدودسازی‌ها - سرور push دلخواه کاربر برای رساندن اعلان‌های push از راه XMPP به دستگاه شما. وصل شدن ورود شما وصل نیستید. بعداً دوباره تلاش کنید diff --git a/src/main/res/values-fi/strings.xml b/src/main/res/values-fi/strings.xml index fbf1efce1..c614a8ffe 100644 --- a/src/main/res/values-fi/strings.xml +++ b/src/main/res/values-fi/strings.xml @@ -423,7 +423,6 @@ Poista käsin hyväksytyt varmenteet Ei käsin hyväksyttyjä varmenteita Poista varmenteet - Peruuta %d varmenne poistettiin %d varmennetta poistettiin diff --git a/src/main/res/values-fr/strings.xml b/src/main/res/values-fr/strings.xml index ba31ba5ef..dfd6ee54f 100644 --- a/src/main/res/values-fr/strings.xml +++ b/src/main/res/values-fr/strings.xml @@ -437,7 +437,6 @@ Aucun certificat approuvé manuellement Retirer les certificats Supprimer la sélection - Annuler %d certificat supprimé %d certificats supprimés @@ -990,7 +989,6 @@ Compte XMPP Le compte par lequel les messages push seront reçus. Serveur Push - Un serveur push choisi par l\'utilisateur pour relayer les messages push via XMPP vers votre appareil. Aucun (désactivé) %1$d appels manqués de %2$d contact diff --git a/src/main/res/values-gl/strings.xml b/src/main/res/values-gl/strings.xml index 4eb5eabe7..76d9332a4 100644 --- a/src/main/res/values-gl/strings.xml +++ b/src/main/res/values-gl/strings.xml @@ -440,7 +440,6 @@ Sen certificados aprobados manualmente Eliminar certificados Borrar seleción - Cancelar %d certificado eliminado %d certificados eleminados @@ -984,7 +983,6 @@ Conta XMPP A conta a través da cal se recibirán as mensaxes push. Servidor Push - O servidor elexido pola usuaria para obter as mensaxes push a través de XMPP. Ningún (desactivado) Rexeitar Chamada entrante (%s) · %s diff --git a/src/main/res/values-hu/strings.xml b/src/main/res/values-hu/strings.xml index 2850a67ff..9ba1876ee 100644 --- a/src/main/res/values-hu/strings.xml +++ b/src/main/res/values-hu/strings.xml @@ -422,7 +422,6 @@ Nincsenek kézzel jóváhagyott tanúsítványok Tanúsítványok eltávolítása Kijelölés törlése - Mégse %d tanúsítvány törölve %d tanúsítvány törölve diff --git a/src/main/res/values-id/strings.xml b/src/main/res/values-id/strings.xml index 06c08abda..e0a2c0a54 100644 --- a/src/main/res/values-id/strings.xml +++ b/src/main/res/values-id/strings.xml @@ -357,7 +357,6 @@ Tidak ada sertifikat yang disahkan secara manual Hapus sertifikat Hapus seleksi - Batal %d sertifikat dihapus diff --git a/src/main/res/values-it/strings.xml b/src/main/res/values-it/strings.xml index 8f03a6f56..8b3489761 100644 --- a/src/main/res/values-it/strings.xml +++ b/src/main/res/values-it/strings.xml @@ -441,7 +441,6 @@ Non sono presenti certificati accettati manualmente Elimina i certificati Cancella la selezione - Annulla Cancellato il %d certificato Cancellati %d certificati @@ -999,7 +998,6 @@ Profilo XMPP Il profilo attraverso cui verranno ricevuti i messaggi push. Server push - Un server scelto dall\'utente per inoltrare i messaggi push via XMPP al tuo dispositivo. Nessuno (disattivato) Rifiuta Chiamata in arrivo (%s) · %s diff --git a/src/main/res/values-iw/strings.xml b/src/main/res/values-iw/strings.xml index 15aa6fb83..5d1ed7b0c 100644 --- a/src/main/res/values-iw/strings.xml +++ b/src/main/res/values-iw/strings.xml @@ -240,7 +240,6 @@ אין חתימות דיגטליות שאושרו ידנית מחק חתימות דיגטליות מחק פריטים שנבחרו - ביטול %d חתימה נמחקה %d חתימות נמחקו diff --git a/src/main/res/values-ja/strings.xml b/src/main/res/values-ja/strings.xml index 4ac5f8221..0299f1fdb 100644 --- a/src/main/res/values-ja/strings.xml +++ b/src/main/res/values-ja/strings.xml @@ -436,7 +436,6 @@ 手動で承認した証明書がありません 証明書を削除 選択したものを削除 - 中止 %d個の証明書を削除しました @@ -973,7 +972,6 @@ 発信通話 · %s オーディオブック 自分で保存したバックアップしか復元しないでください! - XMPP経由でPushメッセージを端末に転送するユーザー指定のPushサーバー。 ログイン 通知を表示しない アカウントをサーバーから削除 diff --git a/src/main/res/values-ko/strings.xml b/src/main/res/values-ko/strings.xml index b051797cb..b7d4e483e 100644 --- a/src/main/res/values-ko/strings.xml +++ b/src/main/res/values-ko/strings.xml @@ -279,7 +279,6 @@ 수동으로 승인된 인증서 없음 인증서 삭제 선택 삭제 - 취소 %d 인증서 삭제됨 diff --git a/src/main/res/values-ml/strings.xml b/src/main/res/values-ml/strings.xml index b966f88ca..cb93885b5 100644 --- a/src/main/res/values-ml/strings.xml +++ b/src/main/res/values-ml/strings.xml @@ -225,7 +225,6 @@ ലൊക്കേഷൻ അയയ്‌ക്കുക ലൊക്കേഷൻ കാണിക്കൂ ലൊക്കേഷൻ - റദ്ദാക്കൂ സമീപകാലത്ത് ഉപയോഗിച്ചത് കോൺ‌ടാക്റ്റുകൾ തിരയുക സ്വകാര്യ സന്ദേശം അയയ്‌ക്കൂ diff --git a/src/main/res/values-nb-rNO/strings.xml b/src/main/res/values-nb-rNO/strings.xml index 7427815e7..055e98fe1 100644 --- a/src/main/res/values-nb-rNO/strings.xml +++ b/src/main/res/values-nb-rNO/strings.xml @@ -306,7 +306,6 @@ Ingen manuelt godkjente sertifikater Fjern sertifikater Slett innhold i merket område - Avbryt %d sertifikat slettet %d sertifikater slettet diff --git a/src/main/res/values-nl/strings.xml b/src/main/res/values-nl/strings.xml index bad9c7fab..ddbd66fd7 100644 --- a/src/main/res/values-nl/strings.xml +++ b/src/main/res/values-nl/strings.xml @@ -399,7 +399,6 @@ Geen handmatig goedgekeurde certificaten Certificaten verwijderen Selectie verwijderen - Annuleren %d certificaat verwijderd %d certificaten verwijderd diff --git a/src/main/res/values-pl/strings.xml b/src/main/res/values-pl/strings.xml index dbe3faebe..1a7c2fc8c 100644 --- a/src/main/res/values-pl/strings.xml +++ b/src/main/res/values-pl/strings.xml @@ -444,7 +444,6 @@ Brak ręcznie zaufanych certyfikatów Usuń certyfikaty Usuń zaznaczone - Anuluj Usunięto %d certyfikat Usunięto %d certyfikaty @@ -1016,7 +1015,6 @@ Konto XMPP Konto, poprzez które będą odbierane powiadomienia push. Serwer push - Dowolnie wybrany serwer push do przekazywania wiadomości push przez XMPP na Twoje urządzenie. Brak (nieaktywne) Odrzuć Połączenie przychodzące (%s) · %s diff --git a/src/main/res/values-pt-rBR/strings.xml b/src/main/res/values-pt-rBR/strings.xml index aede07bfc..9240999bb 100644 --- a/src/main/res/values-pt-rBR/strings.xml +++ b/src/main/res/values-pt-rBR/strings.xml @@ -437,7 +437,6 @@ Nenhum certificado aprovado manualmente Remover certificados Excluir a seleção - Cancelar %d certificado cancelado %d certificados cancelados diff --git a/src/main/res/values-pt/strings.xml b/src/main/res/values-pt/strings.xml index 4f76633e1..e6fa1eb14 100644 --- a/src/main/res/values-pt/strings.xml +++ b/src/main/res/values-pt/strings.xml @@ -299,7 +299,6 @@ Não existem certificados aprovados manualmente Remover certificados Apagar seleção - Cancelar %d certificado apagado %d certificados apagados diff --git a/src/main/res/values-ro-rRO/strings.xml b/src/main/res/values-ro-rRO/strings.xml index 6f5a78be3..0c86d9651 100644 --- a/src/main/res/values-ro-rRO/strings.xml +++ b/src/main/res/values-ro-rRO/strings.xml @@ -443,7 +443,6 @@ Nici un certificat aprobat manual Înlătură certificatele Șterge selecția - Anuleaza %d certificat sters %d certificate sterse @@ -1001,7 +1000,6 @@ Respinge solicitarea de comutare la video Cont XMPP Server Push - Un server ales de utilizator pentru a intermedia mesajele push către dispozitivul vostru prin XMPP. Nici unul (dezactivat) Distribuitor UnifiedPush Contul prin care vor fi primite notificările push. diff --git a/src/main/res/values-ru/strings.xml b/src/main/res/values-ru/strings.xml index 9dee49654..ae8d7851f 100644 --- a/src/main/res/values-ru/strings.xml +++ b/src/main/res/values-ru/strings.xml @@ -435,7 +435,6 @@ Не найдено сертификатов, подтверждённых вручную Удалить сертификаты Удалить отмеченные - Отмена Удалён %d сертификат Удалено %d сертификата @@ -1009,7 +1008,6 @@ Регистрации учётных записей не поддерживаются Звонки выключены, пока используется Tor Учётная запись для получения пуш-уведомлений. - Выбираемый пользователем сервер для перенаправления уведомлений на Ваше устройство. Нет (неактивно) Вы собираетесь проверить ключи OMEMO своей учетной записи. Это безопасно только в том случае, если вы перешли по этой ссылке из надежного источника, где только вы могли опубликовать эту ссылку. Не пытайтесь восстановить резервные копии, которые не были созданы вами! diff --git a/src/main/res/values-sk/strings.xml b/src/main/res/values-sk/strings.xml index d9e13fe18..13bba3c14 100644 --- a/src/main/res/values-sk/strings.xml +++ b/src/main/res/values-sk/strings.xml @@ -387,7 +387,6 @@ Žiadne ručne schválené certifikáty Odstrániť certifikáty Vymazať výber - Zrušiť %d certifikátu vymazaných %d certifikátu vymazaných diff --git a/src/main/res/values-sq-rAL/strings.xml b/src/main/res/values-sq-rAL/strings.xml index 6adc1a99e..54d172a32 100644 --- a/src/main/res/values-sq-rAL/strings.xml +++ b/src/main/res/values-sq-rAL/strings.xml @@ -354,7 +354,6 @@ S’u dhanë dëshmi dorazi Hiqi dëshmitë Fshije përzgjedhjen - Anuloje Veprim i Shpejtë Asnjë Më të përdorur së fundi @@ -968,7 +967,6 @@ Thirrjet janë të çaktivizuara, kur përdoret Tor-i Llogaria përmes së cilës do të merren mesazhet push. Shërbyes Push - Një shërbyes push i zgjedhur nga përdoruesi, përmes të cilit të kalohen te pajisja juaj mesazhet push përmes XMPP-je. Ka të hartuar një udhërrëfyes mbi krijim llogarish te conversations.im. \nKu zgjidhet conversations.im si shërbim, do të jeni në gjendje të komunikoni me përdorues prej shërbimesh të tjera duke u dhënë atyre adresën tuaj të plotë XMPP. @@ -1027,7 +1025,6 @@ Doni të hiqet faqerojtësi për %s dhe të mbyllet biseda? Fshije & Mbylle Doni të hiqet faqerojtësi për %s? - Pikasja e kanaleve përdor një shërbim palë të tretë të quajtur <a href=https://search.jabber.network>search.jabber.network</a>.<br><br>Përdorimi i kësaj veçorie do t’i transmetojë atij shërbimi adresën tuaj IP dhe terma kërkimesh. Për më tepër hollësi, shihni <a href=https://search.jabber.network/privacy>Rregullat e tyre mbi Privatësinë</a>. Flluska të ngjyrosura fjalosjeje ndihmojnë të dalloni mesazhe të dërguar dhe të marrë Ngjyra dinamike Ngjyra Sistemi (Material You) diff --git a/src/main/res/values-sr/strings.xml b/src/main/res/values-sr/strings.xml index 0399e3ef3..fc36b94db 100644 --- a/src/main/res/values-sr/strings.xml +++ b/src/main/res/values-sr/strings.xml @@ -424,7 +424,6 @@ Нема ручно одобрених сертификата Уклањање сертификата Обриши изабрано - Одустани %d сертификат обрисан %d сертификата обрисана diff --git a/src/main/res/values-sv/strings.xml b/src/main/res/values-sv/strings.xml index 04f0ee817..c72acebe4 100644 --- a/src/main/res/values-sv/strings.xml +++ b/src/main/res/values-sv/strings.xml @@ -447,7 +447,6 @@ Inga manuellt godkända certifikat Ta bort certifikaten Ta bort val - Avbryt %d certifikat borttaget %d certifikat borttagna @@ -974,7 +973,6 @@ XMPP-konto Kontot genom vilket push-meddelanden tas emot. Push-server - En användarvald push-server för att vidarebefordra push-meddelanden via XMPP till din enhet. Ingen (inaktiverad) Det här telefonnumret är för närvarande inloggat med en annan enhet. Var god ange ditt namn för att låta personer som inte har dig i sina adressböcker, veta vem du är. diff --git a/src/main/res/values-szl/strings.xml b/src/main/res/values-szl/strings.xml index 4a99e5a4a..64e9558c1 100644 --- a/src/main/res/values-szl/strings.xml +++ b/src/main/res/values-szl/strings.xml @@ -451,7 +451,6 @@ Brak ryncznie zadufanych certyfikatōw Wymaż certyfikaty Wymaż zaznaczōne - Pociep Wymazany %d certyfikat Wymazane %d certyfikaty diff --git a/src/main/res/values-tr-rTR/strings.xml b/src/main/res/values-tr-rTR/strings.xml index 5fa2be1f9..d6a6b84e3 100644 --- a/src/main/res/values-tr-rTR/strings.xml +++ b/src/main/res/values-tr-rTR/strings.xml @@ -442,7 +442,6 @@ Bizzat onaylanmış sertifika yok Sertifikaları kaldır Seçilenleri sil - İptal %d sertifikaları silindi %d sertifikaları silindi diff --git a/src/main/res/values-uk/strings.xml b/src/main/res/values-uk/strings.xml index 74e127750..7f94e1f6c 100644 --- a/src/main/res/values-uk/strings.xml +++ b/src/main/res/values-uk/strings.xml @@ -435,7 +435,6 @@ Немає сертифікатів, підтверджених вручну Вилучити сертифікати Вилучити вибране - Скасувати %d сертифікат вилучено %d сертифікати вилучено @@ -969,7 +968,6 @@ Деякі повідомлення не вдалося надіслати Деякі повідомлення не вдалося надіслати - Оберіть сервер для доставки push-повідомлень через XMPP на Ваш пристрій. Застосунок для передачі зображення не надав достатніх дозволів. Виклики вимкнені при використанні Tor %1$s обробляє Ваш список контактів локально, на Вашому пристрої, щоб показати імена та зображення профілю для відповідних контактів у XMPP. diff --git a/src/main/res/values-vi/strings.xml b/src/main/res/values-vi/strings.xml index 319a79f6e..96c3e9f08 100644 --- a/src/main/res/values-vi/strings.xml +++ b/src/main/res/values-vi/strings.xml @@ -434,7 +434,6 @@ Không có chứng nhận được phê duyệt thủ công Xoá các chứng nhận Xoá lựa chọn - Huỷ Đã xoá %d chứng nhận @@ -959,7 +958,6 @@ Tài khoản sẽ nhận được tin nhắn đã đẩy đi. Tài khoản XMPP Máy chủ đẩy - Một máy chủ đẩy do người dùng chọn để phát lại tin nhắn đẩy qua XMPP đến thiết bị của bạn. Không tồn tại (đã vô hiệu hóa) Từ chối Lưu thành nhóm trò chuyện diff --git a/src/main/res/values-zh-rCN/strings.xml b/src/main/res/values-zh-rCN/strings.xml index 7364f343a..2c3344076 100644 --- a/src/main/res/values-zh-rCN/strings.xml +++ b/src/main/res/values-zh-rCN/strings.xml @@ -454,7 +454,6 @@ 没有手动批准的证书 移除证书 删除所选 - 取消 %d 个证书已删除 @@ -991,7 +990,6 @@ 无 (已停用) UnifiedPush 分发程序 接收推送消息的账号。 - 用户选择的推送服务器,通过 XMPP 将推送消息转送至设备。 拒绝 来电 (%s) · %s 去电 (%s) · %s @@ -1024,7 +1022,6 @@ 是否移除 %s 的书签并关闭对话? 是否移除 %s 的书签? 删除 & 关闭 - 频道发现使用称为 <a href=https://search.jabber.network>search.jabber.network</a> 的第三方服务。<br><br>使用此功能会将您的 IP 地址和搜索词传输到此服务。请参阅其 <a href=https://search.jabber.network/privacy>隐私政策</a> 以获取更多信息。 开始聊天 分享至… 彩色聊天气泡有助于区分发送和接收的信息 diff --git a/src/main/res/values-zh-rTW/strings.xml b/src/main/res/values-zh-rTW/strings.xml index a7d203192..cc09d04bf 100644 --- a/src/main/res/values-zh-rTW/strings.xml +++ b/src/main/res/values-zh-rTW/strings.xml @@ -414,7 +414,6 @@ 沒有手動核准的憑證 移除憑證 刪除選取項目 - 取消 %d 個憑證已刪除 @@ -964,7 +963,6 @@ UnifiedPush 散發者 XMPP 帳戶 推送伺服器 - 使用者選擇的推送伺服器,透過 XMPP 將訊息推送至您的裝置。 無 (已停用) 接收推送訊息的帳戶。 拒絕 diff --git a/src/main/res/values/defaults.xml b/src/main/res/values/defaults.xml index 288e4ae74..929aee1a3 100644 --- a/src/main/res/values/defaults.xml +++ b/src/main/res/values/defaults.xml @@ -24,6 +24,7 @@ true 0 false + true true false false @@ -44,7 +45,7 @@ false 360 JABBER_NETWORK - false + true up.conversations.im none diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 0405599fd..290b54404 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -282,7 +282,7 @@ Ignore Warning: Sending this without mutual presence updates could cause unexpected problems.\n\nGo to “Contact details” to verify your presence subscriptions. Security - Allow message correction + Message correction Allow your contacts to retroactively edit their messages Expert settings Please be careful with these @@ -446,7 +446,6 @@ No manually approved certificates Remove certificates Delete selection - Cancel %d certificate deleted %d certificates deleted @@ -479,8 +478,8 @@ Show as Busy when device is in silent mode Treat vibrate as silent mode Show as Busy when device is on vibrate - Extended connection settings - Show hostname and port settings when setting up an account + Hostname & Port + Show extended connection settings when setting up an account xmpp.example.com Login with certificate Could not parse certificate @@ -571,8 +570,8 @@ Short Medium Long - Broadcast use - Lets your contacts know when you use Conversations + Last seen + Let your contacts see when you last used the app Privacy Theme Select the color palette @@ -749,7 +748,7 @@ Copy XMPP address HTTP File Sharing for S3 Direct Search - At ‘Start chat’ screen open keyboard and place cursor in search field + At ‘New chat’ screen open keyboard and place cursor in search field Group chat avatar Host does not support group chat avatars Only the owner can change group chat avatar @@ -1009,7 +1008,6 @@ XMPP Account The account through which push messages will be received. Push Server - A user-chosen push server to relay push messages via XMPP to your device. None (deactivated) Decline Remove account from server @@ -1027,4 +1025,39 @@ Delete & Archive chat Start chat No client certificate selected! + + + + Interface + Theme, Colors, Screenshots, Input + Security + E2E Encryption, Blind Trust Before Verification, MIM Detection + Notification relay for UnifiedPush compatible third party apps + Notifications + File size, Image compression, Video quality + Grace period, Ringtone, Vibration, Strangers + Sending + Receiving + Automatic download + Appearance + Light/dark mode + Allow screenshots + Show app content in app switcher and allow screenshots to be taken + End-to-end encryption + Certificate authorities + Trust the system’s CA certificates + Require channel binding + Channel binding can detect some machine-in-the-middle attacks + Server connection + Operating System + Typing notifications, Last Seen, Availability + Hostname & Port, Tor + Hostname & Port, Tor, Channel Discovery + Keyboard + Engagement notifications + Application + Interaction + On device + When acting as a UnifiedPush Distributor the persistent, reliably and battery-friendly XMPP connection will be utilized to wake up other UnifiedPush compatible app such as Tusky, Ltt.rs, FluffyChat and more. + diff --git a/src/main/res/xml/preferences.xml b/src/main/res/xml/preferences.xml deleted file mode 100644 index cde8240a2..000000000 --- a/src/main/res/xml/preferences.xml +++ /dev/null @@ -1,376 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/main/res/xml/preferences_attachments.xml b/src/main/res/xml/preferences_attachments.xml new file mode 100644 index 000000000..7577fb2ea --- /dev/null +++ b/src/main/res/xml/preferences_attachments.xml @@ -0,0 +1,32 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/main/res/xml/preferences_connection.xml b/src/main/res/xml/preferences_connection.xml new file mode 100644 index 000000000..3ac78e4be --- /dev/null +++ b/src/main/res/xml/preferences_connection.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/res/xml/preferences_interface.xml b/src/main/res/xml/preferences_interface.xml new file mode 100644 index 000000000..390e1e591 --- /dev/null +++ b/src/main/res/xml/preferences_interface.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/res/xml/preferences_main.xml b/src/main/res/xml/preferences_main.xml new file mode 100644 index 000000000..2de980c40 --- /dev/null +++ b/src/main/res/xml/preferences_main.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/res/xml/preferences_notifications.xml b/src/main/res/xml/preferences_notifications.xml new file mode 100644 index 000000000..82e74efc9 --- /dev/null +++ b/src/main/res/xml/preferences_notifications.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/res/xml/preferences_privacy.xml b/src/main/res/xml/preferences_privacy.xml new file mode 100644 index 000000000..b425c35cd --- /dev/null +++ b/src/main/res/xml/preferences_privacy.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/res/xml/preferences_security.xml b/src/main/res/xml/preferences_security.xml new file mode 100644 index 000000000..86bd6c87e --- /dev/null +++ b/src/main/res/xml/preferences_security.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/res/xml/preferences_up.xml b/src/main/res/xml/preferences_up.xml new file mode 100644 index 000000000..de07d7016 --- /dev/null +++ b/src/main/res/xml/preferences_up.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file