repo created
This commit is contained in:
commit
93184d21d1
1403 changed files with 189511 additions and 0 deletions
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* AlphanumComparator
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2012 Dave Koelle
|
||||
* SPDX-FileCopyrightText: 2012 Daniel Migowski
|
||||
* SPDX-FileCopyrightText: 2012 Andre Bogus
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
package third.parties.daveKoeller;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
import java.text.Collator;
|
||||
import java.util.Comparator;
|
||||
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* This is an updated version with enhancements made by Daniel Migowski, Andre Bogus, and David Koelle
|
||||
* *
|
||||
* To convert to use Templates (Java 1.5+):
|
||||
* - Change "implements Comparator" to "implements Comparator<String>"
|
||||
* - Change "compare(Object o1, Object o2)" to "compare(String s1, String s2)"
|
||||
* - Remove the type checking and casting in compare().
|
||||
*
|
||||
* To use this class:
|
||||
* Use the static "sort" method from the java.util.Collections class:
|
||||
* Collections.sort(your list, new AlphanumComparator());
|
||||
*
|
||||
* Adapted to fit
|
||||
* https://github.com/nextcloud/server/blob/9a4253ef7c34f9dc71a6a9f7828a10df769f0c32/tests/lib/NaturalSortTest.php
|
||||
* by Tobias Kaminsky
|
||||
*/
|
||||
public class AlphanumComparator<T> implements Comparator<T>, Serializable {
|
||||
private boolean isDigit(char ch) {
|
||||
return ch >= 48 && ch <= 57;
|
||||
}
|
||||
|
||||
private boolean isSpecialChar(char ch) {
|
||||
return ch <= 47 || ch >= 58 && ch <= 64 || ch >= 91 && ch <= 96 || ch >= 123 && ch <= 126;
|
||||
}
|
||||
|
||||
/**
|
||||
* Length of string is passed in for improved efficiency (only need to calculate it once)
|
||||
**/
|
||||
private String getChunk(String string, int stringLength, int marker) {
|
||||
StringBuilder chunk = new StringBuilder();
|
||||
char c = string.charAt(marker);
|
||||
chunk.append(c);
|
||||
marker++;
|
||||
if (isDigit(c)) {
|
||||
while (marker < stringLength) {
|
||||
c = string.charAt(marker);
|
||||
if (!isDigit(c)) {
|
||||
break;
|
||||
}
|
||||
chunk.append(c);
|
||||
marker++;
|
||||
}
|
||||
} else if (!isSpecialChar(c)) {
|
||||
while (marker < stringLength) {
|
||||
c = string.charAt(marker);
|
||||
if (isDigit(c) || isSpecialChar(c)) {
|
||||
break;
|
||||
}
|
||||
chunk.append(c);
|
||||
marker++;
|
||||
}
|
||||
}
|
||||
return chunk.toString();
|
||||
}
|
||||
|
||||
public int compare(T t1, T t2) {
|
||||
return compare(t1.toString(), t2.toString());
|
||||
}
|
||||
|
||||
public int compare(String s1, String s2) {
|
||||
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 = 0;
|
||||
if (isDigit(thisChunk.charAt(0)) && isDigit(thatChunk.charAt(0))) {
|
||||
// extract digits
|
||||
int thisChunkZeroCount = 0;
|
||||
boolean zero = true;
|
||||
int countThis = 0;
|
||||
while (countThis < (thisChunk.length()) && isDigit(thisChunk.charAt(countThis))) {
|
||||
if (zero) {
|
||||
if (Character.getNumericValue(thisChunk.charAt(countThis)) == 0) {
|
||||
thisChunkZeroCount++;
|
||||
} else {
|
||||
zero = false;
|
||||
}
|
||||
}
|
||||
countThis++;
|
||||
}
|
||||
|
||||
|
||||
int thatChunkZeroCount = 0;
|
||||
int countThat = 0;
|
||||
zero = true;
|
||||
while (countThat < (thatChunk.length()) && isDigit(thatChunk.charAt(countThat))) {
|
||||
if (zero) {
|
||||
if (Character.getNumericValue(thatChunk.charAt(countThat)) == 0) {
|
||||
thatChunkZeroCount++;
|
||||
} else {
|
||||
zero = false;
|
||||
}
|
||||
}
|
||||
countThat++;
|
||||
}
|
||||
|
||||
BigInteger thisChunkValue = new BigInteger(thisChunk.substring(0, countThis));
|
||||
BigInteger thatChunkValue = new BigInteger(thatChunk.substring(0, countThat));
|
||||
|
||||
result = thisChunkValue.compareTo(thatChunkValue);
|
||||
|
||||
if (result == 0) {
|
||||
// value is equal, compare leading zeros
|
||||
result = Integer.compare(thisChunkZeroCount, thatChunkZeroCount);
|
||||
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
} else if (isSpecialChar(thisChunk.charAt(0)) && isSpecialChar(thatChunk.charAt(0))) {
|
||||
for (int i = 0; i < thisChunk.length(); i++) {
|
||||
if (thisChunk.charAt(i) == '.' && thatChunk.charAt(i) != '.') {
|
||||
return -1;
|
||||
} else if (thatChunk.charAt(i) == '.' && thisChunk.charAt(i) != '.') {
|
||||
return 1;
|
||||
} else {
|
||||
result = thisChunk.charAt(i) - thatChunk.charAt(i);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (isSpecialChar(thisChunk.charAt(0)) && !isSpecialChar(thatChunk.charAt(0))) {
|
||||
return -1;
|
||||
} else if (!isSpecialChar(thisChunk.charAt(0)) && isSpecialChar(thatChunk.charAt(0))) {
|
||||
return 1;
|
||||
} else {
|
||||
result = Collator.getInstance().compare(thisChunk, thatChunk);
|
||||
}
|
||||
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return s1Length - s2Length;
|
||||
}
|
||||
}
|
||||
110
app/src/main/java/third/parties/fresco/BetterImageSpan.kt
Normal file
110
app/src/main/java/third/parties/fresco/BetterImageSpan.kt
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2015-present, Facebook, Inc. and its affiliates.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
package third.parties.fresco
|
||||
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Paint.FontMetricsInt
|
||||
import android.graphics.Rect
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.text.style.ReplacementSpan
|
||||
import androidx.annotation.IntDef
|
||||
|
||||
/**
|
||||
* A better implementation of image spans that also supports centering images against the text.
|
||||
*
|
||||
* In order to migrate from ImageSpan, replace `new ImageSpan(drawable, alignment)` with
|
||||
* `new BetterImageSpan(drawable, BetterImageSpan.normalizeAlignment(alignment))`.
|
||||
*
|
||||
* There are 2 main differences between BetterImageSpan and ImageSpan:
|
||||
* 1. Pass in ALIGN_CENTER to center images against the text.
|
||||
* 2. ALIGN_BOTTOM no longer unnecessarily increases the size of the text:
|
||||
* DynamicDrawableSpan (ImageSpan's parent) adjusts sizes as if alignment was ALIGN_BASELINE
|
||||
* which can lead to unnecessary whitespace.
|
||||
*/
|
||||
open class BetterImageSpan @JvmOverloads constructor(
|
||||
val drawable: Drawable,
|
||||
@param:BetterImageSpanAlignment private val mAlignment: Int = ALIGN_BASELINE
|
||||
) : ReplacementSpan() {
|
||||
@IntDef(*[ALIGN_BASELINE, ALIGN_BOTTOM, ALIGN_CENTER])
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class BetterImageSpanAlignment
|
||||
|
||||
private var mWidth = 0
|
||||
private var mHeight = 0
|
||||
private var mBounds: Rect? = null
|
||||
private val mFontMetricsInt = FontMetricsInt()
|
||||
|
||||
init {
|
||||
updateBounds()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the width of the image span and increases the height if font metrics are available.
|
||||
*/
|
||||
override fun getSize(paint: Paint, text: CharSequence, start: Int, end: Int, fontMetrics: FontMetricsInt?): Int {
|
||||
updateBounds()
|
||||
if (fontMetrics == null) {
|
||||
return mWidth
|
||||
}
|
||||
val offsetAbove = getOffsetAboveBaseline(fontMetrics)
|
||||
val offsetBelow = mHeight + offsetAbove
|
||||
if (offsetAbove < fontMetrics.ascent) {
|
||||
fontMetrics.ascent = offsetAbove
|
||||
}
|
||||
if (offsetAbove < fontMetrics.top) {
|
||||
fontMetrics.top = offsetAbove
|
||||
}
|
||||
if (offsetBelow > fontMetrics.descent) {
|
||||
fontMetrics.descent = offsetBelow
|
||||
}
|
||||
if (offsetBelow > fontMetrics.bottom) {
|
||||
fontMetrics.bottom = offsetBelow
|
||||
}
|
||||
return mWidth
|
||||
}
|
||||
|
||||
override fun draw(
|
||||
canvas: Canvas,
|
||||
text: CharSequence,
|
||||
start: Int,
|
||||
end: Int,
|
||||
x: Float,
|
||||
top: Int,
|
||||
y: Int,
|
||||
bottom: Int,
|
||||
paint: Paint
|
||||
) {
|
||||
paint.getFontMetricsInt(mFontMetricsInt)
|
||||
val iconTop = y + getOffsetAboveBaseline(mFontMetricsInt)
|
||||
canvas.translate(x, iconTop.toFloat())
|
||||
drawable.draw(canvas)
|
||||
canvas.translate(-x, -iconTop.toFloat())
|
||||
}
|
||||
|
||||
private fun updateBounds() {
|
||||
mBounds = drawable.bounds
|
||||
mWidth = mBounds!!.width()
|
||||
mHeight = mBounds!!.height()
|
||||
}
|
||||
|
||||
private fun getOffsetAboveBaseline(fm: FontMetricsInt): Int =
|
||||
when (mAlignment) {
|
||||
ALIGN_BOTTOM -> fm.descent - mHeight
|
||||
ALIGN_CENTER -> {
|
||||
val textHeight = fm.descent - fm.ascent
|
||||
val offset = (textHeight - mHeight) / 2
|
||||
fm.ascent + offset
|
||||
}
|
||||
ALIGN_BASELINE -> -mHeight
|
||||
else -> -mHeight
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ALIGN_BOTTOM = 0
|
||||
const val ALIGN_BASELINE = 1
|
||||
const val ALIGN_CENTER = 2
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue