From ad8d4451d07b5566117de2165539ab7b537843de Mon Sep 17 00:00:00 2001 From: frankknoll Date: Sat, 7 Dec 2024 01:54:38 +0100 Subject: [PATCH] sorting preference search results by their paths --- OsmAnd/build-common.gradle | 3 +- .../search/LexicographicalListComparator.java | 44 ++++++++++++ .../SearchResultsByPreferencePathSorter.java | 41 +++++++++++ .../search/SettingsSearchButtonHelper.java | 1 + .../fragments/search/POJOTestFactory.java | 43 ++++++++++++ ...archResultsByPreferencePathSorterTest.java | 70 +++++++++++++++++++ 6 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 OsmAnd/src/net/osmand/plus/settings/fragments/search/LexicographicalListComparator.java create mode 100644 OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchResultsByPreferencePathSorter.java create mode 100644 OsmAnd/test/java/net/osmand/plus/settings/fragments/search/POJOTestFactory.java create mode 100644 OsmAnd/test/java/net/osmand/plus/settings/fragments/search/SearchResultsByPreferencePathSorterTest.java diff --git a/OsmAnd/build-common.gradle b/OsmAnd/build-common.gradle index c9e7c91dcc9..79303b11d38 100644 --- a/OsmAnd/build-common.gradle +++ b/OsmAnd/build-common.gradle @@ -375,9 +375,10 @@ dependencies { implementation "androidx.car.app:app-projected:1.4.0" implementation 'com.google.android.gms:play-services-location:21.3.0' - implementation 'com.github.KnollFrank:SettingsSearch:d5f48a4a0a' + implementation 'com.github.KnollFrank:SettingsSearch:f4865ec77a' // https://mvnrepository.com/artifact/com.google.guava/guava implementation 'com.google.guava:guava:33.3.1-android' + androidTestImplementation 'com.codepoetics:ambivalence:0.2' //implementation "androidx.tracing:tracing:1.1.0" //debugImplementation 'androidx.test:monitor:1.6.1' diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/LexicographicalListComparator.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/LexicographicalListComparator.java new file mode 100644 index 00000000000..c7b4c7753b8 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/LexicographicalListComparator.java @@ -0,0 +1,44 @@ +package net.osmand.plus.settings.fragments.search; + +import android.util.Pair; + +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +class LexicographicalListComparator implements Comparator> { + + private final Comparator elementComparator; + + public LexicographicalListComparator(final Comparator elementComparator) { + this.elementComparator = elementComparator; + } + + @Override + public int compare(final List list1, final List list2) { + if (list1.size() < list2.size()) { + return -1; + } else if (list1.size() > list2.size()) { + return +1; + } else { + return LexicographicalListComparator + .zip(list1, list2) + .stream() + .map(elementPair -> elementComparator.compare(elementPair.first, elementPair.second)) + .filter(compareResult -> compareResult != 0) + .findFirst() + .orElse(0); + } + } + + // adapted from https://stackoverflow.com/questions/31963297/how-to-zip-two-java-lists + private static List> zip(final List as, final List bs) { + if (as.size() != bs.size()) { + throw new IllegalArgumentException(); + } + return IntStream.range(0, as.size()) + .mapToObj(i -> Pair.create(as.get(i), bs.get(i))) + .collect(Collectors.toList()); + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchResultsByPreferencePathSorter.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchResultsByPreferencePathSorter.java new file mode 100644 index 00000000000..4206568b521 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SearchResultsByPreferencePathSorter.java @@ -0,0 +1,41 @@ +package net.osmand.plus.settings.fragments.search; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +import de.KnollFrank.lib.settingssearch.PreferencePath; +import de.KnollFrank.lib.settingssearch.db.preference.pojo.SearchablePreferencePOJO; +import de.KnollFrank.lib.settingssearch.results.SearchablePreferencePOJOComparatorFactory; + +class SearchResultsByPreferencePathSorter implements de.KnollFrank.lib.settingssearch.results.SearchResultsSorter { + + @Override + public List sort(final Collection searchResults) { + return searchResults + .stream() + .sorted(getPreferenceByPreferencePathComparator()) + .collect(Collectors.toList()); + } + + private static Comparator getPreferenceByPreferencePathComparator() { + return Comparator.comparing( + SearchablePreferencePOJO::getPreferencePath, + getPreferencePathComparator()); + } + + private static Comparator getPreferencePathComparator() { + return Comparator.comparing( + preferencePath -> reverse(preferencePath.preferences()), + new LexicographicalListComparator<>(SearchablePreferencePOJOComparatorFactory.lexicographicalComparator())); + } + + private static List reverse(final List ts) { + final List tsReversed = new ArrayList<>(ts); + Collections.reverse(tsReversed); + return tsReversed; + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/search/SettingsSearchButtonHelper.java b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SettingsSearchButtonHelper.java index fb5ac4f8403..e170b3699c5 100644 --- a/OsmAnd/src/net/osmand/plus/settings/fragments/search/SettingsSearchButtonHelper.java +++ b/OsmAnd/src/net/osmand/plus/settings/fragments/search/SettingsSearchButtonHelper.java @@ -72,6 +72,7 @@ public static SearchPreferenceFragments createSearchPreferenceFragments( .withSearchResultsFragmentUI(new SearchResultsFragmentUI()) .withPrepareShow(new PrepareShow()) .withIncludePreferenceInSearchResultsPredicate(new IncludePreferenceInSearchResultsPredicate()) + .withSearchResultsSorter(new SearchResultsByPreferencePathSorter()) .build()) .withCreateSearchDatabaseTaskSupplier(createSearchDatabaseTaskSupplier) .build(); diff --git a/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/POJOTestFactory.java b/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/POJOTestFactory.java new file mode 100644 index 00000000000..d0710bf9edd --- /dev/null +++ b/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/POJOTestFactory.java @@ -0,0 +1,43 @@ +package net.osmand.plus.settings.fragments.search; + +import android.os.Bundle; + +import androidx.preference.PreferenceFragmentCompat; + +import java.util.List; +import java.util.Optional; + +import de.KnollFrank.lib.settingssearch.db.preference.converter.IdGenerator; +import de.KnollFrank.lib.settingssearch.db.preference.pojo.SearchablePreferencePOJO; + +class POJOTestFactory { + + private static final IdGenerator idGenerator = new IdGenerator(); + + public static SearchablePreferencePOJO createSearchablePreferencePOJO( + final String title, + final Class host) { + final SearchablePreferencePOJO searchablePreferencePOJO = + new SearchablePreferencePOJO( + idGenerator.nextId(), + Optional.of(title), + Optional.empty(), + 0, + Optional.empty(), + Optional.of(title), + 0, + Optional.empty(), + true, + Optional.empty(), + new Bundle(), + List.of()); + searchablePreferencePOJO.setHost(host); + return searchablePreferencePOJO; + } + + public static SearchablePreferencePOJO copy(final SearchablePreferencePOJO preference) { + return createSearchablePreferencePOJO( + preference.getTitle().orElseThrow(), + preference.getHost()); + } +} diff --git a/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/SearchResultsByPreferencePathSorterTest.java b/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/SearchResultsByPreferencePathSorterTest.java new file mode 100644 index 00000000000..4285783461d --- /dev/null +++ b/OsmAnd/test/java/net/osmand/plus/settings/fragments/search/SearchResultsByPreferencePathSorterTest.java @@ -0,0 +1,70 @@ +package net.osmand.plus.settings.fragments.search; + +import static net.osmand.plus.settings.fragments.search.POJOTestFactory.copy; +import static net.osmand.plus.settings.fragments.search.POJOTestFactory.createSearchablePreferencePOJO; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import net.osmand.plus.settings.fragments.MainSettingsFragment; +import net.osmand.plus.settings.fragments.VehicleParametersFragment; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Collection; +import java.util.List; + +import de.KnollFrank.lib.settingssearch.PreferencePath; +import de.KnollFrank.lib.settingssearch.db.preference.pojo.SearchablePreferencePOJO; + +@RunWith(AndroidJUnit4.class) +public class SearchResultsByPreferencePathSorterTest { + + @Test + public void shouldSortSearchResultsByPreferencePath() { + // Given + final SearchablePreferencePOJO defaultSpeed = + createSearchablePreferencePOJO( + "default speed", + VehicleParametersFragment.class); + defaultSpeed.setPreferencePath(new PreferencePath(List.of(defaultSpeed))); + + final SearchablePreferencePOJO car = + createSearchablePreferencePOJO( + "car", + MainSettingsFragment.class); + car.setPreferencePath(new PreferencePath(List.of(car))); + + final SearchablePreferencePOJO defaultSpeedOfCar = copy(defaultSpeed); + defaultSpeedOfCar.setPreferencePath(new PreferencePath(List.of(car, defaultSpeedOfCar))); + + final SearchablePreferencePOJO walk = + createSearchablePreferencePOJO( + "walk", + MainSettingsFragment.class); + walk.setPreferencePath(new PreferencePath(List.of(walk))); + + final SearchablePreferencePOJO defaultSpeedOfWalk = copy(defaultSpeed); + defaultSpeedOfWalk.setPreferencePath(new PreferencePath(List.of(walk, defaultSpeedOfWalk))); + + final Collection searchResults = + List.of( + defaultSpeedOfWalk, + defaultSpeed, + defaultSpeedOfCar); + final de.KnollFrank.lib.settingssearch.results.SearchResultsSorter searchResultsSorter = new SearchResultsByPreferencePathSorter(); + + // When + final List sortedSearchResults = searchResultsSorter.sort(searchResults); + + // Then + assertThat( + sortedSearchResults, + contains( + defaultSpeed, + defaultSpeedOfCar, + defaultSpeedOfWalk)); + } +}