Add trim conversations by time option.

This commit is contained in:
Cody Henthorne
2020-09-03 17:52:44 -04:00
parent 6a14dc69c0
commit bcd27355f9
36 changed files with 1183 additions and 233 deletions

View File

@@ -0,0 +1,21 @@
package org.thoughtcrime.securesms.components.settings;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.MappingAdapter;
/**
* Reusable adapter for generic settings list.
*/
public class BaseSettingsAdapter extends MappingAdapter {
public void configureSingleSelect(@NonNull SingleSelectSetting.SingleSelectSelectionChangedListener selectionChangedListener) {
registerFactory(SingleSelectSetting.Item.class,
new LayoutFactory<>(v -> new SingleSelectSetting.ViewHolder(v, selectionChangedListener), R.layout.single_select_item));
}
public void configureCustomizableSingleSelect(@NonNull CustomizableSingleSelectSetting.CustomizableSingleSelectionListener selectionListener) {
registerFactory(CustomizableSingleSelectSetting.Item.class,
new LayoutFactory<>(v -> new CustomizableSingleSelectSetting.ViewHolder(v, selectionListener), R.layout.customizable_single_select_item));
}
}

View File

@@ -0,0 +1,93 @@
package org.thoughtcrime.securesms.components.settings;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.MappingModelList;
import java.io.Serializable;
import java.util.Objects;
/**
* A simple settings screen that takes its configuration via {@link Configuration}.
*/
public class BaseSettingsFragment extends Fragment {
private static final String CONFIGURATION_ARGUMENT = "current_selection";
private RecyclerView recycler;
public static @NonNull BaseSettingsFragment create(@NonNull Configuration configuration) {
BaseSettingsFragment fragment = new BaseSettingsFragment();
Bundle arguments = new Bundle();
arguments.putSerializable(CONFIGURATION_ARGUMENT, configuration);
fragment.setArguments(arguments);
return fragment;
}
@Override
public @Nullable View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.base_settings_fragment, container, false);
recycler = view.findViewById(R.id.base_settings_list);
recycler.setItemAnimator(null);
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
BaseSettingsAdapter adapter = new BaseSettingsAdapter();
recycler.setLayoutManager(new LinearLayoutManager(requireContext()));
recycler.setAdapter(adapter);
Configuration configuration = (Configuration) Objects.requireNonNull(requireArguments().getSerializable(CONFIGURATION_ARGUMENT));
configuration.configure(requireActivity(), adapter);
configuration.setArguments(getArguments());
configuration.configureAdapter(adapter);
adapter.submitList(configuration.getSettings());
}
/**
* A configuration for a settings screen. Utilizes serializable to hide
* reflection of instantiating from a fragment argument.
*/
public static abstract class Configuration implements Serializable {
protected transient FragmentActivity activity;
protected transient BaseSettingsAdapter adapter;
public void configure(@NonNull FragmentActivity activity, @NonNull BaseSettingsAdapter adapter) {
this.activity = activity;
this.adapter = adapter;
}
/**
* Retrieve any runtime information from the fragment's arguments.
*/
public void setArguments(@Nullable Bundle arguments) {}
protected void updateSettingsList() {
adapter.submitList(getSettings());
}
public abstract void configureAdapter(@NonNull BaseSettingsAdapter adapter);
public abstract @NonNull MappingModelList getSettings();
}
}

View File

@@ -0,0 +1,92 @@
package org.thoughtcrime.securesms.components.settings;
import android.view.View;
import android.widget.RadioButton;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.Group;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.MappingModel;
import org.thoughtcrime.securesms.util.MappingViewHolder;
import java.util.Objects;
/**
* Adds ability to customize a value for a single select (radio) setting.
*/
public class CustomizableSingleSelectSetting {
public interface CustomizableSingleSelectionListener extends SingleSelectSetting.SingleSelectSelectionChangedListener {
void onCustomizeClicked(@NonNull Item item);
}
public static class ViewHolder extends MappingViewHolder<Item> {
private final TextView summaryText;
private final View customize;
private final RadioButton radio;
private final SingleSelectSetting.ViewHolder delegate;
private final Group customizeGroup;
private final CustomizableSingleSelectionListener selectionListener;
public ViewHolder(@NonNull View itemView, @NonNull CustomizableSingleSelectionListener selectionListener) {
super(itemView);
this.selectionListener = selectionListener;
radio = findViewById(R.id.customizable_single_select_radio);
summaryText = findViewById(R.id.customizable_single_select_summary);
customize = findViewById(R.id.customizable_single_select_customize);
customizeGroup = findViewById(R.id.customizable_single_select_customize_group);
delegate = new SingleSelectSetting.ViewHolder(itemView, selectionListener) {
@Override
protected void setChecked(boolean checked) {
radio.setChecked(checked);
}
};
}
@Override
public void bind(@NonNull Item model) {
delegate.bind(model.singleSelectItem);
customizeGroup.setVisibility(radio.isChecked() ? View.VISIBLE : View.GONE);
customize.setOnClickListener(v -> selectionListener.onCustomizeClicked(model));
if (model.getCustomValue() != null) {
summaryText.setText(model.getSummaryText());
}
}
}
public static class Item implements MappingModel<Item> {
private SingleSelectSetting.Item singleSelectItem;
private Object customValue;
private String summaryText;
public <T> Item(@NonNull T item, @Nullable String text, boolean isSelected, @Nullable Object customValue, @Nullable String summaryText) {
this.customValue = customValue;
this.summaryText = summaryText;
singleSelectItem = new SingleSelectSetting.Item(item, text, isSelected);
}
public @Nullable Object getCustomValue() {
return customValue;
}
public @Nullable String getSummaryText() {
return summaryText;
}
@Override
public boolean areItemsTheSame(@NonNull Item newItem) {
return singleSelectItem.areItemsTheSame(newItem.singleSelectItem);
}
@Override
public boolean areContentsTheSame(@NonNull Item newItem) {
return singleSelectItem.areContentsTheSame(newItem.singleSelectItem) && Objects.equals(customValue, newItem.customValue) && Objects.equals(summaryText, newItem.summaryText);
}
}
}

View File

@@ -0,0 +1,76 @@
package org.thoughtcrime.securesms.components.settings;
import android.view.View;
import android.widget.CheckedTextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.MappingModel;
import org.thoughtcrime.securesms.util.MappingViewHolder;
import java.util.Objects;
/**
* Single select (radio) setting option
*/
public class SingleSelectSetting {
public interface SingleSelectSelectionChangedListener {
void onSelectionChanged(@NonNull Object selection);
}
public static class ViewHolder extends MappingViewHolder<Item> {
protected final CheckedTextView text;
protected final SingleSelectSelectionChangedListener selectionChangedListener;
public ViewHolder(@NonNull View itemView, @NonNull SingleSelectSelectionChangedListener selectionChangedListener) {
super(itemView);
this.selectionChangedListener = selectionChangedListener;
this.text = findViewById(R.id.single_select_item_text);
}
@Override
public void bind(@NonNull Item model) {
text.setText(model.text);
setChecked(model.isSelected);
itemView.setOnClickListener(v -> selectionChangedListener.onSelectionChanged(model.item));
}
protected void setChecked(boolean checked) {
text.setChecked(checked);
}
}
public static class Item implements MappingModel<Item> {
private final String text;
private final Object item;
private final boolean isSelected;
public <T> Item(@NonNull T item, @Nullable String text, boolean isSelected) {
this.item = item;
this.text = text != null ? text : item.toString();
this.isSelected = isSelected;
}
public @NonNull String getText() {
return text;
}
public @NonNull Object getItem() {
return item;
}
@Override
public boolean areItemsTheSame(@NonNull Item newItem) {
return item.equals(newItem.item);
}
@Override
public boolean areContentsTheSame(@NonNull Item newItem) {
return Objects.equals(text, newItem.text) && isSelected == newItem.isSelected;
}
}
}