diff --git a/app/src/main/java/org/tasks/filters/AlphanumComparator.java b/app/src/main/java/org/tasks/filters/AlphanumComparator.java deleted file mode 100644 index b9577f9b8..000000000 --- a/app/src/main/java/org/tasks/filters/AlphanumComparator.java +++ /dev/null @@ -1,124 +0,0 @@ -package org.tasks.filters; - -/* - * The Alphanum Algorithm is an improved sorting algorithm for strings - * containing numbers. Instead of sorting numbers in ASCII order like - * a standard sort, this algorithm sorts numbers in numeric order. - * - * The Alphanum Algorithm is discussed at http://www.DaveKoelle.com - * - * Released under the MIT License - https://opensource.org/licenses/MIT - * - * Copyright 2007-2017 David Koelle - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -import androidx.arch.core.util.Function; -import com.todoroo.astrid.api.Filter; -import java.util.Comparator; - -/** - * This is an updated version with enhancements made by Daniel Migowski, Andre Bogus, and David - * Koelle. Updated by David Koelle in 2017. - * - *

To use this class: Use the static "sort" method from the java.util.Collections class: - * Collections.sort(your list, new AlphanumComparator()); - */ -public class AlphanumComparator implements Comparator { - - public static final Function FILTER = f -> f.listingTitle; - - private final Function getTitle; - - private boolean isDigit(char ch) { - return ((ch >= 48) && (ch <= 57)); - } - - public AlphanumComparator(Function getTitle) { - this.getTitle = getTitle; - } - - /** Length of string is passed in for improved efficiency (only need to calculate it once) * */ - private String getChunk(String s, int slength, int marker) { - StringBuilder chunk = new StringBuilder(); - char c = s.charAt(marker); - chunk.append(c); - marker++; - if (isDigit(c)) { - while (marker < slength) { - c = s.charAt(marker); - if (!isDigit(c)) break; - chunk.append(c); - marker++; - } - } else { - while (marker < slength) { - c = s.charAt(marker); - if (isDigit(c)) break; - chunk.append(c); - marker++; - } - } - return chunk.toString(); - } - - public int compare(T t1, T t2) { - String s1 = getTitle.apply(t1); - String s2 = getTitle.apply(t2); - if ((s1 == null) || (s2 == null)) { - return 0; - } - int thisMarker = 0; - int thatMarker = 0; - int s1Length = s1.length(); - int s2Length = s2.length(); - - while (thisMarker < s1Length && thatMarker < s2Length) { - String thisChunk = getChunk(s1, s1Length, thisMarker); - thisMarker += thisChunk.length(); - - String thatChunk = getChunk(s2, s2Length, thatMarker); - thatMarker += thatChunk.length(); - - // If both chunks contain numeric characters, sort them numerically - int result; - if (isDigit(thisChunk.charAt(0)) && isDigit(thatChunk.charAt(0))) { - // Simple chunk comparison by length. - int thisChunkLength = thisChunk.length(); - result = thisChunkLength - thatChunk.length(); - // If equal, the first different number counts - if (result == 0) { - for (int i = 0; i < thisChunkLength; i++) { - result = thisChunk.charAt(i) - thatChunk.charAt(i); - if (result != 0) { - return result; - } - } - } - } else { - result = String.CASE_INSENSITIVE_ORDER.compare(thisChunk, thatChunk); - } - - if (result != 0) return result; - } - - return s1Length - s2Length; - } -} diff --git a/app/src/main/java/org/tasks/filters/AlphanumComparator.kt b/app/src/main/java/org/tasks/filters/AlphanumComparator.kt new file mode 100644 index 000000000..797e994e2 --- /dev/null +++ b/app/src/main/java/org/tasks/filters/AlphanumComparator.kt @@ -0,0 +1,115 @@ +package org.tasks.filters + +import com.todoroo.astrid.api.Filter +import java.util.* + +/* + * The Alphanum Algorithm is an improved sorting algorithm for strings + * containing numbers. Instead of sorting numbers in ASCII order like + * a standard sort, this algorithm sorts numbers in numeric order. + * + * The Alphanum Algorithm is discussed at http://www.DaveKoelle.com + * + * Released under the MIT License - https://opensource.org/licenses/MIT + * + * Copyright 2007-2017 David Koelle + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + */ /** + * This is an updated version with enhancements made by Daniel Migowski, Andre Bogus, and David + * Koelle. Updated by David Koelle in 2017. + * + * + * To use this class: Use the static "sort" method from the java.util.Collections class: + * Collections.sort(your list, new AlphanumComparator()); + */ +class AlphanumComparator(private val getTitle: (T) -> String?) : Comparator { + private fun isDigit(ch: Char): Boolean { + return ch.toInt() in 48..57 + } + + /** Length of string is passed in for improved efficiency (only need to calculate it once) * */ + private fun getChunk(s: String, slength: Int, marker: Int): String { + var marker = marker + val chunk = StringBuilder() + var c = s[marker] + chunk.append(c) + marker++ + if (isDigit(c)) { + while (marker < slength) { + c = s[marker] + if (!isDigit(c)) break + chunk.append(c) + marker++ + } + } else { + while (marker < slength) { + c = s[marker] + if (isDigit(c)) break + chunk.append(c) + marker++ + } + } + return chunk.toString() + } + + override fun compare(t1: T, t2: T): Int { + val s1 = getTitle.invoke(t1) + val s2 = getTitle.invoke(t2) + if (s1 == null || s2 == null) { + return 0 + } + var thisMarker = 0 + var thatMarker = 0 + val s1Length = s1.length + val s2Length = s2.length + while (thisMarker < s1Length && thatMarker < s2Length) { + val thisChunk = getChunk(s1, s1Length, thisMarker) + thisMarker += thisChunk.length + val thatChunk = getChunk(s2, s2Length, thatMarker) + thatMarker += thatChunk.length + + // If both chunks contain numeric characters, sort them numerically + var result: Int + if (isDigit(thisChunk[0]) && isDigit(thatChunk[0])) { + // Simple chunk comparison by length. + val thisChunkLength = thisChunk.length + result = thisChunkLength - thatChunk.length + // If equal, the first different number counts + if (result == 0) { + for (i in 0 until thisChunkLength) { + result = thisChunk[i] - thatChunk[i] + if (result != 0) { + return result + } + } + } + } else { + result = java.lang.String.CASE_INSENSITIVE_ORDER.compare(thisChunk, thatChunk) + } + if (result != 0) return result + } + return s1Length - s2Length + } + + companion object { + @JvmField + val FILTER = AlphanumComparator(Filter::listingTitle) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/tasks/filters/FilterProvider.kt b/app/src/main/java/org/tasks/filters/FilterProvider.kt index 9ef9ed371..c5dffa6f4 100644 --- a/app/src/main/java/org/tasks/filters/FilterProvider.kt +++ b/app/src/main/java/org/tasks/filters/FilterProvider.kt @@ -92,8 +92,7 @@ class FilterProvider @Inject constructor( if (preferences.getBoolean(R.string.p_tags_hide_unused, false)) { filters = filters.filter { it.count > 0 } } - val tags = filters.map(TagFilters::toTagFilter) - Collections.sort(tags, AlphanumComparator(AlphanumComparator.FILTER)) + val tags = filters.map(TagFilters::toTagFilter).sortedWith(AlphanumComparator.FILTER) items.addAll( getSubmenu( context.getString(R.string.tags), @@ -232,7 +231,7 @@ class FilterProvider @Inject constructor( } filters.addAll(filterDao.getFilters() .map(::CustomFilter) - .sortedWith(AlphanumComparator(AlphanumComparator.FILTER))) + .sortedWith(AlphanumComparator.FILTER)) return filters } @@ -247,11 +246,9 @@ class FilterProvider @Inject constructor( googleTaskListDao .getGoogleTaskFilters(account.account!!, DateUtilities.now()) .map(GoogleTaskFilters::toGtasksFilter) + .sortedWith(AlphanumComparator.FILTER) } } - for ((_, value) in filters) { - Collections.sort(value, AlphanumComparator(AlphanumComparator.FILTER)) - } return filters.entries } @@ -271,11 +268,9 @@ class FilterProvider @Inject constructor( caldavDao .getCaldavFilters(account.uuid!!, DateUtilities.now()) .map(CaldavFilters::toCaldavFilter) + .sortedWith(AlphanumComparator.FILTER) } } - for ((_, value) in filters) { - Collections.sort(value, AlphanumComparator(AlphanumComparator.FILTER)) - } return filters.entries }