1package eu.siacs.conversations.ui.adapter;
2
3import android.content.Context;
4import android.widget.ArrayAdapter;
5import android.widget.Filter;
6import androidx.annotation.NonNull;
7import com.google.common.collect.ImmutableList;
8import com.google.common.collect.Ordering;
9import eu.siacs.conversations.Config;
10import java.util.ArrayList;
11import java.util.Collection;
12import java.util.List;
13import java.util.Locale;
14import java.util.regex.Pattern;
15
16public class KnownHostsAdapter extends ArrayAdapter<String> {
17
18 private static final Pattern E164_PATTERN = Pattern.compile("^\\+[1-9]\\d{1,14}$");
19
20 private List<String> domains;
21 private final Filter domainFilter =
22 new Filter() {
23
24 @Override
25 protected FilterResults performFiltering(final CharSequence constraint) {
26 final ImmutableList.Builder<String> builder = new ImmutableList.Builder<>();
27 final String[] split =
28 constraint == null ? new String[0] : constraint.toString().split("@");
29 if (split.length == 1) {
30 final String local = split[0].toLowerCase(Locale.ENGLISH);
31 if (Config.QUICKSY_DOMAIN != null
32 && E164_PATTERN.matcher(local).matches()) {
33 builder.add(local + '@' + Config.QUICKSY_DOMAIN);
34 } else {
35 for (String domain : domains) {
36 builder.add(local + '@' + domain);
37 }
38 }
39 } else if (split.length == 2) {
40 final String localPart = split[0].toLowerCase(Locale.ENGLISH);
41 final String domainPart = split[1].toLowerCase(Locale.ENGLISH);
42 if (domains.contains(domainPart)) {
43 return new FilterResults();
44 }
45 for (final String domain : domains) {
46 if (domain.contains(domainPart)) {
47 builder.add(localPart + "@" + domain);
48 }
49 }
50 } else {
51 return new FilterResults();
52 }
53 final var suggestions = builder.build();
54 final FilterResults filterResults = new FilterResults();
55 filterResults.values = suggestions;
56 filterResults.count = suggestions.size();
57 return filterResults;
58 }
59
60 @Override
61 protected void publishResults(
62 final CharSequence constraint, final FilterResults results) {
63 final ImmutableList.Builder<String> suggestions = new ImmutableList.Builder<>();
64 if (results.values instanceof Collection<?> collection) {
65 for (final Object item : collection) {
66 if (item instanceof String string) {
67 suggestions.add(string);
68 }
69 }
70 }
71 clear();
72 addAll(suggestions.build());
73 notifyDataSetChanged();
74 }
75 };
76
77 public KnownHostsAdapter(
78 final Context context, final int viewResourceId, final Collection<String> knownHosts) {
79 super(context, viewResourceId, new ArrayList<>());
80 domains = Ordering.natural().sortedCopy(knownHosts);
81 }
82
83 public KnownHostsAdapter(final Context context, final int viewResourceId) {
84 super(context, viewResourceId, new ArrayList<>());
85 domains = ImmutableList.of();
86 }
87
88 public void refresh(final Collection<String> knownHosts) {
89 this.domains = Ordering.natural().sortedCopy(knownHosts);
90 notifyDataSetChanged();
91 }
92
93 @Override
94 @NonNull
95 public Filter getFilter() {
96 return domainFilter;
97 }
98}