mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-30 05:31:34 +01:00
Refactor app settings.
This commit is contained in:
committed by
Greyson Parrelli
parent
a94d77d81e
commit
f2d5ea0391
@@ -1,404 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Whisper Systems
|
||||
* Copyright (C) 2013-2017 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.conversationlist.model.UnreadPayments;
|
||||
import org.thoughtcrime.securesms.conversationlist.model.UnreadPaymentsLiveData;
|
||||
import org.thoughtcrime.securesms.help.HelpFragment;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.payments.preferences.PaymentsActivity;
|
||||
import org.thoughtcrime.securesms.preferences.AdvancedPreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.AppearancePreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.BackupsPreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.ChatsPreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.CorrectedPreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.DataAndStoragePreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.EditProxyFragment;
|
||||
import org.thoughtcrime.securesms.preferences.NotificationsPreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.SmsMmsPreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.widgets.PaymentsPreference;
|
||||
import org.thoughtcrime.securesms.preferences.widgets.ProfilePreference;
|
||||
import org.thoughtcrime.securesms.preferences.widgets.UsernamePreference;
|
||||
import org.thoughtcrime.securesms.profiles.manage.ManageProfileActivity;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||
import org.thoughtcrime.securesms.util.CachedInflater;
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions;
|
||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
||||
/**
|
||||
* The Activity for application preference display and management.
|
||||
*
|
||||
* @author Moxie Marlinspike
|
||||
*
|
||||
*/
|
||||
|
||||
public class ApplicationPreferencesActivity extends PassphraseRequiredActivity
|
||||
implements SharedPreferences.OnSharedPreferenceChangeListener
|
||||
{
|
||||
public static final String LAUNCH_TO_BACKUPS_FRAGMENT = "launch.to.backups.fragment";
|
||||
public static final String LAUNCH_TO_HELP_FRAGMENT = "launch.to.help.fragment";
|
||||
public static final String LAUNCH_TO_PROXY_FRAGMENT = "launch.to.proxy.fragment";
|
||||
public static final String LAUNCH_TO_NOTIFICATIONS_FRAGMENT = "launch.to.notifications.fragment";
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = Log.tag(ApplicationPreferencesActivity.class);
|
||||
|
||||
private static final String PREFERENCE_CATEGORY_PROFILE = "preference_category_profile";
|
||||
private static final String PREFERENCE_CATEGORY_USERNAME = "preference_category_username";
|
||||
private static final String PREFERENCE_CATEGORY_SMS_MMS = "preference_category_sms_mms";
|
||||
private static final String PREFERENCE_CATEGORY_NOTIFICATIONS = "preference_category_notifications";
|
||||
private static final String PREFERENCE_CATEGORY_APP_PROTECTION = "preference_category_app_protection";
|
||||
private static final String PREFERENCE_CATEGORY_APPEARANCE = "preference_category_appearance";
|
||||
private static final String PREFERENCE_CATEGORY_CHATS = "preference_category_chats";
|
||||
private static final String PREFERENCE_CATEGORY_STORAGE = "preference_category_storage";
|
||||
private static final String PREFERENCE_CATEGORY_DEVICES = "preference_category_devices";
|
||||
private static final String PREFERENCE_CATEGORY_HELP = "preference_category_help";
|
||||
private static final String PREFERENCE_CATEGORY_ADVANCED = "preference_category_advanced";
|
||||
private static final String PREFERENCE_CATEGORY_DONATE = "preference_category_donate";
|
||||
private static final String PREFERENCE_CATEGORY_PAYMENTS = "preference_category_payments";
|
||||
|
||||
private static final String WAS_CONFIGURATION_UPDATED = "was_configuration_updated";
|
||||
|
||||
private final DynamicTheme dynamicTheme = new DynamicTheme();
|
||||
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
|
||||
|
||||
private boolean wasConfigurationUpdated = false;
|
||||
|
||||
@Override
|
||||
protected void onPreCreate() {
|
||||
dynamicTheme.onCreate(this);
|
||||
dynamicLanguage.onCreate(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle icicle, boolean ready) {
|
||||
//noinspection ConstantConditions
|
||||
this.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
if (getIntent() != null && getIntent().getCategories() != null && getIntent().getCategories().contains("android.intent.category.NOTIFICATION_PREFERENCES")) {
|
||||
initFragment(android.R.id.content, new NotificationsPreferenceFragment());
|
||||
} else if (getIntent() != null && getIntent().getBooleanExtra(LAUNCH_TO_BACKUPS_FRAGMENT, false)) {
|
||||
initFragment(android.R.id.content, new BackupsPreferenceFragment());
|
||||
} else if (getIntent() != null && getIntent().getBooleanExtra(LAUNCH_TO_HELP_FRAGMENT, false)) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt(HelpFragment.START_CATEGORY_INDEX, getIntent().getIntExtra(HelpFragment.START_CATEGORY_INDEX, 0));
|
||||
|
||||
initFragment(android.R.id.content, new HelpFragment(), null, bundle);
|
||||
} else if (getIntent() != null && getIntent().getBooleanExtra(LAUNCH_TO_PROXY_FRAGMENT, false)) {
|
||||
initFragment(android.R.id.content, EditProxyFragment.newInstance());
|
||||
} else if (getIntent() != null && getIntent().getBooleanExtra(LAUNCH_TO_NOTIFICATIONS_FRAGMENT, false)) {
|
||||
initFragment(android.R.id.content, new NotificationsPreferenceFragment());
|
||||
} else if (icicle == null) {
|
||||
initFragment(android.R.id.content, new ApplicationPreferenceFragment());
|
||||
} else {
|
||||
wasConfigurationUpdated = icicle.getBoolean(WAS_CONFIGURATION_UPDATED);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
outState.putBoolean(WAS_CONFIGURATION_UPDATED, wasConfigurationUpdated);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
dynamicTheme.onResume(this);
|
||||
dynamicLanguage.onResume(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data)
|
||||
{
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
Fragment fragment = getSupportFragmentManager().findFragmentById(android.R.id.content);
|
||||
fragment.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSupportNavigateUp() {
|
||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
if (fragmentManager.getBackStackEntryCount() > 0) {
|
||||
fragmentManager.popBackStack();
|
||||
} else {
|
||||
if (wasConfigurationUpdated) {
|
||||
setResult(MainActivity.RESULT_CONFIG_CHANGED);
|
||||
} else {
|
||||
setResult(RESULT_OK);
|
||||
}
|
||||
finish();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
onSupportNavigateUp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
if (key.equals(TextSecurePreferences.THEME_PREF)) {
|
||||
DynamicTheme.setDefaultDayNightMode(this);
|
||||
recreate();
|
||||
} else if (key.equals(TextSecurePreferences.LANGUAGE_PREF)) {
|
||||
CachedInflater.from(this).clear();
|
||||
wasConfigurationUpdated = true;
|
||||
recreate();
|
||||
|
||||
Intent intent = new Intent(this, KeyCachingService.class);
|
||||
intent.setAction(KeyCachingService.LOCALE_CHANGE_EVENT);
|
||||
startService(intent);
|
||||
}
|
||||
}
|
||||
|
||||
public void pushFragment(@NonNull Fragment fragment) {
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.setCustomAnimations(R.anim.slide_from_end, R.anim.slide_to_start, R.anim.slide_from_start, R.anim.slide_to_end)
|
||||
.replace(android.R.id.content, fragment)
|
||||
.addToBackStack(null)
|
||||
.commit();
|
||||
}
|
||||
|
||||
public static class ApplicationPreferenceFragment extends CorrectedPreferenceFragment {
|
||||
|
||||
private final UnreadPaymentsLiveData unreadPaymentsLiveData = new UnreadPaymentsLiveData();
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
|
||||
this.findPreference(PREFERENCE_CATEGORY_PROFILE)
|
||||
.setOnPreferenceClickListener(new ProfileClickListener());
|
||||
this.findPreference(PREFERENCE_CATEGORY_USERNAME)
|
||||
.setOnPreferenceClickListener(new UsernameClickListener());
|
||||
this.findPreference(PREFERENCE_CATEGORY_SMS_MMS)
|
||||
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_SMS_MMS));
|
||||
this.findPreference(PREFERENCE_CATEGORY_NOTIFICATIONS)
|
||||
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_NOTIFICATIONS));
|
||||
this.findPreference(PREFERENCE_CATEGORY_APP_PROTECTION)
|
||||
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_APP_PROTECTION));
|
||||
this.findPreference(PREFERENCE_CATEGORY_APPEARANCE)
|
||||
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_APPEARANCE));
|
||||
this.findPreference(PREFERENCE_CATEGORY_CHATS)
|
||||
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_CHATS));
|
||||
this.findPreference(PREFERENCE_CATEGORY_STORAGE)
|
||||
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_STORAGE));
|
||||
this.findPreference(PREFERENCE_CATEGORY_DEVICES)
|
||||
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_DEVICES));
|
||||
this.findPreference(PREFERENCE_CATEGORY_HELP)
|
||||
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_HELP));
|
||||
this.findPreference(PREFERENCE_CATEGORY_ADVANCED)
|
||||
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_ADVANCED));
|
||||
this.findPreference(PREFERENCE_CATEGORY_DONATE)
|
||||
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_DONATE));
|
||||
|
||||
Preference paymentsPreference = this.findPreference(PREFERENCE_CATEGORY_PAYMENTS);
|
||||
|
||||
if (SignalStore.paymentsValues().getPaymentsAvailability().showPaymentsMenu()) {
|
||||
paymentsPreference.setVisible(true);
|
||||
paymentsPreference.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_PAYMENTS));
|
||||
} else {
|
||||
paymentsPreference.setVisible(false);
|
||||
}
|
||||
|
||||
tintIcons();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
if (SignalStore.paymentsValues().getPaymentsAvailability().showPaymentsMenu()) {
|
||||
PaymentsPreference paymentsPreference = (PaymentsPreference) this.findPreference(PREFERENCE_CATEGORY_PAYMENTS);
|
||||
|
||||
unreadPaymentsLiveData.observe(getViewLifecycleOwner(), unreadPayments -> paymentsPreference.setUnreadCount(unreadPayments.transform(UnreadPayments::getUnreadCount).or(-1)));
|
||||
}
|
||||
}
|
||||
|
||||
private void tintIcons() {
|
||||
if (Build.VERSION.SDK_INT >= 21) return;
|
||||
|
||||
Preference preference = this.findPreference(PREFERENCE_CATEGORY_SMS_MMS);
|
||||
preference.getIcon().setColorFilter(ContextCompat.getColor(requireContext(), R.color.signal_icon_tint_primary), PorterDuff.Mode.SRC_IN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
|
||||
addPreferencesFromResource(R.xml.preferences);
|
||||
|
||||
if (FeatureFlags.usernames()) {
|
||||
UsernamePreference pref = (UsernamePreference) findPreference(PREFERENCE_CATEGORY_USERNAME);
|
||||
pref.setVisible(shouldDisplayUsernameReminder());
|
||||
pref.setOnLongClickListener(v -> {
|
||||
new AlertDialog.Builder(requireContext())
|
||||
.setMessage(R.string.ApplicationPreferencesActivity_hide_reminder)
|
||||
.setPositiveButton(R.string.ApplicationPreferencesActivity_hide, (dialog, which) -> {
|
||||
dialog.dismiss();
|
||||
SignalStore.misc().hideUsernameReminder();
|
||||
findPreference(PREFERENCE_CATEGORY_USERNAME).setVisible(false);
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, ((dialog, which) -> dialog.dismiss()))
|
||||
.setCancelable(true)
|
||||
.show();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
//noinspection ConstantConditions
|
||||
((ApplicationPreferencesActivity) getActivity()).getSupportActionBar().setTitle(R.string.text_secure_normal__menu_settings);
|
||||
setCategorySummaries();
|
||||
setCategoryVisibility();
|
||||
}
|
||||
|
||||
private void setCategorySummaries() {
|
||||
((ProfilePreference)this.findPreference(PREFERENCE_CATEGORY_PROFILE)).refresh();
|
||||
|
||||
if (FeatureFlags.usernames()) {
|
||||
this.findPreference(PREFERENCE_CATEGORY_USERNAME)
|
||||
.setVisible(shouldDisplayUsernameReminder());
|
||||
}
|
||||
|
||||
this.findPreference(PREFERENCE_CATEGORY_SMS_MMS)
|
||||
.setSummary(SmsMmsPreferenceFragment.getSummary(getActivity()));
|
||||
this.findPreference(PREFERENCE_CATEGORY_NOTIFICATIONS)
|
||||
.setSummary(NotificationsPreferenceFragment.getSummary(getActivity()));
|
||||
this.findPreference(PREFERENCE_CATEGORY_APP_PROTECTION)
|
||||
.setSummary(AppProtectionPreferenceFragment.getSummary(getActivity()));
|
||||
this.findPreference(PREFERENCE_CATEGORY_APPEARANCE)
|
||||
.setSummary(AppearancePreferenceFragment.getSummary(getActivity()));
|
||||
this.findPreference(PREFERENCE_CATEGORY_CHATS)
|
||||
.setSummary(ChatsPreferenceFragment.getSummary(getActivity()));
|
||||
}
|
||||
|
||||
private void setCategoryVisibility() {
|
||||
Preference devicePreference = this.findPreference(PREFERENCE_CATEGORY_DEVICES);
|
||||
if (devicePreference != null && !TextSecurePreferences.isPushRegistered(getActivity())) {
|
||||
getPreferenceScreen().removePreference(devicePreference);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean shouldDisplayUsernameReminder() {
|
||||
return FeatureFlags.usernames() && !Recipient.self().getUsername().isPresent() && SignalStore.misc().shouldShowUsernameReminder();
|
||||
}
|
||||
|
||||
private class CategoryClickListener implements Preference.OnPreferenceClickListener {
|
||||
private String category;
|
||||
|
||||
CategoryClickListener(String category) {
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
Fragment fragment = null;
|
||||
|
||||
switch (category) {
|
||||
case PREFERENCE_CATEGORY_SMS_MMS:
|
||||
fragment = new SmsMmsPreferenceFragment();
|
||||
break;
|
||||
case PREFERENCE_CATEGORY_NOTIFICATIONS:
|
||||
fragment = new NotificationsPreferenceFragment();
|
||||
break;
|
||||
case PREFERENCE_CATEGORY_APP_PROTECTION:
|
||||
fragment = new AppProtectionPreferenceFragment();
|
||||
break;
|
||||
case PREFERENCE_CATEGORY_APPEARANCE:
|
||||
fragment = new AppearancePreferenceFragment();
|
||||
break;
|
||||
case PREFERENCE_CATEGORY_CHATS:
|
||||
fragment = new ChatsPreferenceFragment();
|
||||
break;
|
||||
case PREFERENCE_CATEGORY_STORAGE:
|
||||
fragment = new DataAndStoragePreferenceFragment();
|
||||
break;
|
||||
case PREFERENCE_CATEGORY_DEVICES:
|
||||
Intent intent = new Intent(getActivity(), DeviceActivity.class);
|
||||
startActivity(intent);
|
||||
break;
|
||||
case PREFERENCE_CATEGORY_ADVANCED:
|
||||
fragment = new AdvancedPreferenceFragment();
|
||||
break;
|
||||
case PREFERENCE_CATEGORY_HELP:
|
||||
fragment = new HelpFragment();
|
||||
break;
|
||||
case PREFERENCE_CATEGORY_DONATE:
|
||||
CommunicationActions.openBrowserLink(requireContext(), getString(R.string.donate_url));
|
||||
break;
|
||||
case PREFERENCE_CATEGORY_PAYMENTS:
|
||||
startActivity(new Intent(requireContext(), PaymentsActivity.class));
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
if (fragment != null) {
|
||||
Bundle args = new Bundle();
|
||||
fragment.setArguments(args);
|
||||
|
||||
((ApplicationPreferencesActivity) requireActivity()).pushFragment(fragment);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class ProfileClickListener implements Preference.OnPreferenceClickListener {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
requireActivity().startActivity(ManageProfileActivity.getIntent(requireActivity()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class UsernameClickListener implements Preference.OnPreferenceClickListener {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
requireActivity().startActivity(ManageProfileActivity.getIntentForUsernameEdit(preference.getContext()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,11 +26,12 @@ import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.components.ContactFilterToolbar;
|
||||
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader.DisplayMode;
|
||||
import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -65,8 +66,8 @@ public abstract class ContactSelectionActivity extends PassphraseRequiredActivit
|
||||
@Override
|
||||
protected void onCreate(Bundle icicle, boolean ready) {
|
||||
if (!getIntent().hasExtra(ContactSelectionListFragment.DISPLAY_MODE)) {
|
||||
int displayMode = TextSecurePreferences.isSmsEnabled(this) ? DisplayMode.FLAG_ALL
|
||||
: DisplayMode.FLAG_PUSH | DisplayMode.FLAG_ACTIVE_GROUPS | DisplayMode.FLAG_INACTIVE_GROUPS | DisplayMode.FLAG_SELF;
|
||||
int displayMode = Util.isDefaultSmsProvider(this) ? DisplayMode.FLAG_ALL
|
||||
: DisplayMode.FLAG_PUSH | DisplayMode.FLAG_ACTIVE_GROUPS | DisplayMode.FLAG_INACTIVE_GROUPS | DisplayMode.FLAG_SELF;
|
||||
getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE, displayMode);
|
||||
}
|
||||
|
||||
|
||||
@@ -77,16 +77,6 @@ public class DeviceActivity extends PassphraseRequiredActivity
|
||||
} else {
|
||||
initFragment(android.R.id.content, deviceListFragment, dynamicLanguage.getCurrentLocale());
|
||||
}
|
||||
|
||||
overridePendingTransition(R.anim.slide_from_end, R.anim.slide_to_start);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
if (isFinishing()) {
|
||||
overridePendingTransition(R.anim.slide_from_start, R.anim.slide_to_end);
|
||||
}
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -9,6 +9,8 @@ import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsActivity;
|
||||
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity;
|
||||
import org.thoughtcrime.securesms.conversation.ConversationIntents;
|
||||
import org.thoughtcrime.securesms.conversationlist.ConversationListArchiveFragment;
|
||||
import org.thoughtcrime.securesms.conversationlist.ConversationListFragment;
|
||||
@@ -69,8 +71,7 @@ public class MainNavigator {
|
||||
}
|
||||
|
||||
public void goToAppSettings() {
|
||||
Intent intent = new Intent(activity, ApplicationPreferencesActivity.class);
|
||||
activity.startActivityForResult(intent, REQUEST_CONFIG_CHANGES);
|
||||
activity.startActivityForResult(AppSettingsActivity.home(activity), REQUEST_CONFIG_CHANGES);
|
||||
}
|
||||
|
||||
public void goToArchiveList() {
|
||||
|
||||
@@ -74,7 +74,7 @@ public class BackupDialog {
|
||||
|
||||
BackupPassphrase.set(context, Util.join(password, " "));
|
||||
TextSecurePreferences.setNextBackupTime(context, 0);
|
||||
TextSecurePreferences.setBackupEnabled(context, true);
|
||||
SignalStore.settings().setBackupEnabled(true);
|
||||
LocalBackupListener.schedule(context);
|
||||
|
||||
onBackupsEnabled.run();
|
||||
|
||||
@@ -3,7 +3,6 @@ package org.thoughtcrime.securesms.backup;
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -11,8 +10,8 @@ import androidx.annotation.StringRes;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity;
|
||||
import org.thoughtcrime.securesms.notifications.NotificationCancellationHelper;
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||
|
||||
@@ -39,11 +38,7 @@ public enum BackupFileIOError {
|
||||
}
|
||||
|
||||
public void postNotification(@NonNull Context context) {
|
||||
Intent intent = new Intent(context, ApplicationPreferencesActivity.class);
|
||||
|
||||
intent.putExtra(ApplicationPreferencesActivity.LAUNCH_TO_BACKUPS_FRAGMENT, true);
|
||||
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(context, -1, intent, 0);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(context, -1, AppSettingsActivity.backups(context), 0);
|
||||
Notification backupFailedNotification = new NotificationCompat.Builder(context, NotificationChannels.FAILURES)
|
||||
.setSmallIcon(R.drawable.ic_signal_backup)
|
||||
.setContentTitle(context.getString(titleId))
|
||||
|
||||
@@ -35,6 +35,7 @@ import org.thoughtcrime.securesms.components.mention.MentionDeleter;
|
||||
import org.thoughtcrime.securesms.components.mention.MentionRendererDelegate;
|
||||
import org.thoughtcrime.securesms.components.mention.MentionValidatorWatcher;
|
||||
import org.thoughtcrime.securesms.database.model.Mention;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.StringUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
@@ -201,7 +202,7 @@ public class ComposeText extends EmojiEditText {
|
||||
}
|
||||
|
||||
public void setTransport(TransportOption transport) {
|
||||
final boolean useSystemEmoji = TextSecurePreferences.isSystemEmojiPreferred(getContext());
|
||||
final boolean useSystemEmoji = SignalStore.settings().isPreferSystemEmoji();
|
||||
|
||||
int imeOptions = (getImeOptions() & ~EditorInfo.IME_MASK_ACTION) | EditorInfo.IME_ACTION_SEND;
|
||||
int inputType = getInputType();
|
||||
@@ -225,7 +226,7 @@ public class ComposeText extends EmojiEditText {
|
||||
public InputConnection onCreateInputConnection(EditorInfo editorInfo) {
|
||||
InputConnection inputConnection = super.onCreateInputConnection(editorInfo);
|
||||
|
||||
if(TextSecurePreferences.isEnterSendsEnabled(getContext())) {
|
||||
if(SignalStore.settings().isEnterKeySends()) {
|
||||
editorInfo.imeOptions &= ~EditorInfo.IME_FLAG_NO_ENTER_ACTION;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.thoughtcrime.securesms.components.emoji.EmojiToggle;
|
||||
import org.thoughtcrime.securesms.components.emoji.MediaKeyboard;
|
||||
import org.thoughtcrime.securesms.conversation.ConversationStickerSuggestionAdapter;
|
||||
import org.thoughtcrime.securesms.database.model.StickerRecord;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
@@ -124,7 +125,7 @@ public class InputPanel extends LinearLayout
|
||||
|
||||
this.recordLockCancel.setOnClickListener(v -> microphoneRecorderView.cancelAction());
|
||||
|
||||
if (TextSecurePreferences.isSystemEmojiPreferred(getContext())) {
|
||||
if (SignalStore.settings().isPreferSystemEmoji()) {
|
||||
mediaKeyboard.setVisibility(View.GONE);
|
||||
emojiVisible = false;
|
||||
} else {
|
||||
|
||||
@@ -13,6 +13,7 @@ import androidx.appcompat.widget.AppCompatEditText;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiProvider.EmojiDrawable;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
||||
|
||||
@@ -34,7 +35,7 @@ public class EmojiEditText extends AppCompatEditText {
|
||||
boolean forceCustom = a.getBoolean(R.styleable.EmojiTextView_emoji_forceCustom, false);
|
||||
a.recycle();
|
||||
|
||||
if (forceCustom || !TextSecurePreferences.isSystemEmojiPreferred(getContext())) {
|
||||
if (forceCustom || !SignalStore.settings().isPreferSystemEmoji()) {
|
||||
if (!isInEditMode()) {
|
||||
setFilters(appendEmojiFilter(this.getFilters()));
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.emoji.parsing.EmojiParser;
|
||||
import org.thoughtcrime.securesms.components.mention.MentionAnnotation;
|
||||
import org.thoughtcrime.securesms.components.mention.MentionRendererDelegate;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
@@ -215,7 +216,7 @@ public class EmojiTextView extends AppCompatTextView {
|
||||
}
|
||||
|
||||
private boolean useSystemEmoji() {
|
||||
return !forceCustom && TextSecurePreferences.isSystemEmojiPreferred(getContext());
|
||||
return !forceCustom && SignalStore.settings().isPreferSystemEmoji();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package org.thoughtcrime.securesms.components.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.Navigation
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActivity
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme
|
||||
|
||||
open class DSLSettingsActivity : PassphraseRequiredActivity() {
|
||||
|
||||
private val dynamicTheme = DynamicNoActionBarTheme()
|
||||
|
||||
protected lateinit var navController: NavController
|
||||
private set
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) {
|
||||
setContentView(R.layout.dsl_settings_activity)
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
val navGraphId = intent.getIntExtra(ARG_NAV_GRAPH, -1)
|
||||
if (navGraphId == -1) {
|
||||
throw IllegalStateException("No navgraph id was passed to activity")
|
||||
}
|
||||
|
||||
val fragment: NavHostFragment = NavHostFragment.create(navGraphId)
|
||||
|
||||
supportFragmentManager.beginTransaction()
|
||||
.replace(R.id.nav_host_fragment, fragment)
|
||||
.commitNow()
|
||||
|
||||
navController = fragment.navController
|
||||
} else {
|
||||
val fragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
|
||||
navController = fragment.navController
|
||||
}
|
||||
|
||||
dynamicTheme.onCreate(this)
|
||||
|
||||
onBackPressedDispatcher.addCallback(this, OnBackPressed())
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
dynamicTheme.onResume(this)
|
||||
}
|
||||
|
||||
override fun onNavigateUp(): Boolean {
|
||||
return if (!Navigation.findNavController(this, R.id.nav_host_fragment).popBackStack()) {
|
||||
onWillFinish()
|
||||
finish()
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun onWillFinish() {}
|
||||
|
||||
companion object {
|
||||
const val ARG_NAV_GRAPH = "nav_graph"
|
||||
}
|
||||
|
||||
private inner class OnBackPressed : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
onNavigateUp()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
package org.thoughtcrime.securesms.components.settings
|
||||
|
||||
import android.text.Spanned
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.text.style.ClickableSpan
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.switchmaterial.SwitchMaterial
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions
|
||||
import org.thoughtcrime.securesms.util.MappingAdapter
|
||||
import org.thoughtcrime.securesms.util.MappingViewHolder
|
||||
import org.thoughtcrime.securesms.util.ViewUtil
|
||||
|
||||
class DSLSettingsAdapter : MappingAdapter() {
|
||||
init {
|
||||
registerFactory(ClickPreference::class.java, LayoutFactory(::ClickPreferenceViewHolder, R.layout.dsl_preference_item))
|
||||
registerFactory(TextPreference::class.java, LayoutFactory(::TextPreferenceViewHolder, R.layout.dsl_preference_item))
|
||||
registerFactory(RadioListPreference::class.java, LayoutFactory(::RadioListPreferenceViewHolder, R.layout.dsl_preference_item))
|
||||
registerFactory(MultiSelectListPreference::class.java, LayoutFactory(::MultiSelectListPreferenceViewHolder, R.layout.dsl_preference_item))
|
||||
registerFactory(ExternalLinkPreference::class.java, LayoutFactory(::ExternalLinkPreferenceViewHolder, R.layout.dsl_preference_item))
|
||||
registerFactory(DividerPreference::class.java, LayoutFactory(::DividerPreferenceViewHolder, R.layout.dsl_divider_item))
|
||||
registerFactory(SectionHeaderPreference::class.java, LayoutFactory(::SectionHeaderPreferenceViewHolder, R.layout.dsl_section_header))
|
||||
registerFactory(SwitchPreference::class.java, LayoutFactory(::SwitchPreferenceViewHolder, R.layout.dsl_switch_preference_item))
|
||||
}
|
||||
}
|
||||
|
||||
abstract class PreferenceViewHolder<T : PreferenceModel<T>>(itemView: View) : MappingViewHolder<T>(itemView) {
|
||||
protected val iconView: ImageView = itemView.findViewById(R.id.icon)
|
||||
protected val titleView: TextView = itemView.findViewById(R.id.title)
|
||||
protected val summaryView: TextView = itemView.findViewById(R.id.summary)
|
||||
|
||||
@CallSuper
|
||||
override fun bind(model: T) {
|
||||
listOf(itemView, titleView, summaryView).forEach {
|
||||
it.isEnabled = model.isEnabled
|
||||
}
|
||||
|
||||
if (model.iconId != -1) {
|
||||
iconView.setImageResource(model.iconId)
|
||||
iconView.visibility = View.VISIBLE
|
||||
} else {
|
||||
iconView.setImageDrawable(null)
|
||||
iconView.visibility = View.GONE
|
||||
}
|
||||
|
||||
val title = model.title?.resolve(context)
|
||||
if (title != null) {
|
||||
titleView.text = model.title?.resolve(context)
|
||||
titleView.visibility = View.VISIBLE
|
||||
} else {
|
||||
titleView.visibility = View.GONE
|
||||
}
|
||||
|
||||
val summary = model.summary?.resolve(context)
|
||||
if (summary != null) {
|
||||
summaryView.text = summary
|
||||
summaryView.visibility = View.VISIBLE
|
||||
|
||||
val spans = (summaryView.text as? Spanned)?.getSpans(0, summaryView.text.length, ClickableSpan::class.java)
|
||||
if (spans?.isEmpty() == false) {
|
||||
summaryView.movementMethod = LinkMovementMethod.getInstance()
|
||||
} else {
|
||||
summaryView.movementMethod = null
|
||||
}
|
||||
} else {
|
||||
summaryView.visibility = View.GONE
|
||||
summaryView.movementMethod = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TextPreferenceViewHolder(itemView: View) : PreferenceViewHolder<TextPreference>(itemView)
|
||||
|
||||
class ClickPreferenceViewHolder(itemView: View) : PreferenceViewHolder<ClickPreference>(itemView) {
|
||||
override fun bind(model: ClickPreference) {
|
||||
super.bind(model)
|
||||
itemView.setOnClickListener { model.onClick() }
|
||||
}
|
||||
}
|
||||
|
||||
class RadioListPreferenceViewHolder(itemView: View) : PreferenceViewHolder<RadioListPreference>(itemView) {
|
||||
override fun bind(model: RadioListPreference) {
|
||||
super.bind(model)
|
||||
|
||||
summaryView.visibility = View.VISIBLE
|
||||
summaryView.text = model.listItems[model.selected]
|
||||
|
||||
itemView.setOnClickListener {
|
||||
MaterialAlertDialogBuilder(context)
|
||||
.setTitle(model.title.resolve(context))
|
||||
.setSingleChoiceItems(model.listItems, model.selected) { dialog, which ->
|
||||
model.onSelected(which)
|
||||
dialog.dismiss()
|
||||
}
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MultiSelectListPreferenceViewHolder(itemView: View) : PreferenceViewHolder<MultiSelectListPreference>(itemView) {
|
||||
override fun bind(model: MultiSelectListPreference) {
|
||||
super.bind(model)
|
||||
|
||||
summaryView.visibility = View.VISIBLE
|
||||
val summaryText = model.selected
|
||||
.mapIndexed { index, isChecked -> if (isChecked) model.listItems[index] else null }
|
||||
.filterNotNull()
|
||||
.joinToString(", ")
|
||||
|
||||
if (summaryText.isEmpty()) {
|
||||
summaryView.setText(R.string.preferences__none)
|
||||
} else {
|
||||
summaryView.text = summaryText
|
||||
}
|
||||
|
||||
val selected = model.selected.copyOf()
|
||||
|
||||
itemView.setOnClickListener {
|
||||
MaterialAlertDialogBuilder(context)
|
||||
.setTitle(model.title.resolve(context))
|
||||
.setMultiChoiceItems(model.listItems, selected) { _, _, _ ->
|
||||
// Intentionally empty
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel) { d, _ -> d.dismiss() }
|
||||
.setPositiveButton(android.R.string.ok) { d, _ ->
|
||||
model.onSelected(selected)
|
||||
d.dismiss()
|
||||
}
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SwitchPreferenceViewHolder(itemView: View) : PreferenceViewHolder<SwitchPreference>(itemView) {
|
||||
|
||||
private val switchWidget: SwitchMaterial = itemView.findViewById(R.id.switch_widget)
|
||||
|
||||
override fun bind(model: SwitchPreference) {
|
||||
super.bind(model)
|
||||
switchWidget.isEnabled = model.isEnabled
|
||||
switchWidget.isChecked = model.isChecked
|
||||
itemView.setOnClickListener {
|
||||
model.onClick()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ExternalLinkPreferenceViewHolder(itemView: View) : PreferenceViewHolder<ExternalLinkPreference>(itemView) {
|
||||
override fun bind(model: ExternalLinkPreference) {
|
||||
super.bind(model)
|
||||
|
||||
val externalLinkIcon = requireNotNull(ContextCompat.getDrawable(context, R.drawable.ic_open_20))
|
||||
externalLinkIcon.setBounds(0, 0, ViewUtil.dpToPx(20), ViewUtil.dpToPx(20))
|
||||
|
||||
if (itemView.layoutDirection == View.LAYOUT_DIRECTION_LTR) {
|
||||
titleView.setCompoundDrawables(null, null, externalLinkIcon, null)
|
||||
} else {
|
||||
titleView.setCompoundDrawables(externalLinkIcon, null, null, null)
|
||||
}
|
||||
|
||||
itemView.setOnClickListener { CommunicationActions.openBrowserLink(itemView.context, itemView.context.getString(model.linkId)) }
|
||||
}
|
||||
}
|
||||
|
||||
class DividerPreferenceViewHolder(itemView: View) : MappingViewHolder<DividerPreference>(itemView) {
|
||||
override fun bind(model: DividerPreference) = Unit
|
||||
}
|
||||
|
||||
class SectionHeaderPreferenceViewHolder(itemView: View) : MappingViewHolder<SectionHeaderPreference>(itemView) {
|
||||
|
||||
private val sectionHeader: TextView = itemView.findViewById(R.id.section_header)
|
||||
|
||||
override fun bind(model: SectionHeaderPreference) {
|
||||
sectionHeader.text = model.title.resolve(context)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package org.thoughtcrime.securesms.components.settings
|
||||
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.EdgeEffect
|
||||
import androidx.annotation.MenuRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.thoughtcrime.securesms.R
|
||||
|
||||
abstract class DSLSettingsFragment(
|
||||
@StringRes private val titleId: Int,
|
||||
@MenuRes private val menuId: Int = -1
|
||||
) : Fragment(R.layout.dsl_settings_fragment) {
|
||||
|
||||
private lateinit var recyclerView: RecyclerView
|
||||
private lateinit var toolbarShadowHelper: ToolbarShadowHelper
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
val toolbar: Toolbar = view.findViewById(R.id.toolbar)
|
||||
val toolbarShadow: View = view.findViewById(R.id.toolbar_shadow)
|
||||
|
||||
toolbar.setTitle(titleId)
|
||||
|
||||
toolbar.setNavigationOnClickListener {
|
||||
requireActivity().onBackPressed()
|
||||
}
|
||||
|
||||
if (menuId != -1) {
|
||||
toolbar.inflateMenu(menuId)
|
||||
toolbar.setOnMenuItemClickListener { onOptionsItemSelected(it) }
|
||||
}
|
||||
|
||||
recyclerView = view.findViewById(R.id.recycler)
|
||||
recyclerView.edgeEffectFactory = EdgeEffectFactory()
|
||||
toolbarShadowHelper = ToolbarShadowHelper(toolbarShadow)
|
||||
val adapter = DSLSettingsAdapter()
|
||||
|
||||
recyclerView.adapter = adapter
|
||||
recyclerView.addOnScrollListener(toolbarShadowHelper)
|
||||
|
||||
bindAdapter(adapter)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
toolbarShadowHelper.onScrolled(recyclerView, 0, 0)
|
||||
}
|
||||
|
||||
abstract fun bindAdapter(adapter: DSLSettingsAdapter)
|
||||
|
||||
private class EdgeEffectFactory : RecyclerView.EdgeEffectFactory() {
|
||||
override fun createEdgeEffect(view: RecyclerView, direction: Int): EdgeEffect {
|
||||
return super.createEdgeEffect(view, direction).apply {
|
||||
if (Build.VERSION.SDK_INT > 21) {
|
||||
color =
|
||||
requireNotNull(ContextCompat.getColor(view.context, R.color.settings_ripple_color))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ToolbarShadowHelper(private val toolbarShadow: View) : RecyclerView.OnScrollListener() {
|
||||
|
||||
private var lastAnimationState = ToolbarAnimationState.NONE
|
||||
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
val newAnimationState =
|
||||
if (recyclerView.canScrollVertically(-1)) ToolbarAnimationState.SHOW else ToolbarAnimationState.HIDE
|
||||
|
||||
if (newAnimationState == lastAnimationState) {
|
||||
return
|
||||
}
|
||||
|
||||
when (newAnimationState) {
|
||||
ToolbarAnimationState.NONE -> throw AssertionError()
|
||||
ToolbarAnimationState.HIDE -> toolbarShadow.animate().alpha(0f)
|
||||
ToolbarAnimationState.SHOW -> toolbarShadow.animate().alpha(1f)
|
||||
}
|
||||
|
||||
lastAnimationState = newAnimationState
|
||||
}
|
||||
}
|
||||
|
||||
private enum class ToolbarAnimationState {
|
||||
NONE,
|
||||
HIDE,
|
||||
SHOW
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.thoughtcrime.securesms.components.settings
|
||||
|
||||
import android.content.Context
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.StringRes
|
||||
import org.thoughtcrime.securesms.util.SpanUtil
|
||||
|
||||
sealed class DSLSettingsText {
|
||||
|
||||
private data class FromResource(
|
||||
@StringRes private val stringId: Int,
|
||||
@ColorInt private val textColor: Int?
|
||||
) : DSLSettingsText() {
|
||||
override fun resolve(context: Context): CharSequence {
|
||||
val text = context.getString(stringId)
|
||||
|
||||
return if (textColor == null) {
|
||||
text
|
||||
} else {
|
||||
SpanUtil.color(textColor, text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private data class FromCharSequence(private val charSequence: CharSequence) : DSLSettingsText() {
|
||||
override fun resolve(context: Context): CharSequence = charSequence
|
||||
}
|
||||
|
||||
abstract fun resolve(context: Context): CharSequence
|
||||
|
||||
companion object {
|
||||
fun from(@StringRes stringId: Int, @ColorInt textColor: Int? = null): DSLSettingsText =
|
||||
FromResource(stringId, textColor)
|
||||
|
||||
fun from(charSequence: CharSequence): DSLSettingsText = FromCharSequence(charSequence)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.navigation.NavDirections
|
||||
import org.thoughtcrime.securesms.MainActivity
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsActivity
|
||||
import org.thoughtcrime.securesms.help.HelpFragment
|
||||
import org.thoughtcrime.securesms.keyvalue.SettingsValues
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService
|
||||
import org.thoughtcrime.securesms.util.CachedInflater
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme
|
||||
|
||||
private const val START_LOCATION = "app.settings.start.location"
|
||||
private const val NOTIFICATION_CATEGORY = "android.intent.category.NOTIFICATION_PREFERENCES"
|
||||
private const val STATE_WAS_CONFIGURATION_UPDATED = "app.settings.state.configuration.updated"
|
||||
|
||||
class AppSettingsActivity : DSLSettingsActivity() {
|
||||
|
||||
private var wasConfigurationUpdated = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) {
|
||||
if (intent?.hasExtra(ARG_NAV_GRAPH) != true) {
|
||||
intent?.putExtra(ARG_NAV_GRAPH, R.navigation.app_settings)
|
||||
}
|
||||
|
||||
super.onCreate(savedInstanceState, ready)
|
||||
|
||||
val startingAction: NavDirections? = if (intent?.categories?.contains(NOTIFICATION_CATEGORY) == true) {
|
||||
AppSettingsFragmentDirections.actionDirectToNotificationsSettingsFragment()
|
||||
} else {
|
||||
when (StartLocation.fromCode(intent?.getIntExtra(START_LOCATION, StartLocation.HOME.code))) {
|
||||
StartLocation.HOME -> null
|
||||
StartLocation.BACKUPS -> AppSettingsFragmentDirections.actionDirectToBackupsPreferenceFragment()
|
||||
StartLocation.HELP -> AppSettingsFragmentDirections.actionDirectToHelpFragment()
|
||||
.setStartCategoryIndex(intent.getIntExtra(HelpFragment.START_CATEGORY_INDEX, 0))
|
||||
StartLocation.PROXY -> AppSettingsFragmentDirections.actionDirectToEditProxyFragment()
|
||||
StartLocation.NOTIFICATIONS -> AppSettingsFragmentDirections.actionDirectToNotificationsSettingsFragment()
|
||||
}
|
||||
}
|
||||
|
||||
if (startingAction == null && savedInstanceState != null) {
|
||||
wasConfigurationUpdated = savedInstanceState.getBoolean(STATE_WAS_CONFIGURATION_UPDATED)
|
||||
}
|
||||
|
||||
startingAction?.let {
|
||||
navController.navigate(it)
|
||||
}
|
||||
|
||||
SignalStore.settings().onConfigurationSettingChanged.observe(this) { key ->
|
||||
if (key == SettingsValues.THEME) {
|
||||
DynamicTheme.setDefaultDayNightMode(this)
|
||||
recreate()
|
||||
} else if (key == SettingsValues.LANGUAGE) {
|
||||
CachedInflater.from(this).clear()
|
||||
wasConfigurationUpdated = true
|
||||
recreate()
|
||||
val intent = Intent(this, KeyCachingService::class.java)
|
||||
intent.action = KeyCachingService.LOCALE_CHANGE_EVENT
|
||||
startService(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
outState.putBoolean(STATE_WAS_CONFIGURATION_UPDATED, wasConfigurationUpdated)
|
||||
}
|
||||
|
||||
override fun onWillFinish() {
|
||||
if (wasConfigurationUpdated) {
|
||||
setResult(MainActivity.RESULT_CONFIG_CHANGED)
|
||||
} else {
|
||||
setResult(RESULT_OK)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
fun home(context: Context): Intent = getIntentForStartLocation(context, StartLocation.HOME)
|
||||
|
||||
@JvmStatic
|
||||
fun backups(context: Context): Intent = getIntentForStartLocation(context, StartLocation.BACKUPS)
|
||||
|
||||
@JvmStatic
|
||||
fun help(context: Context, startCategoryIndex: Int = 0): Intent {
|
||||
return getIntentForStartLocation(context, StartLocation.HOME)
|
||||
.putExtra(HelpFragment.START_CATEGORY_INDEX, startCategoryIndex)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun proxy(context: Context): Intent = getIntentForStartLocation(context, StartLocation.HELP)
|
||||
|
||||
@JvmStatic
|
||||
fun notifications(context: Context): Intent = getIntentForStartLocation(context, StartLocation.NOTIFICATIONS)
|
||||
|
||||
private fun getIntentForStartLocation(context: Context, startLocation: StartLocation): Intent {
|
||||
return Intent(context, AppSettingsActivity::class.java)
|
||||
.putExtra(ARG_NAV_GRAPH, R.navigation.app_settings)
|
||||
.putExtra(START_LOCATION, startLocation.code)
|
||||
}
|
||||
}
|
||||
|
||||
private enum class StartLocation(val code: Int) {
|
||||
HOME(0),
|
||||
BACKUPS(1),
|
||||
HELP(2),
|
||||
PROXY(3),
|
||||
NOTIFICATIONS(4);
|
||||
|
||||
companion object {
|
||||
fun fromCode(code: Int?): StartLocation {
|
||||
return values().find { code == it.code } ?: HOME
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app
|
||||
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import androidx.navigation.Navigation
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.AvatarImageView
|
||||
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
|
||||
import org.thoughtcrime.securesms.components.settings.PreferenceModel
|
||||
import org.thoughtcrime.securesms.components.settings.PreferenceViewHolder
|
||||
import org.thoughtcrime.securesms.components.settings.configure
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.mms.GlideApp
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags
|
||||
import org.thoughtcrime.securesms.util.MappingAdapter
|
||||
import org.thoughtcrime.securesms.util.MappingViewHolder
|
||||
|
||||
class AppSettingsFragment : DSLSettingsFragment(R.string.text_secure_normal__menu_settings) {
|
||||
|
||||
override fun bindAdapter(adapter: DSLSettingsAdapter) {
|
||||
adapter.registerFactory(BioPreference::class.java, MappingAdapter.LayoutFactory(::BioPreferenceViewHolder, R.layout.bio_preference_item))
|
||||
adapter.registerFactory(PaymentsPreference::class.java, MappingAdapter.LayoutFactory(::PaymentsPreferenceViewHolder, R.layout.dsl_payments_preference))
|
||||
|
||||
val viewModel = ViewModelProviders.of(this)[AppSettingsViewModel::class.java]
|
||||
|
||||
viewModel.state.observe(viewLifecycleOwner) { state ->
|
||||
adapter.submitList(getConfiguration(state).toMappingModelList())
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConfiguration(state: AppSettingsState): DSLConfiguration {
|
||||
return configure {
|
||||
|
||||
customPref(
|
||||
BioPreference(state.self) {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.action_appSettingsFragment_to_manageProfileActivity)
|
||||
}
|
||||
)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.AccountSettingsFragment__account),
|
||||
iconId = R.drawable.ic_profile_circle_24,
|
||||
onClick = {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.action_appSettingsFragment_to_accountSettingsFragment)
|
||||
}
|
||||
)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__linked_devices),
|
||||
iconId = R.drawable.ic_linked_devices_24,
|
||||
onClick = {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.action_appSettingsFragment_to_deviceActivity)
|
||||
}
|
||||
)
|
||||
|
||||
if (SignalStore.paymentsValues().paymentsAvailability.showPaymentsMenu()) {
|
||||
customPref(
|
||||
PaymentsPreference(
|
||||
unreadCount = state.unreadPaymentsCount
|
||||
) {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.action_appSettingsFragment_to_paymentsActivity)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
dividerPref()
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__appearance),
|
||||
iconId = R.drawable.ic_appearance_24,
|
||||
onClick = {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.action_appSettingsFragment_to_appearanceSettingsFragment)
|
||||
}
|
||||
)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_chats__chats),
|
||||
iconId = R.drawable.ic_message_tinted_bitmap_24,
|
||||
onClick = {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.action_appSettingsFragment_to_chatsSettingsFragment)
|
||||
}
|
||||
)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__notifications),
|
||||
iconId = R.drawable.ic_bell_24,
|
||||
onClick = {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.action_appSettingsFragment_to_notificationsSettingsFragment)
|
||||
}
|
||||
)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__privacy),
|
||||
iconId = R.drawable.ic_lock_24,
|
||||
onClick = {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.action_appSettingsFragment_to_privacySettingsFragment)
|
||||
}
|
||||
)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__data_and_storage),
|
||||
iconId = R.drawable.ic_archive_24dp,
|
||||
onClick = {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.action_appSettingsFragment_to_dataAndStorageSettingsFragment)
|
||||
}
|
||||
)
|
||||
|
||||
dividerPref()
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__help),
|
||||
iconId = R.drawable.ic_help_24,
|
||||
onClick = {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.action_appSettingsFragment_to_helpSettingsFragment)
|
||||
}
|
||||
)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.AppSettingsFragment__invite_your_friends),
|
||||
iconId = R.drawable.ic_invite_24,
|
||||
onClick = {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.action_appSettingsFragment_to_inviteActivity)
|
||||
}
|
||||
)
|
||||
|
||||
externalLinkPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__donate_to_signal),
|
||||
iconId = R.drawable.ic_heart_24,
|
||||
linkId = R.string.donate_url
|
||||
)
|
||||
|
||||
if (FeatureFlags.internalUser()) {
|
||||
dividerPref()
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__internal_preferences),
|
||||
onClick = {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.action_appSettingsFragment_to_internalSettingsFragment)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class BioPreference(val recipient: Recipient, val onClick: () -> Unit) : PreferenceModel<BioPreference>() {
|
||||
override fun areContentsTheSame(newItem: BioPreference): Boolean {
|
||||
return super.areContentsTheSame(newItem) && recipient.hasSameContent(newItem.recipient)
|
||||
}
|
||||
|
||||
override fun areItemsTheSame(newItem: BioPreference): Boolean {
|
||||
return recipient == newItem.recipient
|
||||
}
|
||||
}
|
||||
|
||||
private class BioPreferenceViewHolder(itemView: View) : PreferenceViewHolder<BioPreference>(itemView) {
|
||||
|
||||
private val avatarView: AvatarImageView = itemView.findViewById(R.id.icon)
|
||||
|
||||
override fun bind(model: BioPreference) {
|
||||
super.bind(model)
|
||||
|
||||
itemView.setOnClickListener { model.onClick() }
|
||||
|
||||
titleView.text = model.recipient.getDisplayName(itemView.context)
|
||||
summaryView.text = model.recipient.requireE164()
|
||||
avatarView.setAvatar(GlideApp.with(itemView), model.recipient, false, true)
|
||||
|
||||
titleView.visibility = View.VISIBLE
|
||||
summaryView.visibility = View.VISIBLE
|
||||
avatarView.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
private class PaymentsPreference(val unreadCount: Int, val onClick: () -> Unit) : PreferenceModel<PaymentsPreference>() {
|
||||
override fun areContentsTheSame(newItem: PaymentsPreference): Boolean {
|
||||
return super.areContentsTheSame(newItem) && unreadCount == newItem.unreadCount
|
||||
}
|
||||
}
|
||||
|
||||
private class PaymentsPreferenceViewHolder(itemView: View) : MappingViewHolder<PaymentsPreference>(itemView) {
|
||||
|
||||
private val unreadCountView: TextView = itemView.findViewById(R.id.unread_indicator)
|
||||
|
||||
override fun bind(model: PaymentsPreference) {
|
||||
unreadCountView.text = model.unreadCount.toString()
|
||||
unreadCountView.visibility = if (model.unreadCount > 0) View.VISIBLE else View.GONE
|
||||
|
||||
itemView.setOnClickListener {
|
||||
model.onClick()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app
|
||||
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
|
||||
data class AppSettingsState(val self: Recipient, val unreadPaymentsCount: Int)
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import org.thoughtcrime.securesms.conversationlist.model.UnreadPaymentsLiveData
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil
|
||||
|
||||
class AppSettingsViewModel : ViewModel() {
|
||||
|
||||
val unreadPaymentsLiveData = UnreadPaymentsLiveData()
|
||||
val selfLiveData: LiveData<Recipient> = Recipient.self().live().liveData
|
||||
|
||||
val state: LiveData<AppSettingsState> = LiveDataUtil.combineLatest(unreadPaymentsLiveData, selfLiveData) { payments, self ->
|
||||
val unreadPaymentsCount = payments.transform { it.unreadCount }.or(0)
|
||||
|
||||
AppSettingsState(self, unreadPaymentsCount)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.account
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.graphics.Typeface
|
||||
import android.text.InputType
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.ViewGroup
|
||||
import android.widget.EditText
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.autofill.HintConstants
|
||||
import androidx.core.app.DialogCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import androidx.navigation.Navigation
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
|
||||
import org.thoughtcrime.securesms.components.settings.configure
|
||||
import org.thoughtcrime.securesms.contactshare.SimpleTextWatcher
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.lock.PinHashing
|
||||
import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity
|
||||
import org.thoughtcrime.securesms.lock.v2.KbsConstants
|
||||
import org.thoughtcrime.securesms.lock.v2.PinKeyboardType
|
||||
import org.thoughtcrime.securesms.pin.RegistrationLockV2Dialog
|
||||
import org.thoughtcrime.securesms.util.ServiceUtil
|
||||
import org.thoughtcrime.securesms.util.ThemeUtil
|
||||
|
||||
class AccountSettingsFragment : DSLSettingsFragment(R.string.AccountSettingsFragment__account) {
|
||||
|
||||
lateinit var viewModel: AccountSettingsViewModel
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (requestCode == CreateKbsPinActivity.REQUEST_NEW_PIN && resultCode == CreateKbsPinActivity.RESULT_OK) {
|
||||
Snackbar.make(requireView(), R.string.ConfirmKbsPinFragment__pin_created, Snackbar.LENGTH_LONG).setTextColor(Color.WHITE).show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun bindAdapter(adapter: DSLSettingsAdapter) {
|
||||
viewModel = ViewModelProviders.of(this)[AccountSettingsViewModel::class.java]
|
||||
|
||||
viewModel.state.observe(viewLifecycleOwner) { state ->
|
||||
adapter.submitList(getConfiguration(state).toMappingModelList())
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConfiguration(state: AccountSettingsState): DSLConfiguration {
|
||||
return configure {
|
||||
|
||||
sectionHeaderPref(R.string.preferences_app_protection__signal_pin)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(if (state.hasPin) R.string.preferences_app_protection__change_your_pin else R.string.preferences_app_protection__create_a_pin),
|
||||
onClick = {
|
||||
if (state.hasPin) {
|
||||
startActivityForResult(CreateKbsPinActivity.getIntentForPinChangeFromSettings(requireContext()), CreateKbsPinActivity.REQUEST_NEW_PIN)
|
||||
} else {
|
||||
startActivityForResult(CreateKbsPinActivity.getIntentForPinCreate(requireContext()), CreateKbsPinActivity.REQUEST_NEW_PIN)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_app_protection__pin_reminders),
|
||||
summary = DSLSettingsText.from(R.string.AccountSettingsFragment__youll_be_asked_less_frequently),
|
||||
isChecked = state.pinRemindersEnabled,
|
||||
onClick = {
|
||||
setPinRemindersEnabled(!state.pinRemindersEnabled)
|
||||
}
|
||||
)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_app_protection__registration_lock),
|
||||
summary = DSLSettingsText.from(R.string.AccountSettingsFragment__require_your_signal_pin),
|
||||
isChecked = state.registrationLockEnabled,
|
||||
onClick = {
|
||||
setRegistrationLockEnabled(!state.registrationLockEnabled)
|
||||
}
|
||||
)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__advanced_pin_settings),
|
||||
onClick = {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.action_accountSettingsFragment_to_advancedPinSettingsActivity)
|
||||
}
|
||||
)
|
||||
|
||||
dividerPref()
|
||||
|
||||
sectionHeaderPref(R.string.AccountSettingsFragment__account)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_chats__transfer_account),
|
||||
summary = DSLSettingsText.from(R.string.preferences_chats__transfer_account_to_a_new_android_device),
|
||||
onClick = {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.action_accountSettingsFragment_to_oldDeviceTransferActivity)
|
||||
}
|
||||
)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__delete_account, ContextCompat.getColor(requireContext(), R.color.signal_alert_primary)),
|
||||
onClick = {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.action_accountSettingsFragment_to_deleteAccountFragment)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setRegistrationLockEnabled(enabled: Boolean) {
|
||||
if (enabled) {
|
||||
RegistrationLockV2Dialog.showEnableDialog(requireContext()) { viewModel.refreshState() }
|
||||
} else {
|
||||
RegistrationLockV2Dialog.showDisableDialog(requireContext()) { viewModel.refreshState() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun setPinRemindersEnabled(enabled: Boolean) {
|
||||
if (!enabled) {
|
||||
val context: Context = requireContext()
|
||||
val metrics: DisplayMetrics = resources.displayMetrics
|
||||
|
||||
val dialog: AlertDialog = MaterialAlertDialogBuilder(context, if (ThemeUtil.isDarkTheme(context)) R.style.Theme_Signal_AlertDialog_Dark_Cornered_ColoredAccent else R.style.Theme_Signal_AlertDialog_Light_Cornered_ColoredAccent)
|
||||
.setView(R.layout.pin_disable_reminders_dialog)
|
||||
.create()
|
||||
|
||||
dialog.show()
|
||||
dialog.window!!.setLayout((metrics.widthPixels * .80).toInt(), ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
|
||||
val pinEditText = DialogCompat.requireViewById(dialog, R.id.reminder_disable_pin) as EditText
|
||||
val statusText = DialogCompat.requireViewById(dialog, R.id.reminder_disable_status) as TextView
|
||||
val cancelButton = DialogCompat.requireViewById(dialog, R.id.reminder_disable_cancel)
|
||||
val turnOffButton = DialogCompat.requireViewById(dialog, R.id.reminder_disable_turn_off)
|
||||
|
||||
pinEditText.post {
|
||||
if (pinEditText.requestFocus()) {
|
||||
ServiceUtil.getInputMethodManager(pinEditText.context).showSoftInput(pinEditText, 0)
|
||||
}
|
||||
}
|
||||
|
||||
ViewCompat.setAutofillHints(pinEditText, HintConstants.AUTOFILL_HINT_PASSWORD)
|
||||
|
||||
when (SignalStore.pinValues().keyboardType) {
|
||||
PinKeyboardType.NUMERIC -> pinEditText.inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_PASSWORD
|
||||
PinKeyboardType.ALPHA_NUMERIC -> pinEditText.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
|
||||
}
|
||||
|
||||
pinEditText.addTextChangedListener(object : SimpleTextWatcher() {
|
||||
override fun onTextChanged(text: String) {
|
||||
turnOffButton.isEnabled = text.length >= KbsConstants.MINIMUM_PIN_LENGTH
|
||||
}
|
||||
})
|
||||
|
||||
pinEditText.typeface = Typeface.DEFAULT
|
||||
turnOffButton.setOnClickListener {
|
||||
val pin = pinEditText.text.toString()
|
||||
val correct = PinHashing.verifyLocalPinHash(SignalStore.kbsValues().localPinHash!!, pin)
|
||||
if (correct) {
|
||||
SignalStore.pinValues().setPinRemindersEnabled(false)
|
||||
viewModel.refreshState()
|
||||
dialog.dismiss()
|
||||
} else {
|
||||
statusText.setText(R.string.preferences_app_protection__incorrect_pin_try_again)
|
||||
}
|
||||
}
|
||||
|
||||
cancelButton.setOnClickListener { dialog.dismiss() }
|
||||
} else {
|
||||
SignalStore.pinValues().setPinRemindersEnabled(true)
|
||||
viewModel.refreshState()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.account
|
||||
|
||||
data class AccountSettingsState(
|
||||
val hasPin: Boolean,
|
||||
val pinRemindersEnabled: Boolean,
|
||||
val registrationLockEnabled: Boolean
|
||||
)
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.account
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.util.livedata.Store
|
||||
|
||||
class AccountSettingsViewModel : ViewModel() {
|
||||
private val store: Store<AccountSettingsState> = Store(getCurrentState())
|
||||
|
||||
val state: LiveData<AccountSettingsState> = store.stateLiveData
|
||||
|
||||
fun refreshState() {
|
||||
store.update { getCurrentState() }
|
||||
}
|
||||
|
||||
private fun getCurrentState(): AccountSettingsState {
|
||||
return AccountSettingsState(
|
||||
hasPin = SignalStore.kbsValues().hasPin() && !SignalStore.kbsValues().hasOptedOut(),
|
||||
pinRemindersEnabled = SignalStore.pinValues().arePinRemindersEnabled(),
|
||||
registrationLockEnabled = SignalStore.kbsValues().isV2RegistrationLockEnabled
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.appearance
|
||||
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import androidx.navigation.Navigation
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
|
||||
import org.thoughtcrime.securesms.components.settings.configure
|
||||
|
||||
class AppearanceSettingsFragment : DSLSettingsFragment(R.string.preferences__appearance) {
|
||||
|
||||
private lateinit var viewModel: AppearanceSettingsViewModel
|
||||
|
||||
private val themeLabels by lazy { resources.getStringArray(R.array.pref_theme_entries) }
|
||||
private val themeValues by lazy { resources.getStringArray(R.array.pref_theme_values) }
|
||||
|
||||
private val messageFontSizeLabels by lazy { resources.getStringArray(R.array.pref_message_font_size_entries) }
|
||||
private val messageFontSizeValues by lazy { resources.getStringArray(R.array.pref_message_font_size_values) }
|
||||
|
||||
private val languageLabels by lazy { resources.getStringArray(R.array.language_entries) }
|
||||
private val languageValues by lazy { resources.getStringArray(R.array.language_values) }
|
||||
|
||||
override fun bindAdapter(adapter: DSLSettingsAdapter) {
|
||||
viewModel = ViewModelProviders.of(this)[AppearanceSettingsViewModel::class.java]
|
||||
|
||||
viewModel.state.observe(viewLifecycleOwner) { state ->
|
||||
adapter.submitList(getConfiguration(state).toMappingModelList())
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConfiguration(state: AppearanceSettingsState): DSLConfiguration {
|
||||
return configure {
|
||||
radioListPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__theme),
|
||||
listItems = themeLabels,
|
||||
selected = themeValues.indexOf(state.theme),
|
||||
onSelected = {
|
||||
viewModel.setTheme(themeValues[it])
|
||||
}
|
||||
)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__chat_wallpaper),
|
||||
onClick = {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.action_appearanceSettings_to_wallpaperActivity)
|
||||
}
|
||||
)
|
||||
|
||||
radioListPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_chats__message_text_size),
|
||||
listItems = messageFontSizeLabels,
|
||||
selected = messageFontSizeValues.indexOf(state.messageFontSize.toString()),
|
||||
onSelected = {
|
||||
viewModel.setMessageFontSize(messageFontSizeValues[it].toInt())
|
||||
}
|
||||
)
|
||||
|
||||
radioListPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__language),
|
||||
listItems = languageLabels,
|
||||
selected = languageValues.indexOf(state.language),
|
||||
onSelected = {
|
||||
viewModel.setLanguage(languageValues[it])
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.appearance
|
||||
|
||||
data class AppearanceSettingsState(
|
||||
val theme: String,
|
||||
val messageFontSize: Int,
|
||||
val language: String
|
||||
)
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.appearance
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.util.livedata.Store
|
||||
|
||||
class AppearanceSettingsViewModel : ViewModel() {
|
||||
private val store: Store<AppearanceSettingsState>
|
||||
|
||||
init {
|
||||
val initialState = AppearanceSettingsState(
|
||||
SignalStore.settings().theme,
|
||||
SignalStore.settings().messageFontSize,
|
||||
SignalStore.settings().language
|
||||
)
|
||||
|
||||
store = Store(initialState)
|
||||
}
|
||||
|
||||
val state: LiveData<AppearanceSettingsState> = store.stateLiveData
|
||||
|
||||
fun setTheme(theme: String) {
|
||||
store.update { it.copy(theme = theme) }
|
||||
SignalStore.settings().theme = theme
|
||||
}
|
||||
|
||||
fun setLanguage(language: String) {
|
||||
store.update { it.copy(language = language) }
|
||||
SignalStore.settings().language = language
|
||||
}
|
||||
|
||||
fun setMessageFontSize(size: Int) {
|
||||
store.update { it.copy(messageFontSize = size) }
|
||||
SignalStore.settings().messageFontSize = size
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.chats
|
||||
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import androidx.navigation.Navigation
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
|
||||
import org.thoughtcrime.securesms.components.settings.configure
|
||||
|
||||
class ChatsSettingsFragment : DSLSettingsFragment(R.string.preferences_chats__chats) {
|
||||
|
||||
private lateinit var viewModel: ChatsSettingsViewModel
|
||||
|
||||
override fun bindAdapter(adapter: DSLSettingsAdapter) {
|
||||
val repository = ChatsSettingsRepository()
|
||||
val factory = ChatsSettingsViewModel.Factory(repository)
|
||||
viewModel = ViewModelProviders.of(this, factory)[ChatsSettingsViewModel::class.java]
|
||||
|
||||
viewModel.state.observe(viewLifecycleOwner) {
|
||||
adapter.submitList(getConfiguration(it).toMappingModelList())
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConfiguration(state: ChatsSettingsState): DSLConfiguration {
|
||||
return configure {
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__sms_mms),
|
||||
onClick = {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.action_chatsSettingsFragment_to_smsSettingsFragment)
|
||||
}
|
||||
)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__generate_link_previews),
|
||||
summary = DSLSettingsText.from(R.string.preferences__retrieve_link_previews_from_websites_for_messages),
|
||||
isChecked = state.generateLinkPreviews,
|
||||
onClick = {
|
||||
viewModel.setGenerateLinkPreviewsEnabled(!state.generateLinkPreviews)
|
||||
}
|
||||
)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__pref_use_address_book_photos),
|
||||
summary = DSLSettingsText.from(R.string.preferences__display_contact_photos_from_your_address_book_if_available),
|
||||
isChecked = state.useAddressBook,
|
||||
onClick = {
|
||||
viewModel.setUseAddressBook(!state.useAddressBook)
|
||||
}
|
||||
)
|
||||
|
||||
dividerPref()
|
||||
|
||||
sectionHeaderPref(R.string.ChatsSettingsFragment__keyboard)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_advanced__use_system_emoji),
|
||||
isChecked = state.useSystemEmoji,
|
||||
onClick = {
|
||||
viewModel.setUseSystemEmoji(!state.useSystemEmoji)
|
||||
}
|
||||
)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.ChatsSettingsFragment__enter_key_sends),
|
||||
isChecked = state.enterKeySends,
|
||||
onClick = {
|
||||
viewModel.setEnterKeySends(!state.enterKeySends)
|
||||
}
|
||||
)
|
||||
|
||||
dividerPref()
|
||||
|
||||
sectionHeaderPref(R.string.preferences_chats__backups)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_chats__chat_backups),
|
||||
summary = DSLSettingsText.from(if (state.chatBackupsEnabled) R.string.arrays__enabled else R.string.arrays__disabled),
|
||||
onClick = {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.action_chatsSettingsFragment_to_backupsPreferenceFragment)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.chats
|
||||
|
||||
import android.content.Context
|
||||
import org.signal.core.util.concurrent.SignalExecutors
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceConfigurationUpdateJob
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.megaphone.Megaphones
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
|
||||
class ChatsSettingsRepository {
|
||||
|
||||
private val context: Context = ApplicationDependencies.getApplication()
|
||||
|
||||
fun syncLinkPreviewsState() {
|
||||
SignalExecutors.BOUNDED.execute {
|
||||
val isLinkPreviewsEnabled = SignalStore.settings().isLinkPreviewsEnabled
|
||||
|
||||
DatabaseFactory.getRecipientDatabase(context).markNeedsSync(Recipient.self().id)
|
||||
StorageSyncHelper.scheduleSyncForDataChange()
|
||||
ApplicationDependencies.getJobManager().add(
|
||||
MultiDeviceConfigurationUpdateJob(
|
||||
TextSecurePreferences.isReadReceiptsEnabled(context),
|
||||
TextSecurePreferences.isTypingIndicatorsEnabled(context),
|
||||
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(context),
|
||||
isLinkPreviewsEnabled
|
||||
)
|
||||
)
|
||||
if (isLinkPreviewsEnabled) {
|
||||
ApplicationDependencies.getMegaphoneRepository().markFinished(Megaphones.Event.LINK_PREVIEWS)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.chats
|
||||
|
||||
data class ChatsSettingsState(
|
||||
val generateLinkPreviews: Boolean,
|
||||
val useAddressBook: Boolean,
|
||||
val useSystemEmoji: Boolean,
|
||||
val enterKeySends: Boolean,
|
||||
val chatBackupsEnabled: Boolean
|
||||
)
|
||||
@@ -0,0 +1,56 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.chats
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper
|
||||
import org.thoughtcrime.securesms.util.ConversationUtil
|
||||
import org.thoughtcrime.securesms.util.ThrottledDebouncer
|
||||
import org.thoughtcrime.securesms.util.livedata.Store
|
||||
|
||||
class ChatsSettingsViewModel(private val repository: ChatsSettingsRepository) : ViewModel() {
|
||||
|
||||
private val refreshDebouncer = ThrottledDebouncer(500L)
|
||||
|
||||
private val store: Store<ChatsSettingsState> = Store(
|
||||
ChatsSettingsState(
|
||||
generateLinkPreviews = SignalStore.settings().isLinkPreviewsEnabled,
|
||||
useAddressBook = SignalStore.settings().isPreferSystemContactPhotos,
|
||||
useSystemEmoji = SignalStore.settings().isPreferSystemEmoji,
|
||||
enterKeySends = SignalStore.settings().isEnterKeySends,
|
||||
chatBackupsEnabled = SignalStore.settings().isBackupEnabled
|
||||
)
|
||||
)
|
||||
|
||||
val state: LiveData<ChatsSettingsState> = store.stateLiveData
|
||||
|
||||
fun setGenerateLinkPreviewsEnabled(enabled: Boolean) {
|
||||
store.update { it.copy(generateLinkPreviews = enabled) }
|
||||
SignalStore.settings().isLinkPreviewsEnabled = enabled
|
||||
repository.syncLinkPreviewsState()
|
||||
}
|
||||
|
||||
fun setUseAddressBook(enabled: Boolean) {
|
||||
store.update { it.copy(useAddressBook = enabled) }
|
||||
SignalStore.settings().isPreferSystemContactPhotos = enabled
|
||||
refreshDebouncer.publish { ConversationUtil.refreshRecipientShortcuts() }
|
||||
StorageSyncHelper.scheduleSyncForDataChange()
|
||||
}
|
||||
|
||||
fun setUseSystemEmoji(enabled: Boolean) {
|
||||
store.update { it.copy(useSystemEmoji = enabled) }
|
||||
SignalStore.settings().isPreferSystemEmoji = enabled
|
||||
}
|
||||
|
||||
fun setEnterKeySends(enabled: Boolean) {
|
||||
store.update { it.copy(enterKeySends = enabled) }
|
||||
SignalStore.settings().isEnterKeySends = enabled
|
||||
}
|
||||
|
||||
class Factory(private val repository: ChatsSettingsRepository) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
|
||||
return requireNotNull(modelClass.cast(ChatsSettingsViewModel(repository)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.chats.sms
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import androidx.navigation.Navigation
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
|
||||
import org.thoughtcrime.securesms.components.settings.configure
|
||||
import org.thoughtcrime.securesms.util.SmsUtil
|
||||
|
||||
private const val SMS_REQUEST_CODE: Short = 1234
|
||||
|
||||
class SmsSettingsFragment : DSLSettingsFragment(R.string.preferences__sms_mms) {
|
||||
|
||||
private lateinit var viewModel: SmsSettingsViewModel
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
viewModel.checkSmsEnabled()
|
||||
}
|
||||
|
||||
override fun bindAdapter(adapter: DSLSettingsAdapter) {
|
||||
viewModel = ViewModelProviders.of(this)[SmsSettingsViewModel::class.java]
|
||||
|
||||
viewModel.state.observe(viewLifecycleOwner) {
|
||||
adapter.submitList(getConfiguration(it).toMappingModelList())
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConfiguration(state: SmsSettingsState): DSLConfiguration {
|
||||
return configure {
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.SmsSettingsFragment__use_as_default_sms_app),
|
||||
summary = DSLSettingsText.from(if (state.useAsDefaultSmsApp) R.string.arrays__enabled else R.string.arrays__disabled),
|
||||
onClick = {
|
||||
if (state.useAsDefaultSmsApp) {
|
||||
startDefaultAppSelectionIntent()
|
||||
} else {
|
||||
startActivityForResult(SmsUtil.getSmsRoleIntent(requireContext()), SMS_REQUEST_CODE.toInt())
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__sms_delivery_reports),
|
||||
summary = DSLSettingsText.from(R.string.preferences__request_a_delivery_report_for_each_sms_message_you_send),
|
||||
isChecked = state.smsDeliveryReportsEnabled,
|
||||
onClick = {
|
||||
viewModel.setSmsDeliveryReportsEnabled(!state.smsDeliveryReportsEnabled)
|
||||
}
|
||||
)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__support_wifi_calling),
|
||||
summary = DSLSettingsText.from(R.string.preferences__enable_if_your_device_supports_sms_mms_delivery_over_wifi),
|
||||
isChecked = state.wifiCallingCompatibilityEnabled,
|
||||
onClick = {
|
||||
viewModel.setWifiCallingCompatibilityEnabled(!state.wifiCallingCompatibilityEnabled)
|
||||
}
|
||||
)
|
||||
|
||||
if (Build.VERSION.SDK_INT < 21) {
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__advanced_mms_access_point_names),
|
||||
onClick = {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.action_smsSettingsFragment_to_mmsPreferencesFragment)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Linter isn't smart enough to figure out the else only happens if API >= 24
|
||||
@SuppressLint("InlinedApi")
|
||||
private fun startDefaultAppSelectionIntent() {
|
||||
startActivity(
|
||||
when {
|
||||
Build.VERSION.SDK_INT < 23 -> Intent(Settings.ACTION_WIRELESS_SETTINGS)
|
||||
Build.VERSION.SDK_INT < 24 -> Intent(Settings.ACTION_SETTINGS)
|
||||
else -> Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.chats.sms
|
||||
|
||||
data class SmsSettingsState(
|
||||
val useAsDefaultSmsApp: Boolean,
|
||||
val smsDeliveryReportsEnabled: Boolean,
|
||||
val wifiCallingCompatibilityEnabled: Boolean
|
||||
)
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.chats.sms
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.util.Util
|
||||
import org.thoughtcrime.securesms.util.livedata.Store
|
||||
|
||||
class SmsSettingsViewModel : ViewModel() {
|
||||
|
||||
private val store = Store(
|
||||
SmsSettingsState(
|
||||
useAsDefaultSmsApp = Util.isDefaultSmsProvider(ApplicationDependencies.getApplication()),
|
||||
smsDeliveryReportsEnabled = SignalStore.settings().isSmsDeliveryReportsEnabled,
|
||||
wifiCallingCompatibilityEnabled = SignalStore.settings().isWifiCallingCompatibilityModeEnabled
|
||||
)
|
||||
)
|
||||
|
||||
val state: LiveData<SmsSettingsState> = store.stateLiveData
|
||||
|
||||
fun setSmsDeliveryReportsEnabled(enabled: Boolean) {
|
||||
store.update { it.copy(smsDeliveryReportsEnabled = enabled) }
|
||||
SignalStore.settings().isSmsDeliveryReportsEnabled = enabled
|
||||
}
|
||||
|
||||
fun setWifiCallingCompatibilityEnabled(enabled: Boolean) {
|
||||
store.update { it.copy(wifiCallingCompatibilityEnabled = enabled) }
|
||||
SignalStore.settings().isWifiCallingCompatibilityModeEnabled = enabled
|
||||
}
|
||||
|
||||
fun checkSmsEnabled() {
|
||||
store.update { it.copy(useAsDefaultSmsApp = Util.isDefaultSmsProvider(ApplicationDependencies.getApplication())) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.data
|
||||
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import androidx.navigation.Navigation
|
||||
import androidx.preference.PreferenceManager
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
|
||||
import org.thoughtcrime.securesms.components.settings.configure
|
||||
import org.thoughtcrime.securesms.util.Util
|
||||
import org.thoughtcrime.securesms.webrtc.CallBandwidthMode
|
||||
import kotlin.math.abs
|
||||
|
||||
class DataAndStorageSettingsFragment : DSLSettingsFragment(R.string.preferences__data_and_storage) {
|
||||
|
||||
private val autoDownloadValues by lazy { resources.getStringArray(R.array.pref_media_download_entries) }
|
||||
private val autoDownloadLabels by lazy { resources.getStringArray(R.array.pref_media_download_values) }
|
||||
|
||||
private val callBandwidthLabels by lazy { resources.getStringArray(R.array.pref_data_and_storage_call_bandwidth_values) }
|
||||
|
||||
private lateinit var viewModel: DataAndStorageSettingsViewModel
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
override fun bindAdapter(adapter: DSLSettingsAdapter) {
|
||||
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
val repository = DataAndStorageSettingsRepository()
|
||||
val factory = DataAndStorageSettingsViewModel.Factory(preferences, repository)
|
||||
viewModel = ViewModelProviders.of(this, factory)[DataAndStorageSettingsViewModel::class.java]
|
||||
|
||||
viewModel.state.observe(viewLifecycleOwner) {
|
||||
adapter.submitList(getConfiguration(it).toMappingModelList())
|
||||
}
|
||||
}
|
||||
|
||||
fun getConfiguration(state: DataAndStorageSettingsState): DSLConfiguration {
|
||||
return configure {
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_data_and_storage__manage_storage),
|
||||
summary = DSLSettingsText.from(Util.getPrettyFileSize(state.totalStorageUse)),
|
||||
onClick = {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.action_dataAndStorageSettingsFragment_to_storagePreferenceFragment)
|
||||
}
|
||||
)
|
||||
|
||||
dividerPref()
|
||||
|
||||
sectionHeaderPref(R.string.preferences_chats__media_auto_download)
|
||||
|
||||
multiSelectPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_chats__when_using_mobile_data),
|
||||
listItems = autoDownloadLabels,
|
||||
selected = autoDownloadValues.map { state.mobileAutoDownloadValues.contains(it) }.toBooleanArray(),
|
||||
onSelected = {
|
||||
val resultSet = it.mapIndexed { index, selected -> if (selected) autoDownloadValues[index] else null }.filterNotNull().toSet()
|
||||
viewModel.setMobileAutoDownloadValues(resultSet)
|
||||
}
|
||||
)
|
||||
|
||||
multiSelectPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_chats__when_using_wifi),
|
||||
listItems = autoDownloadLabels,
|
||||
selected = autoDownloadValues.map { state.wifiAutoDownloadValues.contains(it) }.toBooleanArray(),
|
||||
onSelected = {
|
||||
val resultSet = it.mapIndexed { index, selected -> if (selected) autoDownloadValues[index] else null }.filterNotNull().toSet()
|
||||
viewModel.setWifiAutoDownloadValues(resultSet)
|
||||
}
|
||||
)
|
||||
|
||||
multiSelectPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_chats__when_roaming),
|
||||
listItems = autoDownloadLabels,
|
||||
selected = autoDownloadValues.map { state.roamingAutoDownloadValues.contains(it) }.toBooleanArray(),
|
||||
onSelected = {
|
||||
val resultSet = it.mapIndexed { index, selected -> if (selected) autoDownloadValues[index] else null }.filterNotNull().toSet()
|
||||
viewModel.setRoamingAutoDownloadValues(resultSet)
|
||||
}
|
||||
)
|
||||
|
||||
dividerPref()
|
||||
|
||||
sectionHeaderPref(R.string.DataAndStorageSettingsFragment__calls)
|
||||
|
||||
radioListPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_data_and_storage__use_less_data_for_calls),
|
||||
listItems = callBandwidthLabels,
|
||||
selected = abs(state.callBandwidthMode.code - 2),
|
||||
onSelected = {
|
||||
viewModel.setCallBandwidthMode(CallBandwidthMode.fromCode(abs(it - 2)))
|
||||
}
|
||||
)
|
||||
|
||||
textPref(
|
||||
summary = DSLSettingsText.from(R.string.preference_data_and_storage__using_less_data_may_improve_calls_on_bad_networks)
|
||||
)
|
||||
|
||||
dividerPref()
|
||||
|
||||
sectionHeaderPref(R.string.preferences_proxy)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_use_proxy),
|
||||
summary = DSLSettingsText.from(if (state.isProxyEnabled) R.string.preferences_on else R.string.preferences_off),
|
||||
onClick = {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.action_dataAndStorageSettingsFragment_to_editProxyFragment)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.data
|
||||
|
||||
import android.content.Context
|
||||
import org.signal.core.util.concurrent.SignalExecutors
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
|
||||
class DataAndStorageSettingsRepository {
|
||||
|
||||
private val context: Context = ApplicationDependencies.getApplication()
|
||||
|
||||
fun getTotalStorageUse(consumer: (Long) -> Unit) {
|
||||
SignalExecutors.BOUNDED.execute {
|
||||
val breakdown = DatabaseFactory.getMediaDatabase(context).storageBreakdown
|
||||
|
||||
consumer(listOf(breakdown.audioSize, breakdown.documentSize, breakdown.photoSize, breakdown.videoSize).sum())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.data
|
||||
|
||||
import org.thoughtcrime.securesms.webrtc.CallBandwidthMode
|
||||
|
||||
data class DataAndStorageSettingsState(
|
||||
val totalStorageUse: Long,
|
||||
val mobileAutoDownloadValues: Set<String>,
|
||||
val wifiAutoDownloadValues: Set<String>,
|
||||
val roamingAutoDownloadValues: Set<String>,
|
||||
val callBandwidthMode: CallBandwidthMode,
|
||||
val isProxyEnabled: Boolean
|
||||
)
|
||||
@@ -0,0 +1,77 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.data
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.thoughtcrime.securesms.util.livedata.Store
|
||||
import org.thoughtcrime.securesms.webrtc.CallBandwidthMode
|
||||
|
||||
class DataAndStorageSettingsViewModel(
|
||||
private val sharedPreferences: SharedPreferences,
|
||||
private val repository: DataAndStorageSettingsRepository
|
||||
) : ViewModel() {
|
||||
|
||||
private val store = Store(getState())
|
||||
|
||||
val state: LiveData<DataAndStorageSettingsState> = store.stateLiveData
|
||||
|
||||
fun refresh() {
|
||||
repository.getTotalStorageUse { totalStorageUse ->
|
||||
store.update { getState().copy(totalStorageUse = totalStorageUse) }
|
||||
}
|
||||
}
|
||||
|
||||
fun setMobileAutoDownloadValues(resultSet: Set<String>) {
|
||||
sharedPreferences.edit().putStringSet(TextSecurePreferences.MEDIA_DOWNLOAD_MOBILE_PREF, resultSet).apply()
|
||||
getStateAndCopyStorageUsage()
|
||||
}
|
||||
|
||||
fun setWifiAutoDownloadValues(resultSet: Set<String>) {
|
||||
sharedPreferences.edit().putStringSet(TextSecurePreferences.MEDIA_DOWNLOAD_WIFI_PREF, resultSet).apply()
|
||||
getStateAndCopyStorageUsage()
|
||||
}
|
||||
|
||||
fun setRoamingAutoDownloadValues(resultSet: Set<String>) {
|
||||
sharedPreferences.edit().putStringSet(TextSecurePreferences.MEDIA_DOWNLOAD_ROAMING_PREF, resultSet).apply()
|
||||
getStateAndCopyStorageUsage()
|
||||
}
|
||||
|
||||
fun setCallBandwidthMode(callBandwidthMode: CallBandwidthMode) {
|
||||
SignalStore.settings().callBandwidthMode = callBandwidthMode
|
||||
ApplicationDependencies.getSignalCallManager().bandwidthModeUpdate()
|
||||
getStateAndCopyStorageUsage()
|
||||
}
|
||||
|
||||
private fun getStateAndCopyStorageUsage() {
|
||||
store.update { getState().copy(totalStorageUse = it.totalStorageUse) }
|
||||
}
|
||||
|
||||
private fun getState() = DataAndStorageSettingsState(
|
||||
totalStorageUse = 0,
|
||||
mobileAutoDownloadValues = TextSecurePreferences.getMobileMediaDownloadAllowed(
|
||||
ApplicationDependencies.getApplication()
|
||||
),
|
||||
wifiAutoDownloadValues = TextSecurePreferences.getWifiMediaDownloadAllowed(
|
||||
ApplicationDependencies.getApplication()
|
||||
),
|
||||
roamingAutoDownloadValues = TextSecurePreferences.getRoamingMediaDownloadAllowed(
|
||||
ApplicationDependencies.getApplication()
|
||||
),
|
||||
callBandwidthMode = SignalStore.settings().callBandwidthMode,
|
||||
isProxyEnabled = SignalStore.proxy().isProxyEnabled
|
||||
)
|
||||
|
||||
class Factory(
|
||||
private val sharedPreferences: SharedPreferences,
|
||||
private val repository: DataAndStorageSettingsRepository
|
||||
) :
|
||||
ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
|
||||
return requireNotNull(modelClass.cast(DataAndStorageSettingsViewModel(sharedPreferences, repository)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.help
|
||||
|
||||
import android.view.MenuItem
|
||||
import androidx.navigation.Navigation
|
||||
import org.thoughtcrime.securesms.BuildConfig
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
|
||||
import org.thoughtcrime.securesms.components.settings.configure
|
||||
|
||||
class HelpSettingsFragment : DSLSettingsFragment(R.string.preferences__help, R.menu.help_settings) {
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return if (item.itemId == R.id.action_submit_debug_log) {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.action_helpSettingsFragment_to_submitDebugLogActivity)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun bindAdapter(adapter: DSLSettingsAdapter) {
|
||||
adapter.submitList(getConfiguration().toMappingModelList())
|
||||
}
|
||||
|
||||
fun getConfiguration(): DSLConfiguration {
|
||||
return configure {
|
||||
externalLinkPref(
|
||||
title = DSLSettingsText.from(R.string.HelpSettingsFragment__support_center),
|
||||
linkId = R.string.support_center_url
|
||||
)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.HelpSettingsFragment__contact_us),
|
||||
onClick = {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.action_helpSettingsFragment_to_helpFragment)
|
||||
}
|
||||
)
|
||||
|
||||
dividerPref()
|
||||
|
||||
textPref(
|
||||
title = DSLSettingsText.from(R.string.HelpSettingsFragment__version),
|
||||
summary = DSLSettingsText.from(BuildConfig.VERSION_NAME)
|
||||
)
|
||||
|
||||
externalLinkPref(
|
||||
title = DSLSettingsText.from(R.string.HelpSettingsFragment__terms_amp_privacy_policy),
|
||||
linkId = R.string.terms_and_privacy_policy_url
|
||||
)
|
||||
|
||||
textPref(
|
||||
summary = DSLSettingsText.from(
|
||||
StringBuilder().apply {
|
||||
append(getString(R.string.HelpFragment__copyright_signal_messenger))
|
||||
append("\n")
|
||||
append(getString(R.string.HelpFragment__licenced_under_the_gplv3))
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.internal
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.widget.Toast
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import org.signal.core.util.concurrent.SignalExecutors
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
|
||||
import org.thoughtcrime.securesms.components.settings.configure
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob
|
||||
import org.thoughtcrime.securesms.jobs.RefreshOwnProfileJob
|
||||
import org.thoughtcrime.securesms.jobs.RemoteConfigRefreshJob
|
||||
import org.thoughtcrime.securesms.jobs.RotateProfileKeyJob
|
||||
import org.thoughtcrime.securesms.jobs.StorageForcePushJob
|
||||
import org.thoughtcrime.securesms.payments.DataExportUtil
|
||||
import org.thoughtcrime.securesms.util.ConversationUtil
|
||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask
|
||||
|
||||
class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__internal_preferences) {
|
||||
|
||||
private lateinit var viewModel: InternalSettingsViewModel
|
||||
|
||||
override fun bindAdapter(adapter: DSLSettingsAdapter) {
|
||||
val repository = InternalSettingsRepository(requireContext())
|
||||
val factory = InternalSettingsViewModel.Factory(repository)
|
||||
viewModel = ViewModelProviders.of(this, factory)[InternalSettingsViewModel::class.java]
|
||||
|
||||
viewModel.state.observe(viewLifecycleOwner) {
|
||||
adapter.submitList(getConfiguration(it).toMappingModelList())
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConfiguration(state: InternalSettingsState): DSLConfiguration {
|
||||
return configure {
|
||||
sectionHeaderPref(R.string.preferences__internal_payments)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__internal_payment_copy_data),
|
||||
summary = DSLSettingsText.from(R.string.preferences__internal_payment_copy_data_description),
|
||||
onClick = {
|
||||
copyPaymentsDataToClipboard()
|
||||
}
|
||||
)
|
||||
|
||||
dividerPref()
|
||||
|
||||
sectionHeaderPref(R.string.preferences__internal_account)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__internal_refresh_attributes),
|
||||
summary = DSLSettingsText.from(R.string.preferences__internal_refresh_attributes_description),
|
||||
onClick = {
|
||||
refreshAttributes()
|
||||
}
|
||||
)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__internal_rotate_profile_key),
|
||||
summary = DSLSettingsText.from(R.string.preferences__internal_rotate_profile_key_description),
|
||||
onClick = {
|
||||
rotateProfileKey()
|
||||
}
|
||||
)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__internal_refresh_remote_values),
|
||||
summary = DSLSettingsText.from(R.string.preferences__internal_refresh_remote_values_description),
|
||||
onClick = {
|
||||
refreshRemoteValues()
|
||||
}
|
||||
)
|
||||
|
||||
dividerPref()
|
||||
|
||||
sectionHeaderPref(R.string.preferences__internal_display)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__internal_user_details),
|
||||
summary = DSLSettingsText.from(R.string.preferences__internal_user_details_description),
|
||||
isChecked = state.seeMoreUserDetails,
|
||||
onClick = {
|
||||
viewModel.setSeeMoreUserDetails(!state.seeMoreUserDetails)
|
||||
}
|
||||
)
|
||||
|
||||
dividerPref()
|
||||
|
||||
sectionHeaderPref(R.string.preferences__internal_storage_service)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__internal_force_storage_service_sync),
|
||||
summary = DSLSettingsText.from(R.string.preferences__internal_force_storage_service_sync_description),
|
||||
onClick = {
|
||||
forceStorageServiceSync()
|
||||
}
|
||||
)
|
||||
|
||||
dividerPref()
|
||||
|
||||
sectionHeaderPref(R.string.preferences__internal_preferences_groups_v2)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__internal_do_not_create_gv2),
|
||||
summary = DSLSettingsText.from(R.string.preferences__internal_do_not_create_gv2_description),
|
||||
isChecked = state.gv2doNotCreateGv2Groups,
|
||||
onClick = {
|
||||
viewModel.setGv2DoNotCreateGv2Groups(!state.gv2doNotCreateGv2Groups)
|
||||
}
|
||||
)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__internal_force_gv2_invites),
|
||||
summary = DSLSettingsText.from(R.string.preferences__internal_force_gv2_invites_description),
|
||||
isChecked = state.gv2forceInvites,
|
||||
onClick = {
|
||||
viewModel.setGv2ForceInvites(!state.gv2forceInvites)
|
||||
}
|
||||
)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__internal_ignore_gv2_server_changes),
|
||||
summary = DSLSettingsText.from(R.string.preferences__internal_ignore_gv2_server_changes_description),
|
||||
isChecked = state.gv2ignoreServerChanges,
|
||||
onClick = {
|
||||
viewModel.setGv2IgnoreServerChanges(!state.gv2ignoreServerChanges)
|
||||
}
|
||||
)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__internal_ignore_gv2_p2p_changes),
|
||||
summary = DSLSettingsText.from(R.string.preferences__internal_ignore_gv2_server_changes_description),
|
||||
isChecked = state.gv2ignoreP2PChanges,
|
||||
onClick = {
|
||||
viewModel.setGv2IgnoreP2PChanges(!state.gv2ignoreP2PChanges)
|
||||
}
|
||||
)
|
||||
|
||||
dividerPref()
|
||||
|
||||
sectionHeaderPref(R.string.preferences__internal_preferences_groups_v1_migration)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__internal_do_not_initiate_automigrate),
|
||||
summary = DSLSettingsText.from(R.string.preferences__internal_do_not_initiate_automigrate_description),
|
||||
isChecked = state.disableAutoMigrationInitiation,
|
||||
onClick = {
|
||||
viewModel.setDisableAutoMigrationInitiation(!state.disableAutoMigrationInitiation)
|
||||
}
|
||||
)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__internal_do_not_notify_automigrate),
|
||||
summary = DSLSettingsText.from(R.string.preferences__internal_do_not_notify_automigrate_description),
|
||||
isChecked = state.disableAutoMigrationNotification,
|
||||
onClick = {
|
||||
viewModel.setDisableAutoMigrationNotification(!state.disableAutoMigrationNotification)
|
||||
}
|
||||
)
|
||||
|
||||
dividerPref()
|
||||
|
||||
sectionHeaderPref(R.string.preferences__internal_network)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__internal_force_censorship),
|
||||
summary = DSLSettingsText.from(R.string.preferences__internal_force_censorship_description),
|
||||
isChecked = state.forceCensorship,
|
||||
onClick = {
|
||||
viewModel.setDisableAutoMigrationNotification(!state.forceCensorship)
|
||||
}
|
||||
)
|
||||
|
||||
dividerPref()
|
||||
|
||||
sectionHeaderPref(R.string.preferences__internal_conversations_and_shortcuts)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__internal_delete_all_dynamic_shortcuts),
|
||||
summary = DSLSettingsText.from(R.string.preferences__internal_click_to_delete_all_dynamic_shortcuts),
|
||||
onClick = {
|
||||
deleteAllDynamicShortcuts()
|
||||
}
|
||||
)
|
||||
|
||||
dividerPref()
|
||||
|
||||
sectionHeaderPref(R.string.preferences__internal_emoji)
|
||||
|
||||
val emojiSummary = if (state.emojiVersion == null) {
|
||||
getString(R.string.preferences__internal_use_built_in_emoji_set)
|
||||
} else {
|
||||
getString(
|
||||
R.string.preferences__internal_current_version_d_at_density_s,
|
||||
state.emojiVersion.version,
|
||||
state.emojiVersion.density
|
||||
)
|
||||
}
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__internal_use_built_in_emoji_set),
|
||||
summary = DSLSettingsText.from(emojiSummary),
|
||||
isChecked = state.useBuiltInEmojiSet,
|
||||
onClick = {
|
||||
viewModel.setDisableAutoMigrationNotification(!state.useBuiltInEmojiSet)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyPaymentsDataToClipboard() {
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setMessage(
|
||||
"""
|
||||
Local payments history will be copied to the clipboard.
|
||||
It may therefore compromise privacy.
|
||||
However, no private keys will be copied.
|
||||
""".trimIndent()
|
||||
)
|
||||
.setPositiveButton(
|
||||
"Copy"
|
||||
) { _: DialogInterface?, _: Int ->
|
||||
SimpleTask.run<Any?>(
|
||||
SignalExecutors.UNBOUNDED,
|
||||
{
|
||||
val context: Context = ApplicationDependencies.getApplication()
|
||||
val clipboard =
|
||||
context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val tsv = DataExportUtil.createTsv()
|
||||
val clip = ClipData.newPlainText(context.getString(R.string.app_name), tsv)
|
||||
clipboard.setPrimaryClip(clip)
|
||||
null
|
||||
},
|
||||
{
|
||||
Toast.makeText(
|
||||
context,
|
||||
"Payments have been copied",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
)
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun refreshAttributes() {
|
||||
ApplicationDependencies.getJobManager()
|
||||
.startChain(RefreshAttributesJob())
|
||||
.then(RefreshOwnProfileJob())
|
||||
.enqueue()
|
||||
Toast.makeText(context, "Scheduled attribute refresh", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
private fun rotateProfileKey() {
|
||||
ApplicationDependencies.getJobManager().add(RotateProfileKeyJob())
|
||||
Toast.makeText(context, "Scheduled profile key rotation", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
private fun refreshRemoteValues() {
|
||||
ApplicationDependencies.getJobManager().add(RemoteConfigRefreshJob())
|
||||
Toast.makeText(context, "Scheduled remote config refresh", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
private fun forceStorageServiceSync() {
|
||||
ApplicationDependencies.getJobManager().add(StorageForcePushJob())
|
||||
Toast.makeText(context, "Scheduled storage force push", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
private fun deleteAllDynamicShortcuts() {
|
||||
ConversationUtil.clearAllShortcuts(requireContext())
|
||||
Toast.makeText(context, "Deleted all dynamic shortcuts.", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.internal
|
||||
|
||||
import android.content.Context
|
||||
import org.signal.core.util.concurrent.SignalExecutors
|
||||
import org.thoughtcrime.securesms.emoji.EmojiFiles
|
||||
|
||||
class InternalSettingsRepository(context: Context) {
|
||||
|
||||
private val context = context.applicationContext
|
||||
|
||||
fun getEmojiVersionInfo(consumer: (EmojiFiles.Version?) -> Unit) {
|
||||
SignalExecutors.BOUNDED.execute {
|
||||
consumer(EmojiFiles.Version.readVersion(context))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.internal
|
||||
|
||||
import org.thoughtcrime.securesms.emoji.EmojiFiles
|
||||
|
||||
data class InternalSettingsState(
|
||||
val seeMoreUserDetails: Boolean,
|
||||
val gv2doNotCreateGv2Groups: Boolean,
|
||||
val gv2forceInvites: Boolean,
|
||||
val gv2ignoreServerChanges: Boolean,
|
||||
val gv2ignoreP2PChanges: Boolean,
|
||||
val disableAutoMigrationInitiation: Boolean,
|
||||
val disableAutoMigrationNotification: Boolean,
|
||||
val forceCensorship: Boolean,
|
||||
val useBuiltInEmojiSet: Boolean,
|
||||
val emojiVersion: EmojiFiles.Version?
|
||||
)
|
||||
@@ -0,0 +1,90 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.internal
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import org.thoughtcrime.securesms.keyvalue.InternalValues
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.util.livedata.Store
|
||||
|
||||
class InternalSettingsViewModel(private val repository: InternalSettingsRepository) : ViewModel() {
|
||||
private val preferenceDataStore = SignalStore.getPreferenceDataStore()
|
||||
|
||||
private val store = Store(getState())
|
||||
|
||||
init {
|
||||
repository.getEmojiVersionInfo { version ->
|
||||
store.update { it.copy(emojiVersion = version) }
|
||||
}
|
||||
}
|
||||
|
||||
val state: LiveData<InternalSettingsState> = store.stateLiveData
|
||||
|
||||
fun setSeeMoreUserDetails(enabled: Boolean) {
|
||||
preferenceDataStore.putBoolean(InternalValues.RECIPIENT_DETAILS, enabled)
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun setGv2DoNotCreateGv2Groups(enabled: Boolean) {
|
||||
preferenceDataStore.putBoolean(InternalValues.GV2_DO_NOT_CREATE_GV2, enabled)
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun setGv2ForceInvites(enabled: Boolean) {
|
||||
preferenceDataStore.putBoolean(InternalValues.GV2_FORCE_INVITES, enabled)
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun setGv2IgnoreServerChanges(enabled: Boolean) {
|
||||
preferenceDataStore.putBoolean(InternalValues.GV2_IGNORE_SERVER_CHANGES, enabled)
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun setGv2IgnoreP2PChanges(enabled: Boolean) {
|
||||
preferenceDataStore.putBoolean(InternalValues.GV2_IGNORE_P2P_CHANGES, enabled)
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun setDisableAutoMigrationInitiation(enabled: Boolean) {
|
||||
preferenceDataStore.putBoolean(InternalValues.GV2_DISABLE_AUTOMIGRATE_INITIATION, enabled)
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun setDisableAutoMigrationNotification(enabled: Boolean) {
|
||||
preferenceDataStore.putBoolean(InternalValues.GV2_DISABLE_AUTOMIGRATE_NOTIFICATION, enabled)
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun setForceCensorship(enabled: Boolean) {
|
||||
preferenceDataStore.putBoolean(InternalValues.FORCE_CENSORSHIP, enabled)
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun setUseBuiltInEmoji(enabled: Boolean) {
|
||||
preferenceDataStore.putBoolean(InternalValues.FORCE_BUILT_IN_EMOJI, enabled)
|
||||
refresh()
|
||||
}
|
||||
|
||||
private fun refresh() {
|
||||
store.update { getState().copy(emojiVersion = it.emojiVersion) }
|
||||
}
|
||||
|
||||
private fun getState() = InternalSettingsState(
|
||||
seeMoreUserDetails = SignalStore.internalValues().recipientDetails(),
|
||||
gv2doNotCreateGv2Groups = SignalStore.internalValues().gv2DoNotCreateGv2Groups(),
|
||||
gv2forceInvites = SignalStore.internalValues().gv2ForceInvites(),
|
||||
gv2ignoreServerChanges = SignalStore.internalValues().gv2IgnoreServerChanges(),
|
||||
gv2ignoreP2PChanges = SignalStore.internalValues().gv2IgnoreP2PChanges(),
|
||||
disableAutoMigrationInitiation = SignalStore.internalValues().disableGv1AutoMigrateInitiation(),
|
||||
disableAutoMigrationNotification = SignalStore.internalValues().disableGv1AutoMigrateNotification(),
|
||||
forceCensorship = SignalStore.internalValues().forcedCensorship(),
|
||||
useBuiltInEmojiSet = SignalStore.internalValues().forceBuiltInEmoji(),
|
||||
emojiVersion = null
|
||||
)
|
||||
|
||||
class Factory(private val repository: InternalSettingsRepository) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
|
||||
return requireNotNull(modelClass.cast(InternalSettingsViewModel(repository)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,337 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.notifications
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.graphics.ColorFilter
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import android.media.RingtoneManager
|
||||
import android.net.Uri
|
||||
import android.provider.Settings
|
||||
import android.text.TextUtils
|
||||
import android.view.View
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import androidx.preference.PreferenceManager
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
|
||||
import org.thoughtcrime.securesms.components.settings.PreferenceModel
|
||||
import org.thoughtcrime.securesms.components.settings.PreferenceViewHolder
|
||||
import org.thoughtcrime.securesms.components.settings.RadioListPreference
|
||||
import org.thoughtcrime.securesms.components.settings.RadioListPreferenceViewHolder
|
||||
import org.thoughtcrime.securesms.components.settings.configure
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels
|
||||
import org.thoughtcrime.securesms.util.MappingAdapter
|
||||
import org.thoughtcrime.securesms.util.RingtoneUtil
|
||||
import org.thoughtcrime.securesms.util.ViewUtil
|
||||
|
||||
private const val MESSAGE_SOUND_SELECT: Int = 1
|
||||
private const val CALL_RINGTONE_SELECT: Int = 2
|
||||
|
||||
class NotificationsSettingsFragment : DSLSettingsFragment(R.string.preferences__notifications) {
|
||||
|
||||
private val repeatAlertsValues by lazy { resources.getStringArray(R.array.pref_repeat_alerts_values) }
|
||||
private val repeatAlertsLabels by lazy { resources.getStringArray(R.array.pref_repeat_alerts_entries) }
|
||||
|
||||
private val notificationPrivacyValues by lazy { resources.getStringArray(R.array.pref_notification_privacy_values) }
|
||||
private val notificationPrivacyLabels by lazy { resources.getStringArray(R.array.pref_notification_privacy_entries) }
|
||||
|
||||
private val notificationPriorityValues by lazy { resources.getStringArray(R.array.pref_notification_priority_values) }
|
||||
private val notificationPriorityLabels by lazy { resources.getStringArray(R.array.pref_notification_priority_entries) }
|
||||
|
||||
private val ledColorValues by lazy { resources.getStringArray(R.array.pref_led_color_values) }
|
||||
private val ledColorLabels by lazy { resources.getStringArray(R.array.pref_led_color_entries) }
|
||||
|
||||
private val ledBlinkValues by lazy { resources.getStringArray(R.array.pref_led_blink_pattern_values) }
|
||||
private val ledBlinkLabels by lazy { resources.getStringArray(R.array.pref_led_blink_pattern_entries) }
|
||||
|
||||
private lateinit var viewModel: NotificationsSettingsViewModel
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (requestCode == MESSAGE_SOUND_SELECT && resultCode == Activity.RESULT_OK && data != null) {
|
||||
val uri = data.getParcelableExtra<Uri>(RingtoneManager.EXTRA_RINGTONE_PICKED_URI)
|
||||
viewModel.setMessageNotificationsSound(uri)
|
||||
} else if (requestCode == CALL_RINGTONE_SELECT && resultCode == Activity.RESULT_OK && data != null) {
|
||||
val uri = data.getParcelableExtra<Uri>(RingtoneManager.EXTRA_RINGTONE_PICKED_URI)
|
||||
viewModel.setCallRingtone(uri)
|
||||
}
|
||||
}
|
||||
|
||||
override fun bindAdapter(adapter: DSLSettingsAdapter) {
|
||||
adapter.registerFactory(
|
||||
LedColorPreference::class.java,
|
||||
MappingAdapter.LayoutFactory(::LedColorPreferenceViewHolder, R.layout.dsl_preference_item)
|
||||
)
|
||||
|
||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
val factory = NotificationsSettingsViewModel.Factory(sharedPreferences)
|
||||
|
||||
viewModel = ViewModelProviders.of(this, factory)[NotificationsSettingsViewModel::class.java]
|
||||
|
||||
viewModel.state.observe(viewLifecycleOwner) {
|
||||
adapter.submitList(getConfiguration(it).toMappingModelList())
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConfiguration(state: NotificationsSettingsState): DSLConfiguration {
|
||||
return configure {
|
||||
sectionHeaderPref(R.string.NotificationsSettingsFragment__messages)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__notifications),
|
||||
isChecked = state.messageNotificationsState.notificationsEnabled,
|
||||
onClick = {
|
||||
viewModel.setMessageNotificationsEnabled(!state.messageNotificationsState.notificationsEnabled)
|
||||
}
|
||||
)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__sound),
|
||||
summary = DSLSettingsText.from(getRingtoneSummary(state.messageNotificationsState.sound)),
|
||||
isEnabled = state.messageNotificationsState.notificationsEnabled,
|
||||
onClick = {
|
||||
launchMessageSoundSelectionIntent()
|
||||
}
|
||||
)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__vibrate),
|
||||
isChecked = state.messageNotificationsState.vibrateEnabled,
|
||||
isEnabled = state.messageNotificationsState.notificationsEnabled,
|
||||
onClick = {
|
||||
viewModel.setMessageNotificationVibration(!state.messageNotificationsState.vibrateEnabled)
|
||||
}
|
||||
)
|
||||
|
||||
customPref(
|
||||
LedColorPreference(
|
||||
colorValues = ledColorValues,
|
||||
radioListPreference = RadioListPreference(
|
||||
title = DSLSettingsText.from(R.string.preferences__led_color),
|
||||
listItems = ledColorLabels,
|
||||
selected = ledColorValues.indexOf(state.messageNotificationsState.ledColor),
|
||||
isEnabled = state.messageNotificationsState.notificationsEnabled,
|
||||
onSelected = {
|
||||
viewModel.setMessageNotificationLedColor(ledColorValues[it])
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
if (!NotificationChannels.supported()) {
|
||||
radioListPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__pref_led_blink_title),
|
||||
listItems = ledBlinkLabels,
|
||||
selected = ledBlinkValues.indexOf(state.messageNotificationsState.ledBlink),
|
||||
isEnabled = state.messageNotificationsState.notificationsEnabled,
|
||||
onSelected = {
|
||||
viewModel.setMessageNotificationLedBlink(ledBlinkValues[it])
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_notifications__in_chat_sounds),
|
||||
isChecked = state.messageNotificationsState.inChatSoundsEnabled,
|
||||
isEnabled = state.messageNotificationsState.notificationsEnabled,
|
||||
onClick = {
|
||||
viewModel.setMessageNotificationInChatSoundsEnabled(!state.messageNotificationsState.inChatSoundsEnabled)
|
||||
}
|
||||
)
|
||||
|
||||
radioListPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__repeat_alerts),
|
||||
listItems = repeatAlertsLabels,
|
||||
selected = repeatAlertsValues.indexOf(state.messageNotificationsState.repeatAlerts.toString()),
|
||||
isEnabled = state.messageNotificationsState.notificationsEnabled,
|
||||
onSelected = {
|
||||
viewModel.setMessageRepeatAlerts(repeatAlertsValues[it].toInt())
|
||||
}
|
||||
)
|
||||
|
||||
radioListPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_notifications__show),
|
||||
listItems = notificationPrivacyLabels,
|
||||
selected = notificationPrivacyValues.indexOf(state.messageNotificationsState.messagePrivacy),
|
||||
isEnabled = state.messageNotificationsState.notificationsEnabled,
|
||||
onSelected = {
|
||||
viewModel.setMessageNotificationPrivacy(notificationPrivacyValues[it])
|
||||
}
|
||||
)
|
||||
|
||||
if (NotificationChannels.supported()) {
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_notifications__priority),
|
||||
isEnabled = state.messageNotificationsState.notificationsEnabled,
|
||||
onClick = {
|
||||
launchNotificationPriorityIntent()
|
||||
}
|
||||
)
|
||||
} else {
|
||||
radioListPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_notifications__priority),
|
||||
listItems = notificationPriorityLabels,
|
||||
selected = notificationPriorityValues.indexOf(state.messageNotificationsState.priority.toString()),
|
||||
isEnabled = state.messageNotificationsState.notificationsEnabled,
|
||||
onSelected = {
|
||||
viewModel.setMessageNotificationPriority(notificationPriorityValues[it].toInt())
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
dividerPref()
|
||||
|
||||
sectionHeaderPref(R.string.NotificationsSettingsFragment__calls)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__notifications),
|
||||
isChecked = state.callNotificationsState.notificationsEnabled,
|
||||
onClick = {
|
||||
viewModel.setCallNotificationsEnabled(!state.callNotificationsState.notificationsEnabled)
|
||||
}
|
||||
)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_notifications__ringtone),
|
||||
summary = DSLSettingsText.from(getRingtoneSummary(state.callNotificationsState.ringtone)),
|
||||
isEnabled = state.callNotificationsState.notificationsEnabled,
|
||||
onClick = {
|
||||
launchCallRingtoneSelectionIntent()
|
||||
}
|
||||
)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__vibrate),
|
||||
isChecked = state.callNotificationsState.vibrateEnabled,
|
||||
isEnabled = state.callNotificationsState.notificationsEnabled,
|
||||
onClick = {
|
||||
viewModel.setCallVibrateEnabled(!state.callNotificationsState.vibrateEnabled)
|
||||
}
|
||||
)
|
||||
|
||||
dividerPref()
|
||||
|
||||
sectionHeaderPref(R.string.NotificationsSettingsFragment__notify_when)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.NotificationsSettingsFragment__contact_joins_signal),
|
||||
isChecked = state.notifyWhenContactJoinsSignal,
|
||||
onClick = {
|
||||
viewModel.setNotifyWhenContactJoinsSignal(!state.notifyWhenContactJoinsSignal)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getRingtoneSummary(uri: Uri): String {
|
||||
return if (TextUtils.isEmpty(uri.toString())) {
|
||||
getString(R.string.preferences__silent)
|
||||
} else {
|
||||
val tone = RingtoneUtil.getRingtone(requireContext(), uri)
|
||||
if (tone != null) {
|
||||
tone.getTitle(requireContext())
|
||||
} else {
|
||||
getString(R.string.preferences__default)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun launchMessageSoundSelectionIntent() {
|
||||
val current = SignalStore.settings().messageNotificationSound
|
||||
|
||||
val intent = Intent(RingtoneManager.ACTION_RINGTONE_PICKER)
|
||||
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true)
|
||||
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true)
|
||||
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION)
|
||||
intent.putExtra(
|
||||
RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI,
|
||||
Settings.System.DEFAULT_NOTIFICATION_URI
|
||||
)
|
||||
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, current)
|
||||
|
||||
startActivityForResult(intent, MESSAGE_SOUND_SELECT)
|
||||
}
|
||||
|
||||
@RequiresApi(26)
|
||||
private fun launchNotificationPriorityIntent() {
|
||||
val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
|
||||
intent.putExtra(
|
||||
Settings.EXTRA_CHANNEL_ID,
|
||||
NotificationChannels.getMessagesChannel(requireContext())
|
||||
)
|
||||
intent.putExtra(Settings.EXTRA_APP_PACKAGE, requireContext().packageName)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
private fun launchCallRingtoneSelectionIntent() {
|
||||
val current = SignalStore.settings().callRingtone
|
||||
|
||||
val intent = Intent(RingtoneManager.ACTION_RINGTONE_PICKER)
|
||||
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true)
|
||||
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true)
|
||||
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_RINGTONE)
|
||||
intent.putExtra(
|
||||
RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI,
|
||||
Settings.System.DEFAULT_RINGTONE_URI
|
||||
)
|
||||
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, current)
|
||||
|
||||
startActivityForResult(intent, CALL_RINGTONE_SELECT)
|
||||
}
|
||||
|
||||
private class LedColorPreference(
|
||||
val colorValues: Array<String>,
|
||||
val radioListPreference: RadioListPreference
|
||||
) : PreferenceModel<LedColorPreference>(
|
||||
title = radioListPreference.title,
|
||||
iconId = radioListPreference.iconId,
|
||||
summary = radioListPreference.summary
|
||||
) {
|
||||
override fun areContentsTheSame(newItem: LedColorPreference): Boolean {
|
||||
return super.areContentsTheSame(newItem) && radioListPreference.areContentsTheSame(newItem.radioListPreference)
|
||||
}
|
||||
}
|
||||
|
||||
private class LedColorPreferenceViewHolder(itemView: View) :
|
||||
PreferenceViewHolder<LedColorPreference>(itemView) {
|
||||
|
||||
val radioListPreferenceViewHolder = RadioListPreferenceViewHolder(itemView)
|
||||
|
||||
override fun bind(model: LedColorPreference) {
|
||||
super.bind(model)
|
||||
radioListPreferenceViewHolder.bind(model.radioListPreference)
|
||||
|
||||
summaryView.visibility = View.GONE
|
||||
|
||||
val circleDrawable = requireNotNull(ContextCompat.getDrawable(context, R.drawable.circle_tintable))
|
||||
circleDrawable.setBounds(0, 0, ViewUtil.dpToPx(20), ViewUtil.dpToPx(20))
|
||||
circleDrawable.colorFilter = model.colorValues[model.radioListPreference.selected].toColorFilter()
|
||||
|
||||
if (titleView.layoutDirection == View.LAYOUT_DIRECTION_LTR) {
|
||||
titleView.setCompoundDrawables(null, null, circleDrawable, null)
|
||||
} else {
|
||||
titleView.setCompoundDrawables(circleDrawable, null, null, null)
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.toColorFilter(): ColorFilter {
|
||||
val color = when (this) {
|
||||
"green" -> ContextCompat.getColor(context, R.color.green_500)
|
||||
"red" -> ContextCompat.getColor(context, R.color.red_500)
|
||||
"blue" -> ContextCompat.getColor(context, R.color.blue_500)
|
||||
"yellow" -> ContextCompat.getColor(context, R.color.yellow_500)
|
||||
"cyan" -> ContextCompat.getColor(context, R.color.cyan_500)
|
||||
"magenta" -> ContextCompat.getColor(context, R.color.pink_500)
|
||||
"white" -> ContextCompat.getColor(context, R.color.white)
|
||||
else -> ContextCompat.getColor(context, R.color.transparent)
|
||||
}
|
||||
|
||||
return PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.notifications
|
||||
|
||||
import android.net.Uri
|
||||
|
||||
data class NotificationsSettingsState(
|
||||
val messageNotificationsState: MessageNotificationsState,
|
||||
val callNotificationsState: CallNotificationsState,
|
||||
val notifyWhenContactJoinsSignal: Boolean
|
||||
)
|
||||
|
||||
data class MessageNotificationsState(
|
||||
val notificationsEnabled: Boolean,
|
||||
val sound: Uri,
|
||||
val vibrateEnabled: Boolean,
|
||||
val ledColor: String,
|
||||
val ledBlink: String,
|
||||
val inChatSoundsEnabled: Boolean,
|
||||
val repeatAlerts: Int,
|
||||
val messagePrivacy: String,
|
||||
val priority: Int
|
||||
)
|
||||
|
||||
data class CallNotificationsState(
|
||||
val notificationsEnabled: Boolean,
|
||||
val ringtone: Uri,
|
||||
val vibrateEnabled: Boolean
|
||||
)
|
||||
@@ -0,0 +1,121 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.notifications
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels
|
||||
import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.thoughtcrime.securesms.util.livedata.Store
|
||||
|
||||
class NotificationsSettingsViewModel(private val sharedPreferences: SharedPreferences) : ViewModel() {
|
||||
|
||||
init {
|
||||
if (NotificationChannels.supported()) {
|
||||
SignalStore.settings().messageNotificationSound = NotificationChannels.getMessageRingtone(ApplicationDependencies.getApplication())
|
||||
SignalStore.settings().isMessageVibrateEnabled = NotificationChannels.getMessageVibrate(ApplicationDependencies.getApplication())
|
||||
}
|
||||
}
|
||||
|
||||
private val store = Store(getState())
|
||||
|
||||
val state: LiveData<NotificationsSettingsState> = store.stateLiveData
|
||||
|
||||
fun setMessageNotificationsEnabled(enabled: Boolean) {
|
||||
SignalStore.settings().isMessageNotificationsEnabled = enabled
|
||||
store.update { getState() }
|
||||
}
|
||||
|
||||
fun setMessageNotificationsSound(sound: Uri?) {
|
||||
SignalStore.settings().messageNotificationSound = sound ?: Uri.EMPTY
|
||||
NotificationChannels.updateMessageRingtone(ApplicationDependencies.getApplication(), sound)
|
||||
store.update { getState() }
|
||||
}
|
||||
|
||||
fun setMessageNotificationVibration(enabled: Boolean) {
|
||||
SignalStore.settings().isMessageVibrateEnabled = enabled
|
||||
NotificationChannels.updateMessageVibrate(ApplicationDependencies.getApplication(), enabled)
|
||||
store.update { getState() }
|
||||
}
|
||||
|
||||
fun setMessageNotificationLedColor(color: String) {
|
||||
SignalStore.settings().messageLedColor = color
|
||||
NotificationChannels.updateMessagesLedColor(ApplicationDependencies.getApplication(), color)
|
||||
store.update { getState() }
|
||||
}
|
||||
|
||||
fun setMessageNotificationLedBlink(blink: String) {
|
||||
SignalStore.settings().messageLedBlinkPattern = blink
|
||||
store.update { getState() }
|
||||
}
|
||||
|
||||
fun setMessageNotificationInChatSoundsEnabled(enabled: Boolean) {
|
||||
SignalStore.settings().isMessageNotificationsInChatSoundsEnabled = enabled
|
||||
store.update { getState() }
|
||||
}
|
||||
|
||||
fun setMessageRepeatAlerts(repeats: Int) {
|
||||
SignalStore.settings().messageNotificationsRepeatAlerts = repeats
|
||||
store.update { getState() }
|
||||
}
|
||||
|
||||
fun setMessageNotificationPrivacy(preference: String) {
|
||||
SignalStore.settings().messageNotificationsPrivacy = NotificationPrivacyPreference(preference)
|
||||
store.update { getState() }
|
||||
}
|
||||
|
||||
fun setMessageNotificationPriority(priority: Int) {
|
||||
sharedPreferences.edit().putInt(TextSecurePreferences.NOTIFICATION_PRIORITY_PREF, priority).apply()
|
||||
store.update { getState() }
|
||||
}
|
||||
|
||||
fun setCallNotificationsEnabled(enabled: Boolean) {
|
||||
SignalStore.settings().isCallNotificationsEnabled = enabled
|
||||
store.update { getState() }
|
||||
}
|
||||
|
||||
fun setCallRingtone(ringtone: Uri?) {
|
||||
SignalStore.settings().callRingtone = ringtone ?: Uri.EMPTY
|
||||
store.update { getState() }
|
||||
}
|
||||
|
||||
fun setCallVibrateEnabled(enabled: Boolean) {
|
||||
SignalStore.settings().isCallVibrateEnabled = enabled
|
||||
store.update { getState() }
|
||||
}
|
||||
|
||||
fun setNotifyWhenContactJoinsSignal(enabled: Boolean) {
|
||||
SignalStore.settings().isNotifyWhenContactJoinsSignal = enabled
|
||||
store.update { getState() }
|
||||
}
|
||||
|
||||
private fun getState(): NotificationsSettingsState = NotificationsSettingsState(
|
||||
messageNotificationsState = MessageNotificationsState(
|
||||
notificationsEnabled = SignalStore.settings().isMessageNotificationsEnabled,
|
||||
sound = SignalStore.settings().messageNotificationSound,
|
||||
vibrateEnabled = SignalStore.settings().isMessageVibrateEnabled,
|
||||
ledColor = SignalStore.settings().messageLedColor,
|
||||
ledBlink = SignalStore.settings().messageLedBlinkPattern,
|
||||
inChatSoundsEnabled = SignalStore.settings().isMessageNotificationsInChatSoundsEnabled,
|
||||
repeatAlerts = SignalStore.settings().messageNotificationsRepeatAlerts,
|
||||
messagePrivacy = SignalStore.settings().messageNotificationsPrivacy.toString(),
|
||||
priority = TextSecurePreferences.getNotificationPriority(ApplicationDependencies.getApplication())
|
||||
),
|
||||
callNotificationsState = CallNotificationsState(
|
||||
notificationsEnabled = SignalStore.settings().isCallNotificationsEnabled,
|
||||
ringtone = SignalStore.settings().callRingtone,
|
||||
vibrateEnabled = SignalStore.settings().isCallVibrateEnabled
|
||||
),
|
||||
notifyWhenContactJoinsSignal = SignalStore.settings().isNotifyWhenContactJoinsSignal
|
||||
)
|
||||
|
||||
class Factory(private val sharedPreferences: SharedPreferences) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
|
||||
return requireNotNull(modelClass.cast(NotificationsSettingsViewModel(sharedPreferences)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,391 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.privacy
|
||||
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.Spanned
|
||||
import android.text.style.TextAppearanceSpan
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import androidx.navigation.Navigation
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import mobi.upod.timedurationpicker.TimeDurationPicker
|
||||
import mobi.upod.timedurationpicker.TimeDurationPickerDialog
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.PassphraseChangeActivity
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
|
||||
import org.thoughtcrime.securesms.components.settings.configure
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecretUtil
|
||||
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues
|
||||
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues.PhoneNumberListingMode
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions
|
||||
import org.thoughtcrime.securesms.util.ConversationUtil
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags
|
||||
import org.thoughtcrime.securesms.util.ServiceUtil
|
||||
import org.thoughtcrime.securesms.util.SpanUtil
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import java.lang.Integer.max
|
||||
import java.util.ArrayList
|
||||
import java.util.LinkedHashMap
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
private val TAG = Log.tag(PrivacySettingsFragment::class.java)
|
||||
|
||||
class PrivacySettingsFragment : DSLSettingsFragment(R.string.preferences__privacy) {
|
||||
|
||||
private lateinit var viewModel: PrivacySettingsViewModel
|
||||
|
||||
private val incognitoSummary: CharSequence by lazy {
|
||||
SpannableStringBuilder(getString(R.string.preferences__this_setting_is_not_a_guarantee))
|
||||
.append(" ")
|
||||
.append(
|
||||
SpanUtil.learnMore(requireContext(), ContextCompat.getColor(requireContext(), R.color.signal_text_primary)) {
|
||||
CommunicationActions.openBrowserLink(requireContext(), getString(R.string.preferences__incognito_keyboard_learn_more))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
viewModel.refreshBlockedCount()
|
||||
}
|
||||
|
||||
override fun bindAdapter(adapter: DSLSettingsAdapter) {
|
||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
val repository = PrivacySettingsRepository()
|
||||
val factory = PrivacySettingsViewModel.Factory(sharedPreferences, repository)
|
||||
viewModel = ViewModelProviders.of(this, factory)[PrivacySettingsViewModel::class.java]
|
||||
|
||||
viewModel.state.observe(viewLifecycleOwner) { state ->
|
||||
adapter.submitList(getConfiguration(state).toMappingModelList())
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConfiguration(state: PrivacySettingsState): DSLConfiguration {
|
||||
return configure {
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.PrivacySettingsFragment__blocked),
|
||||
summary = DSLSettingsText.from(getString(R.string.PrivacySettingsFragment__d_contacts, state.blockedCount)),
|
||||
onClick = {
|
||||
Navigation.findNavController(requireView())
|
||||
.navigate(R.id.action_privacySettingsFragment_to_blockedUsersActivity)
|
||||
}
|
||||
)
|
||||
|
||||
dividerPref()
|
||||
|
||||
if (FeatureFlags.phoneNumberPrivacy()) {
|
||||
sectionHeaderPref(R.string.preferences_app_protection__who_can)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_app_protection__see_my_phone_number),
|
||||
summary = DSLSettingsText.from(getWhoCanSeeMyPhoneNumberSummary(state.seeMyPhoneNumber)),
|
||||
onClick = {
|
||||
onSeeMyPhoneNumberClicked(state.seeMyPhoneNumber)
|
||||
}
|
||||
)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_app_protection__find_me_by_phone_number),
|
||||
summary = DSLSettingsText.from(getWhoCanFindMeByPhoneNumberSummary(state.findMeByPhoneNumber)),
|
||||
onClick = {
|
||||
onFindMyPhoneNumberClicked(state.findMeByPhoneNumber)
|
||||
}
|
||||
)
|
||||
|
||||
dividerPref()
|
||||
}
|
||||
|
||||
sectionHeaderPref(R.string.PrivacySettingsFragment__messaging)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__read_receipts),
|
||||
summary = DSLSettingsText.from(R.string.preferences__if_read_receipts_are_disabled_you_wont_be_able_to_see_read_receipts),
|
||||
isChecked = state.readReceipts,
|
||||
onClick = {
|
||||
viewModel.setReadReceiptsEnabled(!state.readReceipts)
|
||||
}
|
||||
)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__typing_indicators),
|
||||
summary = DSLSettingsText.from(R.string.preferences__if_typing_indicators_are_disabled_you_wont_be_able_to_see_typing_indicators),
|
||||
isChecked = state.typingIndicators,
|
||||
onClick = {
|
||||
viewModel.setTypingIndicatorsEnabled(!state.typingIndicators)
|
||||
}
|
||||
)
|
||||
|
||||
dividerPref()
|
||||
|
||||
sectionHeaderPref(R.string.PrivacySettingsFragment__app_security)
|
||||
|
||||
if (state.isObsoletePasswordEnabled) {
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__enable_passphrase),
|
||||
summary = DSLSettingsText.from(R.string.preferences__lock_signal_and_message_notifications_with_a_passphrase),
|
||||
isChecked = true,
|
||||
onClick = {
|
||||
MaterialAlertDialogBuilder(requireContext()).apply {
|
||||
setTitle(R.string.ApplicationPreferencesActivity_disable_passphrase)
|
||||
setMessage(R.string.ApplicationPreferencesActivity_this_will_permanently_unlock_signal_and_message_notifications)
|
||||
setIcon(R.drawable.ic_warning)
|
||||
setPositiveButton(R.string.ApplicationPreferencesActivity_disable) { dialog, which ->
|
||||
MasterSecretUtil.changeMasterSecretPassphrase(
|
||||
activity,
|
||||
KeyCachingService.getMasterSecret(context),
|
||||
MasterSecretUtil.UNENCRYPTED_PASSPHRASE
|
||||
)
|
||||
TextSecurePreferences.setPasswordDisabled(activity, true)
|
||||
val intent = Intent(activity, KeyCachingService::class.java)
|
||||
intent.action = KeyCachingService.DISABLE_ACTION
|
||||
requireActivity().startService(intent)
|
||||
viewModel.refresh()
|
||||
}
|
||||
setNegativeButton(android.R.string.cancel, null)
|
||||
show()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__change_passphrase),
|
||||
summary = DSLSettingsText.from(R.string.preferences__change_your_passphrase),
|
||||
onClick = {
|
||||
if (MasterSecretUtil.isPassphraseInitialized(activity)) {
|
||||
startActivity(Intent(activity, PassphraseChangeActivity::class.java))
|
||||
} else {
|
||||
Toast.makeText(
|
||||
activity,
|
||||
R.string.ApplicationPreferenceActivity_you_havent_set_a_passphrase_yet,
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__inactivity_timeout_passphrase),
|
||||
summary = DSLSettingsText.from(R.string.preferences__auto_lock_signal_after_a_specified_time_interval_of_inactivity),
|
||||
isChecked = state.isObsoletePasswordTimeoutEnabled,
|
||||
onClick = {
|
||||
viewModel.setObsoletePasswordTimeoutEnabled(!state.isObsoletePasswordEnabled)
|
||||
}
|
||||
)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__inactivity_timeout_interval),
|
||||
onClick = {
|
||||
TimeDurationPickerDialog(
|
||||
context,
|
||||
{ _: TimeDurationPicker?, duration: Long ->
|
||||
val timeoutMinutes = max(TimeUnit.MILLISECONDS.toMinutes(duration).toInt(), 1)
|
||||
viewModel.setObsoletePasswordTimeout(timeoutMinutes)
|
||||
},
|
||||
0, TimeDurationPicker.HH_MM
|
||||
).show()
|
||||
}
|
||||
)
|
||||
} else {
|
||||
val isKeyguardSecure = ServiceUtil.getKeyguardManager(requireContext()).isKeyguardSecure
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_app_protection__screen_lock),
|
||||
summary = DSLSettingsText.from(R.string.preferences_app_protection__lock_signal_access_with_android_screen_lock_or_fingerprint),
|
||||
isChecked = state.screenLock && isKeyguardSecure,
|
||||
isEnabled = isKeyguardSecure,
|
||||
onClick = {
|
||||
viewModel.setScreenLockEnabled(!state.screenLock)
|
||||
|
||||
val intent = Intent(requireContext(), KeyCachingService::class.java)
|
||||
intent.action = KeyCachingService.LOCK_TOGGLED_EVENT
|
||||
requireContext().startService(intent)
|
||||
|
||||
ConversationUtil.refreshRecipientShortcuts()
|
||||
}
|
||||
)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_app_protection__screen_lock_inactivity_timeout),
|
||||
summary = DSLSettingsText.from(getScreenLockInactivityTimeoutSummary(state.screenLockActivityTimeout)),
|
||||
isEnabled = isKeyguardSecure,
|
||||
onClick = {
|
||||
TimeDurationPickerDialog(
|
||||
context,
|
||||
{ _: TimeDurationPicker?, duration: Long ->
|
||||
val timeoutSeconds = TimeUnit.MILLISECONDS.toSeconds(duration)
|
||||
viewModel.setScreenLockTimeout(timeoutSeconds)
|
||||
},
|
||||
0, TimeDurationPicker.HH_MM
|
||||
).show()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__screen_security),
|
||||
summary = DSLSettingsText.from(R.string.PrivacySettingsFragment__block_screenshots_in_the_recents_list_and_inside_the_app),
|
||||
isChecked = state.screenSecurity,
|
||||
onClick = {
|
||||
viewModel.setScreenSecurityEnabled(!state.screenSecurity)
|
||||
}
|
||||
)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__incognito_keyboard),
|
||||
summary = DSLSettingsText.from(R.string.preferences__request_keyboard_to_disable),
|
||||
isChecked = state.incognitoKeyboard,
|
||||
onClick = {
|
||||
viewModel.setIncognitoKeyboard(!state.incognitoKeyboard)
|
||||
}
|
||||
)
|
||||
|
||||
textPref(
|
||||
summary = DSLSettingsText.from(incognitoSummary),
|
||||
)
|
||||
|
||||
dividerPref()
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__advanced),
|
||||
summary = DSLSettingsText.from(R.string.PrivacySettingsFragment__signal_message_and_calls),
|
||||
onClick = {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.action_privacySettingsFragment_to_advancedPrivacySettingsFragment)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getScreenLockInactivityTimeoutSummary(timeoutSeconds: Long): String {
|
||||
val hours = TimeUnit.SECONDS.toHours(timeoutSeconds)
|
||||
val minutes =
|
||||
TimeUnit.SECONDS.toMinutes(timeoutSeconds) - TimeUnit.SECONDS.toHours(timeoutSeconds) * 60
|
||||
|
||||
return if (timeoutSeconds <= 0) {
|
||||
getString(R.string.AppProtectionPreferenceFragment_none)
|
||||
} else {
|
||||
String.format(Locale.getDefault(), "%02d:%02d:00", hours, minutes)
|
||||
}
|
||||
}
|
||||
|
||||
@StringRes
|
||||
private fun getWhoCanSeeMyPhoneNumberSummary(phoneNumberSharingMode: PhoneNumberPrivacyValues.PhoneNumberSharingMode): Int {
|
||||
return when (phoneNumberSharingMode) {
|
||||
PhoneNumberPrivacyValues.PhoneNumberSharingMode.EVERYONE -> R.string.PhoneNumberPrivacy_everyone
|
||||
PhoneNumberPrivacyValues.PhoneNumberSharingMode.CONTACTS -> R.string.PhoneNumberPrivacy_my_contacts
|
||||
PhoneNumberPrivacyValues.PhoneNumberSharingMode.NOBODY -> R.string.PhoneNumberPrivacy_nobody
|
||||
}
|
||||
}
|
||||
|
||||
@StringRes
|
||||
private fun getWhoCanFindMeByPhoneNumberSummary(phoneNumberListingMode: PhoneNumberListingMode): Int {
|
||||
return when (phoneNumberListingMode) {
|
||||
PhoneNumberListingMode.LISTED -> R.string.PhoneNumberPrivacy_everyone
|
||||
PhoneNumberListingMode.UNLISTED -> R.string.PhoneNumberPrivacy_nobody
|
||||
}
|
||||
}
|
||||
|
||||
private fun onSeeMyPhoneNumberClicked(phoneNumberSharingMode: PhoneNumberPrivacyValues.PhoneNumberSharingMode) {
|
||||
val value = arrayOf(phoneNumberSharingMode)
|
||||
val items = items(requireContext())
|
||||
val modes: List<PhoneNumberPrivacyValues.PhoneNumberSharingMode> = ArrayList(items.keys)
|
||||
val modeStrings = items.values.toTypedArray()
|
||||
val selectedMode = modes.indexOf(value[0])
|
||||
|
||||
MaterialAlertDialogBuilder(requireActivity()).apply {
|
||||
setTitle(R.string.preferences_app_protection__see_my_phone_number)
|
||||
setCancelable(true)
|
||||
setSingleChoiceItems(
|
||||
modeStrings,
|
||||
selectedMode
|
||||
) { _: DialogInterface?, which: Int -> value[0] = modes[which] }
|
||||
setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int ->
|
||||
val newSharingMode = value[0]
|
||||
Log.i(
|
||||
TAG,
|
||||
String.format(
|
||||
"PhoneNumberSharingMode changed to %s. Scheduling storage value sync",
|
||||
newSharingMode
|
||||
)
|
||||
)
|
||||
viewModel.setPhoneNumberSharingMode(value[0])
|
||||
}
|
||||
setNegativeButton(android.R.string.cancel, null)
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun items(context: Context): Map<PhoneNumberPrivacyValues.PhoneNumberSharingMode, CharSequence> {
|
||||
val map: MutableMap<PhoneNumberPrivacyValues.PhoneNumberSharingMode, CharSequence> = LinkedHashMap()
|
||||
map[PhoneNumberPrivacyValues.PhoneNumberSharingMode.EVERYONE] = titleAndDescription(
|
||||
context,
|
||||
context.getString(R.string.PhoneNumberPrivacy_everyone),
|
||||
context.getString(R.string.PhoneNumberPrivacy_everyone_see_description)
|
||||
)
|
||||
map[PhoneNumberPrivacyValues.PhoneNumberSharingMode.NOBODY] =
|
||||
context.getString(R.string.PhoneNumberPrivacy_nobody)
|
||||
return map
|
||||
}
|
||||
|
||||
private fun titleAndDescription(
|
||||
context: Context,
|
||||
header: String,
|
||||
description: String
|
||||
): CharSequence {
|
||||
return SpannableStringBuilder().apply {
|
||||
append("\n")
|
||||
append(header)
|
||||
append("\n")
|
||||
setSpan(
|
||||
TextAppearanceSpan(context, android.R.style.TextAppearance_Small),
|
||||
length,
|
||||
length,
|
||||
Spanned.SPAN_INCLUSIVE_INCLUSIVE
|
||||
)
|
||||
append(description)
|
||||
append("\n")
|
||||
}
|
||||
}
|
||||
|
||||
fun onFindMyPhoneNumberClicked(phoneNumberListingMode: PhoneNumberListingMode) {
|
||||
val context = requireContext()
|
||||
val value = arrayOf(phoneNumberListingMode)
|
||||
MaterialAlertDialogBuilder(requireActivity()).apply {
|
||||
setTitle(R.string.preferences_app_protection__find_me_by_phone_number)
|
||||
setCancelable(true)
|
||||
setSingleChoiceItems(
|
||||
arrayOf(
|
||||
titleAndDescription(
|
||||
context,
|
||||
context.getString(R.string.PhoneNumberPrivacy_everyone),
|
||||
context.getString(R.string.PhoneNumberPrivacy_everyone_find_description)
|
||||
),
|
||||
context.getString(R.string.PhoneNumberPrivacy_nobody)
|
||||
),
|
||||
value[0].ordinal
|
||||
) { _: DialogInterface?, which: Int -> value[0] = PhoneNumberListingMode.values()[which] }
|
||||
setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int ->
|
||||
Log.i(
|
||||
TAG,
|
||||
String.format(
|
||||
"PhoneNumberListingMode changed to %s. Scheduling storage value sync",
|
||||
value[0]
|
||||
)
|
||||
)
|
||||
viewModel.setPhoneNumberListingMode(value[0])
|
||||
}
|
||||
setNegativeButton(android.R.string.cancel, null)
|
||||
show()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.privacy
|
||||
|
||||
import android.content.Context
|
||||
import org.signal.core.util.concurrent.SignalExecutors
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceConfigurationUpdateJob
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
|
||||
class PrivacySettingsRepository {
|
||||
|
||||
private val context: Context = ApplicationDependencies.getApplication()
|
||||
|
||||
fun getBlockedCount(consumer: (Int) -> Unit) {
|
||||
SignalExecutors.BOUNDED.execute {
|
||||
val recipientDatabase = DatabaseFactory.getRecipientDatabase(context)
|
||||
|
||||
consumer(recipientDatabase.blocked.count)
|
||||
}
|
||||
}
|
||||
|
||||
fun syncReadReceiptState() {
|
||||
SignalExecutors.BOUNDED.execute {
|
||||
DatabaseFactory.getRecipientDatabase(context).markNeedsSync(Recipient.self().id)
|
||||
StorageSyncHelper.scheduleSyncForDataChange()
|
||||
ApplicationDependencies.getJobManager().add(
|
||||
MultiDeviceConfigurationUpdateJob(
|
||||
TextSecurePreferences.isReadReceiptsEnabled(context),
|
||||
TextSecurePreferences.isTypingIndicatorsEnabled(context),
|
||||
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(context),
|
||||
SignalStore.settings().isLinkPreviewsEnabled
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun syncTypingIndicatorsState() {
|
||||
val enabled = TextSecurePreferences.isTypingIndicatorsEnabled(context)
|
||||
|
||||
DatabaseFactory.getRecipientDatabase(context).markNeedsSync(Recipient.self().id)
|
||||
StorageSyncHelper.scheduleSyncForDataChange()
|
||||
ApplicationDependencies.getJobManager().add(
|
||||
MultiDeviceConfigurationUpdateJob(
|
||||
TextSecurePreferences.isReadReceiptsEnabled(context),
|
||||
enabled,
|
||||
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(context),
|
||||
SignalStore.settings().isLinkPreviewsEnabled
|
||||
)
|
||||
)
|
||||
|
||||
if (!enabled) {
|
||||
ApplicationDependencies.getTypingStatusRepository().clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.privacy
|
||||
|
||||
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues
|
||||
|
||||
data class PrivacySettingsState(
|
||||
val blockedCount: Int,
|
||||
val seeMyPhoneNumber: PhoneNumberPrivacyValues.PhoneNumberSharingMode,
|
||||
val findMeByPhoneNumber: PhoneNumberPrivacyValues.PhoneNumberListingMode,
|
||||
val readReceipts: Boolean,
|
||||
val typingIndicators: Boolean,
|
||||
val screenLock: Boolean,
|
||||
val screenLockActivityTimeout: Long,
|
||||
val screenSecurity: Boolean,
|
||||
val incognitoKeyboard: Boolean,
|
||||
val isObsoletePasswordEnabled: Boolean,
|
||||
val isObsoletePasswordTimeoutEnabled: Boolean,
|
||||
val obsoletePasswordTimeout: Int
|
||||
)
|
||||
@@ -0,0 +1,118 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.privacy
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob
|
||||
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.thoughtcrime.securesms.util.livedata.Store
|
||||
|
||||
class PrivacySettingsViewModel(
|
||||
private val sharedPreferences: SharedPreferences,
|
||||
private val repository: PrivacySettingsRepository
|
||||
) : ViewModel() {
|
||||
|
||||
private val store = Store(getState())
|
||||
|
||||
val state: LiveData<PrivacySettingsState> = store.stateLiveData
|
||||
|
||||
fun refreshBlockedCount() {
|
||||
repository.getBlockedCount { count ->
|
||||
store.update { it.copy(blockedCount = count) }
|
||||
}
|
||||
}
|
||||
|
||||
fun setReadReceiptsEnabled(enabled: Boolean) {
|
||||
sharedPreferences.edit().putBoolean(TextSecurePreferences.READ_RECEIPTS_PREF, enabled).apply()
|
||||
repository.syncReadReceiptState()
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun setTypingIndicatorsEnabled(enabled: Boolean) {
|
||||
sharedPreferences.edit().putBoolean(TextSecurePreferences.TYPING_INDICATORS, enabled).apply()
|
||||
repository.syncTypingIndicatorsState()
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun setScreenLockEnabled(enabled: Boolean) {
|
||||
sharedPreferences.edit().putBoolean(TextSecurePreferences.SCREEN_LOCK, enabled).apply()
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun setScreenLockTimeout(seconds: Long) {
|
||||
TextSecurePreferences.setScreenLockTimeout(ApplicationDependencies.getApplication(), seconds)
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun setScreenSecurityEnabled(enabled: Boolean) {
|
||||
sharedPreferences.edit().putBoolean(TextSecurePreferences.SCREEN_SECURITY_PREF, enabled).apply()
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun setPhoneNumberSharingMode(phoneNumberSharingMode: PhoneNumberPrivacyValues.PhoneNumberSharingMode) {
|
||||
SignalStore.phoneNumberPrivacy().phoneNumberSharingMode = phoneNumberSharingMode
|
||||
StorageSyncHelper.scheduleSyncForDataChange()
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun setPhoneNumberListingMode(phoneNumberListingMode: PhoneNumberPrivacyValues.PhoneNumberListingMode) {
|
||||
SignalStore.phoneNumberPrivacy().phoneNumberListingMode = phoneNumberListingMode
|
||||
StorageSyncHelper.scheduleSyncForDataChange()
|
||||
ApplicationDependencies.getJobManager().add(RefreshAttributesJob())
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun setIncognitoKeyboard(enabled: Boolean) {
|
||||
sharedPreferences.edit().putBoolean(TextSecurePreferences.INCOGNITO_KEYBORAD_PREF, enabled).apply()
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun setObsoletePasswordTimeoutEnabled(enabled: Boolean) {
|
||||
sharedPreferences.edit().putBoolean(TextSecurePreferences.PASSPHRASE_TIMEOUT_PREF, enabled).apply()
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun setObsoletePasswordTimeout(minutes: Int) {
|
||||
TextSecurePreferences.setPassphraseTimeoutInterval(ApplicationDependencies.getApplication(), minutes)
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun refresh() {
|
||||
store.update(this::updateState)
|
||||
}
|
||||
|
||||
private fun getState(): PrivacySettingsState {
|
||||
return PrivacySettingsState(
|
||||
blockedCount = 0,
|
||||
readReceipts = TextSecurePreferences.isReadReceiptsEnabled(ApplicationDependencies.getApplication()),
|
||||
typingIndicators = TextSecurePreferences.isTypingIndicatorsEnabled(ApplicationDependencies.getApplication()),
|
||||
screenLock = TextSecurePreferences.isScreenLockEnabled(ApplicationDependencies.getApplication()),
|
||||
screenLockActivityTimeout = TextSecurePreferences.getScreenLockTimeout(ApplicationDependencies.getApplication()),
|
||||
screenSecurity = TextSecurePreferences.isScreenSecurityEnabled(ApplicationDependencies.getApplication()),
|
||||
incognitoKeyboard = TextSecurePreferences.isIncognitoKeyboardEnabled(ApplicationDependencies.getApplication()),
|
||||
seeMyPhoneNumber = SignalStore.phoneNumberPrivacy().phoneNumberSharingMode,
|
||||
findMeByPhoneNumber = SignalStore.phoneNumberPrivacy().phoneNumberListingMode,
|
||||
isObsoletePasswordEnabled = !TextSecurePreferences.isPasswordDisabled(ApplicationDependencies.getApplication()),
|
||||
isObsoletePasswordTimeoutEnabled = TextSecurePreferences.isPassphraseTimeoutEnabled(ApplicationDependencies.getApplication()),
|
||||
obsoletePasswordTimeout = TextSecurePreferences.getPassphraseTimeoutInterval(ApplicationDependencies.getApplication())
|
||||
)
|
||||
}
|
||||
|
||||
private fun updateState(state: PrivacySettingsState): PrivacySettingsState {
|
||||
return getState().copy(blockedCount = state.blockedCount)
|
||||
}
|
||||
|
||||
class Factory(
|
||||
private val sharedPreferences: SharedPreferences,
|
||||
private val repository: PrivacySettingsRepository
|
||||
) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
|
||||
return requireNotNull(modelClass.cast(PrivacySettingsViewModel(sharedPreferences, repository)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.privacy.advanced
|
||||
|
||||
import android.app.ProgressDialog
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
|
||||
import org.thoughtcrime.securesms.components.settings.configure
|
||||
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter
|
||||
import org.thoughtcrime.securesms.registration.RegistrationNavigationActivity
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions
|
||||
import org.thoughtcrime.securesms.util.SpanUtil
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.thoughtcrime.securesms.util.ViewUtil
|
||||
|
||||
class AdvancedPrivacySettingsFragment : DSLSettingsFragment(R.string.preferences__advanced) {
|
||||
|
||||
lateinit var viewModel: AdvancedPrivacySettingsViewModel
|
||||
|
||||
private val sealedSenderSummary: CharSequence by lazy {
|
||||
SpanUtil.learnMore(
|
||||
requireContext(),
|
||||
ContextCompat.getColor(requireContext(), R.color.signal_text_primary)
|
||||
) {
|
||||
CommunicationActions.openBrowserLink(
|
||||
requireContext(),
|
||||
getString(R.string.AdvancedPrivacySettingsFragment__sealed_sender_link)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
var progressDialog: ProgressDialog? = null
|
||||
|
||||
val statusIcon: CharSequence by lazy {
|
||||
val unidentifiedDeliveryIcon = requireNotNull(
|
||||
ContextCompat.getDrawable(
|
||||
requireContext(),
|
||||
R.drawable.ic_unidentified_delivery
|
||||
)
|
||||
)
|
||||
unidentifiedDeliveryIcon.setBounds(0, 0, ViewUtil.dpToPx(20), ViewUtil.dpToPx(20))
|
||||
val iconTint = ContextCompat.getColor(requireContext(), R.color.signal_text_primary_dialog)
|
||||
unidentifiedDeliveryIcon.colorFilter = PorterDuffColorFilter(iconTint, PorterDuff.Mode.SRC_IN)
|
||||
|
||||
SpanUtil.buildImageSpan(unidentifiedDeliveryIcon)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
override fun bindAdapter(adapter: DSLSettingsAdapter) {
|
||||
val repository = AdvancedPrivacySettingsRepository(requireContext())
|
||||
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
val factory = AdvancedPrivacySettingsViewModel.Factory(preferences, repository)
|
||||
|
||||
viewModel = ViewModelProviders.of(this, factory)[AdvancedPrivacySettingsViewModel::class.java]
|
||||
|
||||
viewModel.state.observe(viewLifecycleOwner) {
|
||||
if (it.showProgressSpinner) {
|
||||
if (progressDialog?.isShowing == false) {
|
||||
progressDialog = ProgressDialog.show(requireContext(), null, null, true)
|
||||
}
|
||||
} else {
|
||||
progressDialog?.hide()
|
||||
}
|
||||
|
||||
adapter.submitList(getConfiguration(it).toMappingModelList())
|
||||
}
|
||||
|
||||
viewModel.events.observe(viewLifecycleOwner) {
|
||||
if (it == AdvancedPrivacySettingsViewModel.Event.DISABLE_PUSH_FAILED) {
|
||||
Toast.makeText(
|
||||
requireContext(),
|
||||
R.string.ApplicationPreferencesActivity_error_connecting_to_server,
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConfiguration(state: AdvancedPrivacySettingsState): DSLConfiguration {
|
||||
return configure {
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__signal_messages_and_calls),
|
||||
summary = DSLSettingsText.from(getPushToggleSummary(state.isPushEnabled)),
|
||||
isChecked = state.isPushEnabled
|
||||
) {
|
||||
if (state.isPushEnabled) {
|
||||
MaterialAlertDialogBuilder(requireContext()).apply {
|
||||
setIcon(R.drawable.ic_info_outline)
|
||||
setTitle(R.string.ApplicationPreferencesActivity_disable_signal_messages_and_calls)
|
||||
setMessage(R.string.ApplicationPreferencesActivity_disable_signal_messages_and_calls_by_unregistering)
|
||||
setNegativeButton(android.R.string.cancel, null)
|
||||
setPositiveButton(
|
||||
android.R.string.ok
|
||||
) { _, _ -> viewModel.disablePushMessages() }
|
||||
show()
|
||||
}
|
||||
} else {
|
||||
startActivity(RegistrationNavigationActivity.newIntentForReRegistration(requireContext()))
|
||||
}
|
||||
}
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_advanced__always_relay_calls),
|
||||
summary = DSLSettingsText.from(R.string.preferences_advanced__relay_all_calls_through_the_signal_server_to_avoid_revealing_your_ip_address),
|
||||
isChecked = state.alwaysRelayCalls
|
||||
) {
|
||||
viewModel.setAlwaysRelayCalls(!state.alwaysRelayCalls)
|
||||
}
|
||||
|
||||
dividerPref()
|
||||
|
||||
sectionHeaderPref(R.string.preferences_communication__category_sealed_sender)
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(
|
||||
SpannableStringBuilder(getString(R.string.AdvancedPrivacySettingsFragment__show_status_icon))
|
||||
.append(" ")
|
||||
.append(statusIcon)
|
||||
),
|
||||
summary = DSLSettingsText.from(R.string.AdvancedPrivacySettingsFragment__show_an_icon),
|
||||
isChecked = state.showSealedSenderStatusIcon
|
||||
) {
|
||||
viewModel.setShowStatusIconForSealedSender(!state.showSealedSenderStatusIcon)
|
||||
}
|
||||
|
||||
switchPref(
|
||||
title = DSLSettingsText.from(R.string.preferences_communication__sealed_sender_allow_from_anyone),
|
||||
summary = DSLSettingsText.from(R.string.preferences_communication__sealed_sender_allow_from_anyone_description),
|
||||
isChecked = state.allowSealedSenderFromAnyone
|
||||
) {
|
||||
viewModel.setAllowSealedSenderFromAnyone(!state.allowSealedSenderFromAnyone)
|
||||
}
|
||||
|
||||
textPref(
|
||||
summary = DSLSettingsText.from(sealedSenderSummary)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPushToggleSummary(isPushEnabled: Boolean): String {
|
||||
return if (isPushEnabled) {
|
||||
PhoneNumberFormatter.prettyPrint(TextSecurePreferences.getLocalNumber(requireContext()))
|
||||
} else {
|
||||
getString(R.string.preferences__free_private_messages_and_calls)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.privacy.advanced
|
||||
|
||||
import android.content.Context
|
||||
import com.google.firebase.iid.FirebaseInstanceId
|
||||
import org.signal.core.util.concurrent.SignalExecutors
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceConfigurationUpdateJob
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.libsignal.util.guava.Optional
|
||||
import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException
|
||||
import java.io.IOException
|
||||
|
||||
private val TAG = Log.tag(AdvancedPrivacySettingsRepository::class.java)
|
||||
|
||||
class AdvancedPrivacySettingsRepository(private val context: Context) {
|
||||
|
||||
fun disablePushMessages(consumer: (DisablePushMessagesResult) -> Unit) {
|
||||
SignalExecutors.BOUNDED.execute {
|
||||
val result = try {
|
||||
val accountManager = ApplicationDependencies.getSignalServiceAccountManager()
|
||||
try {
|
||||
accountManager.setGcmId(Optional.absent())
|
||||
} catch (e: AuthorizationFailedException) {
|
||||
Log.w(TAG, e)
|
||||
}
|
||||
if (!TextSecurePreferences.isFcmDisabled(context)) {
|
||||
FirebaseInstanceId.getInstance().deleteInstanceId()
|
||||
}
|
||||
DisablePushMessagesResult.SUCCESS
|
||||
} catch (ioe: IOException) {
|
||||
Log.w(TAG, ioe)
|
||||
DisablePushMessagesResult.NETWORK_ERROR
|
||||
}
|
||||
|
||||
consumer(result)
|
||||
}
|
||||
}
|
||||
|
||||
fun syncShowSealedSenderIconState() {
|
||||
SignalExecutors.BOUNDED.execute {
|
||||
DatabaseFactory.getRecipientDatabase(context).markNeedsSync(Recipient.self().id)
|
||||
StorageSyncHelper.scheduleSyncForDataChange()
|
||||
ApplicationDependencies.getJobManager().add(
|
||||
MultiDeviceConfigurationUpdateJob(
|
||||
TextSecurePreferences.isReadReceiptsEnabled(context),
|
||||
TextSecurePreferences.isTypingIndicatorsEnabled(context),
|
||||
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(context),
|
||||
SignalStore.settings().isLinkPreviewsEnabled
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
enum class DisablePushMessagesResult {
|
||||
SUCCESS,
|
||||
NETWORK_ERROR
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.privacy.advanced
|
||||
|
||||
data class AdvancedPrivacySettingsState(
|
||||
val isPushEnabled: Boolean,
|
||||
val alwaysRelayCalls: Boolean,
|
||||
val showSealedSenderStatusIcon: Boolean,
|
||||
val allowSealedSenderFromAnyone: Boolean,
|
||||
val showProgressSpinner: Boolean
|
||||
)
|
||||
@@ -0,0 +1,95 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.privacy.advanced
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.util.SingleLiveEvent
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.thoughtcrime.securesms.util.livedata.Store
|
||||
|
||||
class AdvancedPrivacySettingsViewModel(
|
||||
private val sharedPreferences: SharedPreferences,
|
||||
private val repository: AdvancedPrivacySettingsRepository
|
||||
) : ViewModel() {
|
||||
|
||||
private val store = Store(getState())
|
||||
private val singleEvents = SingleLiveEvent<Event>()
|
||||
|
||||
val state: LiveData<AdvancedPrivacySettingsState> = store.stateLiveData
|
||||
val events: LiveData<Event> = singleEvents
|
||||
|
||||
fun disablePushMessages() {
|
||||
store.update { getState().copy(showProgressSpinner = true) }
|
||||
|
||||
repository.disablePushMessages {
|
||||
when (it) {
|
||||
AdvancedPrivacySettingsRepository.DisablePushMessagesResult.SUCCESS -> {
|
||||
TextSecurePreferences.setPushRegistered(ApplicationDependencies.getApplication(), false)
|
||||
SignalStore.registrationValues().clearRegistrationComplete()
|
||||
}
|
||||
AdvancedPrivacySettingsRepository.DisablePushMessagesResult.NETWORK_ERROR -> {
|
||||
singleEvents.postValue(Event.DISABLE_PUSH_FAILED)
|
||||
}
|
||||
}
|
||||
|
||||
store.update { getState().copy(showProgressSpinner = false) }
|
||||
}
|
||||
}
|
||||
|
||||
fun setAlwaysRelayCalls(enabled: Boolean) {
|
||||
sharedPreferences.edit().putBoolean(TextSecurePreferences.ALWAYS_RELAY_CALLS_PREF, enabled).apply()
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun setShowStatusIconForSealedSender(enabled: Boolean) {
|
||||
sharedPreferences.edit().putBoolean(TextSecurePreferences.SHOW_UNIDENTIFIED_DELIVERY_INDICATORS, enabled).apply()
|
||||
repository.syncShowSealedSenderIconState()
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun setAllowSealedSenderFromAnyone(enabled: Boolean) {
|
||||
sharedPreferences.edit().putBoolean(TextSecurePreferences.UNIVERSAL_UNIDENTIFIED_ACCESS, enabled).apply()
|
||||
ApplicationDependencies.getJobManager().add(RefreshAttributesJob())
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun refresh() {
|
||||
store.update { getState().copy(showProgressSpinner = it.showProgressSpinner) }
|
||||
}
|
||||
|
||||
private fun getState() = AdvancedPrivacySettingsState(
|
||||
isPushEnabled = TextSecurePreferences.isPushRegistered(ApplicationDependencies.getApplication()),
|
||||
alwaysRelayCalls = TextSecurePreferences.isTurnOnly(ApplicationDependencies.getApplication()),
|
||||
showSealedSenderStatusIcon = TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(
|
||||
ApplicationDependencies.getApplication()
|
||||
),
|
||||
allowSealedSenderFromAnyone = TextSecurePreferences.isUniversalUnidentifiedAccess(
|
||||
ApplicationDependencies.getApplication()
|
||||
),
|
||||
false
|
||||
)
|
||||
|
||||
enum class Event {
|
||||
DISABLE_PUSH_FAILED
|
||||
}
|
||||
|
||||
class Factory(
|
||||
private val sharedPreferences: SharedPreferences,
|
||||
private val repository: AdvancedPrivacySettingsRepository
|
||||
) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
|
||||
return requireNotNull(
|
||||
modelClass.cast(
|
||||
AdvancedPrivacySettingsViewModel(
|
||||
sharedPreferences,
|
||||
repository
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.wrapped
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.fragment.app.Fragment
|
||||
import org.thoughtcrime.securesms.R
|
||||
|
||||
/**
|
||||
* Wraps a fragment to give it a Settings style toolbar. This class should be used sparingly, and
|
||||
* is really only here as stop-gap as we migrate more settings screens to the new UI
|
||||
*/
|
||||
abstract class SettingsWrapperFragment : Fragment(R.layout.settings_wrapper_fragment) {
|
||||
|
||||
protected lateinit var toolbar: Toolbar
|
||||
private set
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
|
||||
toolbar = view.findViewById(R.id.toolbar)
|
||||
|
||||
toolbar.setNavigationOnClickListener {
|
||||
onBackPressed()
|
||||
}
|
||||
|
||||
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, OnBackPressed())
|
||||
|
||||
childFragmentManager
|
||||
.beginTransaction()
|
||||
.replace(R.id.wrapped_fragment, getFragment())
|
||||
.commit()
|
||||
}
|
||||
|
||||
abstract fun getFragment(): Fragment
|
||||
|
||||
fun setTitle(@StringRes titleId: Int) {
|
||||
toolbar.setTitle(titleId)
|
||||
}
|
||||
|
||||
private fun onBackPressed() {
|
||||
if (!childFragmentManager.popBackStackImmediate()) {
|
||||
requireActivity().onNavigateUp()
|
||||
}
|
||||
}
|
||||
|
||||
private inner class OnBackPressed : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
onBackPressed()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.wrapped
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.preferences.AdvancedPinPreferenceFragment
|
||||
|
||||
class WrappedAdvancedPinPreferenceFragment : SettingsWrapperFragment() {
|
||||
override fun getFragment(): Fragment {
|
||||
toolbar.setTitle(R.string.preferences__advanced_pin_settings)
|
||||
return AdvancedPinPreferenceFragment()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.wrapped
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.preferences.BackupsPreferenceFragment
|
||||
|
||||
class WrappedBackupsPreferenceFragment : SettingsWrapperFragment() {
|
||||
override fun getFragment(): Fragment {
|
||||
toolbar.setTitle(R.string.BackupsPreferenceFragment__chat_backups)
|
||||
return BackupsPreferenceFragment()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.wrapped
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.delete.DeleteAccountFragment
|
||||
|
||||
class WrappedDeleteAccountFragment : SettingsWrapperFragment() {
|
||||
override fun getFragment(): Fragment {
|
||||
toolbar.setTitle(R.string.preferences__delete_account)
|
||||
return DeleteAccountFragment()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.wrapped
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.preferences.EditProxyFragment
|
||||
|
||||
class WrappedEditProxyFragment : SettingsWrapperFragment() {
|
||||
override fun getFragment(): Fragment {
|
||||
toolbar.setTitle(R.string.preferences_use_proxy)
|
||||
return EditProxyFragment()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.wrapped
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.help.HelpFragment
|
||||
|
||||
class WrappedHelpFragment : SettingsWrapperFragment() {
|
||||
override fun getFragment(): Fragment {
|
||||
toolbar.title = getString(R.string.preferences__help)
|
||||
|
||||
val fragment = HelpFragment()
|
||||
fragment.arguments = arguments
|
||||
|
||||
return fragment
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.wrapped
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.preferences.MmsPreferencesFragment
|
||||
|
||||
class WrappedMmsPreferencesFragment : SettingsWrapperFragment() {
|
||||
override fun getFragment(): Fragment {
|
||||
toolbar.setTitle(R.string.preferences__advanced_mms_access_point_names)
|
||||
return MmsPreferencesFragment()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.wrapped
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import org.thoughtcrime.securesms.preferences.StoragePreferenceFragment
|
||||
|
||||
class WrappedStoragePreferenceFragment : SettingsWrapperFragment() {
|
||||
override fun getFragment(): Fragment {
|
||||
return StoragePreferenceFragment()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
package org.thoughtcrime.securesms.components.settings
|
||||
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import org.thoughtcrime.securesms.util.MappingModel
|
||||
import org.thoughtcrime.securesms.util.MappingModelList
|
||||
|
||||
private const val UNSET = -1
|
||||
|
||||
fun configure(init: DSLConfiguration.() -> Unit): DSLConfiguration {
|
||||
val configuration = DSLConfiguration()
|
||||
configuration.init()
|
||||
return configuration
|
||||
}
|
||||
|
||||
class DSLConfiguration {
|
||||
private val children = arrayListOf<PreferenceModel<*>>()
|
||||
|
||||
fun customPref(customPreference: PreferenceModel<*>) {
|
||||
children.add(customPreference)
|
||||
}
|
||||
|
||||
fun radioListPref(
|
||||
title: DSLSettingsText,
|
||||
@DrawableRes iconId: Int = UNSET,
|
||||
isEnabled: Boolean = true,
|
||||
listItems: Array<String>,
|
||||
selected: Int,
|
||||
onSelected: (Int) -> Unit
|
||||
) {
|
||||
val preference = RadioListPreference(title, iconId, isEnabled, listItems, selected, onSelected)
|
||||
children.add(preference)
|
||||
}
|
||||
|
||||
fun multiSelectPref(
|
||||
title: DSLSettingsText,
|
||||
isEnabled: Boolean = true,
|
||||
listItems: Array<String>,
|
||||
selected: BooleanArray,
|
||||
onSelected: (BooleanArray) -> Unit
|
||||
) {
|
||||
val preference = MultiSelectListPreference(title, isEnabled, listItems, selected, onSelected)
|
||||
children.add(preference)
|
||||
}
|
||||
|
||||
fun switchPref(
|
||||
title: DSLSettingsText,
|
||||
summary: DSLSettingsText? = null,
|
||||
@DrawableRes iconId: Int = UNSET,
|
||||
isEnabled: Boolean = true,
|
||||
isChecked: Boolean,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
val preference = SwitchPreference(title, summary, iconId, isEnabled, isChecked, onClick)
|
||||
children.add(preference)
|
||||
}
|
||||
|
||||
fun clickPref(
|
||||
title: DSLSettingsText,
|
||||
summary: DSLSettingsText? = null,
|
||||
@DrawableRes iconId: Int = UNSET,
|
||||
isEnabled: Boolean = true,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
val preference = ClickPreference(title, summary, iconId, isEnabled, onClick)
|
||||
children.add(preference)
|
||||
}
|
||||
|
||||
fun externalLinkPref(
|
||||
title: DSLSettingsText,
|
||||
@DrawableRes iconId: Int = UNSET,
|
||||
@StringRes linkId: Int
|
||||
) {
|
||||
val preference = ExternalLinkPreference(title, iconId, linkId)
|
||||
children.add(preference)
|
||||
}
|
||||
|
||||
fun dividerPref() {
|
||||
val preference = DividerPreference()
|
||||
children.add(preference)
|
||||
}
|
||||
|
||||
fun sectionHeaderPref(title: DSLSettingsText) {
|
||||
val preference = SectionHeaderPreference(title)
|
||||
children.add(preference)
|
||||
}
|
||||
|
||||
fun sectionHeaderPref(title: Int) {
|
||||
val preference = SectionHeaderPreference(DSLSettingsText.from(title))
|
||||
children.add(preference)
|
||||
}
|
||||
|
||||
fun textPref(
|
||||
title: DSLSettingsText? = null,
|
||||
summary: DSLSettingsText? = null
|
||||
) {
|
||||
val preference = TextPreference(title, summary)
|
||||
children.add(preference)
|
||||
}
|
||||
|
||||
fun toMappingModelList(): MappingModelList = MappingModelList().apply { addAll(children) }
|
||||
}
|
||||
|
||||
abstract class PreferenceModel<T : PreferenceModel<T>>(
|
||||
open val title: DSLSettingsText? = null,
|
||||
open val summary: DSLSettingsText? = null,
|
||||
@DrawableRes open val iconId: Int = UNSET,
|
||||
open val isEnabled: Boolean = true
|
||||
) : MappingModel<T> {
|
||||
override fun areItemsTheSame(newItem: T): Boolean {
|
||||
return when {
|
||||
title != null -> title == newItem.title
|
||||
summary != null -> summary == newItem.summary
|
||||
else -> throw AssertionError("Could not determine equality.")
|
||||
}
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
override fun areContentsTheSame(newItem: T): Boolean {
|
||||
return areItemsTheSame(newItem) &&
|
||||
newItem.summary == summary &&
|
||||
newItem.iconId == iconId &&
|
||||
newItem.isEnabled == isEnabled
|
||||
}
|
||||
}
|
||||
|
||||
class TextPreference(
|
||||
title: DSLSettingsText?,
|
||||
summary: DSLSettingsText?
|
||||
) : PreferenceModel<TextPreference>(title = title, summary = summary)
|
||||
|
||||
class DividerPreference : PreferenceModel<DividerPreference>() {
|
||||
override fun areItemsTheSame(newItem: DividerPreference) = false
|
||||
}
|
||||
|
||||
class RadioListPreference(
|
||||
override val title: DSLSettingsText,
|
||||
@DrawableRes override val iconId: Int = UNSET,
|
||||
override val isEnabled: Boolean,
|
||||
val listItems: Array<String>,
|
||||
val selected: Int,
|
||||
val onSelected: (Int) -> Unit
|
||||
) : PreferenceModel<RadioListPreference>(title = title, iconId = iconId, isEnabled = isEnabled) {
|
||||
|
||||
override fun areContentsTheSame(newItem: RadioListPreference): Boolean {
|
||||
return super.areContentsTheSame(newItem) && listItems.contentEquals(newItem.listItems) && selected == newItem.selected
|
||||
}
|
||||
}
|
||||
|
||||
class MultiSelectListPreference(
|
||||
override val title: DSLSettingsText,
|
||||
override val isEnabled: Boolean,
|
||||
val listItems: Array<String>,
|
||||
val selected: BooleanArray,
|
||||
val onSelected: (BooleanArray) -> Unit
|
||||
) : PreferenceModel<MultiSelectListPreference>(title = title, isEnabled = isEnabled) {
|
||||
override fun areContentsTheSame(newItem: MultiSelectListPreference): Boolean {
|
||||
return super.areContentsTheSame(newItem) &&
|
||||
listItems.contentEquals(newItem.listItems) &&
|
||||
selected.contentEquals(newItem.selected)
|
||||
}
|
||||
}
|
||||
|
||||
class SwitchPreference(
|
||||
override val title: DSLSettingsText,
|
||||
override val summary: DSLSettingsText? = null,
|
||||
@DrawableRes override val iconId: Int = UNSET,
|
||||
isEnabled: Boolean,
|
||||
val isChecked: Boolean,
|
||||
val onClick: () -> Unit
|
||||
) : PreferenceModel<SwitchPreference>(title = title, summary = summary, iconId = iconId, isEnabled = isEnabled) {
|
||||
override fun areContentsTheSame(newItem: SwitchPreference): Boolean {
|
||||
return super.areContentsTheSame(newItem) && isChecked == newItem.isChecked
|
||||
}
|
||||
}
|
||||
|
||||
class ClickPreference(
|
||||
override val title: DSLSettingsText,
|
||||
override val summary: DSLSettingsText?,
|
||||
@DrawableRes override val iconId: Int,
|
||||
isEnabled: Boolean,
|
||||
val onClick: () -> Unit
|
||||
) : PreferenceModel<ClickPreference>(title = title, summary = summary, iconId = iconId, isEnabled = isEnabled)
|
||||
|
||||
class ExternalLinkPreference(
|
||||
override val title: DSLSettingsText,
|
||||
@DrawableRes override val iconId: Int,
|
||||
@StringRes val linkId: Int
|
||||
) : PreferenceModel<ExternalLinkPreference>(title = title, iconId = iconId)
|
||||
|
||||
class SectionHeaderPreference(override val title: DSLSettingsText) : PreferenceModel<SectionHeaderPreference>(title = title)
|
||||
@@ -13,6 +13,7 @@ import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.DateUtils;
|
||||
@@ -67,7 +68,7 @@ class VoiceNoteMediaDescriptionCompatFactory {
|
||||
extras.putString(EXTRA_COLOR, threadRecipient.getColor().serialize());
|
||||
extras.putLong(EXTRA_MESSAGE_ID, messageRecord.getId());
|
||||
|
||||
NotificationPrivacyPreference preference = TextSecurePreferences.getNotificationPrivacy(context);
|
||||
NotificationPrivacyPreference preference = SignalStore.settings().getMessageNotificationsPrivacy();
|
||||
|
||||
String title;
|
||||
if (preference.isDisplayContact() && threadRecipient.isGroup()) {
|
||||
|
||||
@@ -19,6 +19,7 @@ import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.color.MaterialColor;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
|
||||
import org.thoughtcrime.securesms.conversation.ConversationIntents;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
@@ -130,7 +131,7 @@ class VoiceNoteNotificationManager {
|
||||
|
||||
@Override
|
||||
public @Nullable Bitmap getCurrentLargeIcon(Player player, PlayerNotificationManager.BitmapCallback callback) {
|
||||
if (!hasMetadata() || !TextSecurePreferences.getNotificationPrivacy(context).isDisplayContact()) {
|
||||
if (!hasMetadata() || !SignalStore.settings().getMessageNotificationsPrivacy().isDisplayContact()) {
|
||||
cachedBitmap = null;
|
||||
cachedRecipientId = null;
|
||||
return null;
|
||||
|
||||
@@ -13,6 +13,7 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MessageDatabase;
|
||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||
@@ -57,7 +58,7 @@ public class TurnOffContactJoinedNotificationsActivity extends AppCompatActivity
|
||||
List<MessageDatabase.MarkedMessageInfo> marked = threadDatabase.setRead(getIntent().getLongExtra(EXTRA_THREAD_ID, -1), false);
|
||||
MarkReadReceiver.process(this, marked);
|
||||
|
||||
TextSecurePreferences.setNewContactsNotificationEnabled(this, false);
|
||||
SignalStore.settings().setNotifyWhenContactJoinsSignal(false);
|
||||
ApplicationDependencies.getMessageNotifier().updateNotification(this);
|
||||
|
||||
return null;
|
||||
|
||||
@@ -463,7 +463,7 @@ public class DirectoryHelper {
|
||||
private static void notifyNewUsers(@NonNull Context context,
|
||||
@NonNull Collection<RecipientId> newUsers)
|
||||
{
|
||||
if (!TextSecurePreferences.isNewContactsNotificationEnabled(context)) return;
|
||||
if (!SignalStore.settings().isNotifyWhenContactJoinsSignal()) return;
|
||||
|
||||
for (RecipientId newUser: newUsers) {
|
||||
Recipient recipient = Recipient.resolved(newUser);
|
||||
|
||||
@@ -2184,7 +2184,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
|
||||
stickerViewModel.getStickersAvailability().observe(this, stickersAvailable -> {
|
||||
if (stickersAvailable == null) return;
|
||||
|
||||
boolean isSystemEmojiPreferred = TextSecurePreferences.isSystemEmojiPreferred(this);
|
||||
boolean isSystemEmojiPreferred = SignalStore.settings().isPreferSystemEmoji();
|
||||
MediaKeyboardMode keyboardMode = TextSecurePreferences.getMediaKeyboardMode(this);
|
||||
boolean stickerIntro = !TextSecurePreferences.hasSeenStickerIntroTooltip(this);
|
||||
|
||||
@@ -2631,7 +2631,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
|
||||
}
|
||||
|
||||
private void initializeMediaKeyboardProviders(@NonNull MediaKeyboard mediaKeyboard, boolean stickersAvailable) {
|
||||
boolean isSystemEmojiPreferred = TextSecurePreferences.isSystemEmojiPreferred(this);
|
||||
boolean isSystemEmojiPreferred = SignalStore.settings().isPreferSystemEmoji();
|
||||
|
||||
if (stickersAvailable) {
|
||||
if (isSystemEmojiPreferred) {
|
||||
@@ -3277,7 +3277,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
|
||||
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
if (keyCode == KeyEvent.KEYCODE_ENTER) {
|
||||
if (TextSecurePreferences.isEnterSendsEnabled(ConversationActivity.this)) {
|
||||
if (SignalStore.settings().isEnterKeySends()) {
|
||||
sendButton.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
|
||||
sendButton.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER));
|
||||
return true;
|
||||
|
||||
@@ -69,7 +69,6 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import org.signal.core.util.StreamUtil;
|
||||
import org.signal.core.util.concurrent.SignalExecutors;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
||||
import org.thoughtcrime.securesms.LoggingFragment;
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
@@ -81,6 +80,7 @@ import org.thoughtcrime.securesms.components.MaskView;
|
||||
import org.thoughtcrime.securesms.components.TooltipPopup;
|
||||
import org.thoughtcrime.securesms.components.TypingStatusRepository;
|
||||
import org.thoughtcrime.securesms.components.recyclerview.SmoothScrollingLinearLayoutManager;
|
||||
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity;
|
||||
import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaController;
|
||||
import org.thoughtcrime.securesms.components.voice.VoiceNotePlaybackState;
|
||||
import org.thoughtcrime.securesms.contactshare.Contact;
|
||||
@@ -1568,10 +1568,7 @@ public class ConversationFragment extends LoggingFragment {
|
||||
d.dismiss();
|
||||
})
|
||||
.setNeutralButton(R.string.ConversationFragment_contact_us, (d, w) -> {
|
||||
Intent intent = new Intent(requireContext(), ApplicationPreferencesActivity.class);
|
||||
intent.putExtra(ApplicationPreferencesActivity.LAUNCH_TO_HELP_FRAGMENT, true);
|
||||
|
||||
startActivity(intent);
|
||||
startActivity(AppSettingsActivity.help(requireContext(), 0));
|
||||
d.dismiss();
|
||||
})
|
||||
.show();
|
||||
|
||||
@@ -651,7 +651,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||
{
|
||||
bodyText.setClickable(false);
|
||||
bodyText.setFocusable(false);
|
||||
bodyText.setTextSize(TypedValue.COMPLEX_UNIT_SP, TextSecurePreferences.getMessageBodyTextSize(context));
|
||||
bodyText.setTextSize(TypedValue.COMPLEX_UNIT_SP, SignalStore.settings().getMessageFontSize());
|
||||
bodyText.setMovementMethod(LongClickMovementMethod.getInstance(getContext()));
|
||||
|
||||
if (messageRecord.isRemoteDelete()) {
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.conversation.ConversationFragment;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||
import org.thoughtcrime.securesms.util.DeviceProperties;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
@@ -53,7 +54,7 @@ public final class EnableCallNotificationSettingsDialog extends DialogFragment {
|
||||
|
||||
public static void fixAutomatically(@NonNull Context context) {
|
||||
if (areCallNotificationsDisabled(context)) {
|
||||
TextSecurePreferences.setCallNotificationsEnabled(context, true);
|
||||
SignalStore.settings().setCallNotificationsEnabled(true);
|
||||
Toast.makeText(context, R.string.EnableCallNotificationSettingsDialog__call_notifications_enabled, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
@@ -198,7 +199,7 @@ public final class EnableCallNotificationSettingsDialog extends DialogFragment {
|
||||
}
|
||||
|
||||
private static boolean areCallNotificationsDisabled(Context context) {
|
||||
return !TextSecurePreferences.isCallNotificationsEnabled(context);
|
||||
return !SignalStore.settings().isCallNotificationsEnabled();
|
||||
}
|
||||
|
||||
private static boolean isCallChannelInvalid(Context context) {
|
||||
|
||||
@@ -71,7 +71,6 @@ import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
import org.signal.core.util.concurrent.SignalExecutors;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
||||
import org.thoughtcrime.securesms.MainFragment;
|
||||
import org.thoughtcrime.securesms.MainNavigator;
|
||||
import org.thoughtcrime.securesms.NewConversationActivity;
|
||||
@@ -89,6 +88,7 @@ import org.thoughtcrime.securesms.components.reminder.Reminder;
|
||||
import org.thoughtcrime.securesms.components.reminder.ReminderView;
|
||||
import org.thoughtcrime.securesms.components.reminder.ServiceOutageReminder;
|
||||
import org.thoughtcrime.securesms.components.reminder.UnauthorizedReminder;
|
||||
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity;
|
||||
import org.thoughtcrime.securesms.conversation.ConversationFragment;
|
||||
import org.thoughtcrime.securesms.conversationlist.model.Conversation;
|
||||
import org.thoughtcrime.securesms.conversationlist.model.MessageResult;
|
||||
@@ -132,6 +132,7 @@ import org.thoughtcrime.securesms.util.SnapToTopDataObserver;
|
||||
import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
|
||||
import org.thoughtcrime.securesms.util.Stopwatch;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.thoughtcrime.securesms.util.WindowUtil;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||
@@ -269,7 +270,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||
updateReminders();
|
||||
EventBus.getDefault().register(this);
|
||||
|
||||
if (TextSecurePreferences.isSmsEnabled(requireContext())) {
|
||||
if (Util.isDefaultSmsProvider(requireContext())) {
|
||||
InsightsLauncher.showInsightsModal(requireContext(), requireFragmentManager());
|
||||
}
|
||||
|
||||
@@ -322,7 +323,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
menu.findItem(R.id.menu_insights).setVisible(TextSecurePreferences.isSmsEnabled(requireContext()));
|
||||
menu.findItem(R.id.menu_insights).setVisible(Util.isDefaultSmsProvider(requireContext()));
|
||||
menu.findItem(R.id.menu_clear_passphrase).setVisible(!TextSecurePreferences.isPasswordDisabled(requireContext()));
|
||||
}
|
||||
|
||||
@@ -947,10 +948,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
||||
}
|
||||
|
||||
private void onProxyStatusClicked() {
|
||||
Intent intent = new Intent(requireContext(), ApplicationPreferencesActivity.class);
|
||||
intent.putExtra(ApplicationPreferencesActivity.LAUNCH_TO_PROXY_FRAGMENT, true);
|
||||
|
||||
startActivity(intent);
|
||||
startActivity(AppSettingsActivity.proxy(requireContext()));
|
||||
}
|
||||
|
||||
protected void onPostSubmitList(int conversationCount) {
|
||||
|
||||
@@ -50,6 +50,7 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.ReactionList;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.groups.GroupId;
|
||||
import org.thoughtcrime.securesms.jobs.RefreshPreKeysJob;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
||||
import org.thoughtcrime.securesms.profiles.AvatarHelper;
|
||||
@@ -402,7 +403,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper implements SignalDatab
|
||||
Uri messageSoundUri = messageSound != null ? Uri.parse(messageSound) : null;
|
||||
int vibrateState = cursor.getInt(cursor.getColumnIndexOrThrow("vibrate"));
|
||||
String displayName = NotificationChannels.getChannelDisplayNameFor(context, systemName, profileName, null, address);
|
||||
boolean vibrateEnabled = vibrateState == 0 ? TextSecurePreferences.isNotificationVibrateEnabled(context) : vibrateState == 1;
|
||||
boolean vibrateEnabled = vibrateState == 0 ? SignalStore.settings().isMessageVibrateEnabled() :vibrateState == 1;
|
||||
|
||||
if (GroupId.isEncodedGroup(address)) {
|
||||
try(Cursor groupCursor = db.rawQuery("SELECT title FROM groups WHERE group_id = ?", new String[] { address })) {
|
||||
|
||||
@@ -31,7 +31,6 @@ import com.google.android.material.snackbar.Snackbar;
|
||||
import com.google.i18n.phonenumbers.AsYouTypeFormatter;
|
||||
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.LabeledEditText;
|
||||
import org.thoughtcrime.securesms.util.SpanUtil;
|
||||
@@ -42,13 +41,13 @@ import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
public class DeleteAccountFragment extends Fragment {
|
||||
|
||||
private ArrayAdapter<String> countrySpinnerAdapter;
|
||||
private TextView bullets;
|
||||
private LabeledEditText countryCode;
|
||||
private LabeledEditText number;
|
||||
private AsYouTypeFormatter countryFormatter;
|
||||
private DeleteAccountViewModel viewModel;
|
||||
private DialogInterface deletionProgressDialog;
|
||||
private ArrayAdapter<String> countrySpinnerAdapter;
|
||||
private TextView bullets;
|
||||
private LabeledEditText countryCode;
|
||||
private LabeledEditText number;
|
||||
private AsYouTypeFormatter countryFormatter;
|
||||
private DeleteAccountViewModel viewModel;
|
||||
private DialogInterface deletionProgressDialog;
|
||||
|
||||
@Override
|
||||
public @Nullable View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
@@ -57,8 +56,8 @@ public class DeleteAccountFragment extends Fragment {
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
Spinner countrySpinner = view.findViewById(R.id.delete_account_fragment_country_spinner);
|
||||
View confirm = view.findViewById(R.id.delete_account_fragment_delete);
|
||||
Spinner countrySpinner = view.findViewById(R.id.delete_account_fragment_country_spinner);
|
||||
View confirm = view.findViewById(R.id.delete_account_fragment_delete);
|
||||
|
||||
bullets = view.findViewById(R.id.delete_account_fragment_bullets);
|
||||
countryCode = view.findViewById(R.id.delete_account_fragment_country_code);
|
||||
@@ -80,12 +79,6 @@ public class DeleteAccountFragment extends Fragment {
|
||||
initializeSpinner(countrySpinner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
((ApplicationPreferencesActivity) getActivity()).getSupportActionBar().setTitle(R.string.preferences__delete_account);
|
||||
}
|
||||
|
||||
private void updateBullets(@NonNull Optional<String> formattedBalance) {
|
||||
bullets.setText(buildBulletsText(formattedBalance));
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ import androidx.annotation.StringRes;
|
||||
import androidx.navigation.fragment.NavHostFragment;
|
||||
|
||||
import org.signal.devicetransfer.DeviceToDeviceTransferService;
|
||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.devicetransfer.DeviceTransferSetupFragment;
|
||||
import org.thoughtcrime.securesms.devicetransfer.SetupStep;
|
||||
@@ -46,9 +46,7 @@ public final class OldDeviceTransferSetupFragment extends DeviceTransferSetupFra
|
||||
|
||||
@Override
|
||||
protected void navigateWhenWifiDirectUnavailable() {
|
||||
Intent intent = new Intent(requireContext(), ApplicationPreferencesActivity.class);
|
||||
intent.putExtra(ApplicationPreferencesActivity.LAUNCH_TO_BACKUPS_FRAGMENT, true);
|
||||
startActivity(intent);
|
||||
startActivity(AppSettingsActivity.backups(requireContext()));
|
||||
requireActivity().finish();
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader;
|
||||
import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.groups.GroupsV2CapabilityChecker;
|
||||
import org.thoughtcrime.securesms.groups.ui.creategroup.details.AddGroupDetailsActivity;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
@@ -29,7 +30,7 @@ import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||
import org.thoughtcrime.securesms.util.Stopwatch;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
|
||||
@@ -56,8 +57,8 @@ public class CreateGroupActivity extends ContactSelectionActivity {
|
||||
intent.putExtra(ContactSelectionListFragment.REFRESHABLE, false);
|
||||
intent.putExtra(ContactSelectionActivity.EXTRA_LAYOUT_RES_ID, R.layout.create_group_activity);
|
||||
|
||||
int displayMode = TextSecurePreferences.isSmsEnabled(context) ? ContactsCursorLoader.DisplayMode.FLAG_SMS | ContactsCursorLoader.DisplayMode.FLAG_PUSH
|
||||
: ContactsCursorLoader.DisplayMode.FLAG_PUSH;
|
||||
int displayMode = Util.isDefaultSmsProvider(context) ? ContactsCursorLoader.DisplayMode.FLAG_SMS | ContactsCursorLoader.DisplayMode.FLAG_PUSH
|
||||
: ContactsCursorLoader.DisplayMode.FLAG_PUSH;
|
||||
|
||||
intent.putExtra(ContactSelectionListFragment.DISPLAY_MODE, displayMode);
|
||||
intent.putExtra(ContactSelectionListFragment.SELECTION_LIMITS, FeatureFlags.groupLimits().excludingSelf());
|
||||
|
||||
@@ -24,7 +24,6 @@ import com.annimon.stream.Stream;
|
||||
import com.dd.CircularProgressButton;
|
||||
|
||||
import org.signal.core.util.ResourceUtil;
|
||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
||||
import org.thoughtcrime.securesms.LoggingFragment;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiImageView;
|
||||
@@ -38,19 +37,19 @@ import java.util.List;
|
||||
|
||||
public class HelpFragment extends LoggingFragment {
|
||||
|
||||
public static final String START_CATEGORY_INDEX = "start.category.index";
|
||||
public static final String START_CATEGORY_INDEX = "start_category_index";
|
||||
public static final int PAYMENT_INDEX = 5;
|
||||
|
||||
private EditText problem;
|
||||
private CheckBox includeDebugLogs;
|
||||
private View debugLogInfo;
|
||||
private View faq;
|
||||
private CircularProgressButton next;
|
||||
private View toaster;
|
||||
private List<EmojiImageView> emoji;
|
||||
private HelpViewModel helpViewModel;
|
||||
private Spinner categorySpinner;
|
||||
private ArrayAdapter<CharSequence> categoryAdapter;
|
||||
private EditText problem;
|
||||
private CheckBox includeDebugLogs;
|
||||
private View debugLogInfo;
|
||||
private View faq;
|
||||
private CircularProgressButton next;
|
||||
private View toaster;
|
||||
private List<EmojiImageView> emoji;
|
||||
private HelpViewModel helpViewModel;
|
||||
private Spinner categorySpinner;
|
||||
private ArrayAdapter<CharSequence> categoryAdapter;
|
||||
|
||||
@Override
|
||||
public @Nullable View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
@@ -68,7 +67,6 @@ public class HelpFragment extends LoggingFragment {
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
((ApplicationPreferencesActivity) requireActivity()).requireSupportActionBar().setTitle(R.string.preferences__help);
|
||||
|
||||
cancelSpinning(next);
|
||||
problem.setEnabled(true);
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
package org.thoughtcrime.securesms.keyvalue;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||
import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference;
|
||||
import org.thoughtcrime.securesms.util.SingleLiveEvent;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.webrtc.CallBandwidthMode;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public final class SettingsValues extends SignalStoreValues {
|
||||
|
||||
public static final String LINK_PREVIEWS = "settings.link_previews";
|
||||
@@ -23,8 +31,31 @@ public final class SettingsValues extends SignalStoreValues {
|
||||
|
||||
private static final String CALL_BANDWIDTH_MODE = "settings.signal.call.bandwidth.mode";
|
||||
|
||||
public static final String THREAD_TRIM_LENGTH = "pref_trim_length";
|
||||
public static final String THREAD_TRIM_ENABLED = "pref_trim_threads";
|
||||
public static final String THREAD_TRIM_LENGTH = "pref_trim_length";
|
||||
public static final String THREAD_TRIM_ENABLED = "pref_trim_threads";
|
||||
|
||||
public static final String THEME = "settings.theme";
|
||||
public static final String MESSAGE_FONT_SIZE = "settings.message.font.size";
|
||||
public static final String LANGUAGE = "settings.language";
|
||||
public static final String PREFER_SYSTEM_EMOJI = "settings.use.system.emoji";
|
||||
public static final String ENTER_KEY_SENDS = "settings.enter.key.sends";
|
||||
public static final String BACKUPS_ENABLED = "settings.backups.enabled";
|
||||
public static final String SMS_DELIVERY_REPORTS_ENABLED = "settings.sms.delivery.reports.enabled";
|
||||
public static final String WIFI_CALLING_COMPATIBILITY_MODE_ENABLED = "settings.wifi.calling.compatibility.mode.enabled";
|
||||
public static final String MESSAGE_NOTIFICATIONS_ENABLED = "settings.message.notifications.enabled";
|
||||
public static final String MESSAGE_NOTIFICATION_SOUND = "settings.message.notifications.sound";
|
||||
public static final String MESSAGE_VIBRATE_ENABLED = "settings.message.vibrate.enabled";
|
||||
public static final String MESSAGE_LED_COLOR = "settings.message.led.color";
|
||||
public static final String MESSAGE_LED_BLINK_PATTERN = "settings.message.led.blink";
|
||||
public static final String MESSAGE_IN_CHAT_SOUNDS_ENABLED = "settings.message.in.chats.sounds.enabled";
|
||||
public static final String MESSAGE_REPEAT_ALERTS = "settings.message.repeat.alerts";
|
||||
public static final String MESSAGE_NOTIFICATION_PRIVACY = "settings.message.notification.privacy";
|
||||
public static final String CALL_NOTIFICATIONS_ENABLED = "settings.call.notifications.enabled";
|
||||
public static final String CALL_RINGTONE = "settings.call.ringtone";
|
||||
public static final String CALL_VIBRATE_ENABLED = "settings.call.vibrate.enabled";
|
||||
public static final String NOTIFY_WHEN_CONTACT_JOINS_SIGNAL = "settings.notify.when.contact.joins.signal";
|
||||
|
||||
private final SingleLiveEvent<String> onConfigurationSettingChanged = new SingleLiveEvent<>();
|
||||
|
||||
SettingsValues(@NonNull KeyValueStore store) {
|
||||
super(store);
|
||||
@@ -46,7 +77,29 @@ public final class SettingsValues extends SignalStoreValues {
|
||||
PREFER_SYSTEM_CONTACT_PHOTOS,
|
||||
CALL_BANDWIDTH_MODE,
|
||||
THREAD_TRIM_LENGTH,
|
||||
THREAD_TRIM_ENABLED);
|
||||
THREAD_TRIM_ENABLED,
|
||||
LANGUAGE,
|
||||
THEME,
|
||||
MESSAGE_FONT_SIZE,
|
||||
PREFER_SYSTEM_EMOJI,
|
||||
ENTER_KEY_SENDS,
|
||||
BACKUPS_ENABLED,
|
||||
MESSAGE_NOTIFICATIONS_ENABLED,
|
||||
MESSAGE_NOTIFICATION_SOUND,
|
||||
MESSAGE_VIBRATE_ENABLED,
|
||||
MESSAGE_LED_COLOR,
|
||||
MESSAGE_LED_BLINK_PATTERN,
|
||||
MESSAGE_IN_CHAT_SOUNDS_ENABLED,
|
||||
MESSAGE_REPEAT_ALERTS,
|
||||
MESSAGE_NOTIFICATION_PRIVACY,
|
||||
CALL_NOTIFICATIONS_ENABLED,
|
||||
CALL_RINGTONE,
|
||||
CALL_VIBRATE_ENABLED,
|
||||
NOTIFY_WHEN_CONTACT_JOINS_SIGNAL);
|
||||
}
|
||||
|
||||
public @NonNull LiveData<String> getOnConfigurationSettingChanged() {
|
||||
return onConfigurationSettingChanged;
|
||||
}
|
||||
|
||||
public boolean isLinkPreviewsEnabled() {
|
||||
@@ -114,6 +167,181 @@ public final class SettingsValues extends SignalStoreValues {
|
||||
return CallBandwidthMode.fromCode(getInteger(CALL_BANDWIDTH_MODE, CallBandwidthMode.HIGH_ALWAYS.getCode()));
|
||||
}
|
||||
|
||||
public @NonNull String getTheme() {
|
||||
return getString(THEME, TextSecurePreferences.getTheme(ApplicationDependencies.getApplication()));
|
||||
}
|
||||
|
||||
public void setTheme(@NonNull String theme) {
|
||||
putString(THEME, theme);
|
||||
onConfigurationSettingChanged.postValue(THEME);
|
||||
}
|
||||
|
||||
public int getMessageFontSize() {
|
||||
return getInteger(MESSAGE_FONT_SIZE, TextSecurePreferences.getMessageBodyTextSize(ApplicationDependencies.getApplication()));
|
||||
}
|
||||
|
||||
public void setMessageFontSize(int messageFontSize) {
|
||||
putInteger(MESSAGE_FONT_SIZE, messageFontSize);
|
||||
}
|
||||
|
||||
public @NonNull String getLanguage() {
|
||||
return TextSecurePreferences.getLanguage(ApplicationDependencies.getApplication());
|
||||
}
|
||||
|
||||
public void setLanguage(@NonNull String language) {
|
||||
TextSecurePreferences.setLanguage(ApplicationDependencies.getApplication(), language);
|
||||
onConfigurationSettingChanged.postValue(LANGUAGE);
|
||||
}
|
||||
|
||||
public boolean isPreferSystemEmoji() {
|
||||
return getBoolean(PREFER_SYSTEM_EMOJI, TextSecurePreferences.isSystemEmojiPreferred(ApplicationDependencies.getApplication()));
|
||||
}
|
||||
|
||||
public void setPreferSystemEmoji(boolean useSystemEmoji) {
|
||||
putBoolean(PREFER_SYSTEM_EMOJI, useSystemEmoji);
|
||||
}
|
||||
|
||||
public boolean isEnterKeySends() {
|
||||
return getBoolean(ENTER_KEY_SENDS, TextSecurePreferences.isEnterSendsEnabled(ApplicationDependencies.getApplication()));
|
||||
}
|
||||
|
||||
public void setEnterKeySends(boolean enterKeySends) {
|
||||
putBoolean(ENTER_KEY_SENDS, enterKeySends);
|
||||
}
|
||||
|
||||
public boolean isBackupEnabled() {
|
||||
return getBoolean(BACKUPS_ENABLED, TextSecurePreferences.isBackupEnabled(ApplicationDependencies.getApplication()));
|
||||
}
|
||||
|
||||
public void setBackupEnabled(boolean backupEnabled) {
|
||||
putBoolean(BACKUPS_ENABLED, backupEnabled);
|
||||
}
|
||||
|
||||
public boolean isSmsDeliveryReportsEnabled() {
|
||||
return getBoolean(SMS_DELIVERY_REPORTS_ENABLED, TextSecurePreferences.isSmsDeliveryReportsEnabled(ApplicationDependencies.getApplication()));
|
||||
}
|
||||
|
||||
public void setSmsDeliveryReportsEnabled(boolean smsDeliveryReportsEnabled) {
|
||||
putBoolean(SMS_DELIVERY_REPORTS_ENABLED, smsDeliveryReportsEnabled);
|
||||
}
|
||||
|
||||
public boolean isWifiCallingCompatibilityModeEnabled() {
|
||||
return getBoolean(WIFI_CALLING_COMPATIBILITY_MODE_ENABLED, TextSecurePreferences.isWifiSmsEnabled(ApplicationDependencies.getApplication()));
|
||||
}
|
||||
|
||||
public void setWifiCallingCompatibilityModeEnabled(boolean wifiCallingCompatibilityModeEnabled) {
|
||||
putBoolean(WIFI_CALLING_COMPATIBILITY_MODE_ENABLED, wifiCallingCompatibilityModeEnabled);
|
||||
}
|
||||
|
||||
public void setMessageNotificationsEnabled(boolean messageNotificationsEnabled) {
|
||||
putBoolean(MESSAGE_NOTIFICATIONS_ENABLED, messageNotificationsEnabled);
|
||||
}
|
||||
|
||||
public boolean isMessageNotificationsEnabled() {
|
||||
return getBoolean(MESSAGE_NOTIFICATIONS_ENABLED, TextSecurePreferences.isNotificationsEnabled(ApplicationDependencies.getApplication()));
|
||||
}
|
||||
|
||||
public void setMessageNotificationSound(@NonNull Uri sound) {
|
||||
putString(MESSAGE_NOTIFICATION_SOUND, sound.toString());
|
||||
}
|
||||
|
||||
public @NonNull Uri getMessageNotificationSound() {
|
||||
String result = getString(MESSAGE_NOTIFICATION_SOUND, TextSecurePreferences.getNotificationRingtone(ApplicationDependencies.getApplication()).toString());
|
||||
|
||||
if (result.startsWith("file:")) {
|
||||
result = Settings.System.DEFAULT_NOTIFICATION_URI.toString();
|
||||
}
|
||||
|
||||
return Uri.parse(result);
|
||||
}
|
||||
|
||||
public boolean isMessageVibrateEnabled() {
|
||||
return getBoolean(MESSAGE_VIBRATE_ENABLED, TextSecurePreferences.isNotificationVibrateEnabled(ApplicationDependencies.getApplication()));
|
||||
}
|
||||
|
||||
public void setMessageVibrateEnabled(boolean messageVibrateEnabled) {
|
||||
putBoolean(MESSAGE_VIBRATE_ENABLED, messageVibrateEnabled);
|
||||
}
|
||||
|
||||
public @NonNull String getMessageLedColor() {
|
||||
return getString(MESSAGE_LED_COLOR, TextSecurePreferences.getNotificationLedColor(ApplicationDependencies.getApplication()));
|
||||
}
|
||||
|
||||
public void setMessageLedColor(@NonNull String ledColor) {
|
||||
putString(MESSAGE_LED_COLOR, ledColor);
|
||||
}
|
||||
|
||||
public @NonNull String getMessageLedBlinkPattern() {
|
||||
return getString(MESSAGE_LED_BLINK_PATTERN, TextSecurePreferences.getNotificationLedPattern(ApplicationDependencies.getApplication()));
|
||||
}
|
||||
|
||||
public void setMessageLedBlinkPattern(@NonNull String blinkPattern) {
|
||||
putString(MESSAGE_LED_BLINK_PATTERN, blinkPattern);
|
||||
}
|
||||
|
||||
public boolean isMessageNotificationsInChatSoundsEnabled() {
|
||||
return getBoolean(MESSAGE_IN_CHAT_SOUNDS_ENABLED, TextSecurePreferences.isInThreadNotifications(ApplicationDependencies.getApplication()));
|
||||
}
|
||||
|
||||
public void setMessageNotificationsInChatSoundsEnabled(boolean inChatSoundsEnabled) {
|
||||
putBoolean(MESSAGE_IN_CHAT_SOUNDS_ENABLED, inChatSoundsEnabled);
|
||||
}
|
||||
|
||||
public int getMessageNotificationsRepeatAlerts() {
|
||||
return getInteger(MESSAGE_REPEAT_ALERTS, TextSecurePreferences.getRepeatAlertsCount(ApplicationDependencies.getApplication()));
|
||||
}
|
||||
|
||||
public void setMessageNotificationsRepeatAlerts(int count) {
|
||||
putInteger(MESSAGE_REPEAT_ALERTS, count);
|
||||
}
|
||||
|
||||
public @NonNull NotificationPrivacyPreference getMessageNotificationsPrivacy() {
|
||||
return new NotificationPrivacyPreference(getString(MESSAGE_NOTIFICATION_PRIVACY, TextSecurePreferences.getNotificationPrivacy(ApplicationDependencies.getApplication()).toString()));
|
||||
}
|
||||
|
||||
public void setMessageNotificationsPrivacy(@NonNull NotificationPrivacyPreference messageNotificationsPrivacy) {
|
||||
putString(MESSAGE_NOTIFICATION_PRIVACY, messageNotificationsPrivacy.toString());
|
||||
}
|
||||
|
||||
public boolean isCallNotificationsEnabled() {
|
||||
return getBoolean(CALL_NOTIFICATIONS_ENABLED, TextSecurePreferences.isCallNotificationsEnabled(ApplicationDependencies.getApplication()));
|
||||
}
|
||||
|
||||
public void setCallNotificationsEnabled(boolean callNotificationsEnabled) {
|
||||
putBoolean(CALL_NOTIFICATIONS_ENABLED, callNotificationsEnabled);
|
||||
}
|
||||
|
||||
public @NonNull Uri getCallRingtone() {
|
||||
String result = getString(CALL_RINGTONE, TextSecurePreferences.getCallNotificationRingtone(ApplicationDependencies.getApplication()).toString());
|
||||
|
||||
if (result != null && result.startsWith("file:")) {
|
||||
result = Settings.System.DEFAULT_RINGTONE_URI.toString();
|
||||
}
|
||||
|
||||
return Uri.parse(result);
|
||||
}
|
||||
|
||||
public void setCallRingtone(@NonNull Uri ringtone) {
|
||||
putString(CALL_RINGTONE, ringtone.toString());
|
||||
}
|
||||
|
||||
public boolean isCallVibrateEnabled() {
|
||||
return getBoolean(CALL_VIBRATE_ENABLED, TextSecurePreferences.isCallNotificationVibrateEnabled(ApplicationDependencies.getApplication()));
|
||||
}
|
||||
|
||||
public void setCallVibrateEnabled(boolean callVibrateEnabled) {
|
||||
putBoolean(CALL_VIBRATE_ENABLED, callVibrateEnabled);
|
||||
}
|
||||
|
||||
public boolean isNotifyWhenContactJoinsSignal() {
|
||||
return getBoolean(NOTIFY_WHEN_CONTACT_JOINS_SIGNAL, TextSecurePreferences.isNewContactsNotificationEnabled(ApplicationDependencies.getApplication()));
|
||||
}
|
||||
|
||||
public void setNotifyWhenContactJoinsSignal(boolean notifyWhenContactJoinsSignal) {
|
||||
putBoolean(NOTIFY_WHEN_CONTACT_JOINS_SIGNAL, notifyWhenContactJoinsSignal);
|
||||
}
|
||||
|
||||
|
||||
private @Nullable Uri getUri(@NonNull String key) {
|
||||
String uri = getString(key, "");
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ import android.os.Build;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
||||
@@ -23,12 +23,12 @@ final class LogSectionNotifications implements LogSection {
|
||||
public @NonNull CharSequence getContent(@NonNull Context context) {
|
||||
StringBuilder output = new StringBuilder();
|
||||
|
||||
output.append("Message notifications: ").append(TextSecurePreferences.isNotificationsEnabled(context)).append("\n")
|
||||
.append("Call notifications : ").append(TextSecurePreferences.isCallNotificationsEnabled(context)).append("\n")
|
||||
.append("New contact alerts : ").append(TextSecurePreferences.isNewContactsNotificationEnabled(context)).append("\n")
|
||||
.append("In-chat sounds : ").append(TextSecurePreferences.isInThreadNotifications(context)).append("\n")
|
||||
.append("Repeat alerts : ").append(TextSecurePreferences.getRepeatAlertsCount(context)).append("\n")
|
||||
.append("Notification display : ").append(TextSecurePreferences.getNotificationPrivacy(context)).append("\n\n");
|
||||
output.append("Message notifications: ").append(SignalStore.settings().isMessageNotificationsEnabled()).append("\n")
|
||||
.append("Call notifications : ").append(SignalStore.settings().isCallNotificationsEnabled()).append("\n")
|
||||
.append("New contact alerts : ").append(SignalStore.settings().isNotifyWhenContactJoinsSignal()).append("\n")
|
||||
.append("In-chat sounds : ").append(SignalStore.settings().isMessageNotificationsInChatSoundsEnabled()).append("\n")
|
||||
.append("Repeat alerts : ").append(SignalStore.settings().getMessageNotificationsRepeatAlerts()).append("\n")
|
||||
.append("Notification display : ").append(SignalStore.settings().getMessageNotificationsPrivacy()).append("\n\n");
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 26) {
|
||||
NotificationManager manager = ServiceUtil.getNotificationManager(context);
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.color.MaterialColor;
|
||||
import org.thoughtcrime.securesms.components.ConversationItemFooter;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiTextView;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
@@ -144,7 +145,7 @@ public class LongMessageActivity extends PassphraseRequiredActivity {
|
||||
bubble.setVisibility(View.VISIBLE);
|
||||
text.setText(styledBody);
|
||||
text.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
text.setTextSize(TypedValue.COMPLEX_UNIT_SP, TextSecurePreferences.getMessageBodyTextSize(this));
|
||||
text.setTextSize(TypedValue.COMPLEX_UNIT_SP, SignalStore.settings().getMessageFontSize());
|
||||
if (message.get().getMessageRecord().isOutgoing()) {
|
||||
text.setMentionBackgroundTint(ContextCompat.getColor(this, isDarkTheme(this) ? R.color.core_grey_60 : R.color.core_grey_20));
|
||||
} else {
|
||||
|
||||
@@ -53,6 +53,7 @@ import org.thoughtcrime.securesms.components.mention.MentionAnnotation;
|
||||
import org.thoughtcrime.securesms.contactshare.SimpleTextWatcher;
|
||||
import org.thoughtcrime.securesms.conversation.ui.mentions.MentionsPickerViewModel;
|
||||
import org.thoughtcrime.securesms.imageeditor.model.EditorModel;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.mediapreview.MediaRailAdapter;
|
||||
import org.thoughtcrime.securesms.mediasend.MediaSendViewModel.HudState;
|
||||
import org.thoughtcrime.securesms.mediasend.MediaSendViewModel.ViewOnceState;
|
||||
@@ -348,7 +349,7 @@ public class MediaSendActivity extends PassphraseRequiredActivity implements Med
|
||||
return isSend;
|
||||
});
|
||||
|
||||
if (TextSecurePreferences.isSystemEmojiPreferred(this)) {
|
||||
if (SignalStore.settings().isPreferSystemEmoji()) {
|
||||
emojiToggle.setVisibility(View.GONE);
|
||||
} else {
|
||||
emojiToggle.setOnClickListener(this::onEmojiToggleClicked);
|
||||
@@ -1038,7 +1039,7 @@ public class MediaSendActivity extends PassphraseRequiredActivity implements Med
|
||||
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
if (keyCode == KeyEvent.KEYCODE_ENTER) {
|
||||
if (TextSecurePreferences.isEnterSendsEnabled(getApplicationContext())) {
|
||||
if (SignalStore.settings().isEnterKeySends()) {
|
||||
sendButton.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
|
||||
sendButton.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER));
|
||||
return true;
|
||||
|
||||
@@ -12,8 +12,8 @@ import com.annimon.stream.Stream;
|
||||
|
||||
import org.signal.core.util.TranslationDetection;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity;
|
||||
import org.thoughtcrime.securesms.conversationlist.ConversationListFragment;
|
||||
import org.thoughtcrime.securesms.database.model.MegaphoneRecord;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
@@ -293,9 +293,7 @@ public final class Megaphones {
|
||||
intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName());
|
||||
controller.onMegaphoneNavigationRequested(intent);
|
||||
} else {
|
||||
Intent intent = new Intent(context, ApplicationPreferencesActivity.class);
|
||||
intent.putExtra(ApplicationPreferencesActivity.LAUNCH_TO_NOTIFICATIONS_FRAGMENT, true);
|
||||
controller.onMegaphoneNavigationRequested(intent);
|
||||
controller.onMegaphoneNavigationRequested(AppSettingsActivity.notifications(context));
|
||||
}
|
||||
})
|
||||
.setSecondaryButton(R.string.NotificationsMegaphone_not_now, (megaphone, controller) -> controller.onMegaphoneSnooze(Event.NOTIFICATIONS))
|
||||
@@ -328,8 +326,8 @@ public final class Megaphones {
|
||||
}
|
||||
|
||||
private static boolean shouldShowNotificationsMegaphone(@NonNull Context context) {
|
||||
boolean shouldShow = !TextSecurePreferences.isNotificationsEnabled(context) ||
|
||||
!NotificationChannels.isMessageChannelEnabled(context) ||
|
||||
boolean shouldShow = !SignalStore.settings().isMessageNotificationsEnabled() ||
|
||||
!NotificationChannels.isMessageChannelEnabled(context) ||
|
||||
!NotificationChannels.isMessagesChannelGroupEnabled(context) ||
|
||||
!NotificationChannels.areNotificationsEnabled(context);
|
||||
if (shouldShow) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.backup.BackupFileIOError;
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.util.BackupUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
||||
@@ -43,13 +44,13 @@ public final class BackupNotificationMigrationJob extends MigrationJob {
|
||||
|
||||
@Override
|
||||
public void performMigration() {
|
||||
if (Build.VERSION.SDK_INT >= 29 && !TextSecurePreferences.isBackupEnabled(context) && BackupUtil.hasBackupFiles(context)) {
|
||||
if (Build.VERSION.SDK_INT >= 29 && !SignalStore.settings().isBackupEnabled() && BackupUtil.hasBackupFiles(context)) {
|
||||
Log.w(TAG, "Stranded backup! Notifying.");
|
||||
BackupFileIOError.UNKNOWN.postNotification(context);
|
||||
} else {
|
||||
Log.w(TAG, String.format(Locale.US, "Does not meet criteria. API: %d, BackupsEnabled: %s, HasFiles: %s",
|
||||
Build.VERSION.SDK_INT,
|
||||
TextSecurePreferences.isBackupEnabled(context),
|
||||
SignalStore.settings().isBackupEnabled(),
|
||||
BackupUtil.hasBackupFiles(context)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||
import org.thoughtcrime.securesms.notifications.NotificationIds;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
@@ -63,7 +64,7 @@ public class UserNotificationMigrationJob extends MigrationJob {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TextSecurePreferences.isNewContactsNotificationEnabled(context)) {
|
||||
if (!SignalStore.settings().isNotifyWhenContactJoinsSignal()) {
|
||||
Log.w(TAG, "New contact notifications disabled! Skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import androidx.core.app.NotificationCompat;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
@@ -49,8 +50,8 @@ public abstract class AbstractNotificationBuilder extends NotificationCompat.Bui
|
||||
}
|
||||
|
||||
public void setAlarms(@Nullable Uri ringtone, RecipientDatabase.VibrateState vibrate) {
|
||||
Uri defaultRingtone = NotificationChannels.supported() ? NotificationChannels.getMessageRingtone(context) : TextSecurePreferences.getNotificationRingtone(context);
|
||||
boolean defaultVibrate = NotificationChannels.supported() ? NotificationChannels.getMessageVibrate(context) : TextSecurePreferences.isNotificationVibrateEnabled(context);
|
||||
Uri defaultRingtone = NotificationChannels.supported() ? NotificationChannels.getMessageRingtone(context) : SignalStore.settings().getMessageNotificationSound();
|
||||
boolean defaultVibrate = NotificationChannels.supported() ? NotificationChannels.getMessageVibrate(context) : SignalStore.settings().isMessageVibrateEnabled();
|
||||
|
||||
if (ringtone == null && !TextUtils.isEmpty(defaultRingtone.toString())) setSound(defaultRingtone);
|
||||
else if (ringtone != null && !ringtone.toString().isEmpty()) setSound(ringtone);
|
||||
@@ -63,8 +64,8 @@ public abstract class AbstractNotificationBuilder extends NotificationCompat.Bui
|
||||
}
|
||||
|
||||
private void setLed() {
|
||||
String ledColor = TextSecurePreferences.getNotificationLedColor(context);
|
||||
String ledBlinkPattern = TextSecurePreferences.getNotificationLedPattern(context);
|
||||
String ledColor = SignalStore.settings().getMessageLedColor();
|
||||
String ledBlinkPattern = SignalStore.settings().getMessageLedBlinkPattern();
|
||||
String ledBlinkPatternCustom = TextSecurePreferences.getNotificationLedPatternCustom(context);
|
||||
|
||||
if (!ledColor.equals("none")) {
|
||||
|
||||
@@ -60,6 +60,7 @@ import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.ReactionRecord;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.messages.IncomingMessageObserver;
|
||||
import org.thoughtcrime.securesms.mms.Slide;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
@@ -139,7 +140,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
||||
Intent intent = ConversationIntents.createBuilder(context, recipient.getId(), threadId)
|
||||
.withDataUri(Uri.parse("custom://" + System.currentTimeMillis()))
|
||||
.build();
|
||||
FailedNotificationBuilder builder = new FailedNotificationBuilder(context, TextSecurePreferences.getNotificationPrivacy(context), intent);
|
||||
FailedNotificationBuilder builder = new FailedNotificationBuilder(context, SignalStore.settings().getMessageNotificationsPrivacy(), intent);
|
||||
|
||||
((NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE))
|
||||
.notify((int)threadId, builder.build());
|
||||
@@ -220,7 +221,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
||||
|
||||
@Override
|
||||
public void updateNotification(@NonNull Context context) {
|
||||
if (!TextSecurePreferences.isNotificationsEnabled(context)) {
|
||||
if (!SignalStore.settings().isMessageNotificationsEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -261,7 +262,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
||||
}
|
||||
|
||||
private boolean shouldNotify(@NonNull Context context, @Nullable Recipient recipient, long threadId) {
|
||||
if (!TextSecurePreferences.isNotificationsEnabled(context)) {
|
||||
if (!SignalStore.settings().isMessageNotificationsEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -281,7 +282,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
||||
int reminderCount,
|
||||
@NonNull BubbleUtil.BubbleState defaultBubbleState)
|
||||
{
|
||||
if (!TextSecurePreferences.isNotificationsEnabled(context)) {
|
||||
if (!SignalStore.settings().isMessageNotificationsEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -371,7 +372,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
||||
return false;
|
||||
}
|
||||
|
||||
NotificationPrivacyPreference notificationPrivacy = TextSecurePreferences.getNotificationPrivacy(context);
|
||||
NotificationPrivacyPreference notificationPrivacy = SignalStore.settings().getMessageNotificationsPrivacy();
|
||||
SingleRecipientNotificationBuilder builder = new SingleRecipientNotificationBuilder(context, notificationPrivacy);
|
||||
List<NotificationItem> notifications = notificationState.getNotifications();
|
||||
Recipient recipient = notifications.get(0).getRecipient();
|
||||
@@ -442,7 +443,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
||||
NotificationManagerCompat.from(context).notify(notificationId, notification);
|
||||
Log.i(TAG, "Posted notification.");
|
||||
} catch (SecurityException e) {
|
||||
Uri defaultValue = TextSecurePreferences.getNotificationRingtone(context);
|
||||
Uri defaultValue = SignalStore.settings().getMessageNotificationSound();
|
||||
if (!defaultValue.equals(notificationState.getRingtone(context))) {
|
||||
Log.e(TAG, "Security exception when posting notification with custom ringtone", e);
|
||||
clearNotificationRingtone(context, notifications.get(0).getRecipient());
|
||||
@@ -465,7 +466,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
||||
return;
|
||||
}
|
||||
|
||||
NotificationPrivacyPreference notificationPrivacy = TextSecurePreferences.getNotificationPrivacy(context);
|
||||
NotificationPrivacyPreference notificationPrivacy = SignalStore.settings().getMessageNotificationsPrivacy();
|
||||
MultipleRecipientNotificationBuilder builder = new MultipleRecipientNotificationBuilder(context, notificationPrivacy);
|
||||
List<NotificationItem> notifications = notificationState.getNotifications();
|
||||
boolean shouldAlert = signal && Stream.of(notifications).anyMatch(item -> item.getNotifiedTimestamp() == 0);
|
||||
@@ -506,7 +507,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
||||
NotificationManagerCompat.from(context).notify(NotificationIds.MESSAGE_SUMMARY, builder.build());
|
||||
Log.i(TAG, "Posted notification. " + notification.toString());
|
||||
} catch (SecurityException securityException) {
|
||||
Uri defaultValue = TextSecurePreferences.getNotificationRingtone(context);
|
||||
Uri defaultValue = SignalStore.settings().getMessageNotificationSound();
|
||||
if (!defaultValue.equals(notificationState.getRingtone(context))) {
|
||||
Log.e(TAG, "Security exception when posting notification with custom ringtone", securityException);
|
||||
clearNotificationRingtone(context, notifications.get(0).getRecipient());
|
||||
@@ -524,7 +525,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
||||
}
|
||||
|
||||
private static void sendInThreadNotification(Context context, Recipient recipient) {
|
||||
if (!TextSecurePreferences.isInThreadNotifications(context) ||
|
||||
if (!SignalStore.settings().isMessageNotificationsInChatSoundsEnabled() ||
|
||||
ServiceUtil.getAudioManager(context).getRingerMode() != AudioManager.RINGER_MODE_NORMAL)
|
||||
{
|
||||
return;
|
||||
@@ -536,7 +537,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
||||
}
|
||||
|
||||
if (uri == null) {
|
||||
uri = NotificationChannels.supported() ? NotificationChannels.getMessageRingtone(context) : TextSecurePreferences.getNotificationRingtone(context);
|
||||
uri = NotificationChannels.supported() ? NotificationChannels.getMessageRingtone(context) : SignalStore.settings().getMessageNotificationSound();
|
||||
}
|
||||
|
||||
if (uri.toString().isEmpty()) {
|
||||
@@ -729,7 +730,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
||||
}
|
||||
|
||||
private static void scheduleReminder(Context context, int count) {
|
||||
if (count >= TextSecurePreferences.getRepeatAlertsCount(context)) {
|
||||
if (count >= SignalStore.settings().getMessageNotificationsRepeatAlerts()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase.VibrateState;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
@@ -158,7 +159,7 @@ public class NotificationChannels {
|
||||
if (recipient.getId().isUnknown()) return null;
|
||||
|
||||
VibrateState vibrateState = recipient.getMessageVibrate();
|
||||
boolean vibrationEnabled = vibrateState == VibrateState.DEFAULT ? TextSecurePreferences.isNotificationVibrateEnabled(context) : vibrateState == VibrateState.ENABLED;
|
||||
boolean vibrationEnabled = vibrateState == VibrateState.DEFAULT ? SignalStore.settings().isMessageVibrateEnabled() : vibrateState == VibrateState.ENABLED;
|
||||
Uri messageRingtone = recipient.getMessageRingtone() != null ? recipient.getMessageRingtone() : getMessageRingtone(context);
|
||||
String displayName = recipient.getDisplayName(context);
|
||||
|
||||
@@ -180,7 +181,7 @@ public class NotificationChannels {
|
||||
|
||||
NotificationChannel channel = new NotificationChannel(channelId, displayName, NotificationManager.IMPORTANCE_HIGH);
|
||||
|
||||
setLedPreference(channel, TextSecurePreferences.getNotificationLedColor(context));
|
||||
setLedPreference(channel, SignalStore.settings().getMessageLedColor());
|
||||
channel.setGroup(CATEGORY_MESSAGES);
|
||||
channel.enableVibration(vibrationEnabled);
|
||||
|
||||
@@ -523,9 +524,9 @@ public class NotificationChannels {
|
||||
NotificationChannel joinEvents = new NotificationChannel(JOIN_EVENTS, context.getString(R.string.NotificationChannel_contact_joined_signal), NotificationManager.IMPORTANCE_DEFAULT);
|
||||
|
||||
messages.setGroup(CATEGORY_MESSAGES);
|
||||
messages.enableVibration(TextSecurePreferences.isNotificationVibrateEnabled(context));
|
||||
messages.setSound(TextSecurePreferences.getNotificationRingtone(context), getRingtoneAudioAttributes());
|
||||
setLedPreference(messages, TextSecurePreferences.getNotificationLedColor(context));
|
||||
messages.enableVibration(SignalStore.settings().isMessageVibrateEnabled());
|
||||
messages.setSound(SignalStore.settings().getMessageNotificationSound(), getRingtoneAudioAttributes());
|
||||
setLedPreference(messages, SignalStore.settings().getMessageLedColor());
|
||||
|
||||
calls.setShowBadge(false);
|
||||
backups.setShowBadge(false);
|
||||
|
||||
@@ -16,6 +16,7 @@ import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.database.MessageDatabase
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.messages.IncomingMessageObserver
|
||||
import org.thoughtcrime.securesms.notifications.DefaultMessageNotifier
|
||||
import org.thoughtcrime.securesms.notifications.MessageNotifier
|
||||
@@ -27,7 +28,6 @@ import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService
|
||||
import org.thoughtcrime.securesms.util.BubbleUtil.BubbleState
|
||||
import org.thoughtcrime.securesms.util.ServiceUtil
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.thoughtcrime.securesms.webrtc.CallNotificationBuilder
|
||||
import org.whispersystems.signalservice.internal.util.Util
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
@@ -47,7 +47,7 @@ class MessageNotifierV2(context: Application) : MessageNotifier {
|
||||
@Volatile private var lastAudibleNotification: Long = -1
|
||||
@Volatile private var lastScheduledReminder: Long = 0
|
||||
@Volatile private var previousLockedStatus: Boolean = KeyCachingService.isLocked(context)
|
||||
@Volatile private var previousPrivacyPreference: NotificationPrivacyPreference = TextSecurePreferences.getNotificationPrivacy(context)
|
||||
@Volatile private var previousPrivacyPreference: NotificationPrivacyPreference = SignalStore.settings().messageNotificationsPrivacy
|
||||
@Volatile private var previousState: NotificationStateV2 = NotificationStateV2.EMPTY
|
||||
|
||||
private val threadReminders: MutableMap<Long, Reminder> = ConcurrentHashMap()
|
||||
@@ -116,12 +116,12 @@ class MessageNotifierV2(context: Application) : MessageNotifier {
|
||||
reminderCount: Int,
|
||||
defaultBubbleState: BubbleState
|
||||
) {
|
||||
if (!TextSecurePreferences.isNotificationsEnabled(context)) {
|
||||
if (!SignalStore.settings().isMessageNotificationsEnabled) {
|
||||
return
|
||||
}
|
||||
|
||||
val currentLockStatus: Boolean = KeyCachingService.isLocked(context)
|
||||
val currentPrivacyPreference: NotificationPrivacyPreference = TextSecurePreferences.getNotificationPrivacy(context)
|
||||
val currentPrivacyPreference: NotificationPrivacyPreference = SignalStore.settings().messageNotificationsPrivacy
|
||||
val notificationConfigurationChanged: Boolean = currentLockStatus != previousLockedStatus || currentPrivacyPreference != previousPrivacyPreference
|
||||
previousLockedStatus = currentLockStatus
|
||||
previousPrivacyPreference = currentPrivacyPreference
|
||||
@@ -211,7 +211,7 @@ class MessageNotifierV2(context: Application) : MessageNotifier {
|
||||
}
|
||||
|
||||
private fun updateReminderTimestamps(context: Context, alertOverrides: Set<Long>, threadsThatAlerted: Set<Long>) {
|
||||
if (TextSecurePreferences.getRepeatAlertsCount(context) == 0) {
|
||||
if (SignalStore.settings().messageNotificationsRepeatAlerts == 0) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -221,7 +221,7 @@ class MessageNotifierV2(context: Application) : MessageNotifier {
|
||||
val (id: Long, reminder: Reminder) = entry
|
||||
if (alertOverrides.contains(id)) {
|
||||
val notifyCount: Int = reminder.count + 1
|
||||
if (notifyCount >= TextSecurePreferences.getRepeatAlertsCount(context)) {
|
||||
if (notifyCount >= SignalStore.settings().messageNotificationsRepeatAlerts) {
|
||||
iterator.remove()
|
||||
} else {
|
||||
entry.setValue(Reminder(lastAudibleNotification, notifyCount))
|
||||
|
||||
@@ -21,6 +21,7 @@ import androidx.core.graphics.drawable.IconCompat
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.conversation.ConversationIntents
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.notifications.DefaultMessageNotifier
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels
|
||||
import org.thoughtcrime.securesms.notifications.ReplyMethod
|
||||
@@ -45,7 +46,7 @@ private const val BIG_PICTURE_DIMEN = 500
|
||||
*/
|
||||
sealed class NotificationBuilder(protected val context: Context) {
|
||||
|
||||
private val privacy: NotificationPrivacyPreference = TextSecurePreferences.getNotificationPrivacy(context)
|
||||
private val privacy: NotificationPrivacyPreference = SignalStore.settings().messageNotificationsPrivacy
|
||||
private val isNotLocked: Boolean = !KeyCachingService.isLocked(context)
|
||||
|
||||
abstract fun setSmallIcon(@DrawableRes drawable: Int)
|
||||
@@ -145,10 +146,10 @@ sealed class NotificationBuilder(protected val context: Context) {
|
||||
}
|
||||
|
||||
fun setLights() {
|
||||
val ledColor: String = TextSecurePreferences.getNotificationLedColor(context)
|
||||
val ledColor: String = SignalStore.settings().messageLedColor
|
||||
|
||||
if (ledColor != "none") {
|
||||
var blinkPattern = TextSecurePreferences.getNotificationLedPattern(context)
|
||||
var blinkPattern = SignalStore.settings().messageLedBlinkPattern
|
||||
if (blinkPattern == "custom") {
|
||||
blinkPattern = TextSecurePreferences.getNotificationLedPatternCustom(context)
|
||||
}
|
||||
@@ -297,8 +298,8 @@ sealed class NotificationBuilder(protected val context: Context) {
|
||||
val ringtone: Uri? = recipient?.messageRingtone
|
||||
val vibrate = recipient?.messageVibrate
|
||||
|
||||
val defaultRingtone: Uri = TextSecurePreferences.getNotificationRingtone(context)
|
||||
val defaultVibrate: Boolean = TextSecurePreferences.isNotificationVibrateEnabled(context)
|
||||
val defaultRingtone: Uri = SignalStore.settings().messageNotificationSound
|
||||
val defaultVibrate: Boolean = SignalStore.settings().isMessageVibrateEnabled
|
||||
|
||||
if (ringtone == null && !TextUtils.isEmpty(defaultRingtone.toString())) {
|
||||
builder.setSound(defaultRingtone)
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.thoughtcrime.securesms.contacts.TurnOffContactJoinedNotificationsActi
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ContactColors
|
||||
import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto
|
||||
import org.thoughtcrime.securesms.conversation.ConversationIntents
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.notifications.DeleteNotificationReceiver
|
||||
import org.thoughtcrime.securesms.notifications.MarkReadReceiver
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels
|
||||
@@ -21,7 +22,6 @@ import org.thoughtcrime.securesms.notifications.ReplyMethod
|
||||
import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.thoughtcrime.securesms.util.Util
|
||||
|
||||
/**
|
||||
@@ -41,7 +41,7 @@ data class NotificationConversation(
|
||||
val isOnlyContactJoinedEvent: Boolean = messageCount == 1 && mostRecentNotification.isJoined
|
||||
|
||||
fun getContentTitle(context: Context): CharSequence {
|
||||
return if (TextSecurePreferences.getNotificationPrivacy(context).isDisplayContact) {
|
||||
return if (SignalStore.settings().messageNotificationsPrivacy.isDisplayContact) {
|
||||
recipient.getDisplayName(context)
|
||||
} else {
|
||||
context.getString(R.string.SingleRecipientNotificationBuilder_signal)
|
||||
@@ -49,7 +49,7 @@ data class NotificationConversation(
|
||||
}
|
||||
|
||||
fun getContactLargeIcon(context: Context): Drawable? {
|
||||
return if (TextSecurePreferences.getNotificationPrivacy(context).isDisplayContact) {
|
||||
return if (SignalStore.settings().messageNotificationsPrivacy.isDisplayContact) {
|
||||
recipient.getContactDrawable(context)
|
||||
} else {
|
||||
GeneratedContactPhoto("Unknown", R.drawable.ic_profile_outline_40).asDrawable(context, ContactColors.UNKNOWN_COLOR.toConversationColor(context))
|
||||
@@ -57,7 +57,7 @@ data class NotificationConversation(
|
||||
}
|
||||
|
||||
fun getContactUri(context: Context): String? {
|
||||
return if (TextSecurePreferences.getNotificationPrivacy(context).isDisplayContact) {
|
||||
return if (SignalStore.settings().messageNotificationsPrivacy.isDisplayContact) {
|
||||
recipient.contactUri?.toString()
|
||||
} else {
|
||||
null
|
||||
@@ -65,7 +65,7 @@ data class NotificationConversation(
|
||||
}
|
||||
|
||||
fun getSlideBigPictureUri(context: Context): Uri? {
|
||||
return if (notificationItems.size == 1 && TextSecurePreferences.getNotificationPrivacy(context).isDisplayMessage && !KeyCachingService.isLocked(context)) {
|
||||
return if (notificationItems.size == 1 && SignalStore.settings().messageNotificationsPrivacy.isDisplayMessage && !KeyCachingService.isLocked(context)) {
|
||||
mostRecentNotification.getBigPictureUri()
|
||||
} else {
|
||||
null
|
||||
@@ -73,7 +73,7 @@ data class NotificationConversation(
|
||||
}
|
||||
|
||||
fun getContentText(context: Context): CharSequence? {
|
||||
val privacy: NotificationPrivacyPreference = TextSecurePreferences.getNotificationPrivacy(context)
|
||||
val privacy: NotificationPrivacyPreference = SignalStore.settings().messageNotificationsPrivacy
|
||||
val stringBuilder = SpannableStringBuilder()
|
||||
|
||||
if (privacy.isDisplayContact && recipient.isGroup) {
|
||||
@@ -88,7 +88,7 @@ data class NotificationConversation(
|
||||
}
|
||||
|
||||
fun getConversationTitle(context: Context): CharSequence? {
|
||||
if (TextSecurePreferences.getNotificationPrivacy(context).isDisplayContact) {
|
||||
if (SignalStore.settings().messageNotificationsPrivacy.isDisplayContact) {
|
||||
return if (isGroup) recipient.getDisplayName(context) else null
|
||||
}
|
||||
return context.getString(R.string.SingleRecipientNotificationBuilder_signal)
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.thoughtcrime.securesms.MainActivity
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.conversation.ConversationIntents
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.notifications.DefaultMessageNotifier
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels
|
||||
import org.thoughtcrime.securesms.notifications.NotificationIds
|
||||
@@ -250,7 +251,7 @@ object NotificationFactory {
|
||||
}
|
||||
|
||||
private fun notifyInThread(context: Context, recipient: Recipient, lastAudibleNotification: Long) {
|
||||
if (!TextSecurePreferences.isInThreadNotifications(context) ||
|
||||
if (!SignalStore.settings().isMessageNotificationsInChatSoundsEnabled ||
|
||||
ServiceUtil.getAudioManager(context).ringerMode != AudioManager.RINGER_MODE_NORMAL ||
|
||||
(System.currentTimeMillis() - lastAudibleNotification) < DefaultMessageNotifier.MIN_AUDIBLE_PERIOD_MILLIS
|
||||
) {
|
||||
@@ -260,7 +261,7 @@ object NotificationFactory {
|
||||
val uri: Uri = if (NotificationChannels.supported()) {
|
||||
NotificationChannels.getMessageRingtone(context, recipient) ?: NotificationChannels.getMessageRingtone(context)
|
||||
} else {
|
||||
recipient.messageRingtone ?: TextSecurePreferences.getNotificationRingtone(context)
|
||||
recipient.messageRingtone ?: SignalStore.settings().messageNotificationSound
|
||||
}
|
||||
|
||||
if (uri.toString().isEmpty()) {
|
||||
|
||||
@@ -16,6 +16,7 @@ import org.thoughtcrime.securesms.database.ThreadBodyUtil
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord
|
||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
||||
import org.thoughtcrime.securesms.database.model.ReactionRecord
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.mms.Slide
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck
|
||||
import org.thoughtcrime.securesms.notifications.AbstractNotificationBuilder
|
||||
@@ -25,7 +26,6 @@ import org.thoughtcrime.securesms.service.KeyCachingService
|
||||
import org.thoughtcrime.securesms.util.MediaUtil
|
||||
import org.thoughtcrime.securesms.util.MessageRecordUtil
|
||||
import org.thoughtcrime.securesms.util.SpanUtil
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.thoughtcrime.securesms.util.Util
|
||||
|
||||
private val TAG: String = Log.tag(NotificationItemV2::class.java)
|
||||
@@ -72,7 +72,7 @@ sealed class NotificationItemV2(val threadRecipient: Recipient, protected val re
|
||||
}
|
||||
|
||||
fun getStyledPrimaryText(context: Context, trimmed: Boolean = false): CharSequence {
|
||||
return if (TextSecurePreferences.getNotificationPrivacy(context).isDisplayNothing) {
|
||||
return if (SignalStore.settings().messageNotificationsPrivacy.isDisplayNothing) {
|
||||
context.getString(R.string.SingleRecipientNotificationBuilder_new_message)
|
||||
} else {
|
||||
SpannableStringBuilder().apply {
|
||||
@@ -87,7 +87,7 @@ sealed class NotificationItemV2(val threadRecipient: Recipient, protected val re
|
||||
}
|
||||
|
||||
fun getPersonName(context: Context): CharSequence {
|
||||
return if (TextSecurePreferences.getNotificationPrivacy(context).isDisplayContact) {
|
||||
return if (SignalStore.settings().messageNotificationsPrivacy.isDisplayContact) {
|
||||
individualRecipient.getDisplayName(context)
|
||||
} else {
|
||||
context.getString(R.string.SingleRecipientNotificationBuilder_signal)
|
||||
@@ -99,7 +99,7 @@ sealed class NotificationItemV2(val threadRecipient: Recipient, protected val re
|
||||
}
|
||||
|
||||
fun getPersonUri(context: Context): String? {
|
||||
return if (TextSecurePreferences.getNotificationPrivacy(context).isDisplayContact && individualRecipient.isSystemContact) {
|
||||
return if (SignalStore.settings().messageNotificationsPrivacy.isDisplayContact && individualRecipient.isSystemContact) {
|
||||
individualRecipient.contactUri.toString()
|
||||
} else {
|
||||
null
|
||||
@@ -107,7 +107,7 @@ sealed class NotificationItemV2(val threadRecipient: Recipient, protected val re
|
||||
}
|
||||
|
||||
fun getPersonIcon(context: Context): Bitmap? {
|
||||
return if (TextSecurePreferences.getNotificationPrivacy(context).isDisplayContact) {
|
||||
return if (SignalStore.settings().messageNotificationsPrivacy.isDisplayContact) {
|
||||
individualRecipient.getContactDrawable(context).toLargeBitmap(context)
|
||||
} else {
|
||||
null
|
||||
@@ -115,7 +115,7 @@ sealed class NotificationItemV2(val threadRecipient: Recipient, protected val re
|
||||
}
|
||||
|
||||
fun getPrimaryText(context: Context): CharSequence {
|
||||
return if (TextSecurePreferences.getNotificationPrivacy(context).isDisplayMessage) {
|
||||
return if (SignalStore.settings().messageNotificationsPrivacy.isDisplayMessage) {
|
||||
if (RecipientUtil.isMessageRequestAccepted(context, threadId)) {
|
||||
getPrimaryTextActual(context)
|
||||
} else {
|
||||
@@ -128,7 +128,7 @@ sealed class NotificationItemV2(val threadRecipient: Recipient, protected val re
|
||||
|
||||
fun getInboxLine(context: Context): CharSequence? {
|
||||
return when {
|
||||
TextSecurePreferences.getNotificationPrivacy(context).isDisplayNothing -> null
|
||||
SignalStore.settings().messageNotificationsPrivacy.isDisplayNothing -> null
|
||||
else -> getStyledPrimaryText(context, true)
|
||||
}
|
||||
}
|
||||
@@ -205,7 +205,7 @@ class MessageNotification(threadRecipient: Recipient, record: MessageRecord) : N
|
||||
}
|
||||
|
||||
override fun getThumbnailInfo(context: Context): ThumbnailInfo {
|
||||
return if (TextSecurePreferences.getNotificationPrivacy(context).isDisplayMessage && !KeyCachingService.isLocked(context)) {
|
||||
return if (SignalStore.settings().messageNotificationsPrivacy.isDisplayMessage && !KeyCachingService.isLocked(context)) {
|
||||
val thumbnailSlide: Slide? = slideDeck?.thumbnailSlide
|
||||
ThumbnailInfo(thumbnailSlide?.publicUri, thumbnailSlide?.contentType)
|
||||
} else {
|
||||
|
||||
@@ -25,10 +25,10 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
||||
import org.thoughtcrime.securesms.LoggingFragment;
|
||||
import org.thoughtcrime.securesms.PaymentPreferencesDirections;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity;
|
||||
import org.thoughtcrime.securesms.help.HelpFragment;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity;
|
||||
@@ -224,11 +224,7 @@ public class PaymentsHomeFragment extends LoggingFragment {
|
||||
NavHostFragment.findNavController(this).navigate(R.id.action_paymentsHome_to_paymentsBackup);
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.payments_home_fragment_menu_help) {
|
||||
Intent intent = new Intent(requireContext(), ApplicationPreferencesActivity.class);
|
||||
intent.putExtra(ApplicationPreferencesActivity.LAUNCH_TO_HELP_FRAGMENT, true);
|
||||
intent.putExtra(HelpFragment.START_CATEGORY_INDEX, HelpFragment.PAYMENT_INDEX);
|
||||
|
||||
startActivity(intent);
|
||||
startActivity(AppSettingsActivity.help(requireContext(), HelpFragment.PAYMENT_INDEX));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import androidx.preference.Preference;
|
||||
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity;
|
||||
@@ -68,8 +67,6 @@ public class AdvancedPinPreferenceFragment extends ListSummaryPreferenceFragment
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
((ApplicationPreferencesActivity) getActivity()).getSupportActionBar().setTitle(R.string.preferences__advanced_pin_settings);
|
||||
}
|
||||
|
||||
private void onPreferenceChanged(boolean enabled) {
|
||||
|
||||
@@ -1,306 +0,0 @@
|
||||
package org.thoughtcrime.securesms.preferences;
|
||||
|
||||
import android.app.ActionBar;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.provider.ContactsContract;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.preference.CheckBoxPreference;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.google.firebase.iid.FirebaseInstanceId;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
||||
import org.thoughtcrime.securesms.BuildConfig;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.contacts.ContactAccessor;
|
||||
import org.thoughtcrime.securesms.contacts.ContactIdentityManager;
|
||||
import org.thoughtcrime.securesms.delete.DeleteAccountFragment;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.logsubmit.SubmitDebugLogActivity;
|
||||
import org.thoughtcrime.securesms.payments.preferences.PaymentsActivity;
|
||||
import org.thoughtcrime.securesms.payments.preferences.transfer.PaymentsTransferFragmentArgs;
|
||||
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
||||
import org.thoughtcrime.securesms.registration.RegistrationNavigationActivity;
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||
import org.thoughtcrime.securesms.util.SpanUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
||||
import org.whispersystems.signalservice.api.payments.FormatterOptions;
|
||||
import org.whispersystems.signalservice.api.payments.Money;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class AdvancedPreferenceFragment extends CorrectedPreferenceFragment {
|
||||
private static final String TAG = Log.tag(AdvancedPreferenceFragment.class);
|
||||
|
||||
private static final String PUSH_MESSAGING_PREF = "pref_toggle_push_messaging";
|
||||
private static final String SUBMIT_DEBUG_LOG_PREF = "pref_submit_debug_logs";
|
||||
private static final String INTERNAL_PREF = "pref_internal";
|
||||
private static final String ADVANCED_PIN_PREF = "pref_advanced_pin_settings";
|
||||
private static final String DELETE_ACCOUNT = "pref_delete_account";
|
||||
|
||||
private static final int PICK_IDENTITY_CONTACT = 1;
|
||||
private static final int TRANSFER_CURRENCY = 2;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle paramBundle) {
|
||||
super.onCreate(paramBundle);
|
||||
|
||||
initializeIdentitySelection();
|
||||
|
||||
Preference submitDebugLog = this.findPreference(SUBMIT_DEBUG_LOG_PREF);
|
||||
submitDebugLog.setOnPreferenceClickListener(new SubmitDebugLogListener());
|
||||
submitDebugLog.setSummary(getVersion(getActivity()));
|
||||
|
||||
Preference pinSettings = this.findPreference(ADVANCED_PIN_PREF);
|
||||
pinSettings.setOnPreferenceClickListener(preference -> {
|
||||
getApplicationPreferencesActivity().pushFragment(new AdvancedPinPreferenceFragment());
|
||||
return false;
|
||||
});
|
||||
|
||||
Preference internalPreference = this.findPreference(INTERNAL_PREF);
|
||||
internalPreference.setVisible(FeatureFlags.internalUser());
|
||||
internalPreference.setOnPreferenceClickListener(preference -> {
|
||||
if (FeatureFlags.internalUser()) {
|
||||
getApplicationPreferencesActivity().pushFragment(new InternalOptionsPreferenceFragment());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
Preference deleteAccount = this.findPreference(DELETE_ACCOUNT);
|
||||
deleteAccount.setOnPreferenceClickListener(preference -> {
|
||||
Money.MobileCoin latestBalance = SignalStore.paymentsValues().mobileCoinLatestBalance().getFullAmount().requireMobileCoin();
|
||||
|
||||
if (!latestBalance.equals(Money.MobileCoin.ZERO)) {
|
||||
new AlertDialog.Builder(requireContext())
|
||||
.setTitle(R.string.AdvancedPreferenceFragment__transfer_mob_balance)
|
||||
.setMessage(getString(R.string.AdvancedPreferenceFragment__you_have_a_balance_of_s, latestBalance.toString(FormatterOptions.defaults())))
|
||||
.setPositiveButton(R.string.AdvancedPreferenceFragment__transfer, (dialog, which) -> {
|
||||
Intent intent = new Intent(requireContext(), PaymentsActivity.class);
|
||||
intent.putExtra(PaymentsActivity.EXTRA_PAYMENTS_STARTING_ACTION, R.id.action_directly_to_paymentsTransfer);
|
||||
intent.putExtra(PaymentsActivity.EXTRA_STARTING_ARGUMENTS, new PaymentsTransferFragmentArgs.Builder().setFinishOnConfirm(true).build().toBundle());
|
||||
startActivityForResult(intent, TRANSFER_CURRENCY);
|
||||
dialog.dismiss();
|
||||
})
|
||||
.setNegativeButton(SpanUtil.color(ContextCompat.getColor(requireContext(), R.color.signal_alert_primary), getString(R.string.AdvancedPreferenceFragment__dont_transfer)), (dialog, which) -> {
|
||||
getApplicationPreferencesActivity().pushFragment(new DeleteAccountFragment());
|
||||
dialog.dismiss();
|
||||
})
|
||||
.show();
|
||||
} else {
|
||||
getApplicationPreferencesActivity().pushFragment(new DeleteAccountFragment());
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
view.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.signal_background_tertiary));
|
||||
|
||||
View list = view.findViewById(R.id.recycler_view);
|
||||
ViewGroup.LayoutParams params = list.getLayoutParams();
|
||||
|
||||
params.height = ActionBar.LayoutParams.WRAP_CONTENT;
|
||||
list.setLayoutParams(params);
|
||||
list.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.signal_background_primary));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
|
||||
addPreferencesFromResource(R.xml.preferences_advanced);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
getApplicationPreferencesActivity().getSupportActionBar().setTitle(R.string.preferences__advanced);
|
||||
|
||||
initializePushMessagingToggle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int reqCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(reqCode, resultCode, data);
|
||||
|
||||
Log.i(TAG, "Got result: " + resultCode + " for req: " + reqCode);
|
||||
if (resultCode == Activity.RESULT_OK && reqCode == PICK_IDENTITY_CONTACT) {
|
||||
handleIdentitySelection(data);
|
||||
} else if (resultCode == Activity.RESULT_OK && reqCode == TRANSFER_CURRENCY) {
|
||||
getApplicationPreferencesActivity().pushFragment(new DeleteAccountFragment());
|
||||
}
|
||||
}
|
||||
|
||||
private @NonNull ApplicationPreferencesActivity getApplicationPreferencesActivity() {
|
||||
return (ApplicationPreferencesActivity) requireActivity();
|
||||
}
|
||||
|
||||
private void initializePushMessagingToggle() {
|
||||
CheckBoxPreference preference = (CheckBoxPreference)this.findPreference(PUSH_MESSAGING_PREF);
|
||||
|
||||
if (TextSecurePreferences.isPushRegistered(getActivity())) {
|
||||
preference.setChecked(true);
|
||||
preference.setSummary(PhoneNumberFormatter.prettyPrint(TextSecurePreferences.getLocalNumber(getActivity())));
|
||||
} else {
|
||||
preference.setChecked(false);
|
||||
preference.setSummary(R.string.preferences__free_private_messages_and_calls);
|
||||
}
|
||||
|
||||
preference.setOnPreferenceChangeListener(new PushMessagingClickListener());
|
||||
}
|
||||
|
||||
private void initializeIdentitySelection() {
|
||||
ContactIdentityManager identity = ContactIdentityManager.getInstance(getActivity());
|
||||
|
||||
Preference preference = this.findPreference(TextSecurePreferences.IDENTITY_PREF);
|
||||
|
||||
if (identity.isSelfIdentityAutoDetected()) {
|
||||
this.getPreferenceScreen().removePreference(preference);
|
||||
} else {
|
||||
Uri contactUri = identity.getSelfIdentityUri();
|
||||
|
||||
if (contactUri != null) {
|
||||
String contactName = ContactAccessor.getInstance().getNameFromContact(getActivity(), contactUri);
|
||||
preference.setSummary(String.format(getString(R.string.ApplicationPreferencesActivity_currently_s),
|
||||
contactName));
|
||||
}
|
||||
|
||||
preference.setOnPreferenceClickListener(new IdentityPreferenceClickListener());
|
||||
}
|
||||
}
|
||||
|
||||
private @NonNull String getVersion(@Nullable Context context) {
|
||||
if (context == null) return "";
|
||||
|
||||
String app = context.getString(R.string.app_name);
|
||||
String version = BuildConfig.VERSION_NAME;
|
||||
|
||||
return String.format("%s %s", app, version);
|
||||
}
|
||||
|
||||
private class IdentityPreferenceClickListener implements Preference.OnPreferenceClickListener {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
Intent intent = new Intent(Intent.ACTION_PICK);
|
||||
intent.setType(ContactsContract.Contacts.CONTENT_TYPE);
|
||||
startActivityForResult(intent, PICK_IDENTITY_CONTACT);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleIdentitySelection(Intent data) {
|
||||
Uri contactUri = data.getData();
|
||||
|
||||
if (contactUri != null) {
|
||||
TextSecurePreferences.setIdentityContactUri(getActivity(), contactUri.toString());
|
||||
initializeIdentitySelection();
|
||||
}
|
||||
}
|
||||
|
||||
private class SubmitDebugLogListener implements Preference.OnPreferenceClickListener {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
final Intent intent = new Intent(getActivity(), SubmitDebugLogActivity.class);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class PushMessagingClickListener implements Preference.OnPreferenceChangeListener {
|
||||
private static final int SUCCESS = 0;
|
||||
private static final int NETWORK_ERROR = 1;
|
||||
|
||||
private class DisablePushMessagesTask extends ProgressDialogAsyncTask<Void, Void, Integer> {
|
||||
private final CheckBoxPreference checkBoxPreference;
|
||||
|
||||
public DisablePushMessagesTask(final CheckBoxPreference checkBoxPreference) {
|
||||
super(getActivity(), R.string.ApplicationPreferencesActivity_unregistering, R.string.ApplicationPreferencesActivity_unregistering_from_signal_messages_and_calls);
|
||||
this.checkBoxPreference = checkBoxPreference;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Integer result) {
|
||||
super.onPostExecute(result);
|
||||
switch (result) {
|
||||
case NETWORK_ERROR:
|
||||
Toast.makeText(getActivity(),
|
||||
R.string.ApplicationPreferencesActivity_error_connecting_to_server,
|
||||
Toast.LENGTH_LONG).show();
|
||||
break;
|
||||
case SUCCESS:
|
||||
TextSecurePreferences.setPushRegistered(getActivity(), false);
|
||||
SignalStore.registrationValues().clearRegistrationComplete();
|
||||
initializePushMessagingToggle();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer doInBackground(Void... params) {
|
||||
try {
|
||||
Context context = getActivity();
|
||||
SignalServiceAccountManager accountManager = ApplicationDependencies.getSignalServiceAccountManager();
|
||||
|
||||
try {
|
||||
accountManager.setGcmId(Optional.<String>absent());
|
||||
} catch (AuthorizationFailedException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
|
||||
if (!TextSecurePreferences.isFcmDisabled(context)) {
|
||||
FirebaseInstanceId.getInstance().deleteInstanceId();
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
} catch (IOException ioe) {
|
||||
Log.w(TAG, ioe);
|
||||
return NETWORK_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(final Preference preference, Object newValue) {
|
||||
if (((CheckBoxPreference)preference).isChecked()) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
builder.setIcon(R.drawable.ic_info_outline);
|
||||
builder.setTitle(R.string.ApplicationPreferencesActivity_disable_signal_messages_and_calls);
|
||||
builder.setMessage(R.string.ApplicationPreferencesActivity_disable_signal_messages_and_calls_by_unregistering);
|
||||
builder.setNegativeButton(android.R.string.cancel, null);
|
||||
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
new DisablePushMessagesTask((CheckBoxPreference)preference).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
});
|
||||
builder.show();
|
||||
} else {
|
||||
startActivity(RegistrationNavigationActivity.newIntentForReRegistration(requireContext()));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,655 +0,0 @@
|
||||
package org.thoughtcrime.securesms.preferences;
|
||||
|
||||
import android.app.KeyguardManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.Bundle;
|
||||
import android.text.InputType;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
import android.text.style.TextAppearanceSpan;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.autofill.HintConstants;
|
||||
import androidx.core.app.DialogCompat;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.preference.CheckBoxPreference;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import org.signal.core.util.concurrent.SignalExecutors;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
||||
import org.thoughtcrime.securesms.PassphraseChangeActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.blocked.BlockedUsersActivity;
|
||||
import org.thoughtcrime.securesms.components.SwitchPreferenceCompat;
|
||||
import org.thoughtcrime.securesms.contactshare.SimpleTextWatcher;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.jobs.ConversationShortcutUpdateJob;
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceConfigurationUpdateJob;
|
||||
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob;
|
||||
import org.thoughtcrime.securesms.keyvalue.KbsValues;
|
||||
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues;
|
||||
import org.thoughtcrime.securesms.keyvalue.PinValues;
|
||||
import org.thoughtcrime.securesms.keyvalue.SettingsValues;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.lock.PinHashing;
|
||||
import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity;
|
||||
import org.thoughtcrime.securesms.lock.v2.KbsConstants;
|
||||
import org.thoughtcrime.securesms.lock.v2.RegistrationLockUtil;
|
||||
import org.thoughtcrime.securesms.megaphone.Megaphones;
|
||||
import org.thoughtcrime.securesms.pin.RegistrationLockV2Dialog;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions;
|
||||
import org.thoughtcrime.securesms.util.ConversationUtil;
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.ThemeUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import mobi.upod.timedurationpicker.TimeDurationPickerDialog;
|
||||
import mobi.upod.timedurationpicker.TimeDurationPicker;
|
||||
|
||||
public class AppProtectionPreferenceFragment extends CorrectedPreferenceFragment {
|
||||
|
||||
private static final String TAG = Log.tag(AppProtectionPreferenceFragment.class);
|
||||
|
||||
private static final String PREFERENCE_CATEGORY_BLOCKED = "preference_category_blocked";
|
||||
private static final String PREFERENCE_UNIDENTIFIED_LEARN_MORE = "pref_unidentified_learn_more";
|
||||
private static final String PREFERENCE_INCOGNITO_LEARN_MORE = "pref_incognito_learn_more";
|
||||
private static final String PREFERENCE_WHO_CAN_SEE_PHONE_NUMBER = "pref_who_can_see_phone_number";
|
||||
private static final String PREFERENCE_WHO_CAN_FIND_BY_PHONE_NUMBER = "pref_who_can_find_by_phone_number";
|
||||
|
||||
private CheckBoxPreference disablePassphrase;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle paramBundle) {
|
||||
super.onCreate(paramBundle);
|
||||
|
||||
disablePassphrase = (CheckBoxPreference) this.findPreference("pref_enable_passphrase_temporary");
|
||||
|
||||
this.findPreference(KbsValues.V2_LOCK_ENABLED).setPreferenceDataStore(SignalStore.getPreferenceDataStore());
|
||||
((SwitchPreferenceCompat) this.findPreference(KbsValues.V2_LOCK_ENABLED)).setChecked(SignalStore.kbsValues().isV2RegistrationLockEnabled());
|
||||
this.findPreference(KbsValues.V2_LOCK_ENABLED).setOnPreferenceChangeListener(new RegistrationLockV2ChangedListener());
|
||||
|
||||
this.findPreference(PinValues.PIN_REMINDERS_ENABLED).setPreferenceDataStore(SignalStore.getPreferenceDataStore());
|
||||
((SwitchPreferenceCompat) this.findPreference(PinValues.PIN_REMINDERS_ENABLED)).setChecked(SignalStore.pinValues().arePinRemindersEnabled());
|
||||
this.findPreference(PinValues.PIN_REMINDERS_ENABLED).setOnPreferenceChangeListener(new PinRemindersChangedListener());
|
||||
|
||||
this.findPreference(TextSecurePreferences.SCREEN_LOCK).setOnPreferenceChangeListener(new ScreenLockListener());
|
||||
this.findPreference(TextSecurePreferences.SCREEN_LOCK_TIMEOUT).setOnPreferenceClickListener(new ScreenLockTimeoutListener());
|
||||
|
||||
this.findPreference(TextSecurePreferences.CHANGE_PASSPHRASE_PREF).setOnPreferenceClickListener(new ChangePassphraseClickListener());
|
||||
this.findPreference(TextSecurePreferences.PASSPHRASE_TIMEOUT_INTERVAL_PREF).setOnPreferenceClickListener(new PassphraseIntervalClickListener());
|
||||
this.findPreference(TextSecurePreferences.READ_RECEIPTS_PREF).setOnPreferenceChangeListener(new ReadReceiptToggleListener());
|
||||
this.findPreference(TextSecurePreferences.TYPING_INDICATORS).setOnPreferenceChangeListener(new TypingIndicatorsToggleListener());
|
||||
this.findPreference(PREFERENCE_CATEGORY_BLOCKED).setOnPreferenceClickListener(new BlockedContactsClickListener());
|
||||
this.findPreference(TextSecurePreferences.SHOW_UNIDENTIFIED_DELIVERY_INDICATORS).setOnPreferenceChangeListener(new ShowUnidentifiedDeliveryIndicatorsChangedListener());
|
||||
this.findPreference(TextSecurePreferences.UNIVERSAL_UNIDENTIFIED_ACCESS).setOnPreferenceChangeListener(new UniversalUnidentifiedAccessChangedListener());
|
||||
this.findPreference(PREFERENCE_UNIDENTIFIED_LEARN_MORE).setOnPreferenceClickListener(new UnidentifiedLearnMoreClickListener());
|
||||
this.findPreference(PREFERENCE_INCOGNITO_LEARN_MORE).setOnPreferenceClickListener(new IncognitoLearnMoreClickListener());
|
||||
disablePassphrase.setOnPreferenceChangeListener(new DisablePassphraseClickListener());
|
||||
|
||||
if (FeatureFlags.phoneNumberPrivacy()) {
|
||||
Preference whoCanSeePhoneNumber = this.findPreference(PREFERENCE_WHO_CAN_SEE_PHONE_NUMBER);
|
||||
Preference whoCanFindByPhoneNumber = this.findPreference(PREFERENCE_WHO_CAN_FIND_BY_PHONE_NUMBER);
|
||||
|
||||
whoCanSeePhoneNumber.setPreferenceDataStore(null);
|
||||
whoCanSeePhoneNumber.setOnPreferenceClickListener(new PhoneNumberPrivacyWhoCanSeeClickListener());
|
||||
|
||||
whoCanFindByPhoneNumber.setPreferenceDataStore(null);
|
||||
whoCanFindByPhoneNumber.setOnPreferenceClickListener(new PhoneNumberPrivacyWhoCanFindClickListener());
|
||||
} else {
|
||||
this.findPreference("category_phone_number_privacy").setVisible(false);
|
||||
}
|
||||
|
||||
SwitchPreferenceCompat linkPreviewPref = (SwitchPreferenceCompat) this.findPreference(SettingsValues.LINK_PREVIEWS);
|
||||
linkPreviewPref.setChecked(SignalStore.settings().isLinkPreviewsEnabled());
|
||||
linkPreviewPref.setPreferenceDataStore(SignalStore.getPreferenceDataStore());
|
||||
linkPreviewPref.setOnPreferenceChangeListener(new LinkPreviewToggleListener());
|
||||
|
||||
initializeVisibility();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
|
||||
addPreferencesFromResource(R.xml.preferences_app_protection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
((ApplicationPreferencesActivity) getActivity()).getSupportActionBar().setTitle(R.string.preferences__privacy);
|
||||
|
||||
if (!TextSecurePreferences.isPasswordDisabled(getContext())) initializePassphraseTimeoutSummary();
|
||||
else initializeScreenLockTimeoutSummary();
|
||||
|
||||
disablePassphrase.setChecked(!TextSecurePreferences.isPasswordDisabled(getActivity()));
|
||||
|
||||
Preference signalPinCreateChange = this.findPreference(TextSecurePreferences.SIGNAL_PIN_CHANGE);
|
||||
SwitchPreferenceCompat signalPinReminders = (SwitchPreferenceCompat) this.findPreference(PinValues.PIN_REMINDERS_ENABLED);
|
||||
SwitchPreferenceCompat registrationLockV2 = (SwitchPreferenceCompat) this.findPreference(KbsValues.V2_LOCK_ENABLED);
|
||||
|
||||
if (SignalStore.kbsValues().hasPin() && !SignalStore.kbsValues().hasOptedOut()) {
|
||||
signalPinCreateChange.setOnPreferenceClickListener(new KbsPinUpdateListener());
|
||||
signalPinCreateChange.setTitle(R.string.preferences_app_protection__change_your_pin);
|
||||
signalPinReminders.setEnabled(true);
|
||||
registrationLockV2.setEnabled(true);
|
||||
} else {
|
||||
signalPinCreateChange.setOnPreferenceClickListener(new KbsPinCreateListener());
|
||||
signalPinCreateChange.setTitle(R.string.preferences_app_protection__create_a_pin);
|
||||
signalPinReminders.setEnabled(false);
|
||||
registrationLockV2.setEnabled(false);
|
||||
}
|
||||
|
||||
initializePhoneNumberPrivacyWhoCanSeeSummary();
|
||||
initializePhoneNumberPrivacyWhoCanFindSummary();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
||||
if (requestCode == CreateKbsPinActivity.REQUEST_NEW_PIN && resultCode == CreateKbsPinActivity.RESULT_OK) {
|
||||
Snackbar.make(requireView(), R.string.ConfirmKbsPinFragment__pin_created, Snackbar.LENGTH_LONG).setTextColor(Color.WHITE).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void initializePassphraseTimeoutSummary() {
|
||||
int timeoutMinutes = TextSecurePreferences.getPassphraseTimeoutInterval(getActivity());
|
||||
this.findPreference(TextSecurePreferences.PASSPHRASE_TIMEOUT_INTERVAL_PREF)
|
||||
.setSummary(getResources().getQuantityString(R.plurals.AppProtectionPreferenceFragment_minutes, timeoutMinutes, timeoutMinutes));
|
||||
}
|
||||
|
||||
private void initializeScreenLockTimeoutSummary() {
|
||||
long timeoutSeconds = TextSecurePreferences.getScreenLockTimeout(getContext());
|
||||
long hours = TimeUnit.SECONDS.toHours(timeoutSeconds);
|
||||
long minutes = TimeUnit.SECONDS.toMinutes(timeoutSeconds) - (TimeUnit.SECONDS.toHours(timeoutSeconds) * 60 );
|
||||
|
||||
findPreference(TextSecurePreferences.SCREEN_LOCK_TIMEOUT)
|
||||
.setSummary(timeoutSeconds <= 0 ? getString(R.string.AppProtectionPreferenceFragment_none) :
|
||||
String.format(Locale.getDefault(), "%02d:%02d:00", hours, minutes));
|
||||
}
|
||||
|
||||
private void initializePhoneNumberPrivacyWhoCanSeeSummary() {
|
||||
Preference preference = findPreference(PREFERENCE_WHO_CAN_SEE_PHONE_NUMBER);
|
||||
|
||||
switch (SignalStore.phoneNumberPrivacy().getPhoneNumberSharingMode()) {
|
||||
case EVERYONE: preference.setSummary(R.string.PhoneNumberPrivacy_everyone); break;
|
||||
case CONTACTS: preference.setSummary(R.string.PhoneNumberPrivacy_my_contacts); break;
|
||||
case NOBODY : preference.setSummary(R.string.PhoneNumberPrivacy_nobody); break;
|
||||
default : throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
private void initializePhoneNumberPrivacyWhoCanFindSummary() {
|
||||
Preference preference = findPreference(PREFERENCE_WHO_CAN_FIND_BY_PHONE_NUMBER);
|
||||
|
||||
switch (SignalStore.phoneNumberPrivacy().getPhoneNumberListingMode()) {
|
||||
case LISTED : preference.setSummary(R.string.PhoneNumberPrivacy_everyone); break;
|
||||
case UNLISTED: preference.setSummary(R.string.PhoneNumberPrivacy_nobody); break;
|
||||
default : throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeVisibility() {
|
||||
if (TextSecurePreferences.isPasswordDisabled(getContext())) {
|
||||
findPreference("pref_enable_passphrase_temporary").setVisible(false);
|
||||
findPreference(TextSecurePreferences.CHANGE_PASSPHRASE_PREF).setVisible(false);
|
||||
findPreference(TextSecurePreferences.PASSPHRASE_TIMEOUT_INTERVAL_PREF).setVisible(false);
|
||||
findPreference(TextSecurePreferences.PASSPHRASE_TIMEOUT_PREF).setVisible(false);
|
||||
|
||||
KeyguardManager keyguardManager = (KeyguardManager)getContext().getSystemService(Context.KEYGUARD_SERVICE);
|
||||
if (!keyguardManager.isKeyguardSecure()) {
|
||||
((SwitchPreferenceCompat)findPreference(TextSecurePreferences.SCREEN_LOCK)).setChecked(false);
|
||||
findPreference(TextSecurePreferences.SCREEN_LOCK).setEnabled(false);
|
||||
}
|
||||
} else {
|
||||
findPreference(TextSecurePreferences.SCREEN_LOCK).setVisible(false);
|
||||
findPreference(TextSecurePreferences.SCREEN_LOCK_TIMEOUT).setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
private class ScreenLockListener implements Preference.OnPreferenceChangeListener {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
Log.w(TAG, "Screen lock preference changed: " + newValue);
|
||||
|
||||
boolean enabled = (Boolean)newValue;
|
||||
TextSecurePreferences.setScreenLockEnabled(getContext(), enabled);
|
||||
|
||||
Intent intent = new Intent(getContext(), KeyCachingService.class);
|
||||
intent.setAction(KeyCachingService.LOCK_TOGGLED_EVENT);
|
||||
getContext().startService(intent);
|
||||
|
||||
ConversationUtil.refreshRecipientShortcuts();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class ScreenLockTimeoutListener implements Preference.OnPreferenceClickListener {
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
new TimeDurationPickerDialog(getContext(), (view, duration) -> {
|
||||
long timeoutSeconds = TimeUnit.MILLISECONDS.toSeconds(duration);
|
||||
TextSecurePreferences.setScreenLockTimeout(getContext(), timeoutSeconds);
|
||||
|
||||
initializeScreenLockTimeoutSummary();
|
||||
}, 0, TimeDurationPicker.HH_MM).show();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class KbsPinUpdateListener implements Preference.OnPreferenceClickListener {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
startActivityForResult(CreateKbsPinActivity.getIntentForPinChangeFromSettings(requireContext()), CreateKbsPinActivity.REQUEST_NEW_PIN);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class KbsPinCreateListener implements Preference.OnPreferenceClickListener {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
startActivityForResult(CreateKbsPinActivity.getIntentForPinCreate(requireContext()), CreateKbsPinActivity.REQUEST_NEW_PIN);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class BlockedContactsClickListener implements Preference.OnPreferenceClickListener {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
Intent intent = new Intent(getActivity(), BlockedUsersActivity.class);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class ReadReceiptToggleListener implements Preference.OnPreferenceChangeListener {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
SignalExecutors.BOUNDED.execute(() -> {
|
||||
boolean enabled = (boolean)newValue;
|
||||
DatabaseFactory.getRecipientDatabase(getContext()).markNeedsSync(Recipient.self().getId());
|
||||
StorageSyncHelper.scheduleSyncForDataChange();
|
||||
ApplicationDependencies.getJobManager().add(new MultiDeviceConfigurationUpdateJob(enabled,
|
||||
TextSecurePreferences.isTypingIndicatorsEnabled(requireContext()),
|
||||
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(getContext()),
|
||||
SignalStore.settings().isLinkPreviewsEnabled()));
|
||||
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class TypingIndicatorsToggleListener implements Preference.OnPreferenceChangeListener {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
SignalExecutors.BOUNDED.execute(() -> {
|
||||
boolean enabled = (boolean)newValue;
|
||||
DatabaseFactory.getRecipientDatabase(getContext()).markNeedsSync(Recipient.self().getId());
|
||||
StorageSyncHelper.scheduleSyncForDataChange();
|
||||
ApplicationDependencies.getJobManager().add(new MultiDeviceConfigurationUpdateJob(TextSecurePreferences.isReadReceiptsEnabled(requireContext()),
|
||||
enabled,
|
||||
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(getContext()),
|
||||
SignalStore.settings().isLinkPreviewsEnabled()));
|
||||
|
||||
if (!enabled) {
|
||||
ApplicationDependencies.getTypingStatusRepository().clear();
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class LinkPreviewToggleListener implements Preference.OnPreferenceChangeListener {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
SignalExecutors.BOUNDED.execute(() -> {
|
||||
boolean enabled = (boolean)newValue;
|
||||
DatabaseFactory.getRecipientDatabase(getContext()).markNeedsSync(Recipient.self().getId());
|
||||
StorageSyncHelper.scheduleSyncForDataChange();
|
||||
ApplicationDependencies.getJobManager().add(new MultiDeviceConfigurationUpdateJob(TextSecurePreferences.isReadReceiptsEnabled(requireContext()),
|
||||
TextSecurePreferences.isTypingIndicatorsEnabled(requireContext()),
|
||||
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(requireContext()),
|
||||
enabled));
|
||||
if (enabled) {
|
||||
ApplicationDependencies.getMegaphoneRepository().markFinished(Megaphones.Event.LINK_PREVIEWS);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static CharSequence getSummary(Context context) {
|
||||
final int privacySummaryResId = R.string.ApplicationPreferencesActivity_privacy_summary;;
|
||||
final String onRes = context.getString(R.string.ApplicationPreferencesActivity_on);
|
||||
final String offRes = context.getString(R.string.ApplicationPreferencesActivity_off);
|
||||
boolean registrationLockEnabled = RegistrationLockUtil.userHasRegistrationLock(context);
|
||||
|
||||
if (TextSecurePreferences.isPasswordDisabled(context) && !TextSecurePreferences.isScreenLockEnabled(context)) {
|
||||
if (registrationLockEnabled) {
|
||||
return context.getString(privacySummaryResId, offRes, onRes);
|
||||
} else {
|
||||
return context.getString(privacySummaryResId, offRes, offRes);
|
||||
}
|
||||
} else {
|
||||
if (registrationLockEnabled) {
|
||||
return context.getString(privacySummaryResId, onRes, onRes);
|
||||
} else {
|
||||
return context.getString(privacySummaryResId, onRes, offRes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Derecated
|
||||
|
||||
private class ChangePassphraseClickListener implements Preference.OnPreferenceClickListener {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
if (MasterSecretUtil.isPassphraseInitialized(getActivity())) {
|
||||
startActivity(new Intent(getActivity(), PassphraseChangeActivity.class));
|
||||
} else {
|
||||
Toast.makeText(getActivity(),
|
||||
R.string.ApplicationPreferenceActivity_you_havent_set_a_passphrase_yet,
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class PassphraseIntervalClickListener implements Preference.OnPreferenceClickListener {
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
new TimeDurationPickerDialog(getContext(), (view, duration) -> {
|
||||
int timeoutMinutes = Math.max((int)TimeUnit.MILLISECONDS.toMinutes(duration), 1);
|
||||
|
||||
TextSecurePreferences.setPassphraseTimeoutInterval(getActivity(), timeoutMinutes);
|
||||
|
||||
initializePassphraseTimeoutSummary();
|
||||
|
||||
}, 0, TimeDurationPicker.HH_MM).show();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class DisablePassphraseClickListener implements Preference.OnPreferenceChangeListener {
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(final Preference preference, Object newValue) {
|
||||
if (((CheckBoxPreference)preference).isChecked()) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
builder.setTitle(R.string.ApplicationPreferencesActivity_disable_passphrase);
|
||||
builder.setMessage(R.string.ApplicationPreferencesActivity_this_will_permanently_unlock_signal_and_message_notifications);
|
||||
builder.setIcon(R.drawable.ic_warning);
|
||||
builder.setPositiveButton(R.string.ApplicationPreferencesActivity_disable, (dialog, which) -> {
|
||||
MasterSecretUtil.changeMasterSecretPassphrase(getActivity(),
|
||||
KeyCachingService.getMasterSecret(getContext()),
|
||||
MasterSecretUtil.UNENCRYPTED_PASSPHRASE);
|
||||
|
||||
TextSecurePreferences.setPasswordDisabled(getActivity(), true);
|
||||
((CheckBoxPreference)preference).setChecked(false);
|
||||
|
||||
Intent intent = new Intent(getActivity(), KeyCachingService.class);
|
||||
intent.setAction(KeyCachingService.DISABLE_ACTION);
|
||||
getActivity().startService(intent);
|
||||
|
||||
initializeVisibility();
|
||||
});
|
||||
builder.setNegativeButton(android.R.string.cancel, null);
|
||||
builder.show();
|
||||
} else {
|
||||
Intent intent = new Intent(getActivity(), PassphraseChangeActivity.class);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private class ShowUnidentifiedDeliveryIndicatorsChangedListener implements Preference.OnPreferenceChangeListener {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
boolean enabled = (boolean) newValue;
|
||||
SignalExecutors.BOUNDED.execute(() -> {
|
||||
DatabaseFactory.getRecipientDatabase(getContext()).markNeedsSync(Recipient.self().getId());
|
||||
StorageSyncHelper.scheduleSyncForDataChange();
|
||||
ApplicationDependencies.getJobManager().add(new MultiDeviceConfigurationUpdateJob(TextSecurePreferences.isReadReceiptsEnabled(getContext()),
|
||||
TextSecurePreferences.isTypingIndicatorsEnabled(getContext()),
|
||||
enabled,
|
||||
SignalStore.settings().isLinkPreviewsEnabled()));
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class UniversalUnidentifiedAccessChangedListener implements Preference.OnPreferenceChangeListener {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object o) {
|
||||
ApplicationDependencies.getJobManager().add(new RefreshAttributesJob());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class UnidentifiedLearnMoreClickListener implements Preference.OnPreferenceClickListener {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
CommunicationActions.openBrowserLink(preference.getContext(), "https://signal.org/blog/sealed-sender/");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class IncognitoLearnMoreClickListener implements Preference.OnPreferenceClickListener {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
CommunicationActions.openBrowserLink(preference.getContext(), "https://support.signal.org/hc/en-us/articles/360055276112");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class RegistrationLockV2ChangedListener implements Preference.OnPreferenceChangeListener {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
boolean value = (boolean) newValue;
|
||||
|
||||
Log.i(TAG, "Getting ready to change registration lock setting to: " + value);
|
||||
|
||||
if (value) {
|
||||
RegistrationLockV2Dialog.showEnableDialog(requireContext(), () -> ((CheckBoxPreference) preference).setChecked(true));
|
||||
} else {
|
||||
RegistrationLockV2Dialog.showDisableDialog(requireContext(), () -> ((CheckBoxPreference) preference).setChecked(false));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private class PinRemindersChangedListener implements Preference.OnPreferenceChangeListener {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
boolean value = (boolean) newValue;
|
||||
|
||||
if (!value) {
|
||||
Context context = preference.getContext();
|
||||
DisplayMetrics metrics = preference.getContext().getResources().getDisplayMetrics();
|
||||
AlertDialog dialog = new AlertDialog.Builder(context, ThemeUtil.isDarkTheme(context) ? R.style.Theme_Signal_AlertDialog_Dark_Cornered_ColoredAccent : R.style.Theme_Signal_AlertDialog_Light_Cornered_ColoredAccent)
|
||||
.setView(R.layout.pin_disable_reminders_dialog)
|
||||
.create();
|
||||
|
||||
|
||||
dialog.show();
|
||||
dialog.getWindow().setLayout((int)(metrics.widthPixels * .80), ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
|
||||
EditText pinEditText = (EditText) DialogCompat.requireViewById(dialog, R.id.reminder_disable_pin);
|
||||
TextView statusText = (TextView) DialogCompat.requireViewById(dialog, R.id.reminder_disable_status);
|
||||
View cancelButton = DialogCompat.requireViewById(dialog, R.id.reminder_disable_cancel);
|
||||
View turnOffButton = DialogCompat.requireViewById(dialog, R.id.reminder_disable_turn_off);
|
||||
|
||||
pinEditText.post(() -> {
|
||||
if (pinEditText.requestFocus()) {
|
||||
ServiceUtil.getInputMethodManager(pinEditText.getContext()).showSoftInput(pinEditText, 0);
|
||||
}
|
||||
});
|
||||
|
||||
ViewCompat.setAutofillHints(pinEditText, HintConstants.AUTOFILL_HINT_PASSWORD);
|
||||
|
||||
switch (SignalStore.pinValues().getKeyboardType()) {
|
||||
case NUMERIC:
|
||||
pinEditText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
|
||||
break;
|
||||
case ALPHA_NUMERIC:
|
||||
pinEditText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError("Unexpected type!");
|
||||
}
|
||||
|
||||
pinEditText.addTextChangedListener(new SimpleTextWatcher() {
|
||||
@Override
|
||||
public void onTextChanged(String text) {
|
||||
turnOffButton.setEnabled(text.length() >= KbsConstants.MINIMUM_PIN_LENGTH);
|
||||
}
|
||||
});
|
||||
|
||||
pinEditText.setTypeface(Typeface.DEFAULT);
|
||||
|
||||
turnOffButton.setOnClickListener(v -> {
|
||||
String pin = pinEditText.getText().toString();
|
||||
boolean correct = PinHashing.verifyLocalPinHash(Objects.requireNonNull(SignalStore.kbsValues().getLocalPinHash()), pin);
|
||||
|
||||
if (correct) {
|
||||
SignalStore.pinValues().setPinRemindersEnabled(false);
|
||||
((SwitchPreferenceCompat) findPreference(PinValues.PIN_REMINDERS_ENABLED)).setChecked(false);
|
||||
dialog.dismiss();
|
||||
} else {
|
||||
statusText.setText(R.string.preferences_app_protection__incorrect_pin_try_again);
|
||||
}
|
||||
});
|
||||
|
||||
cancelButton.setOnClickListener(v -> dialog.dismiss());
|
||||
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class PhoneNumberPrivacyWhoCanSeeClickListener implements Preference.OnPreferenceClickListener {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
PhoneNumberPrivacyValues phoneNumberPrivacyValues = SignalStore.phoneNumberPrivacy();
|
||||
|
||||
final PhoneNumberPrivacyValues.PhoneNumberSharingMode[] value = { phoneNumberPrivacyValues.getPhoneNumberSharingMode() };
|
||||
|
||||
Map<PhoneNumberPrivacyValues.PhoneNumberSharingMode, CharSequence> items = items(requireContext());
|
||||
List<PhoneNumberPrivacyValues.PhoneNumberSharingMode> modes = new ArrayList<>(items.keySet());
|
||||
CharSequence[] modeStrings = items.values().toArray(new CharSequence[0]);
|
||||
int selectedMode = modes.indexOf(value[0]);
|
||||
|
||||
new AlertDialog.Builder(requireActivity())
|
||||
.setTitle(R.string.preferences_app_protection__see_my_phone_number)
|
||||
.setCancelable(true)
|
||||
.setSingleChoiceItems(modeStrings, selectedMode, (dialog, which) -> value[0] = modes.get(which))
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||
PhoneNumberPrivacyValues.PhoneNumberSharingMode phoneNumberSharingMode = value[0];
|
||||
phoneNumberPrivacyValues.setPhoneNumberSharingMode(phoneNumberSharingMode);
|
||||
Log.i(TAG, String.format("PhoneNumberSharingMode changed to %s. Scheduling storage value sync", phoneNumberSharingMode));
|
||||
StorageSyncHelper.scheduleSyncForDataChange();
|
||||
initializePhoneNumberPrivacyWhoCanSeeSummary();
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Map<PhoneNumberPrivacyValues.PhoneNumberSharingMode, CharSequence> items(Context context) {
|
||||
Map<PhoneNumberPrivacyValues.PhoneNumberSharingMode, CharSequence> map = new LinkedHashMap<>();
|
||||
|
||||
map.put(PhoneNumberPrivacyValues.PhoneNumberSharingMode.EVERYONE, titleAndDescription(context, context.getString(R.string.PhoneNumberPrivacy_everyone), context.getString(R.string.PhoneNumberPrivacy_everyone_see_description)));
|
||||
map.put(PhoneNumberPrivacyValues.PhoneNumberSharingMode.NOBODY, context.getString(R.string.PhoneNumberPrivacy_nobody));
|
||||
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
private final class PhoneNumberPrivacyWhoCanFindClickListener implements Preference.OnPreferenceClickListener {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
PhoneNumberPrivacyValues phoneNumberPrivacyValues = SignalStore.phoneNumberPrivacy();
|
||||
|
||||
final PhoneNumberPrivacyValues.PhoneNumberListingMode[] value = { phoneNumberPrivacyValues.getPhoneNumberListingMode() };
|
||||
|
||||
new AlertDialog.Builder(requireActivity())
|
||||
.setTitle(R.string.preferences_app_protection__find_me_by_phone_number)
|
||||
.setCancelable(true)
|
||||
.setSingleChoiceItems(items(requireContext()),
|
||||
value[0].ordinal(),
|
||||
(dialog, which) -> value[0] = PhoneNumberPrivacyValues.PhoneNumberListingMode.values()[which])
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||
PhoneNumberPrivacyValues.PhoneNumberListingMode phoneNumberListingMode = value[0];
|
||||
phoneNumberPrivacyValues.setPhoneNumberListingMode(phoneNumberListingMode);
|
||||
Log.i(TAG, String.format("PhoneNumberListingMode changed to %s. Scheduling storage value sync", phoneNumberListingMode));
|
||||
StorageSyncHelper.scheduleSyncForDataChange();
|
||||
ApplicationDependencies.getJobManager().add(new RefreshAttributesJob());
|
||||
initializePhoneNumberPrivacyWhoCanFindSummary();
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private CharSequence[] items(Context context) {
|
||||
return new CharSequence[]{
|
||||
titleAndDescription(context, context.getString(R.string.PhoneNumberPrivacy_everyone), context.getString(R.string.PhoneNumberPrivacy_everyone_find_description)),
|
||||
context.getString(R.string.PhoneNumberPrivacy_nobody) };
|
||||
}
|
||||
}
|
||||
|
||||
/** Adds a detail row for radio group descriptions. */
|
||||
private static CharSequence titleAndDescription(@NonNull Context context, @NonNull String header, @NonNull String description) {
|
||||
SpannableStringBuilder builder = new SpannableStringBuilder();
|
||||
|
||||
builder.append("\n");
|
||||
builder.append(header);
|
||||
builder.append("\n");
|
||||
|
||||
builder.setSpan(new TextAppearanceSpan(context, android.R.style.TextAppearance_Small), builder.length(), builder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
|
||||
builder.append(description);
|
||||
builder.append("\n");
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package org.thoughtcrime.securesms.preferences;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.preference.ListPreference;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.util.ActivityTransitionUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.wallpaper.ChatWallpaperActivity;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class AppearancePreferenceFragment extends ListSummaryPreferenceFragment {
|
||||
|
||||
private static final String WALLPAPER_PREF = "pref_wallpaper";
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle paramBundle) {
|
||||
super.onCreate(paramBundle);
|
||||
|
||||
this.findPreference(TextSecurePreferences.THEME_PREF).setOnPreferenceChangeListener(new ListSummaryListener());
|
||||
this.findPreference(TextSecurePreferences.LANGUAGE_PREF).setOnPreferenceChangeListener(new ListSummaryListener());
|
||||
this.findPreference(WALLPAPER_PREF).setOnPreferenceClickListener(preference -> {
|
||||
startActivity(ChatWallpaperActivity.createIntent(requireContext()));
|
||||
ActivityTransitionUtil.setSlideInTransition(requireActivity());
|
||||
return true;
|
||||
});
|
||||
initializeListSummary((ListPreference)findPreference(TextSecurePreferences.THEME_PREF));
|
||||
initializeListSummary((ListPreference)findPreference(TextSecurePreferences.LANGUAGE_PREF));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
|
||||
addPreferencesFromResource(R.xml.preferences_appearance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener((ApplicationPreferencesActivity)getActivity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
((ApplicationPreferencesActivity) getActivity()).getSupportActionBar().setTitle(R.string.preferences__appearance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener((ApplicationPreferencesActivity) getActivity());
|
||||
}
|
||||
|
||||
public static CharSequence getSummary(Context context) {
|
||||
String[] languageEntries = context.getResources().getStringArray(R.array.language_entries);
|
||||
String[] languageEntryValues = context.getResources().getStringArray(R.array.language_values);
|
||||
String[] themeEntries = context.getResources().getStringArray(R.array.pref_theme_entries);
|
||||
String[] themeEntryValues = context.getResources().getStringArray(R.array.pref_theme_values);
|
||||
|
||||
int langIndex = Arrays.asList(languageEntryValues).indexOf(TextSecurePreferences.getLanguage(context));
|
||||
int themeIndex = Arrays.asList(themeEntryValues).indexOf(TextSecurePreferences.getTheme(context));
|
||||
|
||||
if (langIndex == -1) langIndex = 0;
|
||||
if (themeIndex == -1) themeIndex = 0;
|
||||
|
||||
return context.getString(R.string.ApplicationPreferencesActivity_appearance_summary,
|
||||
themeEntries[themeIndex],
|
||||
languageEntries[langIndex]);
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,6 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.util.BackupUtil;
|
||||
import org.thoughtcrime.securesms.util.StorageUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
@@ -83,7 +82,6 @@ public class BackupsPreferenceFragment extends Fragment {
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
((AppCompatActivity) getActivity()).getSupportActionBar().setTitle(R.string.BackupsPreferenceFragment__chat_backups);
|
||||
|
||||
setBackupStatus();
|
||||
setBackupSummary();
|
||||
@@ -133,7 +131,7 @@ public class BackupsPreferenceFragment extends Fragment {
|
||||
}
|
||||
|
||||
private void setBackupStatus() {
|
||||
if (TextSecurePreferences.isBackupEnabled(requireContext())) {
|
||||
if (SignalStore.settings().isBackupEnabled()) {
|
||||
if (BackupUtil.canUserAccessBackupDirectory(requireContext())) {
|
||||
setBackupsEnabled();
|
||||
} else {
|
||||
@@ -191,7 +189,7 @@ public class BackupsPreferenceFragment extends Fragment {
|
||||
|
||||
@RequiresApi(29)
|
||||
private void onToggleClickedApi29() {
|
||||
if (!TextSecurePreferences.isBackupEnabled(requireContext())) {
|
||||
if (!SignalStore.settings().isBackupEnabled()) {
|
||||
BackupDialog.showChooseBackupLocationDialog(this, CHOOSE_BACKUPS_LOCATION_REQUEST_CODE);
|
||||
} else {
|
||||
BackupDialog.showDisableBackupDialog(requireContext(), this::setBackupsDisabled);
|
||||
@@ -203,7 +201,7 @@ public class BackupsPreferenceFragment extends Fragment {
|
||||
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
.ifNecessary()
|
||||
.onAllGranted(() -> {
|
||||
if (!TextSecurePreferences.isBackupEnabled(requireContext())) {
|
||||
if (!SignalStore.settings().isBackupEnabled()) {
|
||||
BackupDialog.showEnableBackupDialog(requireContext(), null, null, this::setBackupsEnabled);
|
||||
} else {
|
||||
BackupDialog.showDisableBackupDialog(requireContext(), this::setBackupsDisabled);
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
package org.thoughtcrime.securesms.preferences;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.AvatarImageView;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientForeverObserver;
|
||||
|
||||
public class BlockedContactListItem extends RelativeLayout implements RecipientForeverObserver {
|
||||
|
||||
private AvatarImageView contactPhotoImage;
|
||||
private TextView nameView;
|
||||
private GlideRequests glideRequests;
|
||||
private LiveRecipient recipient;
|
||||
|
||||
public BlockedContactListItem(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public BlockedContactListItem(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public BlockedContactListItem(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
this.contactPhotoImage = findViewById(R.id.contact_photo_image);
|
||||
this.nameView = findViewById(R.id.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
if (this.recipient != null) {
|
||||
recipient.removeForeverObserver(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void set(@NonNull GlideRequests glideRequests, @NonNull LiveRecipient recipient) {
|
||||
this.glideRequests = glideRequests;
|
||||
this.recipient = recipient;
|
||||
|
||||
onRecipientChanged(recipient.get());
|
||||
|
||||
this.recipient.observeForever(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecipientChanged(@NonNull Recipient recipient) {
|
||||
final AvatarImageView contactPhotoImage = this.contactPhotoImage;
|
||||
final TextView nameView = this.nameView;
|
||||
|
||||
contactPhotoImage.setAvatar(glideRequests, recipient, false);
|
||||
nameView.setText(recipient.getDisplayName(getContext()));
|
||||
}
|
||||
|
||||
public Recipient getRecipient() {
|
||||
return recipient.get();
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
package org.thoughtcrime.securesms.preferences;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.preference.ListPreference;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.devicetransfer.olddevice.OldDeviceTransferActivity;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
|
||||
import org.thoughtcrime.securesms.util.ConversationUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.ThrottledDebouncer;
|
||||
|
||||
public class ChatsPreferenceFragment extends ListSummaryPreferenceFragment {
|
||||
private static final String PREFER_SYSTEM_CONTACT_PHOTOS = "pref_system_contact_photos";
|
||||
|
||||
private final ThrottledDebouncer refreshDebouncer = new ThrottledDebouncer(500);
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle paramBundle) {
|
||||
super.onCreate(paramBundle);
|
||||
|
||||
findPreference(TextSecurePreferences.MESSAGE_BODY_TEXT_SIZE_PREF)
|
||||
.setOnPreferenceChangeListener(new ListSummaryListener());
|
||||
|
||||
findPreference(TextSecurePreferences.BACKUP).setOnPreferenceClickListener(unused -> {
|
||||
goToBackupsPreferenceFragment();
|
||||
return true;
|
||||
});
|
||||
|
||||
findPreference(TextSecurePreferences.TRANSFER).setOnPreferenceClickListener(unused -> {
|
||||
goToTransferAccount();
|
||||
return true;
|
||||
});
|
||||
|
||||
findPreference(PREFER_SYSTEM_CONTACT_PHOTOS)
|
||||
.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
SignalStore.settings().setPreferSystemContactPhotos(newValue == Boolean.TRUE);
|
||||
refreshDebouncer.publish(ConversationUtil::refreshRecipientShortcuts);
|
||||
StorageSyncHelper.scheduleSyncForDataChange();
|
||||
return true;
|
||||
});
|
||||
|
||||
initializeListSummary((ListPreference) findPreference(TextSecurePreferences.MESSAGE_BODY_TEXT_SIZE_PREF));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
|
||||
addPreferencesFromResource(R.xml.preferences_chats);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
((ApplicationPreferencesActivity)getActivity()).getSupportActionBar().setTitle(R.string.preferences_chats__chats);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
EventBus.getDefault().unregister(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
|
||||
}
|
||||
|
||||
private void goToBackupsPreferenceFragment() {
|
||||
((ApplicationPreferencesActivity) requireActivity()).pushFragment(new BackupsPreferenceFragment());
|
||||
}
|
||||
|
||||
private void goToTransferAccount() {
|
||||
requireContext().startActivity(new Intent(requireContext(), OldDeviceTransferActivity.class));
|
||||
}
|
||||
|
||||
public static CharSequence getSummary(Context context) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
package org.thoughtcrime.securesms.preferences;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.webrtc.CallBandwidthMode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class DataAndStoragePreferenceFragment extends ListSummaryPreferenceFragment {
|
||||
|
||||
private static final String TAG = Log.tag(DataAndStoragePreferenceFragment.class);
|
||||
private static final String MANAGE_STORAGE_KEY = "pref_data_manage";
|
||||
private static final String USE_PROXY_KEY = "pref_use_proxy";
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
|
||||
findPreference(TextSecurePreferences.MEDIA_DOWNLOAD_MOBILE_PREF)
|
||||
.setOnPreferenceChangeListener(new MediaDownloadChangeListener());
|
||||
findPreference(TextSecurePreferences.MEDIA_DOWNLOAD_WIFI_PREF)
|
||||
.setOnPreferenceChangeListener(new MediaDownloadChangeListener());
|
||||
findPreference(TextSecurePreferences.MEDIA_DOWNLOAD_ROAMING_PREF)
|
||||
.setOnPreferenceChangeListener(new MediaDownloadChangeListener());
|
||||
|
||||
findPreference(TextSecurePreferences.CALL_BANDWIDTH_PREF)
|
||||
.setOnPreferenceChangeListener(new CallBandwidthChangeListener());
|
||||
initializeListSummary((ListPreference) findPreference(TextSecurePreferences.CALL_BANDWIDTH_PREF));
|
||||
|
||||
Preference manageStorage = findPreference(MANAGE_STORAGE_KEY);
|
||||
manageStorage.setOnPreferenceClickListener(unused -> {
|
||||
requireApplicationPreferencesActivity().pushFragment(new StoragePreferenceFragment());
|
||||
return false;
|
||||
});
|
||||
|
||||
ApplicationPreferencesViewModel viewModel = ApplicationPreferencesViewModel.getApplicationPreferencesViewModel(requireActivity());
|
||||
|
||||
viewModel.getStorageBreakdown()
|
||||
.observe(requireActivity(),
|
||||
breakdown -> manageStorage.setSummary(Util.getPrettyFileSize(breakdown.getTotalSize())));
|
||||
|
||||
|
||||
findPreference(USE_PROXY_KEY).setOnPreferenceClickListener(unused -> {
|
||||
requireApplicationPreferencesActivity().pushFragment(EditProxyFragment.newInstance());
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
addPreferencesFromResource(R.xml.preferences_data_and_storage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
requireApplicationPreferencesActivity().getSupportActionBar().setTitle(R.string.preferences__data_and_storage);
|
||||
setMediaDownloadSummaries();
|
||||
ApplicationPreferencesViewModel.getApplicationPreferencesViewModel(requireActivity()).refreshStorageBreakdown(requireContext());
|
||||
findPreference(USE_PROXY_KEY).setSummary(SignalStore.proxy().isProxyEnabled() ? R.string.preferences_on : R.string.preferences_off);
|
||||
}
|
||||
|
||||
private @NonNull ApplicationPreferencesActivity requireApplicationPreferencesActivity() {
|
||||
return (ApplicationPreferencesActivity) requireActivity();
|
||||
}
|
||||
|
||||
private void setMediaDownloadSummaries() {
|
||||
findPreference(TextSecurePreferences.MEDIA_DOWNLOAD_MOBILE_PREF)
|
||||
.setSummary(getSummaryForMediaPreference(TextSecurePreferences.getMobileMediaDownloadAllowed(getActivity())));
|
||||
findPreference(TextSecurePreferences.MEDIA_DOWNLOAD_WIFI_PREF)
|
||||
.setSummary(getSummaryForMediaPreference(TextSecurePreferences.getWifiMediaDownloadAllowed(getActivity())));
|
||||
findPreference(TextSecurePreferences.MEDIA_DOWNLOAD_ROAMING_PREF)
|
||||
.setSummary(getSummaryForMediaPreference(TextSecurePreferences.getRoamingMediaDownloadAllowed(getActivity())));
|
||||
}
|
||||
|
||||
private CharSequence getSummaryForMediaPreference(Set<String> allowedNetworks) {
|
||||
String[] keys = getResources().getStringArray(R.array.pref_media_download_entries);
|
||||
String[] values = getResources().getStringArray(R.array.pref_media_download_values);
|
||||
List<String> outValues = new ArrayList<>(allowedNetworks.size());
|
||||
|
||||
for (int i=0; i < keys.length; i++) {
|
||||
if (allowedNetworks.contains(keys[i])) outValues.add(values[i]);
|
||||
}
|
||||
|
||||
return outValues.isEmpty() ? getResources().getString(R.string.preferences__none)
|
||||
: TextUtils.join(", ", outValues);
|
||||
}
|
||||
|
||||
private class MediaDownloadChangeListener implements Preference.OnPreferenceChangeListener {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
Log.i(TAG, "onPreferenceChange");
|
||||
preference.setSummary(getSummaryForMediaPreference((Set<String>)newValue));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class CallBandwidthChangeListener extends ListSummaryListener {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object value) {
|
||||
ListPreference listPref = (ListPreference) preference;
|
||||
int entryIndex = Arrays.asList(listPref.getEntryValues()).indexOf(value);
|
||||
|
||||
switch (entryIndex) {
|
||||
case 0:
|
||||
SignalStore.settings().setCallBandwidthMode(CallBandwidthMode.HIGH_ALWAYS);
|
||||
break;
|
||||
case 1:
|
||||
SignalStore.settings().setCallBandwidthMode(CallBandwidthMode.HIGH_ON_WIFI);
|
||||
break;
|
||||
case 2:
|
||||
SignalStore.settings().setCallBandwidthMode(CallBandwidthMode.LOW_ALWAYS);
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
ApplicationDependencies.getSignalCallManager().bandwidthModeUpdate();
|
||||
|
||||
return super.onPreferenceChange(preference, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,6 @@ import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.SwitchCompat;
|
||||
import androidx.core.app.ShareCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
@@ -33,13 +32,13 @@ import org.whispersystems.signalservice.internal.configuration.SignalProxy;
|
||||
|
||||
public class EditProxyFragment extends Fragment {
|
||||
|
||||
private SwitchCompat proxySwitch;
|
||||
private EditText proxyText;
|
||||
private TextView proxyTitle;
|
||||
private TextView proxyStatus;
|
||||
private View shareButton;
|
||||
private CircularProgressButton saveButton;
|
||||
private EditProxyViewModel viewModel;
|
||||
private SwitchCompat proxySwitch;
|
||||
private EditText proxyText;
|
||||
private TextView proxyTitle;
|
||||
private TextView proxyStatus;
|
||||
private View shareButton;
|
||||
private CircularProgressButton saveButton;
|
||||
private EditProxyViewModel viewModel;
|
||||
|
||||
public static EditProxyFragment newInstance() {
|
||||
return new EditProxyFragment();
|
||||
@@ -85,7 +84,7 @@ public class EditProxyFragment extends Fragment {
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
((AppCompatActivity) requireActivity()).getSupportActionBar().setTitle(R.string.preferences_use_proxy);
|
||||
|
||||
SignalProxyUtil.startListeningToWebsocket();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
package org.thoughtcrime.securesms.preferences;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.ClipData;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.preference.PreferenceDataStore;
|
||||
|
||||
import org.signal.core.util.concurrent.SignalExecutors;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.SwitchPreferenceCompat;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.emoji.EmojiFiles;
|
||||
import org.thoughtcrime.securesms.emoji.EmojiSource;
|
||||
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob;
|
||||
import org.thoughtcrime.securesms.jobs.RefreshOwnProfileJob;
|
||||
import org.thoughtcrime.securesms.jobs.RemoteConfigRefreshJob;
|
||||
import org.thoughtcrime.securesms.jobs.RotateProfileKeyJob;
|
||||
import org.thoughtcrime.securesms.jobs.StorageForcePushJob;
|
||||
import org.thoughtcrime.securesms.keyvalue.InternalValues;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.payments.DataExportUtil;
|
||||
import org.thoughtcrime.securesms.util.ConversationUtil;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||
|
||||
public class InternalOptionsPreferenceFragment extends CorrectedPreferenceFragment {
|
||||
private static final String TAG = Log.tag(InternalOptionsPreferenceFragment.class);
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle paramBundle) {
|
||||
super.onCreate(paramBundle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
|
||||
addPreferencesFromResource(R.xml.preferences_internal);
|
||||
|
||||
PreferenceDataStore preferenceDataStore = SignalStore.getPreferenceDataStore();
|
||||
|
||||
initializeSwitchPreference(preferenceDataStore, InternalValues.RECIPIENT_DETAILS, SignalStore.internalValues().recipientDetails());
|
||||
initializeSwitchPreference(preferenceDataStore, InternalValues.GV2_DO_NOT_CREATE_GV2, SignalStore.internalValues().gv2DoNotCreateGv2Groups());
|
||||
initializeSwitchPreference(preferenceDataStore, InternalValues.GV2_FORCE_INVITES, SignalStore.internalValues().gv2ForceInvites());
|
||||
initializeSwitchPreference(preferenceDataStore, InternalValues.GV2_IGNORE_SERVER_CHANGES, SignalStore.internalValues().gv2IgnoreServerChanges());
|
||||
initializeSwitchPreference(preferenceDataStore, InternalValues.GV2_IGNORE_P2P_CHANGES, SignalStore.internalValues().gv2IgnoreP2PChanges());
|
||||
initializeSwitchPreference(preferenceDataStore, InternalValues.GV2_DISABLE_AUTOMIGRATE_INITIATION, SignalStore.internalValues().disableGv1AutoMigrateInitiation());
|
||||
initializeSwitchPreference(preferenceDataStore, InternalValues.GV2_DISABLE_AUTOMIGRATE_NOTIFICATION, SignalStore.internalValues().disableGv1AutoMigrateNotification());
|
||||
initializeSwitchPreference(preferenceDataStore, InternalValues.FORCE_CENSORSHIP, SignalStore.internalValues().forcedCensorship());
|
||||
initializeSwitchPreference(preferenceDataStore, InternalValues.FORCE_BUILT_IN_EMOJI, SignalStore.internalValues().forceBuiltInEmoji());
|
||||
|
||||
findPreference("pref_copy_payments_data").setOnPreferenceClickListener(preference -> {
|
||||
new AlertDialog.Builder(getContext())
|
||||
.setMessage("Local payments history will be copied to the clipboard.\n" +
|
||||
"It may therefore compromise privacy.\n" +
|
||||
"However, no private keys will be copied.")
|
||||
.setPositiveButton("Copy", (dialog, which) -> {
|
||||
SimpleTask.run(SignalExecutors.UNBOUNDED,
|
||||
() -> {
|
||||
Context context = ApplicationDependencies.getApplication();
|
||||
android.content.ClipboardManager clipboard =
|
||||
(android.content.ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
String tsv = DataExportUtil.createTsv();
|
||||
ClipData clip = ClipData.newPlainText(context.getString(R.string.app_name), tsv);
|
||||
clipboard.setPrimaryClip(clip);
|
||||
return null;
|
||||
},
|
||||
r -> Toast.makeText(getContext(), "Payments have been copied", Toast.LENGTH_SHORT).show()
|
||||
);
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show();
|
||||
return true;
|
||||
});
|
||||
|
||||
findPreference("pref_refresh_attributes").setOnPreferenceClickListener(preference -> {
|
||||
ApplicationDependencies.getJobManager()
|
||||
.startChain(new RefreshAttributesJob())
|
||||
.then(new RefreshOwnProfileJob())
|
||||
.enqueue();
|
||||
Toast.makeText(getContext(), "Scheduled attribute refresh", Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
});
|
||||
|
||||
findPreference("pref_rotate_profile_key").setOnPreferenceClickListener(preference -> {
|
||||
ApplicationDependencies.getJobManager().add(new RotateProfileKeyJob());
|
||||
Toast.makeText(getContext(), "Scheduled profile key rotation", Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
});
|
||||
|
||||
findPreference("pref_refresh_remote_values").setOnPreferenceClickListener(preference -> {
|
||||
ApplicationDependencies.getJobManager().add(new RemoteConfigRefreshJob());
|
||||
Toast.makeText(getContext(), "Scheduled remote config refresh", Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
});
|
||||
|
||||
findPreference("pref_force_send").setOnPreferenceClickListener(preference -> {
|
||||
ApplicationDependencies.getJobManager().add(new StorageForcePushJob());
|
||||
Toast.makeText(getContext(), "Scheduled storage force push", Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
});
|
||||
|
||||
findPreference("pref_delete_dynamic_shortcuts").setOnPreferenceClickListener(preference -> {
|
||||
ConversationUtil.clearAllShortcuts(requireContext());
|
||||
Toast.makeText(getContext(), "Deleted all dynamic shortcuts.", Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void initializeSwitchPreference(@NonNull PreferenceDataStore preferenceDataStore,
|
||||
@NonNull String key,
|
||||
boolean checked)
|
||||
{
|
||||
SwitchPreferenceCompat forceGv2Preference = (SwitchPreferenceCompat) findPreference(key);
|
||||
forceGv2Preference.setPreferenceDataStore(preferenceDataStore);
|
||||
forceGv2Preference.setChecked(checked);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
//noinspection ConstantConditions
|
||||
((ApplicationPreferencesActivity) getActivity()).getSupportActionBar().setTitle(R.string.preferences__internal_preferences);
|
||||
|
||||
SimpleTask.run(getViewLifecycleOwner().getLifecycle(),
|
||||
() -> EmojiFiles.Version.readVersion(requireContext()),
|
||||
version -> {
|
||||
if (version != null) {
|
||||
findPreference(InternalValues.FORCE_BUILT_IN_EMOJI).setSummary(getString(R.string.preferences__internal_current_version_d_at_density_s, version.getVersion(), version.getDensity()));
|
||||
} else {
|
||||
findPreference(InternalValues.FORCE_BUILT_IN_EMOJI).setSummary(getString(R.string.preferences__internal_current_version_builtin));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
SignalExecutors.BOUNDED.execute(EmojiSource::refresh);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user