mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-05-08 09:18:39 +01:00
Refactor app settings.
This commit is contained in:
committed by
Greyson Parrelli
parent
a94d77d81e
commit
f2d5ea0391
@@ -355,8 +355,9 @@
|
|||||||
<activity android:name=".VerifyIdentityActivity"
|
<activity android:name=".VerifyIdentityActivity"
|
||||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||||
|
|
||||||
<activity android:name=".ApplicationPreferencesActivity"
|
<activity android:name=".components.settings.app.AppSettingsActivity"
|
||||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
|
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
|
||||||
|
android:theme="@style/Signal.DayNight.NoActionBar"
|
||||||
android:windowSoftInputMode="adjustResize">
|
android:windowSoftInputMode="adjustResize">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|||||||
@@ -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.components.ContactFilterToolbar;
|
||||||
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader.DisplayMode;
|
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader.DisplayMode;
|
||||||
import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper;
|
import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper;
|
||||||
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
|
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
|
||||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
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 org.whispersystems.libsignal.util.guava.Optional;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -65,8 +66,8 @@ public abstract class ContactSelectionActivity extends PassphraseRequiredActivit
|
|||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle icicle, boolean ready) {
|
protected void onCreate(Bundle icicle, boolean ready) {
|
||||||
if (!getIntent().hasExtra(ContactSelectionListFragment.DISPLAY_MODE)) {
|
if (!getIntent().hasExtra(ContactSelectionListFragment.DISPLAY_MODE)) {
|
||||||
int displayMode = TextSecurePreferences.isSmsEnabled(this) ? DisplayMode.FLAG_ALL
|
int displayMode = Util.isDefaultSmsProvider(this) ? DisplayMode.FLAG_ALL
|
||||||
: DisplayMode.FLAG_PUSH | DisplayMode.FLAG_ACTIVE_GROUPS | DisplayMode.FLAG_INACTIVE_GROUPS | DisplayMode.FLAG_SELF;
|
: DisplayMode.FLAG_PUSH | DisplayMode.FLAG_ACTIVE_GROUPS | DisplayMode.FLAG_INACTIVE_GROUPS | DisplayMode.FLAG_SELF;
|
||||||
getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE, displayMode);
|
getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE, displayMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -77,16 +77,6 @@ public class DeviceActivity extends PassphraseRequiredActivity
|
|||||||
} else {
|
} else {
|
||||||
initFragment(android.R.id.content, deviceListFragment, dynamicLanguage.getCurrentLocale());
|
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
|
@Override
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentManager;
|
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.conversation.ConversationIntents;
|
||||||
import org.thoughtcrime.securesms.conversationlist.ConversationListArchiveFragment;
|
import org.thoughtcrime.securesms.conversationlist.ConversationListArchiveFragment;
|
||||||
import org.thoughtcrime.securesms.conversationlist.ConversationListFragment;
|
import org.thoughtcrime.securesms.conversationlist.ConversationListFragment;
|
||||||
@@ -69,8 +71,7 @@ public class MainNavigator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void goToAppSettings() {
|
public void goToAppSettings() {
|
||||||
Intent intent = new Intent(activity, ApplicationPreferencesActivity.class);
|
activity.startActivityForResult(AppSettingsActivity.home(activity), REQUEST_CONFIG_CHANGES);
|
||||||
activity.startActivityForResult(intent, REQUEST_CONFIG_CHANGES);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void goToArchiveList() {
|
public void goToArchiveList() {
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ public class BackupDialog {
|
|||||||
|
|
||||||
BackupPassphrase.set(context, Util.join(password, " "));
|
BackupPassphrase.set(context, Util.join(password, " "));
|
||||||
TextSecurePreferences.setNextBackupTime(context, 0);
|
TextSecurePreferences.setNextBackupTime(context, 0);
|
||||||
TextSecurePreferences.setBackupEnabled(context, true);
|
SignalStore.settings().setBackupEnabled(true);
|
||||||
LocalBackupListener.schedule(context);
|
LocalBackupListener.schedule(context);
|
||||||
|
|
||||||
onBackupsEnabled.run();
|
onBackupsEnabled.run();
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package org.thoughtcrime.securesms.backup;
|
|||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@@ -11,8 +10,8 @@ import androidx.annotation.StringRes;
|
|||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
import androidx.core.app.NotificationManagerCompat;
|
import androidx.core.app.NotificationManagerCompat;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
|
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity;
|
||||||
import org.thoughtcrime.securesms.notifications.NotificationCancellationHelper;
|
import org.thoughtcrime.securesms.notifications.NotificationCancellationHelper;
|
||||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||||
|
|
||||||
@@ -39,11 +38,7 @@ public enum BackupFileIOError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void postNotification(@NonNull Context context) {
|
public void postNotification(@NonNull Context context) {
|
||||||
Intent intent = new Intent(context, ApplicationPreferencesActivity.class);
|
PendingIntent pendingIntent = PendingIntent.getActivity(context, -1, AppSettingsActivity.backups(context), 0);
|
||||||
|
|
||||||
intent.putExtra(ApplicationPreferencesActivity.LAUNCH_TO_BACKUPS_FRAGMENT, true);
|
|
||||||
|
|
||||||
PendingIntent pendingIntent = PendingIntent.getActivity(context, -1, intent, 0);
|
|
||||||
Notification backupFailedNotification = new NotificationCompat.Builder(context, NotificationChannels.FAILURES)
|
Notification backupFailedNotification = new NotificationCompat.Builder(context, NotificationChannels.FAILURES)
|
||||||
.setSmallIcon(R.drawable.ic_signal_backup)
|
.setSmallIcon(R.drawable.ic_signal_backup)
|
||||||
.setContentTitle(context.getString(titleId))
|
.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.MentionRendererDelegate;
|
||||||
import org.thoughtcrime.securesms.components.mention.MentionValidatorWatcher;
|
import org.thoughtcrime.securesms.components.mention.MentionValidatorWatcher;
|
||||||
import org.thoughtcrime.securesms.database.model.Mention;
|
import org.thoughtcrime.securesms.database.model.Mention;
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.util.StringUtil;
|
import org.thoughtcrime.securesms.util.StringUtil;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
@@ -201,7 +202,7 @@ public class ComposeText extends EmojiEditText {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setTransport(TransportOption transport) {
|
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 imeOptions = (getImeOptions() & ~EditorInfo.IME_MASK_ACTION) | EditorInfo.IME_ACTION_SEND;
|
||||||
int inputType = getInputType();
|
int inputType = getInputType();
|
||||||
@@ -225,7 +226,7 @@ public class ComposeText extends EmojiEditText {
|
|||||||
public InputConnection onCreateInputConnection(EditorInfo editorInfo) {
|
public InputConnection onCreateInputConnection(EditorInfo editorInfo) {
|
||||||
InputConnection inputConnection = super.onCreateInputConnection(editorInfo);
|
InputConnection inputConnection = super.onCreateInputConnection(editorInfo);
|
||||||
|
|
||||||
if(TextSecurePreferences.isEnterSendsEnabled(getContext())) {
|
if(SignalStore.settings().isEnterKeySends()) {
|
||||||
editorInfo.imeOptions &= ~EditorInfo.IME_FLAG_NO_ENTER_ACTION;
|
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.components.emoji.MediaKeyboard;
|
||||||
import org.thoughtcrime.securesms.conversation.ConversationStickerSuggestionAdapter;
|
import org.thoughtcrime.securesms.conversation.ConversationStickerSuggestionAdapter;
|
||||||
import org.thoughtcrime.securesms.database.model.StickerRecord;
|
import org.thoughtcrime.securesms.database.model.StickerRecord;
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository;
|
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository;
|
||||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||||
@@ -124,7 +125,7 @@ public class InputPanel extends LinearLayout
|
|||||||
|
|
||||||
this.recordLockCancel.setOnClickListener(v -> microphoneRecorderView.cancelAction());
|
this.recordLockCancel.setOnClickListener(v -> microphoneRecorderView.cancelAction());
|
||||||
|
|
||||||
if (TextSecurePreferences.isSystemEmojiPreferred(getContext())) {
|
if (SignalStore.settings().isPreferSystemEmoji()) {
|
||||||
mediaKeyboard.setVisibility(View.GONE);
|
mediaKeyboard.setVisibility(View.GONE);
|
||||||
emojiVisible = false;
|
emojiVisible = false;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import androidx.appcompat.widget.AppCompatEditText;
|
|||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.components.emoji.EmojiProvider.EmojiDrawable;
|
import org.thoughtcrime.securesms.components.emoji.EmojiProvider.EmojiDrawable;
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
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);
|
boolean forceCustom = a.getBoolean(R.styleable.EmojiTextView_emoji_forceCustom, false);
|
||||||
a.recycle();
|
a.recycle();
|
||||||
|
|
||||||
if (forceCustom || !TextSecurePreferences.isSystemEmojiPreferred(getContext())) {
|
if (forceCustom || !SignalStore.settings().isPreferSystemEmoji()) {
|
||||||
if (!isInEditMode()) {
|
if (!isInEditMode()) {
|
||||||
setFilters(appendEmojiFilter(this.getFilters()));
|
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.emoji.parsing.EmojiParser;
|
||||||
import org.thoughtcrime.securesms.components.mention.MentionAnnotation;
|
import org.thoughtcrime.securesms.components.mention.MentionAnnotation;
|
||||||
import org.thoughtcrime.securesms.components.mention.MentionRendererDelegate;
|
import org.thoughtcrime.securesms.components.mention.MentionRendererDelegate;
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
@@ -215,7 +216,7 @@ public class EmojiTextView extends AppCompatTextView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean useSystemEmoji() {
|
private boolean useSystemEmoji() {
|
||||||
return !forceCustom && TextSecurePreferences.isSystemEmojiPreferred(getContext());
|
return !forceCustom && SignalStore.settings().isPreferSystemEmoji();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+71
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+181
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
+94
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
+121
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+198
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
@@ -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)
|
||||||
+19
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
+180
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package org.thoughtcrime.securesms.components.settings.app.account
|
||||||
|
|
||||||
|
data class AccountSettingsState(
|
||||||
|
val hasPin: Boolean,
|
||||||
|
val pinRemindersEnabled: Boolean,
|
||||||
|
val registrationLockEnabled: Boolean
|
||||||
|
)
|
||||||
+24
@@ -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
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
+70
@@ -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])
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package org.thoughtcrime.securesms.components.settings.app.appearance
|
||||||
|
|
||||||
|
data class AppearanceSettingsState(
|
||||||
|
val theme: String,
|
||||||
|
val messageFontSize: Int,
|
||||||
|
val language: String
|
||||||
|
)
|
||||||
+37
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
+87
@@ -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)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+37
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
@@ -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
|
||||||
|
)
|
||||||
+56
@@ -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)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+90
@@ -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)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
@@ -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
|
||||||
|
)
|
||||||
+35
@@ -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())) }
|
||||||
|
}
|
||||||
|
}
|
||||||
+115
@@ -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)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+19
@@ -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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
@@ -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
|
||||||
|
)
|
||||||
+77
@@ -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)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+65
@@ -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))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+281
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
+16
@@ -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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+16
@@ -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?
|
||||||
|
)
|
||||||
+90
@@ -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)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+337
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+27
@@ -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
|
||||||
|
)
|
||||||
+121
@@ -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)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+391
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+58
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+18
@@ -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
|
||||||
|
)
|
||||||
+118
@@ -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)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+161
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+63
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
@@ -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
|
||||||
|
)
|
||||||
+95
@@ -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
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+53
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
+16
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -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)
|
||||||
+2
-1
@@ -13,6 +13,7 @@ import org.thoughtcrime.securesms.R;
|
|||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference;
|
import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.util.DateUtils;
|
import org.thoughtcrime.securesms.util.DateUtils;
|
||||||
@@ -67,7 +68,7 @@ class VoiceNoteMediaDescriptionCompatFactory {
|
|||||||
extras.putString(EXTRA_COLOR, threadRecipient.getColor().serialize());
|
extras.putString(EXTRA_COLOR, threadRecipient.getColor().serialize());
|
||||||
extras.putLong(EXTRA_MESSAGE_ID, messageRecord.getId());
|
extras.putLong(EXTRA_MESSAGE_ID, messageRecord.getId());
|
||||||
|
|
||||||
NotificationPrivacyPreference preference = TextSecurePreferences.getNotificationPrivacy(context);
|
NotificationPrivacyPreference preference = SignalStore.settings().getMessageNotificationsPrivacy();
|
||||||
|
|
||||||
String title;
|
String title;
|
||||||
if (preference.isDisplayContact() && threadRecipient.isGroup()) {
|
if (preference.isDisplayContact() && threadRecipient.isGroup()) {
|
||||||
|
|||||||
+2
-1
@@ -19,6 +19,7 @@ import org.thoughtcrime.securesms.R;
|
|||||||
import org.thoughtcrime.securesms.color.MaterialColor;
|
import org.thoughtcrime.securesms.color.MaterialColor;
|
||||||
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
|
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
|
||||||
import org.thoughtcrime.securesms.conversation.ConversationIntents;
|
import org.thoughtcrime.securesms.conversation.ConversationIntents;
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
@@ -130,7 +131,7 @@ class VoiceNoteNotificationManager {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable Bitmap getCurrentLargeIcon(Player player, PlayerNotificationManager.BitmapCallback callback) {
|
public @Nullable Bitmap getCurrentLargeIcon(Player player, PlayerNotificationManager.BitmapCallback callback) {
|
||||||
if (!hasMetadata() || !TextSecurePreferences.getNotificationPrivacy(context).isDisplayContact()) {
|
if (!hasMetadata() || !SignalStore.settings().getMessageNotificationsPrivacy().isDisplayContact()) {
|
||||||
cachedBitmap = null;
|
cachedBitmap = null;
|
||||||
cachedRecipientId = null;
|
cachedRecipientId = null;
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
+2
-1
@@ -13,6 +13,7 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
|
|||||||
import org.thoughtcrime.securesms.database.MessageDatabase;
|
import org.thoughtcrime.securesms.database.MessageDatabase;
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
|
import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
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);
|
List<MessageDatabase.MarkedMessageInfo> marked = threadDatabase.setRead(getIntent().getLongExtra(EXTRA_THREAD_ID, -1), false);
|
||||||
MarkReadReceiver.process(this, marked);
|
MarkReadReceiver.process(this, marked);
|
||||||
|
|
||||||
TextSecurePreferences.setNewContactsNotificationEnabled(this, false);
|
SignalStore.settings().setNotifyWhenContactJoinsSignal(false);
|
||||||
ApplicationDependencies.getMessageNotifier().updateNotification(this);
|
ApplicationDependencies.getMessageNotifier().updateNotification(this);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -463,7 +463,7 @@ public class DirectoryHelper {
|
|||||||
private static void notifyNewUsers(@NonNull Context context,
|
private static void notifyNewUsers(@NonNull Context context,
|
||||||
@NonNull Collection<RecipientId> newUsers)
|
@NonNull Collection<RecipientId> newUsers)
|
||||||
{
|
{
|
||||||
if (!TextSecurePreferences.isNewContactsNotificationEnabled(context)) return;
|
if (!SignalStore.settings().isNotifyWhenContactJoinsSignal()) return;
|
||||||
|
|
||||||
for (RecipientId newUser: newUsers) {
|
for (RecipientId newUser: newUsers) {
|
||||||
Recipient recipient = Recipient.resolved(newUser);
|
Recipient recipient = Recipient.resolved(newUser);
|
||||||
|
|||||||
@@ -2184,7 +2184,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
|
|||||||
stickerViewModel.getStickersAvailability().observe(this, stickersAvailable -> {
|
stickerViewModel.getStickersAvailability().observe(this, stickersAvailable -> {
|
||||||
if (stickersAvailable == null) return;
|
if (stickersAvailable == null) return;
|
||||||
|
|
||||||
boolean isSystemEmojiPreferred = TextSecurePreferences.isSystemEmojiPreferred(this);
|
boolean isSystemEmojiPreferred = SignalStore.settings().isPreferSystemEmoji();
|
||||||
MediaKeyboardMode keyboardMode = TextSecurePreferences.getMediaKeyboardMode(this);
|
MediaKeyboardMode keyboardMode = TextSecurePreferences.getMediaKeyboardMode(this);
|
||||||
boolean stickerIntro = !TextSecurePreferences.hasSeenStickerIntroTooltip(this);
|
boolean stickerIntro = !TextSecurePreferences.hasSeenStickerIntroTooltip(this);
|
||||||
|
|
||||||
@@ -2631,7 +2631,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void initializeMediaKeyboardProviders(@NonNull MediaKeyboard mediaKeyboard, boolean stickersAvailable) {
|
private void initializeMediaKeyboardProviders(@NonNull MediaKeyboard mediaKeyboard, boolean stickersAvailable) {
|
||||||
boolean isSystemEmojiPreferred = TextSecurePreferences.isSystemEmojiPreferred(this);
|
boolean isSystemEmojiPreferred = SignalStore.settings().isPreferSystemEmoji();
|
||||||
|
|
||||||
if (stickersAvailable) {
|
if (stickersAvailable) {
|
||||||
if (isSystemEmojiPreferred) {
|
if (isSystemEmojiPreferred) {
|
||||||
@@ -3277,7 +3277,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
|
|||||||
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
||||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||||
if (keyCode == KeyEvent.KEYCODE_ENTER) {
|
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_DOWN, KeyEvent.KEYCODE_ENTER));
|
||||||
sendButton.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER));
|
sendButton.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER));
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -69,7 +69,6 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
|||||||
import org.signal.core.util.StreamUtil;
|
import org.signal.core.util.StreamUtil;
|
||||||
import org.signal.core.util.concurrent.SignalExecutors;
|
import org.signal.core.util.concurrent.SignalExecutors;
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
|
||||||
import org.thoughtcrime.securesms.LoggingFragment;
|
import org.thoughtcrime.securesms.LoggingFragment;
|
||||||
import org.thoughtcrime.securesms.PassphraseRequiredActivity;
|
import org.thoughtcrime.securesms.PassphraseRequiredActivity;
|
||||||
import org.thoughtcrime.securesms.R;
|
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.TooltipPopup;
|
||||||
import org.thoughtcrime.securesms.components.TypingStatusRepository;
|
import org.thoughtcrime.securesms.components.TypingStatusRepository;
|
||||||
import org.thoughtcrime.securesms.components.recyclerview.SmoothScrollingLinearLayoutManager;
|
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.VoiceNoteMediaController;
|
||||||
import org.thoughtcrime.securesms.components.voice.VoiceNotePlaybackState;
|
import org.thoughtcrime.securesms.components.voice.VoiceNotePlaybackState;
|
||||||
import org.thoughtcrime.securesms.contactshare.Contact;
|
import org.thoughtcrime.securesms.contactshare.Contact;
|
||||||
@@ -1568,10 +1568,7 @@ public class ConversationFragment extends LoggingFragment {
|
|||||||
d.dismiss();
|
d.dismiss();
|
||||||
})
|
})
|
||||||
.setNeutralButton(R.string.ConversationFragment_contact_us, (d, w) -> {
|
.setNeutralButton(R.string.ConversationFragment_contact_us, (d, w) -> {
|
||||||
Intent intent = new Intent(requireContext(), ApplicationPreferencesActivity.class);
|
startActivity(AppSettingsActivity.help(requireContext(), 0));
|
||||||
intent.putExtra(ApplicationPreferencesActivity.LAUNCH_TO_HELP_FRAGMENT, true);
|
|
||||||
|
|
||||||
startActivity(intent);
|
|
||||||
d.dismiss();
|
d.dismiss();
|
||||||
})
|
})
|
||||||
.show();
|
.show();
|
||||||
|
|||||||
@@ -651,7 +651,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
|||||||
{
|
{
|
||||||
bodyText.setClickable(false);
|
bodyText.setClickable(false);
|
||||||
bodyText.setFocusable(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()));
|
bodyText.setMovementMethod(LongClickMovementMethod.getInstance(getContext()));
|
||||||
|
|
||||||
if (messageRecord.isRemoteDelete()) {
|
if (messageRecord.isRemoteDelete()) {
|
||||||
|
|||||||
+3
-2
@@ -26,6 +26,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
|||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.conversation.ConversationFragment;
|
import org.thoughtcrime.securesms.conversation.ConversationFragment;
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||||
import org.thoughtcrime.securesms.util.DeviceProperties;
|
import org.thoughtcrime.securesms.util.DeviceProperties;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
@@ -53,7 +54,7 @@ public final class EnableCallNotificationSettingsDialog extends DialogFragment {
|
|||||||
|
|
||||||
public static void fixAutomatically(@NonNull Context context) {
|
public static void fixAutomatically(@NonNull Context context) {
|
||||||
if (areCallNotificationsDisabled(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();
|
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) {
|
private static boolean areCallNotificationsDisabled(Context context) {
|
||||||
return !TextSecurePreferences.isCallNotificationsEnabled(context);
|
return !SignalStore.settings().isCallNotificationsEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isCallChannelInvalid(Context context) {
|
private static boolean isCallChannelInvalid(Context context) {
|
||||||
|
|||||||
+5
-7
@@ -71,7 +71,6 @@ import org.greenrobot.eventbus.Subscribe;
|
|||||||
import org.greenrobot.eventbus.ThreadMode;
|
import org.greenrobot.eventbus.ThreadMode;
|
||||||
import org.signal.core.util.concurrent.SignalExecutors;
|
import org.signal.core.util.concurrent.SignalExecutors;
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
|
||||||
import org.thoughtcrime.securesms.MainFragment;
|
import org.thoughtcrime.securesms.MainFragment;
|
||||||
import org.thoughtcrime.securesms.MainNavigator;
|
import org.thoughtcrime.securesms.MainNavigator;
|
||||||
import org.thoughtcrime.securesms.NewConversationActivity;
|
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.ReminderView;
|
||||||
import org.thoughtcrime.securesms.components.reminder.ServiceOutageReminder;
|
import org.thoughtcrime.securesms.components.reminder.ServiceOutageReminder;
|
||||||
import org.thoughtcrime.securesms.components.reminder.UnauthorizedReminder;
|
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.conversation.ConversationFragment;
|
||||||
import org.thoughtcrime.securesms.conversationlist.model.Conversation;
|
import org.thoughtcrime.securesms.conversationlist.model.Conversation;
|
||||||
import org.thoughtcrime.securesms.conversationlist.model.MessageResult;
|
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.StickyHeaderDecoration;
|
||||||
import org.thoughtcrime.securesms.util.Stopwatch;
|
import org.thoughtcrime.securesms.util.Stopwatch;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||||
import org.thoughtcrime.securesms.util.WindowUtil;
|
import org.thoughtcrime.securesms.util.WindowUtil;
|
||||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||||
@@ -269,7 +270,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||||||
updateReminders();
|
updateReminders();
|
||||||
EventBus.getDefault().register(this);
|
EventBus.getDefault().register(this);
|
||||||
|
|
||||||
if (TextSecurePreferences.isSmsEnabled(requireContext())) {
|
if (Util.isDefaultSmsProvider(requireContext())) {
|
||||||
InsightsLauncher.showInsightsModal(requireContext(), requireFragmentManager());
|
InsightsLauncher.showInsightsModal(requireContext(), requireFragmentManager());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,7 +323,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPrepareOptionsMenu(Menu menu) {
|
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()));
|
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() {
|
private void onProxyStatusClicked() {
|
||||||
Intent intent = new Intent(requireContext(), ApplicationPreferencesActivity.class);
|
startActivity(AppSettingsActivity.proxy(requireContext()));
|
||||||
intent.putExtra(ApplicationPreferencesActivity.LAUNCH_TO_PROXY_FRAGMENT, true);
|
|
||||||
|
|
||||||
startActivity(intent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onPostSubmitList(int conversationCount) {
|
protected void onPostSubmitList(int conversationCount) {
|
||||||
|
|||||||
+2
-1
@@ -50,6 +50,7 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.ReactionList;
|
|||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.groups.GroupId;
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.jobs.RefreshPreKeysJob;
|
import org.thoughtcrime.securesms.jobs.RefreshPreKeysJob;
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||||
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
||||||
import org.thoughtcrime.securesms.profiles.AvatarHelper;
|
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;
|
Uri messageSoundUri = messageSound != null ? Uri.parse(messageSound) : null;
|
||||||
int vibrateState = cursor.getInt(cursor.getColumnIndexOrThrow("vibrate"));
|
int vibrateState = cursor.getInt(cursor.getColumnIndexOrThrow("vibrate"));
|
||||||
String displayName = NotificationChannels.getChannelDisplayNameFor(context, systemName, profileName, null, address);
|
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)) {
|
if (GroupId.isEncodedGroup(address)) {
|
||||||
try(Cursor groupCursor = db.rawQuery("SELECT title FROM groups WHERE group_id = ?", new String[] { 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.AsYouTypeFormatter;
|
||||||
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.components.LabeledEditText;
|
import org.thoughtcrime.securesms.components.LabeledEditText;
|
||||||
import org.thoughtcrime.securesms.util.SpanUtil;
|
import org.thoughtcrime.securesms.util.SpanUtil;
|
||||||
@@ -42,13 +41,13 @@ import org.whispersystems.libsignal.util.guava.Optional;
|
|||||||
|
|
||||||
public class DeleteAccountFragment extends Fragment {
|
public class DeleteAccountFragment extends Fragment {
|
||||||
|
|
||||||
private ArrayAdapter<String> countrySpinnerAdapter;
|
private ArrayAdapter<String> countrySpinnerAdapter;
|
||||||
private TextView bullets;
|
private TextView bullets;
|
||||||
private LabeledEditText countryCode;
|
private LabeledEditText countryCode;
|
||||||
private LabeledEditText number;
|
private LabeledEditText number;
|
||||||
private AsYouTypeFormatter countryFormatter;
|
private AsYouTypeFormatter countryFormatter;
|
||||||
private DeleteAccountViewModel viewModel;
|
private DeleteAccountViewModel viewModel;
|
||||||
private DialogInterface deletionProgressDialog;
|
private DialogInterface deletionProgressDialog;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
public @Nullable View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
@@ -57,8 +56,8 @@ public class DeleteAccountFragment extends Fragment {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
Spinner countrySpinner = view.findViewById(R.id.delete_account_fragment_country_spinner);
|
Spinner countrySpinner = view.findViewById(R.id.delete_account_fragment_country_spinner);
|
||||||
View confirm = view.findViewById(R.id.delete_account_fragment_delete);
|
View confirm = view.findViewById(R.id.delete_account_fragment_delete);
|
||||||
|
|
||||||
bullets = view.findViewById(R.id.delete_account_fragment_bullets);
|
bullets = view.findViewById(R.id.delete_account_fragment_bullets);
|
||||||
countryCode = view.findViewById(R.id.delete_account_fragment_country_code);
|
countryCode = view.findViewById(R.id.delete_account_fragment_country_code);
|
||||||
@@ -80,12 +79,6 @@ public class DeleteAccountFragment extends Fragment {
|
|||||||
initializeSpinner(countrySpinner);
|
initializeSpinner(countrySpinner);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
((ApplicationPreferencesActivity) getActivity()).getSupportActionBar().setTitle(R.string.preferences__delete_account);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateBullets(@NonNull Optional<String> formattedBalance) {
|
private void updateBullets(@NonNull Optional<String> formattedBalance) {
|
||||||
bullets.setText(buildBulletsText(formattedBalance));
|
bullets.setText(buildBulletsText(formattedBalance));
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-4
@@ -11,8 +11,8 @@ import androidx.annotation.StringRes;
|
|||||||
import androidx.navigation.fragment.NavHostFragment;
|
import androidx.navigation.fragment.NavHostFragment;
|
||||||
|
|
||||||
import org.signal.devicetransfer.DeviceToDeviceTransferService;
|
import org.signal.devicetransfer.DeviceToDeviceTransferService;
|
||||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
|
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.devicetransfer.DeviceTransferSetupFragment;
|
import org.thoughtcrime.securesms.devicetransfer.DeviceTransferSetupFragment;
|
||||||
import org.thoughtcrime.securesms.devicetransfer.SetupStep;
|
import org.thoughtcrime.securesms.devicetransfer.SetupStep;
|
||||||
@@ -46,9 +46,7 @@ public final class OldDeviceTransferSetupFragment extends DeviceTransferSetupFra
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void navigateWhenWifiDirectUnavailable() {
|
protected void navigateWhenWifiDirectUnavailable() {
|
||||||
Intent intent = new Intent(requireContext(), ApplicationPreferencesActivity.class);
|
startActivity(AppSettingsActivity.backups(requireContext()));
|
||||||
intent.putExtra(ApplicationPreferencesActivity.LAUNCH_TO_BACKUPS_FRAGMENT, true);
|
|
||||||
startActivity(intent);
|
|
||||||
requireActivity().finish();
|
requireActivity().finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-3
@@ -22,6 +22,7 @@ import org.thoughtcrime.securesms.R;
|
|||||||
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader;
|
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader;
|
||||||
import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper;
|
import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper;
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||||
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.groups.GroupsV2CapabilityChecker;
|
import org.thoughtcrime.securesms.groups.GroupsV2CapabilityChecker;
|
||||||
import org.thoughtcrime.securesms.groups.ui.creategroup.details.AddGroupDetailsActivity;
|
import org.thoughtcrime.securesms.groups.ui.creategroup.details.AddGroupDetailsActivity;
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
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.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||||
import org.thoughtcrime.securesms.util.Stopwatch;
|
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.ViewUtil;
|
||||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||||
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
|
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
|
||||||
@@ -56,8 +57,8 @@ public class CreateGroupActivity extends ContactSelectionActivity {
|
|||||||
intent.putExtra(ContactSelectionListFragment.REFRESHABLE, false);
|
intent.putExtra(ContactSelectionListFragment.REFRESHABLE, false);
|
||||||
intent.putExtra(ContactSelectionActivity.EXTRA_LAYOUT_RES_ID, R.layout.create_group_activity);
|
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
|
int displayMode = Util.isDefaultSmsProvider(context) ? ContactsCursorLoader.DisplayMode.FLAG_SMS | ContactsCursorLoader.DisplayMode.FLAG_PUSH
|
||||||
: ContactsCursorLoader.DisplayMode.FLAG_PUSH;
|
: ContactsCursorLoader.DisplayMode.FLAG_PUSH;
|
||||||
|
|
||||||
intent.putExtra(ContactSelectionListFragment.DISPLAY_MODE, displayMode);
|
intent.putExtra(ContactSelectionListFragment.DISPLAY_MODE, displayMode);
|
||||||
intent.putExtra(ContactSelectionListFragment.SELECTION_LIMITS, FeatureFlags.groupLimits().excludingSelf());
|
intent.putExtra(ContactSelectionListFragment.SELECTION_LIMITS, FeatureFlags.groupLimits().excludingSelf());
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import com.annimon.stream.Stream;
|
|||||||
import com.dd.CircularProgressButton;
|
import com.dd.CircularProgressButton;
|
||||||
|
|
||||||
import org.signal.core.util.ResourceUtil;
|
import org.signal.core.util.ResourceUtil;
|
||||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
|
||||||
import org.thoughtcrime.securesms.LoggingFragment;
|
import org.thoughtcrime.securesms.LoggingFragment;
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.components.emoji.EmojiImageView;
|
import org.thoughtcrime.securesms.components.emoji.EmojiImageView;
|
||||||
@@ -38,19 +37,19 @@ import java.util.List;
|
|||||||
|
|
||||||
public class HelpFragment extends LoggingFragment {
|
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;
|
public static final int PAYMENT_INDEX = 5;
|
||||||
|
|
||||||
private EditText problem;
|
private EditText problem;
|
||||||
private CheckBox includeDebugLogs;
|
private CheckBox includeDebugLogs;
|
||||||
private View debugLogInfo;
|
private View debugLogInfo;
|
||||||
private View faq;
|
private View faq;
|
||||||
private CircularProgressButton next;
|
private CircularProgressButton next;
|
||||||
private View toaster;
|
private View toaster;
|
||||||
private List<EmojiImageView> emoji;
|
private List<EmojiImageView> emoji;
|
||||||
private HelpViewModel helpViewModel;
|
private HelpViewModel helpViewModel;
|
||||||
private Spinner categorySpinner;
|
private Spinner categorySpinner;
|
||||||
private ArrayAdapter<CharSequence> categoryAdapter;
|
private ArrayAdapter<CharSequence> categoryAdapter;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
public @Nullable View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
@@ -68,7 +67,6 @@ public class HelpFragment extends LoggingFragment {
|
|||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
((ApplicationPreferencesActivity) requireActivity()).requireSupportActionBar().setTitle(R.string.preferences__help);
|
|
||||||
|
|
||||||
cancelSpinning(next);
|
cancelSpinning(next);
|
||||||
problem.setEnabled(true);
|
problem.setEnabled(true);
|
||||||
|
|||||||
@@ -1,16 +1,24 @@
|
|||||||
package org.thoughtcrime.securesms.keyvalue;
|
package org.thoughtcrime.securesms.keyvalue;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.provider.Settings;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
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 org.thoughtcrime.securesms.webrtc.CallBandwidthMode;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public final class SettingsValues extends SignalStoreValues {
|
public final class SettingsValues extends SignalStoreValues {
|
||||||
|
|
||||||
public static final String LINK_PREVIEWS = "settings.link_previews";
|
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";
|
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_LENGTH = "pref_trim_length";
|
||||||
public static final String THREAD_TRIM_ENABLED = "pref_trim_threads";
|
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) {
|
SettingsValues(@NonNull KeyValueStore store) {
|
||||||
super(store);
|
super(store);
|
||||||
@@ -46,7 +77,29 @@ public final class SettingsValues extends SignalStoreValues {
|
|||||||
PREFER_SYSTEM_CONTACT_PHOTOS,
|
PREFER_SYSTEM_CONTACT_PHOTOS,
|
||||||
CALL_BANDWIDTH_MODE,
|
CALL_BANDWIDTH_MODE,
|
||||||
THREAD_TRIM_LENGTH,
|
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() {
|
public boolean isLinkPreviewsEnabled() {
|
||||||
@@ -114,6 +167,181 @@ public final class SettingsValues extends SignalStoreValues {
|
|||||||
return CallBandwidthMode.fromCode(getInteger(CALL_BANDWIDTH_MODE, CallBandwidthMode.HIGH_ALWAYS.getCode()));
|
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) {
|
private @Nullable Uri getUri(@NonNull String key) {
|
||||||
String uri = getString(key, "");
|
String uri = getString(key, "");
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import android.os.Build;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.RequiresApi;
|
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.ServiceUtil;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
|
|
||||||
@@ -23,12 +23,12 @@ final class LogSectionNotifications implements LogSection {
|
|||||||
public @NonNull CharSequence getContent(@NonNull Context context) {
|
public @NonNull CharSequence getContent(@NonNull Context context) {
|
||||||
StringBuilder output = new StringBuilder();
|
StringBuilder output = new StringBuilder();
|
||||||
|
|
||||||
output.append("Message notifications: ").append(TextSecurePreferences.isNotificationsEnabled(context)).append("\n")
|
output.append("Message notifications: ").append(SignalStore.settings().isMessageNotificationsEnabled()).append("\n")
|
||||||
.append("Call notifications : ").append(TextSecurePreferences.isCallNotificationsEnabled(context)).append("\n")
|
.append("Call notifications : ").append(SignalStore.settings().isCallNotificationsEnabled()).append("\n")
|
||||||
.append("New contact alerts : ").append(TextSecurePreferences.isNewContactsNotificationEnabled(context)).append("\n")
|
.append("New contact alerts : ").append(SignalStore.settings().isNotifyWhenContactJoinsSignal()).append("\n")
|
||||||
.append("In-chat sounds : ").append(TextSecurePreferences.isInThreadNotifications(context)).append("\n")
|
.append("In-chat sounds : ").append(SignalStore.settings().isMessageNotificationsInChatSoundsEnabled()).append("\n")
|
||||||
.append("Repeat alerts : ").append(TextSecurePreferences.getRepeatAlertsCount(context)).append("\n")
|
.append("Repeat alerts : ").append(SignalStore.settings().getMessageNotificationsRepeatAlerts()).append("\n")
|
||||||
.append("Notification display : ").append(TextSecurePreferences.getNotificationPrivacy(context)).append("\n\n");
|
.append("Notification display : ").append(SignalStore.settings().getMessageNotificationsPrivacy()).append("\n\n");
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= 26) {
|
if (Build.VERSION.SDK_INT >= 26) {
|
||||||
NotificationManager manager = ServiceUtil.getNotificationManager(context);
|
NotificationManager manager = ServiceUtil.getNotificationManager(context);
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import org.thoughtcrime.securesms.R;
|
|||||||
import org.thoughtcrime.securesms.color.MaterialColor;
|
import org.thoughtcrime.securesms.color.MaterialColor;
|
||||||
import org.thoughtcrime.securesms.components.ConversationItemFooter;
|
import org.thoughtcrime.securesms.components.ConversationItemFooter;
|
||||||
import org.thoughtcrime.securesms.components.emoji.EmojiTextView;
|
import org.thoughtcrime.securesms.components.emoji.EmojiTextView;
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
|
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
|
||||||
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
@@ -144,7 +145,7 @@ public class LongMessageActivity extends PassphraseRequiredActivity {
|
|||||||
bubble.setVisibility(View.VISIBLE);
|
bubble.setVisibility(View.VISIBLE);
|
||||||
text.setText(styledBody);
|
text.setText(styledBody);
|
||||||
text.setMovementMethod(LinkMovementMethod.getInstance());
|
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()) {
|
if (message.get().getMessageRecord().isOutgoing()) {
|
||||||
text.setMentionBackgroundTint(ContextCompat.getColor(this, isDarkTheme(this) ? R.color.core_grey_60 : R.color.core_grey_20));
|
text.setMentionBackgroundTint(ContextCompat.getColor(this, isDarkTheme(this) ? R.color.core_grey_60 : R.color.core_grey_20));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ import org.thoughtcrime.securesms.components.mention.MentionAnnotation;
|
|||||||
import org.thoughtcrime.securesms.contactshare.SimpleTextWatcher;
|
import org.thoughtcrime.securesms.contactshare.SimpleTextWatcher;
|
||||||
import org.thoughtcrime.securesms.conversation.ui.mentions.MentionsPickerViewModel;
|
import org.thoughtcrime.securesms.conversation.ui.mentions.MentionsPickerViewModel;
|
||||||
import org.thoughtcrime.securesms.imageeditor.model.EditorModel;
|
import org.thoughtcrime.securesms.imageeditor.model.EditorModel;
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
import org.thoughtcrime.securesms.mediapreview.MediaRailAdapter;
|
import org.thoughtcrime.securesms.mediapreview.MediaRailAdapter;
|
||||||
import org.thoughtcrime.securesms.mediasend.MediaSendViewModel.HudState;
|
import org.thoughtcrime.securesms.mediasend.MediaSendViewModel.HudState;
|
||||||
import org.thoughtcrime.securesms.mediasend.MediaSendViewModel.ViewOnceState;
|
import org.thoughtcrime.securesms.mediasend.MediaSendViewModel.ViewOnceState;
|
||||||
@@ -348,7 +349,7 @@ public class MediaSendActivity extends PassphraseRequiredActivity implements Med
|
|||||||
return isSend;
|
return isSend;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (TextSecurePreferences.isSystemEmojiPreferred(this)) {
|
if (SignalStore.settings().isPreferSystemEmoji()) {
|
||||||
emojiToggle.setVisibility(View.GONE);
|
emojiToggle.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
emojiToggle.setOnClickListener(this::onEmojiToggleClicked);
|
emojiToggle.setOnClickListener(this::onEmojiToggleClicked);
|
||||||
@@ -1038,7 +1039,7 @@ public class MediaSendActivity extends PassphraseRequiredActivity implements Med
|
|||||||
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
||||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||||
if (keyCode == KeyEvent.KEYCODE_ENTER) {
|
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_DOWN, KeyEvent.KEYCODE_ENTER));
|
||||||
sendButton.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER));
|
sendButton.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER));
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import com.annimon.stream.Stream;
|
|||||||
|
|
||||||
import org.signal.core.util.TranslationDetection;
|
import org.signal.core.util.TranslationDetection;
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
|
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity;
|
||||||
import org.thoughtcrime.securesms.conversationlist.ConversationListFragment;
|
import org.thoughtcrime.securesms.conversationlist.ConversationListFragment;
|
||||||
import org.thoughtcrime.securesms.database.model.MegaphoneRecord;
|
import org.thoughtcrime.securesms.database.model.MegaphoneRecord;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
@@ -293,9 +293,7 @@ public final class Megaphones {
|
|||||||
intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName());
|
intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName());
|
||||||
controller.onMegaphoneNavigationRequested(intent);
|
controller.onMegaphoneNavigationRequested(intent);
|
||||||
} else {
|
} else {
|
||||||
Intent intent = new Intent(context, ApplicationPreferencesActivity.class);
|
controller.onMegaphoneNavigationRequested(AppSettingsActivity.notifications(context));
|
||||||
intent.putExtra(ApplicationPreferencesActivity.LAUNCH_TO_NOTIFICATIONS_FRAGMENT, true);
|
|
||||||
controller.onMegaphoneNavigationRequested(intent);
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.setSecondaryButton(R.string.NotificationsMegaphone_not_now, (megaphone, controller) -> controller.onMegaphoneSnooze(Event.NOTIFICATIONS))
|
.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) {
|
private static boolean shouldShowNotificationsMegaphone(@NonNull Context context) {
|
||||||
boolean shouldShow = !TextSecurePreferences.isNotificationsEnabled(context) ||
|
boolean shouldShow = !SignalStore.settings().isMessageNotificationsEnabled() ||
|
||||||
!NotificationChannels.isMessageChannelEnabled(context) ||
|
!NotificationChannels.isMessageChannelEnabled(context) ||
|
||||||
!NotificationChannels.isMessagesChannelGroupEnabled(context) ||
|
!NotificationChannels.isMessagesChannelGroupEnabled(context) ||
|
||||||
!NotificationChannels.areNotificationsEnabled(context);
|
!NotificationChannels.areNotificationsEnabled(context);
|
||||||
if (shouldShow) {
|
if (shouldShow) {
|
||||||
|
|||||||
+3
-2
@@ -8,6 +8,7 @@ import org.signal.core.util.logging.Log;
|
|||||||
import org.thoughtcrime.securesms.backup.BackupFileIOError;
|
import org.thoughtcrime.securesms.backup.BackupFileIOError;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
import org.thoughtcrime.securesms.util.BackupUtil;
|
import org.thoughtcrime.securesms.util.BackupUtil;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
|
|
||||||
@@ -43,13 +44,13 @@ public final class BackupNotificationMigrationJob extends MigrationJob {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void performMigration() {
|
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.");
|
Log.w(TAG, "Stranded backup! Notifying.");
|
||||||
BackupFileIOError.UNKNOWN.postNotification(context);
|
BackupFileIOError.UNKNOWN.postNotification(context);
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, String.format(Locale.US, "Does not meet criteria. API: %d, BackupsEnabled: %s, HasFiles: %s",
|
Log.w(TAG, String.format(Locale.US, "Does not meet criteria. API: %d, BackupsEnabled: %s, HasFiles: %s",
|
||||||
Build.VERSION.SDK_INT,
|
Build.VERSION.SDK_INT,
|
||||||
TextSecurePreferences.isBackupEnabled(context),
|
SignalStore.settings().isBackupEnabled(),
|
||||||
BackupUtil.hasBackupFiles(context)));
|
BackupUtil.hasBackupFiles(context)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -17,6 +17,7 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
|
|||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||||
import org.thoughtcrime.securesms.notifications.NotificationIds;
|
import org.thoughtcrime.securesms.notifications.NotificationIds;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
@@ -63,7 +64,7 @@ public class UserNotificationMigrationJob extends MigrationJob {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TextSecurePreferences.isNewContactsNotificationEnabled(context)) {
|
if (!SignalStore.settings().isNotifyWhenContactJoinsSignal()) {
|
||||||
Log.w(TAG, "New contact notifications disabled! Skipping.");
|
Log.w(TAG, "New contact notifications disabled! Skipping.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-4
@@ -14,6 +14,7 @@ import androidx.core.app.NotificationCompat;
|
|||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference;
|
import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
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) {
|
public void setAlarms(@Nullable Uri ringtone, RecipientDatabase.VibrateState vibrate) {
|
||||||
Uri defaultRingtone = NotificationChannels.supported() ? NotificationChannels.getMessageRingtone(context) : TextSecurePreferences.getNotificationRingtone(context);
|
Uri defaultRingtone = NotificationChannels.supported() ? NotificationChannels.getMessageRingtone(context) : SignalStore.settings().getMessageNotificationSound();
|
||||||
boolean defaultVibrate = NotificationChannels.supported() ? NotificationChannels.getMessageVibrate(context) : TextSecurePreferences.isNotificationVibrateEnabled(context);
|
boolean defaultVibrate = NotificationChannels.supported() ? NotificationChannels.getMessageVibrate(context) : SignalStore.settings().isMessageVibrateEnabled();
|
||||||
|
|
||||||
if (ringtone == null && !TextUtils.isEmpty(defaultRingtone.toString())) setSound(defaultRingtone);
|
if (ringtone == null && !TextUtils.isEmpty(defaultRingtone.toString())) setSound(defaultRingtone);
|
||||||
else if (ringtone != null && !ringtone.toString().isEmpty()) setSound(ringtone);
|
else if (ringtone != null && !ringtone.toString().isEmpty()) setSound(ringtone);
|
||||||
@@ -63,8 +64,8 @@ public abstract class AbstractNotificationBuilder extends NotificationCompat.Bui
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setLed() {
|
private void setLed() {
|
||||||
String ledColor = TextSecurePreferences.getNotificationLedColor(context);
|
String ledColor = SignalStore.settings().getMessageLedColor();
|
||||||
String ledBlinkPattern = TextSecurePreferences.getNotificationLedPattern(context);
|
String ledBlinkPattern = SignalStore.settings().getMessageLedBlinkPattern();
|
||||||
String ledBlinkPatternCustom = TextSecurePreferences.getNotificationLedPatternCustom(context);
|
String ledBlinkPatternCustom = TextSecurePreferences.getNotificationLedPatternCustom(context);
|
||||||
|
|
||||||
if (!ledColor.equals("none")) {
|
if (!ledColor.equals("none")) {
|
||||||
|
|||||||
+12
-11
@@ -60,6 +60,7 @@ import org.thoughtcrime.securesms.database.model.MessageRecord;
|
|||||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.ReactionRecord;
|
import org.thoughtcrime.securesms.database.model.ReactionRecord;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
import org.thoughtcrime.securesms.messages.IncomingMessageObserver;
|
import org.thoughtcrime.securesms.messages.IncomingMessageObserver;
|
||||||
import org.thoughtcrime.securesms.mms.Slide;
|
import org.thoughtcrime.securesms.mms.Slide;
|
||||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||||
@@ -139,7 +140,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
|||||||
Intent intent = ConversationIntents.createBuilder(context, recipient.getId(), threadId)
|
Intent intent = ConversationIntents.createBuilder(context, recipient.getId(), threadId)
|
||||||
.withDataUri(Uri.parse("custom://" + System.currentTimeMillis()))
|
.withDataUri(Uri.parse("custom://" + System.currentTimeMillis()))
|
||||||
.build();
|
.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))
|
((NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE))
|
||||||
.notify((int)threadId, builder.build());
|
.notify((int)threadId, builder.build());
|
||||||
@@ -220,7 +221,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateNotification(@NonNull Context context) {
|
public void updateNotification(@NonNull Context context) {
|
||||||
if (!TextSecurePreferences.isNotificationsEnabled(context)) {
|
if (!SignalStore.settings().isMessageNotificationsEnabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,7 +262,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldNotify(@NonNull Context context, @Nullable Recipient recipient, long threadId) {
|
private boolean shouldNotify(@NonNull Context context, @Nullable Recipient recipient, long threadId) {
|
||||||
if (!TextSecurePreferences.isNotificationsEnabled(context)) {
|
if (!SignalStore.settings().isMessageNotificationsEnabled()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,7 +282,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
|||||||
int reminderCount,
|
int reminderCount,
|
||||||
@NonNull BubbleUtil.BubbleState defaultBubbleState)
|
@NonNull BubbleUtil.BubbleState defaultBubbleState)
|
||||||
{
|
{
|
||||||
if (!TextSecurePreferences.isNotificationsEnabled(context)) {
|
if (!SignalStore.settings().isMessageNotificationsEnabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,7 +372,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
NotificationPrivacyPreference notificationPrivacy = TextSecurePreferences.getNotificationPrivacy(context);
|
NotificationPrivacyPreference notificationPrivacy = SignalStore.settings().getMessageNotificationsPrivacy();
|
||||||
SingleRecipientNotificationBuilder builder = new SingleRecipientNotificationBuilder(context, notificationPrivacy);
|
SingleRecipientNotificationBuilder builder = new SingleRecipientNotificationBuilder(context, notificationPrivacy);
|
||||||
List<NotificationItem> notifications = notificationState.getNotifications();
|
List<NotificationItem> notifications = notificationState.getNotifications();
|
||||||
Recipient recipient = notifications.get(0).getRecipient();
|
Recipient recipient = notifications.get(0).getRecipient();
|
||||||
@@ -442,7 +443,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
|||||||
NotificationManagerCompat.from(context).notify(notificationId, notification);
|
NotificationManagerCompat.from(context).notify(notificationId, notification);
|
||||||
Log.i(TAG, "Posted notification.");
|
Log.i(TAG, "Posted notification.");
|
||||||
} catch (SecurityException e) {
|
} catch (SecurityException e) {
|
||||||
Uri defaultValue = TextSecurePreferences.getNotificationRingtone(context);
|
Uri defaultValue = SignalStore.settings().getMessageNotificationSound();
|
||||||
if (!defaultValue.equals(notificationState.getRingtone(context))) {
|
if (!defaultValue.equals(notificationState.getRingtone(context))) {
|
||||||
Log.e(TAG, "Security exception when posting notification with custom ringtone", e);
|
Log.e(TAG, "Security exception when posting notification with custom ringtone", e);
|
||||||
clearNotificationRingtone(context, notifications.get(0).getRecipient());
|
clearNotificationRingtone(context, notifications.get(0).getRecipient());
|
||||||
@@ -465,7 +466,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NotificationPrivacyPreference notificationPrivacy = TextSecurePreferences.getNotificationPrivacy(context);
|
NotificationPrivacyPreference notificationPrivacy = SignalStore.settings().getMessageNotificationsPrivacy();
|
||||||
MultipleRecipientNotificationBuilder builder = new MultipleRecipientNotificationBuilder(context, notificationPrivacy);
|
MultipleRecipientNotificationBuilder builder = new MultipleRecipientNotificationBuilder(context, notificationPrivacy);
|
||||||
List<NotificationItem> notifications = notificationState.getNotifications();
|
List<NotificationItem> notifications = notificationState.getNotifications();
|
||||||
boolean shouldAlert = signal && Stream.of(notifications).anyMatch(item -> item.getNotifiedTimestamp() == 0);
|
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());
|
NotificationManagerCompat.from(context).notify(NotificationIds.MESSAGE_SUMMARY, builder.build());
|
||||||
Log.i(TAG, "Posted notification. " + notification.toString());
|
Log.i(TAG, "Posted notification. " + notification.toString());
|
||||||
} catch (SecurityException securityException) {
|
} catch (SecurityException securityException) {
|
||||||
Uri defaultValue = TextSecurePreferences.getNotificationRingtone(context);
|
Uri defaultValue = SignalStore.settings().getMessageNotificationSound();
|
||||||
if (!defaultValue.equals(notificationState.getRingtone(context))) {
|
if (!defaultValue.equals(notificationState.getRingtone(context))) {
|
||||||
Log.e(TAG, "Security exception when posting notification with custom ringtone", securityException);
|
Log.e(TAG, "Security exception when posting notification with custom ringtone", securityException);
|
||||||
clearNotificationRingtone(context, notifications.get(0).getRecipient());
|
clearNotificationRingtone(context, notifications.get(0).getRecipient());
|
||||||
@@ -524,7 +525,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void sendInThreadNotification(Context context, Recipient recipient) {
|
private static void sendInThreadNotification(Context context, Recipient recipient) {
|
||||||
if (!TextSecurePreferences.isInThreadNotifications(context) ||
|
if (!SignalStore.settings().isMessageNotificationsInChatSoundsEnabled() ||
|
||||||
ServiceUtil.getAudioManager(context).getRingerMode() != AudioManager.RINGER_MODE_NORMAL)
|
ServiceUtil.getAudioManager(context).getRingerMode() != AudioManager.RINGER_MODE_NORMAL)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -536,7 +537,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (uri == null) {
|
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()) {
|
if (uri.toString().isEmpty()) {
|
||||||
@@ -729,7 +730,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void scheduleReminder(Context context, int count) {
|
private static void scheduleReminder(Context context, int count) {
|
||||||
if (count >= TextSecurePreferences.getRepeatAlertsCount(context)) {
|
if (count >= SignalStore.settings().getMessageNotificationsRepeatAlerts()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-5
@@ -29,6 +29,7 @@ import org.thoughtcrime.securesms.R;
|
|||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase.VibrateState;
|
import org.thoughtcrime.securesms.database.RecipientDatabase.VibrateState;
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
@@ -158,7 +159,7 @@ public class NotificationChannels {
|
|||||||
if (recipient.getId().isUnknown()) return null;
|
if (recipient.getId().isUnknown()) return null;
|
||||||
|
|
||||||
VibrateState vibrateState = recipient.getMessageVibrate();
|
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);
|
Uri messageRingtone = recipient.getMessageRingtone() != null ? recipient.getMessageRingtone() : getMessageRingtone(context);
|
||||||
String displayName = recipient.getDisplayName(context);
|
String displayName = recipient.getDisplayName(context);
|
||||||
|
|
||||||
@@ -180,7 +181,7 @@ public class NotificationChannels {
|
|||||||
|
|
||||||
NotificationChannel channel = new NotificationChannel(channelId, displayName, NotificationManager.IMPORTANCE_HIGH);
|
NotificationChannel channel = new NotificationChannel(channelId, displayName, NotificationManager.IMPORTANCE_HIGH);
|
||||||
|
|
||||||
setLedPreference(channel, TextSecurePreferences.getNotificationLedColor(context));
|
setLedPreference(channel, SignalStore.settings().getMessageLedColor());
|
||||||
channel.setGroup(CATEGORY_MESSAGES);
|
channel.setGroup(CATEGORY_MESSAGES);
|
||||||
channel.enableVibration(vibrationEnabled);
|
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);
|
NotificationChannel joinEvents = new NotificationChannel(JOIN_EVENTS, context.getString(R.string.NotificationChannel_contact_joined_signal), NotificationManager.IMPORTANCE_DEFAULT);
|
||||||
|
|
||||||
messages.setGroup(CATEGORY_MESSAGES);
|
messages.setGroup(CATEGORY_MESSAGES);
|
||||||
messages.enableVibration(TextSecurePreferences.isNotificationVibrateEnabled(context));
|
messages.enableVibration(SignalStore.settings().isMessageVibrateEnabled());
|
||||||
messages.setSound(TextSecurePreferences.getNotificationRingtone(context), getRingtoneAudioAttributes());
|
messages.setSound(SignalStore.settings().getMessageNotificationSound(), getRingtoneAudioAttributes());
|
||||||
setLedPreference(messages, TextSecurePreferences.getNotificationLedColor(context));
|
setLedPreference(messages, SignalStore.settings().getMessageLedColor());
|
||||||
|
|
||||||
calls.setShowBadge(false);
|
calls.setShowBadge(false);
|
||||||
backups.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.DatabaseFactory
|
||||||
import org.thoughtcrime.securesms.database.MessageDatabase
|
import org.thoughtcrime.securesms.database.MessageDatabase
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||||
import org.thoughtcrime.securesms.messages.IncomingMessageObserver
|
import org.thoughtcrime.securesms.messages.IncomingMessageObserver
|
||||||
import org.thoughtcrime.securesms.notifications.DefaultMessageNotifier
|
import org.thoughtcrime.securesms.notifications.DefaultMessageNotifier
|
||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier
|
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.service.KeyCachingService
|
||||||
import org.thoughtcrime.securesms.util.BubbleUtil.BubbleState
|
import org.thoughtcrime.securesms.util.BubbleUtil.BubbleState
|
||||||
import org.thoughtcrime.securesms.util.ServiceUtil
|
import org.thoughtcrime.securesms.util.ServiceUtil
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
|
||||||
import org.thoughtcrime.securesms.webrtc.CallNotificationBuilder
|
import org.thoughtcrime.securesms.webrtc.CallNotificationBuilder
|
||||||
import org.whispersystems.signalservice.internal.util.Util
|
import org.whispersystems.signalservice.internal.util.Util
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
@@ -47,7 +47,7 @@ class MessageNotifierV2(context: Application) : MessageNotifier {
|
|||||||
@Volatile private var lastAudibleNotification: Long = -1
|
@Volatile private var lastAudibleNotification: Long = -1
|
||||||
@Volatile private var lastScheduledReminder: Long = 0
|
@Volatile private var lastScheduledReminder: Long = 0
|
||||||
@Volatile private var previousLockedStatus: Boolean = KeyCachingService.isLocked(context)
|
@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
|
@Volatile private var previousState: NotificationStateV2 = NotificationStateV2.EMPTY
|
||||||
|
|
||||||
private val threadReminders: MutableMap<Long, Reminder> = ConcurrentHashMap()
|
private val threadReminders: MutableMap<Long, Reminder> = ConcurrentHashMap()
|
||||||
@@ -116,12 +116,12 @@ class MessageNotifierV2(context: Application) : MessageNotifier {
|
|||||||
reminderCount: Int,
|
reminderCount: Int,
|
||||||
defaultBubbleState: BubbleState
|
defaultBubbleState: BubbleState
|
||||||
) {
|
) {
|
||||||
if (!TextSecurePreferences.isNotificationsEnabled(context)) {
|
if (!SignalStore.settings().isMessageNotificationsEnabled) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val currentLockStatus: Boolean = KeyCachingService.isLocked(context)
|
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
|
val notificationConfigurationChanged: Boolean = currentLockStatus != previousLockedStatus || currentPrivacyPreference != previousPrivacyPreference
|
||||||
previousLockedStatus = currentLockStatus
|
previousLockedStatus = currentLockStatus
|
||||||
previousPrivacyPreference = currentPrivacyPreference
|
previousPrivacyPreference = currentPrivacyPreference
|
||||||
@@ -211,7 +211,7 @@ class MessageNotifierV2(context: Application) : MessageNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun updateReminderTimestamps(context: Context, alertOverrides: Set<Long>, threadsThatAlerted: Set<Long>) {
|
private fun updateReminderTimestamps(context: Context, alertOverrides: Set<Long>, threadsThatAlerted: Set<Long>) {
|
||||||
if (TextSecurePreferences.getRepeatAlertsCount(context) == 0) {
|
if (SignalStore.settings().messageNotificationsRepeatAlerts == 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +221,7 @@ class MessageNotifierV2(context: Application) : MessageNotifier {
|
|||||||
val (id: Long, reminder: Reminder) = entry
|
val (id: Long, reminder: Reminder) = entry
|
||||||
if (alertOverrides.contains(id)) {
|
if (alertOverrides.contains(id)) {
|
||||||
val notifyCount: Int = reminder.count + 1
|
val notifyCount: Int = reminder.count + 1
|
||||||
if (notifyCount >= TextSecurePreferences.getRepeatAlertsCount(context)) {
|
if (notifyCount >= SignalStore.settings().messageNotificationsRepeatAlerts) {
|
||||||
iterator.remove()
|
iterator.remove()
|
||||||
} else {
|
} else {
|
||||||
entry.setValue(Reminder(lastAudibleNotification, notifyCount))
|
entry.setValue(Reminder(lastAudibleNotification, notifyCount))
|
||||||
|
|||||||
+6
-5
@@ -21,6 +21,7 @@ import androidx.core.graphics.drawable.IconCompat
|
|||||||
import org.thoughtcrime.securesms.R
|
import org.thoughtcrime.securesms.R
|
||||||
import org.thoughtcrime.securesms.conversation.ConversationIntents
|
import org.thoughtcrime.securesms.conversation.ConversationIntents
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase
|
import org.thoughtcrime.securesms.database.RecipientDatabase
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||||
import org.thoughtcrime.securesms.notifications.DefaultMessageNotifier
|
import org.thoughtcrime.securesms.notifications.DefaultMessageNotifier
|
||||||
import org.thoughtcrime.securesms.notifications.NotificationChannels
|
import org.thoughtcrime.securesms.notifications.NotificationChannels
|
||||||
import org.thoughtcrime.securesms.notifications.ReplyMethod
|
import org.thoughtcrime.securesms.notifications.ReplyMethod
|
||||||
@@ -45,7 +46,7 @@ private const val BIG_PICTURE_DIMEN = 500
|
|||||||
*/
|
*/
|
||||||
sealed class NotificationBuilder(protected val context: Context) {
|
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)
|
private val isNotLocked: Boolean = !KeyCachingService.isLocked(context)
|
||||||
|
|
||||||
abstract fun setSmallIcon(@DrawableRes drawable: Int)
|
abstract fun setSmallIcon(@DrawableRes drawable: Int)
|
||||||
@@ -145,10 +146,10 @@ sealed class NotificationBuilder(protected val context: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun setLights() {
|
fun setLights() {
|
||||||
val ledColor: String = TextSecurePreferences.getNotificationLedColor(context)
|
val ledColor: String = SignalStore.settings().messageLedColor
|
||||||
|
|
||||||
if (ledColor != "none") {
|
if (ledColor != "none") {
|
||||||
var blinkPattern = TextSecurePreferences.getNotificationLedPattern(context)
|
var blinkPattern = SignalStore.settings().messageLedBlinkPattern
|
||||||
if (blinkPattern == "custom") {
|
if (blinkPattern == "custom") {
|
||||||
blinkPattern = TextSecurePreferences.getNotificationLedPatternCustom(context)
|
blinkPattern = TextSecurePreferences.getNotificationLedPatternCustom(context)
|
||||||
}
|
}
|
||||||
@@ -297,8 +298,8 @@ sealed class NotificationBuilder(protected val context: Context) {
|
|||||||
val ringtone: Uri? = recipient?.messageRingtone
|
val ringtone: Uri? = recipient?.messageRingtone
|
||||||
val vibrate = recipient?.messageVibrate
|
val vibrate = recipient?.messageVibrate
|
||||||
|
|
||||||
val defaultRingtone: Uri = TextSecurePreferences.getNotificationRingtone(context)
|
val defaultRingtone: Uri = SignalStore.settings().messageNotificationSound
|
||||||
val defaultVibrate: Boolean = TextSecurePreferences.isNotificationVibrateEnabled(context)
|
val defaultVibrate: Boolean = SignalStore.settings().isMessageVibrateEnabled
|
||||||
|
|
||||||
if (ringtone == null && !TextUtils.isEmpty(defaultRingtone.toString())) {
|
if (ringtone == null && !TextUtils.isEmpty(defaultRingtone.toString())) {
|
||||||
builder.setSound(defaultRingtone)
|
builder.setSound(defaultRingtone)
|
||||||
|
|||||||
+7
-7
@@ -12,6 +12,7 @@ import org.thoughtcrime.securesms.contacts.TurnOffContactJoinedNotificationsActi
|
|||||||
import org.thoughtcrime.securesms.contacts.avatars.ContactColors
|
import org.thoughtcrime.securesms.contacts.avatars.ContactColors
|
||||||
import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto
|
import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto
|
||||||
import org.thoughtcrime.securesms.conversation.ConversationIntents
|
import org.thoughtcrime.securesms.conversation.ConversationIntents
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||||
import org.thoughtcrime.securesms.notifications.DeleteNotificationReceiver
|
import org.thoughtcrime.securesms.notifications.DeleteNotificationReceiver
|
||||||
import org.thoughtcrime.securesms.notifications.MarkReadReceiver
|
import org.thoughtcrime.securesms.notifications.MarkReadReceiver
|
||||||
import org.thoughtcrime.securesms.notifications.NotificationChannels
|
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.preferences.widgets.NotificationPrivacyPreference
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient
|
import org.thoughtcrime.securesms.recipients.Recipient
|
||||||
import org.thoughtcrime.securesms.service.KeyCachingService
|
import org.thoughtcrime.securesms.service.KeyCachingService
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
|
||||||
import org.thoughtcrime.securesms.util.Util
|
import org.thoughtcrime.securesms.util.Util
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -41,7 +41,7 @@ data class NotificationConversation(
|
|||||||
val isOnlyContactJoinedEvent: Boolean = messageCount == 1 && mostRecentNotification.isJoined
|
val isOnlyContactJoinedEvent: Boolean = messageCount == 1 && mostRecentNotification.isJoined
|
||||||
|
|
||||||
fun getContentTitle(context: Context): CharSequence {
|
fun getContentTitle(context: Context): CharSequence {
|
||||||
return if (TextSecurePreferences.getNotificationPrivacy(context).isDisplayContact) {
|
return if (SignalStore.settings().messageNotificationsPrivacy.isDisplayContact) {
|
||||||
recipient.getDisplayName(context)
|
recipient.getDisplayName(context)
|
||||||
} else {
|
} else {
|
||||||
context.getString(R.string.SingleRecipientNotificationBuilder_signal)
|
context.getString(R.string.SingleRecipientNotificationBuilder_signal)
|
||||||
@@ -49,7 +49,7 @@ data class NotificationConversation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getContactLargeIcon(context: Context): Drawable? {
|
fun getContactLargeIcon(context: Context): Drawable? {
|
||||||
return if (TextSecurePreferences.getNotificationPrivacy(context).isDisplayContact) {
|
return if (SignalStore.settings().messageNotificationsPrivacy.isDisplayContact) {
|
||||||
recipient.getContactDrawable(context)
|
recipient.getContactDrawable(context)
|
||||||
} else {
|
} else {
|
||||||
GeneratedContactPhoto("Unknown", R.drawable.ic_profile_outline_40).asDrawable(context, ContactColors.UNKNOWN_COLOR.toConversationColor(context))
|
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? {
|
fun getContactUri(context: Context): String? {
|
||||||
return if (TextSecurePreferences.getNotificationPrivacy(context).isDisplayContact) {
|
return if (SignalStore.settings().messageNotificationsPrivacy.isDisplayContact) {
|
||||||
recipient.contactUri?.toString()
|
recipient.contactUri?.toString()
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
@@ -65,7 +65,7 @@ data class NotificationConversation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getSlideBigPictureUri(context: Context): Uri? {
|
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()
|
mostRecentNotification.getBigPictureUri()
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
@@ -73,7 +73,7 @@ data class NotificationConversation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getContentText(context: Context): CharSequence? {
|
fun getContentText(context: Context): CharSequence? {
|
||||||
val privacy: NotificationPrivacyPreference = TextSecurePreferences.getNotificationPrivacy(context)
|
val privacy: NotificationPrivacyPreference = SignalStore.settings().messageNotificationsPrivacy
|
||||||
val stringBuilder = SpannableStringBuilder()
|
val stringBuilder = SpannableStringBuilder()
|
||||||
|
|
||||||
if (privacy.isDisplayContact && recipient.isGroup) {
|
if (privacy.isDisplayContact && recipient.isGroup) {
|
||||||
@@ -88,7 +88,7 @@ data class NotificationConversation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getConversationTitle(context: Context): CharSequence? {
|
fun getConversationTitle(context: Context): CharSequence? {
|
||||||
if (TextSecurePreferences.getNotificationPrivacy(context).isDisplayContact) {
|
if (SignalStore.settings().messageNotificationsPrivacy.isDisplayContact) {
|
||||||
return if (isGroup) recipient.getDisplayName(context) else null
|
return if (isGroup) recipient.getDisplayName(context) else null
|
||||||
}
|
}
|
||||||
return context.getString(R.string.SingleRecipientNotificationBuilder_signal)
|
return context.getString(R.string.SingleRecipientNotificationBuilder_signal)
|
||||||
|
|||||||
+3
-2
@@ -21,6 +21,7 @@ import org.thoughtcrime.securesms.MainActivity
|
|||||||
import org.thoughtcrime.securesms.R
|
import org.thoughtcrime.securesms.R
|
||||||
import org.thoughtcrime.securesms.conversation.ConversationIntents
|
import org.thoughtcrime.securesms.conversation.ConversationIntents
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||||
import org.thoughtcrime.securesms.notifications.DefaultMessageNotifier
|
import org.thoughtcrime.securesms.notifications.DefaultMessageNotifier
|
||||||
import org.thoughtcrime.securesms.notifications.NotificationChannels
|
import org.thoughtcrime.securesms.notifications.NotificationChannels
|
||||||
import org.thoughtcrime.securesms.notifications.NotificationIds
|
import org.thoughtcrime.securesms.notifications.NotificationIds
|
||||||
@@ -250,7 +251,7 @@ object NotificationFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun notifyInThread(context: Context, recipient: Recipient, lastAudibleNotification: Long) {
|
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 ||
|
ServiceUtil.getAudioManager(context).ringerMode != AudioManager.RINGER_MODE_NORMAL ||
|
||||||
(System.currentTimeMillis() - lastAudibleNotification) < DefaultMessageNotifier.MIN_AUDIBLE_PERIOD_MILLIS
|
(System.currentTimeMillis() - lastAudibleNotification) < DefaultMessageNotifier.MIN_AUDIBLE_PERIOD_MILLIS
|
||||||
) {
|
) {
|
||||||
@@ -260,7 +261,7 @@ object NotificationFactory {
|
|||||||
val uri: Uri = if (NotificationChannels.supported()) {
|
val uri: Uri = if (NotificationChannels.supported()) {
|
||||||
NotificationChannels.getMessageRingtone(context, recipient) ?: NotificationChannels.getMessageRingtone(context)
|
NotificationChannels.getMessageRingtone(context, recipient) ?: NotificationChannels.getMessageRingtone(context)
|
||||||
} else {
|
} else {
|
||||||
recipient.messageRingtone ?: TextSecurePreferences.getNotificationRingtone(context)
|
recipient.messageRingtone ?: SignalStore.settings().messageNotificationSound
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uri.toString().isEmpty()) {
|
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.MessageRecord
|
||||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
||||||
import org.thoughtcrime.securesms.database.model.ReactionRecord
|
import org.thoughtcrime.securesms.database.model.ReactionRecord
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||||
import org.thoughtcrime.securesms.mms.Slide
|
import org.thoughtcrime.securesms.mms.Slide
|
||||||
import org.thoughtcrime.securesms.mms.SlideDeck
|
import org.thoughtcrime.securesms.mms.SlideDeck
|
||||||
import org.thoughtcrime.securesms.notifications.AbstractNotificationBuilder
|
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.MediaUtil
|
||||||
import org.thoughtcrime.securesms.util.MessageRecordUtil
|
import org.thoughtcrime.securesms.util.MessageRecordUtil
|
||||||
import org.thoughtcrime.securesms.util.SpanUtil
|
import org.thoughtcrime.securesms.util.SpanUtil
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
|
||||||
import org.thoughtcrime.securesms.util.Util
|
import org.thoughtcrime.securesms.util.Util
|
||||||
|
|
||||||
private val TAG: String = Log.tag(NotificationItemV2::class.java)
|
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 {
|
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)
|
context.getString(R.string.SingleRecipientNotificationBuilder_new_message)
|
||||||
} else {
|
} else {
|
||||||
SpannableStringBuilder().apply {
|
SpannableStringBuilder().apply {
|
||||||
@@ -87,7 +87,7 @@ sealed class NotificationItemV2(val threadRecipient: Recipient, protected val re
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getPersonName(context: Context): CharSequence {
|
fun getPersonName(context: Context): CharSequence {
|
||||||
return if (TextSecurePreferences.getNotificationPrivacy(context).isDisplayContact) {
|
return if (SignalStore.settings().messageNotificationsPrivacy.isDisplayContact) {
|
||||||
individualRecipient.getDisplayName(context)
|
individualRecipient.getDisplayName(context)
|
||||||
} else {
|
} else {
|
||||||
context.getString(R.string.SingleRecipientNotificationBuilder_signal)
|
context.getString(R.string.SingleRecipientNotificationBuilder_signal)
|
||||||
@@ -99,7 +99,7 @@ sealed class NotificationItemV2(val threadRecipient: Recipient, protected val re
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getPersonUri(context: Context): String? {
|
fun getPersonUri(context: Context): String? {
|
||||||
return if (TextSecurePreferences.getNotificationPrivacy(context).isDisplayContact && individualRecipient.isSystemContact) {
|
return if (SignalStore.settings().messageNotificationsPrivacy.isDisplayContact && individualRecipient.isSystemContact) {
|
||||||
individualRecipient.contactUri.toString()
|
individualRecipient.contactUri.toString()
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
@@ -107,7 +107,7 @@ sealed class NotificationItemV2(val threadRecipient: Recipient, protected val re
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getPersonIcon(context: Context): Bitmap? {
|
fun getPersonIcon(context: Context): Bitmap? {
|
||||||
return if (TextSecurePreferences.getNotificationPrivacy(context).isDisplayContact) {
|
return if (SignalStore.settings().messageNotificationsPrivacy.isDisplayContact) {
|
||||||
individualRecipient.getContactDrawable(context).toLargeBitmap(context)
|
individualRecipient.getContactDrawable(context).toLargeBitmap(context)
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
@@ -115,7 +115,7 @@ sealed class NotificationItemV2(val threadRecipient: Recipient, protected val re
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getPrimaryText(context: Context): CharSequence {
|
fun getPrimaryText(context: Context): CharSequence {
|
||||||
return if (TextSecurePreferences.getNotificationPrivacy(context).isDisplayMessage) {
|
return if (SignalStore.settings().messageNotificationsPrivacy.isDisplayMessage) {
|
||||||
if (RecipientUtil.isMessageRequestAccepted(context, threadId)) {
|
if (RecipientUtil.isMessageRequestAccepted(context, threadId)) {
|
||||||
getPrimaryTextActual(context)
|
getPrimaryTextActual(context)
|
||||||
} else {
|
} else {
|
||||||
@@ -128,7 +128,7 @@ sealed class NotificationItemV2(val threadRecipient: Recipient, protected val re
|
|||||||
|
|
||||||
fun getInboxLine(context: Context): CharSequence? {
|
fun getInboxLine(context: Context): CharSequence? {
|
||||||
return when {
|
return when {
|
||||||
TextSecurePreferences.getNotificationPrivacy(context).isDisplayNothing -> null
|
SignalStore.settings().messageNotificationsPrivacy.isDisplayNothing -> null
|
||||||
else -> getStyledPrimaryText(context, true)
|
else -> getStyledPrimaryText(context, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -205,7 +205,7 @@ class MessageNotification(threadRecipient: Recipient, record: MessageRecord) : N
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getThumbnailInfo(context: Context): ThumbnailInfo {
|
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
|
val thumbnailSlide: Slide? = slideDeck?.thumbnailSlide
|
||||||
ThumbnailInfo(thumbnailSlide?.publicUri, thumbnailSlide?.contentType)
|
ThumbnailInfo(thumbnailSlide?.publicUri, thumbnailSlide?.contentType)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+2
-6
@@ -25,10 +25,10 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
|||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
|
||||||
import org.thoughtcrime.securesms.LoggingFragment;
|
import org.thoughtcrime.securesms.LoggingFragment;
|
||||||
import org.thoughtcrime.securesms.PaymentPreferencesDirections;
|
import org.thoughtcrime.securesms.PaymentPreferencesDirections;
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
|
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity;
|
||||||
import org.thoughtcrime.securesms.help.HelpFragment;
|
import org.thoughtcrime.securesms.help.HelpFragment;
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity;
|
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);
|
NavHostFragment.findNavController(this).navigate(R.id.action_paymentsHome_to_paymentsBackup);
|
||||||
return true;
|
return true;
|
||||||
} else if (item.getItemId() == R.id.payments_home_fragment_menu_help) {
|
} else if (item.getItemId() == R.id.payments_home_fragment_menu_help) {
|
||||||
Intent intent = new Intent(requireContext(), ApplicationPreferencesActivity.class);
|
startActivity(AppSettingsActivity.help(requireContext(), HelpFragment.PAYMENT_INDEX));
|
||||||
intent.putExtra(ApplicationPreferencesActivity.LAUNCH_TO_HELP_FRAGMENT, true);
|
|
||||||
intent.putExtra(HelpFragment.START_CATEGORY_INDEX, HelpFragment.PAYMENT_INDEX);
|
|
||||||
|
|
||||||
startActivity(intent);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-3
@@ -10,7 +10,6 @@ import androidx.preference.Preference;
|
|||||||
|
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity;
|
import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity;
|
||||||
@@ -68,8 +67,6 @@ public class AdvancedPinPreferenceFragment extends ListSummaryPreferenceFragment
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
((ApplicationPreferencesActivity) getActivity()).getSupportActionBar().setTitle(R.string.preferences__advanced_pin_settings);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onPreferenceChanged(boolean enabled) {
|
private void onPreferenceChanged(boolean enabled) {
|
||||||
|
|||||||
-306
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-655
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-75
@@ -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]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+3
-5
@@ -34,7 +34,6 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
|||||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||||
import org.thoughtcrime.securesms.util.BackupUtil;
|
import org.thoughtcrime.securesms.util.BackupUtil;
|
||||||
import org.thoughtcrime.securesms.util.StorageUtil;
|
import org.thoughtcrime.securesms.util.StorageUtil;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@@ -83,7 +82,6 @@ public class BackupsPreferenceFragment extends Fragment {
|
|||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
((AppCompatActivity) getActivity()).getSupportActionBar().setTitle(R.string.BackupsPreferenceFragment__chat_backups);
|
|
||||||
|
|
||||||
setBackupStatus();
|
setBackupStatus();
|
||||||
setBackupSummary();
|
setBackupSummary();
|
||||||
@@ -133,7 +131,7 @@ public class BackupsPreferenceFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setBackupStatus() {
|
private void setBackupStatus() {
|
||||||
if (TextSecurePreferences.isBackupEnabled(requireContext())) {
|
if (SignalStore.settings().isBackupEnabled()) {
|
||||||
if (BackupUtil.canUserAccessBackupDirectory(requireContext())) {
|
if (BackupUtil.canUserAccessBackupDirectory(requireContext())) {
|
||||||
setBackupsEnabled();
|
setBackupsEnabled();
|
||||||
} else {
|
} else {
|
||||||
@@ -191,7 +189,7 @@ public class BackupsPreferenceFragment extends Fragment {
|
|||||||
|
|
||||||
@RequiresApi(29)
|
@RequiresApi(29)
|
||||||
private void onToggleClickedApi29() {
|
private void onToggleClickedApi29() {
|
||||||
if (!TextSecurePreferences.isBackupEnabled(requireContext())) {
|
if (!SignalStore.settings().isBackupEnabled()) {
|
||||||
BackupDialog.showChooseBackupLocationDialog(this, CHOOSE_BACKUPS_LOCATION_REQUEST_CODE);
|
BackupDialog.showChooseBackupLocationDialog(this, CHOOSE_BACKUPS_LOCATION_REQUEST_CODE);
|
||||||
} else {
|
} else {
|
||||||
BackupDialog.showDisableBackupDialog(requireContext(), this::setBackupsDisabled);
|
BackupDialog.showDisableBackupDialog(requireContext(), this::setBackupsDisabled);
|
||||||
@@ -203,7 +201,7 @@ public class BackupsPreferenceFragment extends Fragment {
|
|||||||
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||||
.ifNecessary()
|
.ifNecessary()
|
||||||
.onAllGranted(() -> {
|
.onAllGranted(() -> {
|
||||||
if (!TextSecurePreferences.isBackupEnabled(requireContext())) {
|
if (!SignalStore.settings().isBackupEnabled()) {
|
||||||
BackupDialog.showEnableBackupDialog(requireContext(), null, null, this::setBackupsEnabled);
|
BackupDialog.showEnableBackupDialog(requireContext(), null, null, this::setBackupsEnabled);
|
||||||
} else {
|
} else {
|
||||||
BackupDialog.showDisableBackupDialog(requireContext(), this::setBackupsDisabled);
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-138
@@ -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.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
import androidx.appcompat.widget.SwitchCompat;
|
import androidx.appcompat.widget.SwitchCompat;
|
||||||
import androidx.core.app.ShareCompat;
|
import androidx.core.app.ShareCompat;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
@@ -33,13 +32,13 @@ import org.whispersystems.signalservice.internal.configuration.SignalProxy;
|
|||||||
|
|
||||||
public class EditProxyFragment extends Fragment {
|
public class EditProxyFragment extends Fragment {
|
||||||
|
|
||||||
private SwitchCompat proxySwitch;
|
private SwitchCompat proxySwitch;
|
||||||
private EditText proxyText;
|
private EditText proxyText;
|
||||||
private TextView proxyTitle;
|
private TextView proxyTitle;
|
||||||
private TextView proxyStatus;
|
private TextView proxyStatus;
|
||||||
private View shareButton;
|
private View shareButton;
|
||||||
private CircularProgressButton saveButton;
|
private CircularProgressButton saveButton;
|
||||||
private EditProxyViewModel viewModel;
|
private EditProxyViewModel viewModel;
|
||||||
|
|
||||||
public static EditProxyFragment newInstance() {
|
public static EditProxyFragment newInstance() {
|
||||||
return new EditProxyFragment();
|
return new EditProxyFragment();
|
||||||
@@ -85,7 +84,7 @@ public class EditProxyFragment extends Fragment {
|
|||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
((AppCompatActivity) requireActivity()).getSupportActionBar().setTitle(R.string.preferences_use_proxy);
|
|
||||||
SignalProxyUtil.startListeningToWebsocket();
|
SignalProxyUtil.startListeningToWebsocket();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user