优化
This commit is contained in:
@@ -35,7 +35,8 @@ data class TextPage(
|
|||||||
var chapterSize: Int = 0,
|
var chapterSize: Int = 0,
|
||||||
var chapterIndex: Int = 0,
|
var chapterIndex: Int = 0,
|
||||||
var height: Float = 0f,
|
var height: Float = 0f,
|
||||||
var leftLineSize: Int = 0
|
var leftLineSize: Int = 0,
|
||||||
|
var renderHeight: Int = 0
|
||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -332,8 +333,7 @@ data class TextPage(
|
|||||||
|
|
||||||
fun render(view: ContentTextView): Boolean {
|
fun render(view: ContentTextView): Boolean {
|
||||||
if (!isCompleted) return false
|
if (!isCompleted) return false
|
||||||
val height = lines.lastOrNull()?.lineBottom?.toInt() ?: 0
|
return canvasRecorder.recordIfNeeded(view.width, renderHeight) {
|
||||||
return canvasRecorder.recordIfNeeded(view.width, height) {
|
|
||||||
drawPage(view, this)
|
drawPage(view, this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,6 +86,9 @@ class TextChapterLayout(
|
|||||||
|
|
||||||
var channel = Channel<TextPage>(Int.MAX_VALUE)
|
var channel = Channel<TextPage>(Int.MAX_VALUE)
|
||||||
|
|
||||||
|
var durY = 0f
|
||||||
|
var absStartX = paddingLeft
|
||||||
|
|
||||||
init {
|
init {
|
||||||
job = Coroutine.async(
|
job = Coroutine.async(
|
||||||
scope,
|
scope,
|
||||||
@@ -127,7 +130,7 @@ class TextChapterLayout(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun onPageCompleted() {
|
private fun onPageCompleted() {
|
||||||
val textPage = textPages.last()
|
val textPage = pendingTextPage
|
||||||
textPage.index = textPages.lastIndex
|
textPage.index = textPages.lastIndex
|
||||||
textPage.chapterIndex = bookChapter.index
|
textPage.chapterIndex = bookChapter.index
|
||||||
textPage.chapterSize = chaptersSize
|
textPage.chapterSize = chaptersSize
|
||||||
@@ -137,6 +140,8 @@ class TextChapterLayout(
|
|||||||
textPage.isCompleted = true
|
textPage.isCompleted = true
|
||||||
textPage.textChapter = textChapter
|
textPage.textChapter = textChapter
|
||||||
textPage.upLinesPosition()
|
textPage.upLinesPosition()
|
||||||
|
textPage.renderHeight = textPage.lines.maxOf { it.lineBottom.toInt() }
|
||||||
|
textPages.add(textPage)
|
||||||
channel.trySend(textPage)
|
channel.trySend(textPage)
|
||||||
try {
|
try {
|
||||||
listener?.onLayoutPageCompleted(textPages.lastIndex, textPage)
|
listener?.onLayoutPageCompleted(textPages.lastIndex, textPage)
|
||||||
@@ -184,16 +189,15 @@ class TextChapterLayout(
|
|||||||
bookContent: BookContent,
|
bookContent: BookContent,
|
||||||
) {
|
) {
|
||||||
val contents = bookContent.textList
|
val contents = bookContent.textList
|
||||||
var absStartX = paddingLeft
|
|
||||||
var durY = 0f
|
|
||||||
val imageStyle = book.getImageStyle()
|
val imageStyle = book.getImageStyle()
|
||||||
val isSingleImageStyle = imageStyle.equals(Book.imgStyleSingle, true)
|
val isSingleImageStyle = imageStyle.equals(Book.imgStyleSingle, true)
|
||||||
|
val isTextImageStyle = imageStyle.equals(Book.imgStyleText, true)
|
||||||
|
|
||||||
if (ReadBookConfig.titleMode != 2 || bookChapter.isVolume || contents.isEmpty()) {
|
if (ReadBookConfig.titleMode != 2 || bookChapter.isVolume || contents.isEmpty()) {
|
||||||
//标题非隐藏
|
//标题非隐藏
|
||||||
displayTitle.splitNotBlank("\n").forEach { text ->
|
displayTitle.splitNotBlank("\n").forEach { text ->
|
||||||
setTypeText(
|
setTypeText(
|
||||||
book, absStartX, durY,
|
book,
|
||||||
if (AppConfig.enableReview) text + ChapterProvider.reviewChar else text,
|
if (AppConfig.enableReview) text + ChapterProvider.reviewChar else text,
|
||||||
titlePaint,
|
titlePaint,
|
||||||
titlePaintTextHeight,
|
titlePaintTextHeight,
|
||||||
@@ -202,10 +206,7 @@ class TextChapterLayout(
|
|||||||
isTitle = true,
|
isTitle = true,
|
||||||
emptyContent = contents.isEmpty(),
|
emptyContent = contents.isEmpty(),
|
||||||
isVolumeTitle = bookChapter.isVolume
|
isVolumeTitle = bookChapter.isVolume
|
||||||
).let {
|
)
|
||||||
absStartX = it.first
|
|
||||||
durY = it.second
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pendingTextPage.lines.last().isParagraphEnd = true
|
pendingTextPage.lines.last().isParagraphEnd = true
|
||||||
stringBuilder.append("\n")
|
stringBuilder.append("\n")
|
||||||
@@ -213,19 +214,15 @@ class TextChapterLayout(
|
|||||||
|
|
||||||
// 如果是单图模式且当前页有内容,强制分页
|
// 如果是单图模式且当前页有内容,强制分页
|
||||||
if (isSingleImageStyle && pendingTextPage.lines.isNotEmpty()) {
|
if (isSingleImageStyle && pendingTextPage.lines.isNotEmpty()) {
|
||||||
pendingTextPage.height = durY
|
prepareNextPageIfNeed()
|
||||||
textPages.add(pendingTextPage)
|
|
||||||
onPageCompleted()
|
|
||||||
pendingTextPage = TextPage()
|
|
||||||
stringBuilder.clear()
|
|
||||||
absStartX = paddingLeft
|
|
||||||
durY = 0f
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val sb = StringBuffer()
|
val sb = StringBuffer()
|
||||||
|
var isSetTypedImage = false
|
||||||
contents.forEach { content ->
|
contents.forEach { content ->
|
||||||
coroutineContext.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
if (book.getImageStyle().equals(Book.imgStyleText, true)) {
|
if (isTextImageStyle) {
|
||||||
//图片样式为文字嵌入类型
|
//图片样式为文字嵌入类型
|
||||||
var text = content.replace(ChapterProvider.srcReplaceChar, "▣")
|
var text = content.replace(ChapterProvider.srcReplaceChar, "▣")
|
||||||
val srcList = LinkedList<String>()
|
val srcList = LinkedList<String>()
|
||||||
@@ -241,19 +238,18 @@ class TextChapterLayout(
|
|||||||
text = sb.toString()
|
text = sb.toString()
|
||||||
setTypeText(
|
setTypeText(
|
||||||
book,
|
book,
|
||||||
absStartX,
|
|
||||||
durY,
|
|
||||||
text,
|
text,
|
||||||
contentPaint,
|
contentPaint,
|
||||||
contentPaintTextHeight,
|
contentPaintTextHeight,
|
||||||
contentPaintFontMetrics,
|
contentPaintFontMetrics,
|
||||||
book.getImageStyle(),
|
book.getImageStyle(),
|
||||||
srcList = srcList
|
srcList = srcList
|
||||||
).let {
|
)
|
||||||
absStartX = it.first
|
|
||||||
durY = it.second
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
if (isSingleImageStyle && isSetTypedImage) {
|
||||||
|
isSetTypedImage = false
|
||||||
|
prepareNextPageIfNeed()
|
||||||
|
}
|
||||||
val matcher = AppPattern.imgPattern.matcher(content)
|
val matcher = AppPattern.imgPattern.matcher(content)
|
||||||
var start = 0
|
var start = 0
|
||||||
while (matcher.find()) {
|
while (matcher.find()) {
|
||||||
@@ -262,57 +258,45 @@ class TextChapterLayout(
|
|||||||
if (text.isNotBlank()) {
|
if (text.isNotBlank()) {
|
||||||
setTypeText(
|
setTypeText(
|
||||||
book,
|
book,
|
||||||
absStartX,
|
|
||||||
durY,
|
|
||||||
text,
|
text,
|
||||||
contentPaint,
|
contentPaint,
|
||||||
contentPaintTextHeight,
|
contentPaintTextHeight,
|
||||||
contentPaintFontMetrics,
|
contentPaintFontMetrics,
|
||||||
book.getImageStyle(),
|
book.getImageStyle(),
|
||||||
isFirstLine = start == 0
|
isFirstLine = start == 0
|
||||||
).let {
|
)
|
||||||
absStartX = it.first
|
|
||||||
durY = it.second
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
setTypeImage(
|
setTypeImage(
|
||||||
book,
|
book,
|
||||||
matcher.group(1)!!,
|
matcher.group(1)!!,
|
||||||
absStartX,
|
|
||||||
durY,
|
|
||||||
contentPaintTextHeight,
|
contentPaintTextHeight,
|
||||||
stringBuilder,
|
|
||||||
book.getImageStyle()
|
book.getImageStyle()
|
||||||
).let {
|
)
|
||||||
absStartX = it.first
|
isSetTypedImage = true
|
||||||
durY = it.second
|
|
||||||
}
|
|
||||||
start = matcher.end()
|
start = matcher.end()
|
||||||
}
|
}
|
||||||
if (start < content.length) {
|
if (start < content.length) {
|
||||||
|
if (isSingleImageStyle && isSetTypedImage) {
|
||||||
|
isSetTypedImage = false
|
||||||
|
prepareNextPageIfNeed()
|
||||||
|
}
|
||||||
val text = content.substring(start, content.length)
|
val text = content.substring(start, content.length)
|
||||||
if (text.isNotBlank()) {
|
if (text.isNotBlank()) {
|
||||||
setTypeText(
|
setTypeText(
|
||||||
book, absStartX, durY,
|
book,
|
||||||
if (AppConfig.enableReview) text + ChapterProvider.reviewChar else text,
|
if (AppConfig.enableReview) text + ChapterProvider.reviewChar else text,
|
||||||
contentPaint,
|
contentPaint,
|
||||||
contentPaintTextHeight,
|
contentPaintTextHeight,
|
||||||
contentPaintFontMetrics,
|
contentPaintFontMetrics,
|
||||||
book.getImageStyle(),
|
book.getImageStyle(),
|
||||||
isFirstLine = start == 0
|
isFirstLine = start == 0
|
||||||
).let {
|
)
|
||||||
absStartX = it.first
|
|
||||||
durY = it.second
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pendingTextPage.lines.isNotEmpty()) {
|
pendingTextPage.lines.last().isParagraphEnd = true
|
||||||
pendingTextPage.lines.last().isParagraphEnd = true
|
|
||||||
}
|
|
||||||
stringBuilder.append("\n")
|
stringBuilder.append("\n")
|
||||||
}
|
}
|
||||||
textPages.add(pendingTextPage)
|
|
||||||
val textPage = pendingTextPage
|
val textPage = pendingTextPage
|
||||||
val endPadding = 20.dpToPx()
|
val endPadding = 20.dpToPx()
|
||||||
val durYPadding = durY + endPadding
|
val durYPadding = durY + endPadding
|
||||||
@@ -333,29 +317,12 @@ class TextChapterLayout(
|
|||||||
private suspend fun setTypeImage(
|
private suspend fun setTypeImage(
|
||||||
book: Book,
|
book: Book,
|
||||||
src: String,
|
src: String,
|
||||||
x: Int,
|
|
||||||
y: Float,
|
|
||||||
textHeight: Float,
|
textHeight: Float,
|
||||||
stringBuilder: StringBuilder,
|
|
||||||
imageStyle: String?,
|
imageStyle: String?,
|
||||||
): Pair<Int, Float> {
|
) {
|
||||||
var absStartX = x
|
|
||||||
var durY = y
|
|
||||||
val size = ImageProvider.getImageSize(book, src, ReadBook.bookSource)
|
val size = ImageProvider.getImageSize(book, src, ReadBook.bookSource)
|
||||||
if (size.width > 0 && size.height > 0) {
|
if (size.width > 0 && size.height > 0) {
|
||||||
if (durY > visibleHeight) {
|
prepareNextPageIfNeed(durY)
|
||||||
val textPage = pendingTextPage
|
|
||||||
if (textPage.height < durY) {
|
|
||||||
textPage.height = durY
|
|
||||||
}
|
|
||||||
textPage.text = stringBuilder.toString().ifEmpty { "本页无文字内容" }
|
|
||||||
stringBuilder.clear()
|
|
||||||
textPages.add(textPage)
|
|
||||||
coroutineContext.ensureActive()
|
|
||||||
onPageCompleted()
|
|
||||||
pendingTextPage = TextPage()
|
|
||||||
durY = 0f
|
|
||||||
}
|
|
||||||
var height = size.height
|
var height = size.height
|
||||||
var width = size.width
|
var width = size.width
|
||||||
when (imageStyle?.uppercase()) {
|
when (imageStyle?.uppercase()) {
|
||||||
@@ -372,17 +339,7 @@ class TextChapterLayout(
|
|||||||
height = visibleHeight
|
height = visibleHeight
|
||||||
}
|
}
|
||||||
if (durY > 0f) {
|
if (durY > 0f) {
|
||||||
val textPage = pendingTextPage
|
prepareNextPageIfNeed()
|
||||||
if (textPage.height < durY) {
|
|
||||||
textPage.height = durY
|
|
||||||
}
|
|
||||||
textPage.text = stringBuilder.toString().ifEmpty { "本页无文字内容" }
|
|
||||||
stringBuilder.clear()
|
|
||||||
textPages.add(textPage)
|
|
||||||
coroutineContext.ensureActive()
|
|
||||||
onPageCompleted()
|
|
||||||
pendingTextPage = TextPage()
|
|
||||||
durY = 0f
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 图片竖直方向居中:调整 Y 坐标
|
// 图片竖直方向居中:调整 Y 坐标
|
||||||
@@ -401,30 +358,7 @@ class TextChapterLayout(
|
|||||||
width = width * visibleHeight / height
|
width = width * visibleHeight / height
|
||||||
height = visibleHeight
|
height = visibleHeight
|
||||||
}
|
}
|
||||||
if (durY + height > visibleHeight) {
|
prepareNextPageIfNeed(durY + height)
|
||||||
val textPage = pendingTextPage
|
|
||||||
// 双页的 durY 不正确,可能会小于实际高度
|
|
||||||
if (textPage.height < durY) {
|
|
||||||
textPage.height = durY
|
|
||||||
}
|
|
||||||
if (doublePage && absStartX < viewWidth / 2) {
|
|
||||||
//当前页面左列结束
|
|
||||||
textPage.leftLineSize = textPage.lineSize
|
|
||||||
absStartX = viewWidth / 2 + paddingLeft
|
|
||||||
} else {
|
|
||||||
//当前页面结束
|
|
||||||
if (textPage.leftLineSize == 0) {
|
|
||||||
textPage.leftLineSize = textPage.lineSize
|
|
||||||
}
|
|
||||||
textPage.text = stringBuilder.toString().ifEmpty { "本页无文字内容" }
|
|
||||||
stringBuilder.clear()
|
|
||||||
textPages.add(textPage)
|
|
||||||
coroutineContext.ensureActive()
|
|
||||||
onPageCompleted()
|
|
||||||
pendingTextPage = TextPage()
|
|
||||||
}
|
|
||||||
durY = 0f
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val textLine = TextLine(isImage = true)
|
val textLine = TextLine(isImage = true)
|
||||||
@@ -439,13 +373,13 @@ class TextChapterLayout(
|
|||||||
Pair(0f, width.toFloat())
|
Pair(0f, width.toFloat())
|
||||||
}
|
}
|
||||||
textLine.addColumn(
|
textLine.addColumn(
|
||||||
ImageColumn(start = x + start, end = x + end, src = src)
|
ImageColumn(start = absStartX + start, end = absStartX + end, src = src)
|
||||||
)
|
)
|
||||||
calcTextLinePosition(textPages, textLine, stringBuilder.length)
|
calcTextLinePosition(textPages, textLine, stringBuilder.length)
|
||||||
stringBuilder.append(" ") // 确保翻页时索引计算正确
|
stringBuilder.append(" ") // 确保翻页时索引计算正确
|
||||||
pendingTextPage.addLine(textLine)
|
pendingTextPage.addLine(textLine)
|
||||||
}
|
}
|
||||||
return absStartX to durY + textHeight * paragraphSpacing / 10f
|
durY += textHeight * paragraphSpacing / 10f
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -454,8 +388,6 @@ class TextChapterLayout(
|
|||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
private suspend fun setTypeText(
|
private suspend fun setTypeText(
|
||||||
book: Book,
|
book: Book,
|
||||||
x: Int,
|
|
||||||
y: Float,
|
|
||||||
text: String,
|
text: String,
|
||||||
textPaint: TextPaint,
|
textPaint: TextPaint,
|
||||||
textHeight: Float,
|
textHeight: Float,
|
||||||
@@ -466,8 +398,7 @@ class TextChapterLayout(
|
|||||||
emptyContent: Boolean = false,
|
emptyContent: Boolean = false,
|
||||||
isVolumeTitle: Boolean = false,
|
isVolumeTitle: Boolean = false,
|
||||||
srcList: LinkedList<String>? = null
|
srcList: LinkedList<String>? = null
|
||||||
): Pair<Int, Float> {
|
) {
|
||||||
var absStartX = x
|
|
||||||
val widthsArray = FloatArray(text.length)
|
val widthsArray = FloatArray(text.length)
|
||||||
textPaint.getTextWidths(text, widthsArray)
|
textPaint.getTextWidths(text, widthsArray)
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
|
||||||
@@ -485,7 +416,7 @@ class TextChapterLayout(
|
|||||||
} else {
|
} else {
|
||||||
StaticLayout(text, textPaint, visibleWidth, Layout.Alignment.ALIGN_NORMAL, 0f, 0f, true)
|
StaticLayout(text, textPaint, visibleWidth, Layout.Alignment.ALIGN_NORMAL, 0f, 0f, true)
|
||||||
}
|
}
|
||||||
var durY = when {
|
durY = when {
|
||||||
//标题y轴居中
|
//标题y轴居中
|
||||||
emptyContent && textPages.isEmpty() -> {
|
emptyContent && textPages.isEmpty() -> {
|
||||||
val textPage = pendingTextPage
|
val textPage = pendingTextPage
|
||||||
@@ -503,7 +434,7 @@ class TextChapterLayout(
|
|||||||
it.lineBase -= textLayoutHeight
|
it.lineBase -= textLayoutHeight
|
||||||
it.lineBottom -= textLayoutHeight
|
it.lineBottom -= textLayoutHeight
|
||||||
}
|
}
|
||||||
y - textLayoutHeight
|
durY - textLayoutHeight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -514,39 +445,15 @@ class TextChapterLayout(
|
|||||||
if (ty > titleTopSpacing) ty else titleTopSpacing.toFloat()
|
if (ty > titleTopSpacing) ty else titleTopSpacing.toFloat()
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> y + titleTopSpacing
|
else -> durY + titleTopSpacing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> y
|
else -> durY
|
||||||
}
|
}
|
||||||
for (lineIndex in 0 until layout.lineCount) {
|
for (lineIndex in 0 until layout.lineCount) {
|
||||||
val textLine = TextLine(isTitle = isTitle)
|
val textLine = TextLine(isTitle = isTitle)
|
||||||
if (durY + textHeight > visibleHeight) {
|
prepareNextPageIfNeed(durY + textHeight)
|
||||||
val textPage = pendingTextPage
|
|
||||||
if (textPage.height < durY) {
|
|
||||||
textPage.height = durY
|
|
||||||
}
|
|
||||||
if (doublePage && absStartX < viewWidth / 2) {
|
|
||||||
//当前页面左列结束
|
|
||||||
textPage.leftLineSize = textPage.lineSize
|
|
||||||
absStartX = viewWidth / 2 + paddingLeft
|
|
||||||
} else {
|
|
||||||
//当前页面结束,设置各种值
|
|
||||||
if (textPage.leftLineSize == 0) {
|
|
||||||
textPage.leftLineSize = textPage.lineSize
|
|
||||||
}
|
|
||||||
textPage.text = stringBuilder.toString()
|
|
||||||
textPages.add(textPage)
|
|
||||||
coroutineContext.ensureActive()
|
|
||||||
onPageCompleted()
|
|
||||||
//新建页面
|
|
||||||
pendingTextPage = TextPage()
|
|
||||||
stringBuilder.clear()
|
|
||||||
absStartX = paddingLeft
|
|
||||||
}
|
|
||||||
durY = 0f
|
|
||||||
}
|
|
||||||
val lineStart = layout.getLineStart(lineIndex)
|
val lineStart = layout.getLineStart(lineIndex)
|
||||||
val lineEnd = layout.getLineEnd(lineIndex)
|
val lineEnd = layout.getLineEnd(lineIndex)
|
||||||
val lineText = text.substring(lineStart, lineEnd)
|
val lineText = text.substring(lineStart, lineEnd)
|
||||||
@@ -615,7 +522,6 @@ class TextChapterLayout(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
durY += textHeight * paragraphSpacing / 10f
|
durY += textHeight * paragraphSpacing / 10f
|
||||||
return Pair(absStartX, durY)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun calcTextLinePosition(
|
private fun calcTextLinePosition(
|
||||||
@@ -850,6 +756,34 @@ class TextChapterLayout(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun prepareNextPageIfNeed(requestHeight: Float = -1f) {
|
||||||
|
if (requestHeight > visibleHeight || requestHeight == -1f) {
|
||||||
|
val textPage = pendingTextPage
|
||||||
|
// 双页的 durY 不正确,可能会小于实际高度
|
||||||
|
if (textPage.height < durY) {
|
||||||
|
textPage.height = durY
|
||||||
|
}
|
||||||
|
if (doublePage && absStartX < viewWidth / 2) {
|
||||||
|
//当前页面左列结束
|
||||||
|
textPage.leftLineSize = textPage.lineSize
|
||||||
|
absStartX = viewWidth / 2 + paddingLeft
|
||||||
|
} else {
|
||||||
|
//当前页面结束,设置各种值
|
||||||
|
if (textPage.leftLineSize == 0) {
|
||||||
|
textPage.leftLineSize = textPage.lineSize
|
||||||
|
}
|
||||||
|
textPage.text = stringBuilder.toString()
|
||||||
|
coroutineContext.ensureActive()
|
||||||
|
onPageCompleted()
|
||||||
|
//新建页面
|
||||||
|
pendingTextPage = TextPage()
|
||||||
|
stringBuilder.clear()
|
||||||
|
absStartX = paddingLeft
|
||||||
|
}
|
||||||
|
durY = 0f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun measureTextSplit(
|
private fun measureTextSplit(
|
||||||
text: String,
|
text: String,
|
||||||
widthsArray: FloatArray,
|
widthsArray: FloatArray,
|
||||||
|
|||||||
Reference in New Issue
Block a user