mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-21 09:20:19 +01:00
Convert and update Manage Storage Settings.
This commit is contained in:
committed by
Greyson Parrelli
parent
adef572abb
commit
6d657b449c
@@ -1,47 +0,0 @@
|
||||
package org.thoughtcrime.securesms.preferences;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import org.signal.core.util.concurrent.SignalExecutors;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.database.MediaTable;
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||
import org.thoughtcrime.securesms.preferences.widgets.StorageGraphView;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ApplicationPreferencesViewModel extends ViewModel {
|
||||
|
||||
private final MutableLiveData<StorageGraphView.StorageBreakdown> storageBreakdown = new MutableLiveData<>();
|
||||
|
||||
LiveData<StorageGraphView.StorageBreakdown> getStorageBreakdown() {
|
||||
return storageBreakdown;
|
||||
}
|
||||
|
||||
static ApplicationPreferencesViewModel getApplicationPreferencesViewModel(@NonNull FragmentActivity activity) {
|
||||
return new ViewModelProvider(activity).get(ApplicationPreferencesViewModel.class);
|
||||
}
|
||||
|
||||
void refreshStorageBreakdown(@NonNull Context context) {
|
||||
SignalExecutors.BOUNDED.execute(() -> {
|
||||
MediaTable.StorageBreakdown breakdown = SignalDatabase.media().getStorageBreakdown();
|
||||
|
||||
StorageGraphView.StorageBreakdown latestStorageBreakdown = new StorageGraphView.StorageBreakdown(Arrays.asList(
|
||||
new StorageGraphView.Entry(ContextCompat.getColor(context, R.color.storage_color_photos), breakdown.getPhotoSize()),
|
||||
new StorageGraphView.Entry(ContextCompat.getColor(context, R.color.storage_color_videos), breakdown.getVideoSize()),
|
||||
new StorageGraphView.Entry(ContextCompat.getColor(context, R.color.storage_color_files), breakdown.getDocumentSize()),
|
||||
new StorageGraphView.Entry(ContextCompat.getColor(context, R.color.storage_color_audio), breakdown.getAudioSize())
|
||||
));
|
||||
|
||||
storageBreakdown.postValue(latestStorageBreakdown);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,312 +0,0 @@
|
||||
package org.thoughtcrime.securesms.preferences;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
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.BaseSettingsAdapter;
|
||||
import org.thoughtcrime.securesms.components.settings.BaseSettingsFragment;
|
||||
import org.thoughtcrime.securesms.components.settings.CustomizableSingleSelectSetting;
|
||||
import org.thoughtcrime.securesms.components.settings.SingleSelectSetting;
|
||||
import org.thoughtcrime.securesms.components.settings.app.wrapped.SettingsWrapperFragment;
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||
import org.thoughtcrime.securesms.database.ThreadTable;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.keyvalue.KeepMessagesDuration;
|
||||
import org.thoughtcrime.securesms.keyvalue.SettingsValues;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.mediaoverview.MediaOverviewActivity;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.preferences.widgets.StoragePreferenceCategory;
|
||||
import org.signal.core.util.StringUtil;
|
||||
import org.thoughtcrime.securesms.util.adapter.mapping.MappingModelList;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
|
||||
public class StoragePreferenceFragment extends ListSummaryPreferenceFragment {
|
||||
|
||||
private Preference keepMessages;
|
||||
private Preference trimLength;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle paramBundle) {
|
||||
super.onCreate(paramBundle);
|
||||
|
||||
findPreference("pref_storage_clear_message_history")
|
||||
.setOnPreferenceClickListener(new ClearMessageHistoryClickListener());
|
||||
|
||||
trimLength = findPreference(SettingsValues.THREAD_TRIM_LENGTH);
|
||||
trimLength.setOnPreferenceClickListener(p -> {
|
||||
updateToolbarTitle(R.string.preferences__conversation_length_limit);
|
||||
pushFragment(BaseSettingsFragment.create(new ConversationLengthLimitConfiguration()));
|
||||
return true;
|
||||
});
|
||||
|
||||
keepMessages = findPreference(SettingsValues.KEEP_MESSAGES_DURATION);
|
||||
keepMessages.setOnPreferenceClickListener(p -> {
|
||||
updateToolbarTitle(R.string.preferences__keep_messages);
|
||||
pushFragment(BaseSettingsFragment.create(new KeepMessagesConfiguration()));
|
||||
return true;
|
||||
});
|
||||
|
||||
StoragePreferenceCategory storageCategory = (StoragePreferenceCategory) findPreference("pref_storage_category");
|
||||
FragmentActivity activity = requireActivity();
|
||||
ApplicationPreferencesViewModel viewModel = ApplicationPreferencesViewModel.getApplicationPreferencesViewModel(activity);
|
||||
|
||||
storageCategory.setOnFreeUpSpace(() -> activity.startActivity(MediaOverviewActivity.forAll(activity)));
|
||||
|
||||
viewModel.getStorageBreakdown().observe(activity, storageCategory::setStorage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) {
|
||||
addPreferencesFromResource(R.xml.preferences_storage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
updateToolbarTitle(R.string.preferences__storage);
|
||||
|
||||
FragmentActivity activity = requireActivity();
|
||||
ApplicationPreferencesViewModel viewModel = ApplicationPreferencesViewModel.getApplicationPreferencesViewModel(activity);
|
||||
|
||||
viewModel.refreshStorageBreakdown(activity.getApplicationContext());
|
||||
|
||||
keepMessages.setSummary(SignalStore.settings().getKeepMessagesDuration().getStringResource());
|
||||
|
||||
trimLength.setSummary(SignalStore.settings().isTrimByLengthEnabled() ? getResources().getQuantityString(R.plurals.preferences_storage__s_messages_plural, SignalStore.settings().getThreadTrimLength(), NumberFormat.getInstance().format(SignalStore.settings().getThreadTrimLength()))
|
||||
: getString(R.string.preferences_storage__none));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
|
||||
}
|
||||
|
||||
private void updateToolbarTitle(@StringRes int title) {
|
||||
if (getParentFragment() instanceof SettingsWrapperFragment) {
|
||||
((SettingsWrapperFragment) getParentFragment()).setTitle(title);
|
||||
}
|
||||
}
|
||||
|
||||
private void pushFragment(@NonNull Fragment fragment) {
|
||||
getParentFragmentManager().beginTransaction()
|
||||
.replace(R.id.wrapped_fragment, fragment)
|
||||
.addToBackStack(null)
|
||||
.commit();
|
||||
}
|
||||
|
||||
private class ClearMessageHistoryClickListener implements Preference.OnPreferenceClickListener {
|
||||
@Override
|
||||
public boolean onPreferenceClick(@NonNull Preference preference) {
|
||||
new MaterialAlertDialogBuilder(requireActivity())
|
||||
.setTitle(R.string.preferences_storage__clear_message_history)
|
||||
.setMessage(R.string.preferences_storage__this_will_delete_all_message_history_and_media_from_your_device)
|
||||
.setPositiveButton(R.string.delete, (d, w) -> showAreYouReallySure())
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void showAreYouReallySure() {
|
||||
new MaterialAlertDialogBuilder(requireActivity())
|
||||
.setTitle(R.string.preferences_storage__are_you_sure_you_want_to_delete_all_message_history)
|
||||
.setMessage(R.string.preferences_storage__all_message_history_will_be_permanently_removed_this_action_cannot_be_undone)
|
||||
.setPositiveButton(R.string.preferences_storage__delete_all_now, (d, w) -> {
|
||||
SignalExecutors.BOUNDED.execute(() -> {
|
||||
SignalDatabase.threads().deleteAllConversations();
|
||||
ApplicationDependencies.getMessageNotifier().updateNotification(requireContext());
|
||||
});
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show();
|
||||
}
|
||||
}
|
||||
|
||||
public static class KeepMessagesConfiguration extends BaseSettingsFragment.Configuration implements SingleSelectSetting.SingleSelectSelectionChangedListener {
|
||||
|
||||
@Override
|
||||
public void configureAdapter(@NonNull BaseSettingsAdapter adapter) {
|
||||
adapter.configureSingleSelect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull MappingModelList getSettings() {
|
||||
KeepMessagesDuration currentDuration = SignalStore.settings().getKeepMessagesDuration();
|
||||
return Stream.of(KeepMessagesDuration.values())
|
||||
.map(duration -> new SingleSelectSetting.Item(duration, activity.getString(duration.getStringResource()), null, duration.equals(currentDuration)))
|
||||
.collect(MappingModelList.toMappingModelList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelectionChanged(@NonNull Object selection) {
|
||||
KeepMessagesDuration currentDuration = SignalStore.settings().getKeepMessagesDuration();
|
||||
KeepMessagesDuration newDuration = (KeepMessagesDuration) selection;
|
||||
|
||||
if (newDuration.ordinal() > currentDuration.ordinal()) {
|
||||
new MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.preferences_storage__delete_older_messages)
|
||||
.setMessage(activity.getString(R.string.preferences_storage__this_will_permanently_delete_all_message_history_and_media, activity.getString(newDuration.getStringResource())))
|
||||
.setPositiveButton(R.string.delete, (d, w) -> updateTrimByTime(newDuration))
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show();
|
||||
} else {
|
||||
updateTrimByTime(newDuration);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTrimByTime(@NonNull KeepMessagesDuration newDuration) {
|
||||
SignalStore.settings().setKeepMessagesForDuration(newDuration);
|
||||
updateSettingsList();
|
||||
ApplicationDependencies.getTrimThreadsByDateManager().scheduleIfNecessary();
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConversationLengthLimitConfiguration extends BaseSettingsFragment.Configuration implements CustomizableSingleSelectSetting.CustomizableSingleSelectionListener {
|
||||
|
||||
private static final int CUSTOM_LENGTH = -1;
|
||||
|
||||
@Override
|
||||
public void configureAdapter(@NonNull BaseSettingsAdapter adapter) {
|
||||
adapter.configureSingleSelect(this);
|
||||
adapter.configureCustomizableSingleSelect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull MappingModelList getSettings() {
|
||||
int trimLength = SignalStore.settings().isTrimByLengthEnabled() ? SignalStore.settings().getThreadTrimLength() : 0;
|
||||
int[] options = activity.getResources().getIntArray(R.array.conversation_length_limit);
|
||||
boolean hasSelection = false;
|
||||
MappingModelList settings = new MappingModelList();
|
||||
|
||||
for (int option : options) {
|
||||
boolean isSelected = option == trimLength;
|
||||
String text = option == 0 ? activity.getString(R.string.preferences_storage__none)
|
||||
: activity.getResources().getQuantityString(R.plurals.preferences_storage__s_messages_plural, option, NumberFormat.getInstance().format(option));
|
||||
|
||||
settings.add(new SingleSelectSetting.Item(option, text, null, isSelected));
|
||||
|
||||
hasSelection = hasSelection || isSelected;
|
||||
}
|
||||
|
||||
int currentValue = SignalStore.settings().getThreadTrimLength();
|
||||
settings.add(new CustomizableSingleSelectSetting.Item(CUSTOM_LENGTH,
|
||||
activity.getString(R.string.preferences_storage__custom),
|
||||
!hasSelection,
|
||||
currentValue,
|
||||
activity.getResources().getQuantityString(R.plurals.preferences_storage__s_messages_plural, currentValue, NumberFormat.getInstance().format(currentValue))));
|
||||
return settings;
|
||||
}
|
||||
|
||||
@SuppressLint("InflateParams")
|
||||
@Override
|
||||
public void onCustomizeClicked(@Nullable CustomizableSingleSelectSetting.Item item) {
|
||||
boolean trimLengthEnabled = SignalStore.settings().isTrimByLengthEnabled();
|
||||
int trimLength = trimLengthEnabled ? SignalStore.settings().getThreadTrimLength() : 0;
|
||||
|
||||
View view = LayoutInflater.from(activity).inflate(R.layout.customizable_setting_edit_text, null, false);
|
||||
EditText editText = view.findViewById(R.id.customizable_setting_edit_text);
|
||||
if (trimLength > 0) {
|
||||
editText.setText(String.valueOf(trimLength));
|
||||
}
|
||||
|
||||
AlertDialog dialog = new MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.preferences__conversation_length_limit)
|
||||
.setView(view)
|
||||
.setPositiveButton(android.R.string.ok, (d, w) -> onSelectionChanged(Integer.parseInt(editText.getText().toString())))
|
||||
.setNegativeButton(android.R.string.cancel, (d, w) -> updateSettingsList())
|
||||
.create();
|
||||
|
||||
dialog.setOnShowListener(d -> {
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(!TextUtils.isEmpty(editText.getText()));
|
||||
editText.requestFocus();
|
||||
editText.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void afterTextChanged(@NonNull Editable sequence) {
|
||||
CharSequence trimmed = StringUtil.trimSequence(sequence);
|
||||
if (TextUtils.isEmpty(trimmed)) {
|
||||
sequence.replace(0, sequence.length(), "");
|
||||
} else {
|
||||
try {
|
||||
Integer.parseInt(trimmed.toString());
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);
|
||||
return;
|
||||
} catch (NumberFormatException e) {
|
||||
String onlyDigits = trimmed.toString().replaceAll("[^\\d]", "");
|
||||
if (!onlyDigits.equals(trimmed.toString())) {
|
||||
sequence.replace(0, sequence.length(), onlyDigits);
|
||||
}
|
||||
}
|
||||
}
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(@NonNull CharSequence sequence, int start, int count, int after) {}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(@NonNull CharSequence sequence, int start, int before, int count) {}
|
||||
});
|
||||
});
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelectionChanged(@NonNull Object selection) {
|
||||
boolean trimLengthEnabled = SignalStore.settings().isTrimByLengthEnabled();
|
||||
int trimLength = trimLengthEnabled ? SignalStore.settings().getThreadTrimLength() : 0;
|
||||
int newTrimLength = (Integer) selection;
|
||||
|
||||
if (newTrimLength > 0 && (!trimLengthEnabled || newTrimLength < trimLength)) {
|
||||
new MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.preferences_storage__delete_older_messages)
|
||||
.setMessage(activity.getResources().getQuantityString(R.plurals.preferences_storage__this_will_permanently_trim_all_conversations_to_the_d_most_recent_messages, newTrimLength, newTrimLength))
|
||||
.setPositiveButton(R.string.delete, (d, w) -> updateTrimByLength(newTrimLength))
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show();
|
||||
} else if (newTrimLength == CUSTOM_LENGTH) {
|
||||
onCustomizeClicked(null);
|
||||
} else {
|
||||
updateTrimByLength(newTrimLength);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTrimByLength(int length) {
|
||||
boolean restrictingChange = !SignalStore.settings().isTrimByLengthEnabled() || length < SignalStore.settings().getThreadTrimLength();
|
||||
|
||||
SignalStore.settings().setThreadTrimByLengthEnabled(length > 0);
|
||||
SignalStore.settings().setThreadTrimLength(length);
|
||||
updateSettingsList();
|
||||
|
||||
if (SignalStore.settings().isTrimByLengthEnabled() && restrictingChange) {
|
||||
KeepMessagesDuration keepMessagesDuration = SignalStore.settings().getKeepMessagesDuration();
|
||||
|
||||
long trimBeforeDate = keepMessagesDuration != KeepMessagesDuration.FOREVER ? System.currentTimeMillis() - keepMessagesDuration.getDuration()
|
||||
: ThreadTable.NO_TRIM_BEFORE_DATE_SET;
|
||||
|
||||
SignalExecutors.BOUNDED.execute(() -> SignalDatabase.threads().trimAllThreads(length, trimBeforeDate));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
package org.thoughtcrime.securesms.preferences.widgets;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
public final class StoragePreferenceCategory extends PreferenceCategory {
|
||||
|
||||
private Runnable onFreeUpSpace;
|
||||
private TextView totalSize;
|
||||
private StorageGraphView storageGraphView;
|
||||
private StorageGraphView.StorageBreakdown storage;
|
||||
|
||||
public StoragePreferenceCategory(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
initialize();
|
||||
}
|
||||
|
||||
public StoragePreferenceCategory(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initialize();
|
||||
}
|
||||
|
||||
public StoragePreferenceCategory(Context context) {
|
||||
super(context);
|
||||
initialize();
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
setLayoutResource(R.layout.preference_storage_category);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(PreferenceViewHolder view) {
|
||||
super.onBindViewHolder(view);
|
||||
|
||||
totalSize = (TextView) view.findViewById(R.id.total_size);
|
||||
storageGraphView = (StorageGraphView) view.findViewById(R.id.storageGraphView);
|
||||
|
||||
view.findViewById(R.id.free_up_space)
|
||||
.setOnClickListener(v -> {
|
||||
if (onFreeUpSpace != null) {
|
||||
onFreeUpSpace.run();
|
||||
}
|
||||
});
|
||||
|
||||
totalSize.setText(Util.getPrettyFileSize(0));
|
||||
|
||||
if (storage != null) {
|
||||
setStorage(storage);
|
||||
}
|
||||
}
|
||||
|
||||
public void setOnFreeUpSpace(Runnable onFreeUpSpace) {
|
||||
this.onFreeUpSpace = onFreeUpSpace;
|
||||
}
|
||||
|
||||
public void setStorage(StorageGraphView.StorageBreakdown storage) {
|
||||
this.storage = storage;
|
||||
if (totalSize != null) {
|
||||
totalSize.setText(Util.getPrettyFileSize(storage.getTotalSize()));
|
||||
}
|
||||
if (storageGraphView != null) {
|
||||
storageGraphView.setStorageBreakdown(storage);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user