From 1744053908df714e1ac68f411e8126d034ec6dbb Mon Sep 17 00:00:00 2001 From: cgspine Date: Wed, 20 Jan 2021 22:17:34 +0800 Subject: [PATCH] convert to kotlin --- build.gradle | 3 +- type/build.gradle | 4 +- .../qmuiteam/qmui/type/EnvironmentUpdater.kt | 9 +- .../main/java/com/qmuiteam/qmui/type/Line.kt | 424 ++++++------ .../java/com/qmuiteam/qmui/type/LineLayout.kt | 610 +++++++++--------- .../com/qmuiteam/qmui/type/TypeEnvironment.kt | 471 ++++++-------- .../java/com/qmuiteam/qmui/type/TypeModel.kt | 200 +++--- .../qmui/type/element/BreakWordLineElement.kt | 13 +- .../qmui/type/element/DrawableElement.kt | 71 +- .../com/qmuiteam/qmui/type/element/Element.kt | 573 +++++++--------- .../qmui/type/element/EmojiElement.kt | 71 +- .../qmui/type/element/IgnoreEffectElement.kt | 40 +- .../qmui/type/element/NextParagraphElement.kt | 38 +- .../qmuiteam/qmui/type/element/TextElement.kt | 47 +- .../qmui/type/parser/EmojiResourceProvider.kt | 29 +- .../qmui/type/parser/EmojiTextParser.kt | 141 ++-- .../qmuiteam/qmui/type/parser/ParserHelper.kt | 35 +- .../qmui/type/parser/PlainTextParser.kt | 71 +- .../qmuiteam/qmui/type/parser/TextParser.kt | 11 +- 19 files changed, 1214 insertions(+), 1647 deletions(-) diff --git a/build.gradle b/build.gradle index 53adf845..f156cf29 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.4.10' + ext.kotlin_version = '1.4.21' repositories { mavenLocal() google() @@ -30,6 +30,7 @@ allprojects { minSdkVersion = 19 targetSdkVersion = 29 compileSdkVersion = 29 + coreVersion='1.5.0-beta01' appcompatVersion= '1.3.0-alpha01' materialVersion='1.2.1' annotationVersion='1.1.0-beta01' diff --git a/type/build.gradle b/type/build.gradle index 58ecffdc..74a026eb 100644 --- a/type/build.gradle +++ b/type/build.gradle @@ -1,4 +1,5 @@ apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' version = QMUI_TYPE_VERSION @@ -25,7 +26,8 @@ android { dependencies { api "androidx.annotation:annotation:$annotationVersion" - api "androidx.core:core:$appcompatVersion" + api "androidx.core:core-ktx:$appcompatVersion" + api "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" } // deploy diff --git a/type/src/main/java/com/qmuiteam/qmui/type/EnvironmentUpdater.kt b/type/src/main/java/com/qmuiteam/qmui/type/EnvironmentUpdater.kt index ed3fd0be..d975f180 100644 --- a/type/src/main/java/com/qmuiteam/qmui/type/EnvironmentUpdater.kt +++ b/type/src/main/java/com/qmuiteam/qmui/type/EnvironmentUpdater.kt @@ -13,9 +13,8 @@ * either express or implied. See the License for the specific language governing permissions and * limitations under the License. */ +package com.qmuiteam.qmui.type -package com.qmuiteam.qmui.type; - -public interface EnvironmentUpdater { - void update(TypeEnvironment env); -} +interface EnvironmentUpdater { + fun update(env: TypeEnvironment) +} \ No newline at end of file diff --git a/type/src/main/java/com/qmuiteam/qmui/type/Line.kt b/type/src/main/java/com/qmuiteam/qmui/type/Line.kt index c7504158..f33a6bc2 100644 --- a/type/src/main/java/com/qmuiteam/qmui/type/Line.kt +++ b/type/src/main/java/com/qmuiteam/qmui/type/Line.kt @@ -13,293 +13,253 @@ * either express or implied. See the License for the specific language governing permissions and * limitations under the License. */ +package com.qmuiteam.qmui.type -package com.qmuiteam.qmui.type; +import android.graphics.Canvas +import androidx.core.util.Pools +import com.qmuiteam.qmui.type.TypeEnvironment +import com.qmuiteam.qmui.type.element.BreakWordLineElement +import com.qmuiteam.qmui.type.element.Element +import com.qmuiteam.qmui.type.element.NextParagraphElement +import com.qmuiteam.qmui.type.element.TextElement +import java.util.* -import android.graphics.Canvas; +class Line private constructor() { + companion object { + private val sLinePool: Pools.Pool = Pools.SimplePool(16) -import androidx.core.util.Pools; - -import com.qmuiteam.qmui.type.element.BreakWordLineElement; -import com.qmuiteam.qmui.type.element.CharOrPhraseElement; -import com.qmuiteam.qmui.type.element.Element; -import com.qmuiteam.qmui.type.element.NextParagraphElement; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; - -public class Line { - private static Pools.Pool sLinePool = new Pools.SimplePool<>(16); - - public static Line acquire() { - Line line = sLinePool.acquire(); - if (line == null) { - line = new Line(); - } - return line; - } - - private Line() { - - } - - private int mX; - private int mY; - private int mWidthLimit; - private int mContentWidth; - private int mContentHeight; - private int mLayoutWidth; - private List mElements = new LinkedList<>(); - private HashMap mVisibleChanged; - - public void init(int x, int y, int widthLimit) { - mX = x; - mY = y; - mWidthLimit = widthLimit; - } - - public void add(Element element) { - mElements.add(element); - mContentWidth += element.getMeasureWidth(); - mContentHeight = (int) Math.max(mContentHeight, element.getMeasureHeight()); - } - - public void addFirst(Element element){ - mElements.add(0, element); - mContentWidth += element.getMeasureWidth(); - mContentHeight = (int) Math.max(mContentHeight, element.getMeasureHeight()); - } - - public Element first(){ - return mElements.isEmpty() ? null : mElements.get(0); - } - - public int getSize() { - return mElements.size(); - } - - public int getContentWidth() { - return mContentWidth; - } - - public int getLayoutWidth() { - return mLayoutWidth; - } - - public int getWidthLimit() { - return mWidthLimit; - } - - public int getContentHeight() { - return mContentHeight; - } - - public int getX() { - return mX; - } - - public int getY() { - return mY; - } - - public void setX(int x) { - mX = x; - } - - public void setY(int y) { - mY = y; - } - - void move(TypeEnvironment environment){ - for(Element el: mElements){ - el.move(environment); - } - } - - public List handleWordBreak(TypeEnvironment environment) { - if (mElements.size() == 0) { - return null; - } - int lastIndex = mElements.size() - 1; - Element last = mElements.get(lastIndex); - Element next = last.getNext(); - - List back = new LinkedList<>(); - if(last.getWordPart() == Element.WORD_PART_WHOLE){ - if(last.getLineBreakType() == Element.LINE_BREAK_TYPE_NOT_END || - (next != null && next.getLineBreakType() == Element.LINE_BREAK_TYPE_NOT_START)){ - mElements.remove(lastIndex); - back.add(last); + fun acquire(): Line { + var line = sLinePool.acquire() + if (line == null) { + line = Line() } - }else if(last.getWordPart() == Element.WORD_PART_END && (next != null && next.getLineBreakType() != Element.LINE_BREAK_TYPE_NOT_START)){ + return line + } + } + + var x = 0 + var y = 0 + var widthLimit = 0 + private set + var contentWidth = 0 + private set + var contentHeight = 0 + private set + var layoutWidth = 0 + private set + private val mElements = LinkedList() + private var mVisibleChanged: HashMap? = null + + + val size: Int + get() = mElements.size + + fun init(x: Int, y: Int, widthLimit: Int) { + this.x = x + this.y = y + this.widthLimit = widthLimit + } + + fun add(element: Element) { + mElements.add(element) + contentWidth = (contentWidth + element.measureWidth).toInt() + contentHeight = contentHeight.toFloat().coerceAtLeast(element.measureHeight).toInt() + } + + fun addFirst(element: Element) { + mElements.add(0, element) + contentWidth = (contentWidth + element.measureWidth).toInt() + contentHeight = contentHeight.toFloat().coerceAtLeast(element.measureHeight).toInt() + } + + fun first(): Element? { + return if (mElements.isEmpty()) null else mElements[0] + } + + fun move(environment: TypeEnvironment?) { + for (el in mElements) { + el.move(environment!!) + } + } + + fun handleWordBreak(environment: TypeEnvironment?): List? { + if (mElements.size == 0) { + return null + } + var lastIndex = mElements.size - 1 + val last = mElements[lastIndex] + val next = last.next + val back: MutableList = LinkedList() + if (last.wordPart == Element.WORD_PART_WHOLE) { + if (last.lineBreakType == Element.LINE_BREAK_TYPE_NOT_END || + next != null && next.lineBreakType == Element.LINE_BREAK_TYPE_NOT_START) { + mElements.removeAt(lastIndex) + back.add(last) + } + } else if (last.wordPart == Element.WORD_PART_END && next != null && next.lineBreakType != Element.LINE_BREAK_TYPE_NOT_START) { // do nothing - }else if(last.getWordPart() == Element.WORD_PART_START){ - mElements.remove(lastIndex); - back.add(last); - }else{ - back.add(last); - mElements.remove(lastIndex); - lastIndex--; - int min = Math.max(0, lastIndex - 30); // try 30 letter. - boolean find = false; + } else if (last.wordPart == Element.WORD_PART_START) { + mElements.removeAt(lastIndex) + back.add(last) + } else { + back.add(last) + mElements.removeAt(lastIndex) + lastIndex-- + val min = Math.max(0, lastIndex - 30) // try 30 letter. + var find = false while (lastIndex > min) { - Element el = mElements.get(lastIndex); - if (el.getWordPart() == Element.WORD_PART_WHOLE || el.getWordPart() == Element.WORD_PART_END) { - find = true; - break; - } else if (el.getLineBreakType() == Element.LINE_BREAK_WORD_BREAK_ALLOWED) { + val el = mElements[lastIndex] + if (el.wordPart == Element.WORD_PART_WHOLE || el.wordPart == Element.WORD_PART_END) { + find = true + break + } else if (el.lineBreakType == Element.LINE_BREAK_WORD_BREAK_ALLOWED) { // TODO what if environment had changed after break? the measure may be wrong - BreakWordLineElement b = new BreakWordLineElement(); - b.measure(environment); - add(b); - find = true; - break; + val b = BreakWordLineElement() + b.measure(environment!!) + add(b) + find = true + break } else { - back.add(0, el); - mElements.remove(lastIndex); - lastIndex--; + back.add(0, el) + mElements.removeAt(lastIndex) + lastIndex-- } } if (!find) { // give up - mElements.addAll(back); - return null; + mElements.addAll(back) + return null } } - if (back.isEmpty()) { - return null; + return null } - - for (Element el : back) { - mContentWidth -= el.getMeasureWidth(); + for (el in back) { + contentWidth = (contentWidth -el.measureWidth).toInt() } - return back; + return back } - private boolean hideLastIfSpaceIfNeeded(boolean dropLastIfSpace) { - Element last = mElements.get(mElements.size() - 1); - if (dropLastIfSpace && last instanceof CharOrPhraseElement && last.getChar() == ' ' && last.getVisible() != Element.GONE) { - changeVisibleInner(last, Element.GONE); - mContentWidth -= last.getMeasureWidth(); - return true; + private fun hideLastIfSpaceIfNeeded(dropLastIfSpace: Boolean): Boolean { + val last = mElements[mElements.size - 1] + if (dropLastIfSpace && last is TextElement && last.length == 1 && last.text[0] == ' ' && last.visible != Element.GONE) { + changeVisibleInner(last, Element.GONE) + contentWidth = (contentWidth - last.measureWidth).toInt() + return true } - return false; + return false } - private void changeVisibleInner(Element element, int visible) { - int oldVal = element.getVisible(); + private fun changeVisibleInner(element: Element, visible: Int) { + val oldVal = element.visible if (visible == oldVal) { - return; + return } if (mVisibleChanged == null) { - mVisibleChanged = new HashMap<>(); + mVisibleChanged = HashMap() } - mVisibleChanged.put(element, oldVal); - element.setVisible(visible); + mVisibleChanged!![element] = oldVal + element.visible = visible } - private int calculateGapCount() { - int ret = 0; - for (int i = 1; i < mElements.size(); i++) { - Element el = mElements.get(i); - if (el.getVisible() != Element.GONE && - (el.getWordPart() == Element.WORD_PART_WHOLE || - el.getWordPart() == Element.WORD_PART_START)) { - ret++; + private fun calculateGapCount(): Int { + var ret = 0 + for (i in 1 until mElements.size) { + val el = mElements[i] + if (el.visible != Element.GONE && + (el.wordPart == Element.WORD_PART_WHOLE || + el.wordPart == Element.WORD_PART_START)) { + ret++ } } - return ret; + return ret } - public boolean isMiddleParagraphEndLine(){ - return !mElements.isEmpty() && mElements.get(mElements.size() - 1) instanceof NextParagraphElement; - } + val isMiddleParagraphEndLine: Boolean + get() = !mElements.isEmpty() && mElements[mElements.size - 1] is NextParagraphElement - public void layout(TypeEnvironment env, boolean dropLastIfSpace, boolean isEnd) { + fun layout(env: TypeEnvironment, dropLastIfSpace: Boolean, isEnd: Boolean) { if (mElements.isEmpty()) { - return; + return } - hideLastIfSpaceIfNeeded(dropLastIfSpace); - mLayoutWidth = mContentWidth; - TypeEnvironment.Alignment alignment = env.getAlignment(); - float start = mX; - float addSpace = 0; - if (alignment == TypeEnvironment.Alignment.RIGHT) { - start = mX + mWidthLimit - mContentWidth; - } else if (alignment == TypeEnvironment.Alignment.CENTER) { - start = mX + (mWidthLimit - mContentWidth) / 2f; - } else if (alignment == TypeEnvironment.Alignment.JUSTIFY) { - float remain = mWidthLimit - mContentWidth; - if (!(isEnd || isMiddleParagraphEndLine()) || remain < env.getLastLineJustifyMaxWidth()) { - int gapCount = calculateGapCount(); + hideLastIfSpaceIfNeeded(dropLastIfSpace) + layoutWidth = contentWidth + val alignment = env.alignment + var start = x.toFloat() + var addSpace = 0f + if (alignment === TypeEnvironment.Alignment.RIGHT) { + start = (x + widthLimit - contentWidth).toFloat() + } else if (alignment === TypeEnvironment.Alignment.CENTER) { + start = x + (widthLimit - contentWidth) / 2f + } else if (alignment === TypeEnvironment.Alignment.JUSTIFY) { + val remain = (widthLimit - contentWidth).toFloat() + if (!(isEnd || isMiddleParagraphEndLine) || remain < env.lastLineJustifyMaxWidth) { + val gapCount = calculateGapCount() if (gapCount > 0) { - addSpace = remain / gapCount; - mLayoutWidth = mWidthLimit; + addSpace = remain / gapCount + layoutWidth = widthLimit } } } - float x = start; - for (int i = 0; i < mElements.size(); i++) { - Element el = mElements.get(i); - if (i > 0 && (el.getWordPart() == Element.WORD_PART_WHOLE - || el.getWordPart() == Element.WORD_PART_START)) { - x += addSpace; - mElements.get(i - 1).setNextGapWidth(addSpace); + var x = start + for (i in mElements.indices) { + val el = mElements[i] + if (i > 0 && (el.wordPart == Element.WORD_PART_WHOLE + || el.wordPart == Element.WORD_PART_START)) { + x += addSpace + mElements[i - 1].nextGapWidth = addSpace } - el.setX((int) x); - x += el.getMeasureWidth(); - el.setY(mY + (mContentHeight - el.getMeasureHeight()) / 2f); + el.x = x + x += el.measureWidth + el.y = y + (contentHeight - el.measureHeight) / 2f } } - public void draw(TypeEnvironment env, Canvas canvas) { - for (Element element : mElements) { - element.draw(env, canvas); + fun draw(env: TypeEnvironment, canvas: Canvas) { + for (element in mElements) { + element.draw(env, canvas) } } - void restoreVisibleChange(){ + fun restoreVisibleChange() { if (mVisibleChanged != null) { - for (Element entry : mVisibleChanged.keySet()) { - Integer visible = mVisibleChanged.get(entry); + for (entry in mVisibleChanged!!.keys) { + val visible = mVisibleChanged!![entry] if (visible != null) { - entry.setVisible(visible); + entry.visible = visible } } - mVisibleChanged.clear(); + mVisibleChanged!!.clear() } } - public List popAll(){ - List elements = new ArrayList<>(mElements); - mElements.clear(); - restoreVisibleChange(); - mContentWidth = 0; - mContentHeight = 0; - mLayoutWidth = 0; - return elements; + fun popAll(): List { + val elements: List = ArrayList(mElements) + mElements.clear() + restoreVisibleChange() + contentWidth = 0 + contentHeight = 0 + layoutWidth = 0 + return elements } - public void clear(){ - mElements.clear(); - restoreVisibleChange(); - mContentWidth = 0; - mContentHeight = 0; - mLayoutWidth = 0; + fun clear() { + mElements.clear() + restoreVisibleChange() + contentWidth = 0 + contentHeight = 0 + layoutWidth = 0 } - public void release() { - mX = 0; - mY = 0; - mWidthLimit = 0; - mContentWidth = 0; - mContentHeight = 0; - mLayoutWidth = 0; - mElements.clear(); - restoreVisibleChange(); - sLinePool.release(this); + fun release() { + x = 0 + y = 0 + widthLimit = 0 + contentWidth = 0 + contentHeight = 0 + layoutWidth = 0 + mElements.clear() + restoreVisibleChange() + sLinePool.release(this) } -} +} \ No newline at end of file diff --git a/type/src/main/java/com/qmuiteam/qmui/type/LineLayout.kt b/type/src/main/java/com/qmuiteam/qmui/type/LineLayout.kt index 87fba966..8a83eff5 100644 --- a/type/src/main/java/com/qmuiteam/qmui/type/LineLayout.kt +++ b/type/src/main/java/com/qmuiteam/qmui/type/LineLayout.kt @@ -13,459 +13,425 @@ * either express or implied. See the License for the specific language governing permissions and * limitations under the License. */ +package com.qmuiteam.qmui.type -package com.qmuiteam.qmui.type; +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Typeface +import android.text.TextUtils.TruncateAt +import com.qmuiteam.qmui.type.element.* +import java.util.* -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Typeface; -import android.text.TextUtils; +class LineLayout(private val mTypeEnvironment: TypeEnvironment) { + private var mMaxLines = Int.MAX_VALUE + private var mEllipsize: TruncateAt? = null + private var mCalculateWholeLines = true + private val mLines: MutableList = ArrayList() + private var mDropLastIfSpace = true + private var mMoreText: String? = null + private var mMoreTextColor = 0 + private var mMoreTextTypeface: Typeface? = null + private var mMoreUnderlineColor = Color.TRANSPARENT + private var mMoreBgColor = 0 + private var mMoreUnderlineHeight = 0 + private var mTotalLineCount = 0 -import com.qmuiteam.qmui.type.element.BreakWordLineElement; -import com.qmuiteam.qmui.type.element.CharOrPhraseElement; -import com.qmuiteam.qmui.type.element.IgnoreEffectElement; -import com.qmuiteam.qmui.type.element.Element; -import com.qmuiteam.qmui.type.element.NextParagraphElement; + var typeModel: TypeModel? = null + private set -import java.util.ArrayList; -import java.util.Deque; -import java.util.LinkedList; -import java.util.List; -import java.util.Queue; - -public class LineLayout { - private int mMaxLines = Integer.MAX_VALUE; - private TextUtils.TruncateAt mEllipsize; - private boolean mCalculateWholeLines = true; - private TypeEnvironment mTypeEnvironment; - private TypeModel mTypeModel; - private List mLines = new ArrayList<>(); - private boolean mDropLastIfSpace = true; - private String mMoreText = null; - private int mMoreTextColor = 0; - private Typeface mMoreTextTypeface = null; - private int mMoreUnderlineColor = Color.TRANSPARENT; - private int mMoreBgColor = 0; - private int mMoreUnderlineHeight = 0; - private int mTotalLineCount = 0; - - public LineLayout(TypeEnvironment environment) { - mTypeEnvironment = environment; + fun setMaxLines(maxLines: Int): LineLayout { + mMaxLines = maxLines + return this } - public LineLayout setMaxLines(int maxLines) { - mMaxLines = maxLines; - return this; + fun setEllipsize(ellipsize: TruncateAt?): LineLayout { + mEllipsize = ellipsize + return this } - public LineLayout setEllipsize(TextUtils.TruncateAt ellipsize) { - mEllipsize = ellipsize; - return this; + fun setCalculateWholeLines(calculateWholeLines: Boolean): LineLayout { + mCalculateWholeLines = calculateWholeLines + return this } - public LineLayout setCalculateWholeLines(boolean calculateWholeLines) { - mCalculateWholeLines = calculateWholeLines; - return this; + fun setDropLastIfSpace(dropLastIfSpace: Boolean): LineLayout { + mDropLastIfSpace = dropLastIfSpace + return this } - public LineLayout setDropLastIfSpace(boolean dropLastIfSpace) { - mDropLastIfSpace = dropLastIfSpace; - return this; + fun setMoreText(text: String?, color: Int, typeface: Typeface?): LineLayout { + mMoreText = text + mMoreTextColor = color + mMoreTextTypeface = typeface + return this } - public LineLayout setMoreText(String text, int color, Typeface typeface) { - mMoreText = text; - mMoreTextColor = color; - mMoreTextTypeface = typeface; - return this; + fun setMoreBackgroundColor(color: Int): LineLayout { + mMoreBgColor = color + return this } - public LineLayout setMoreBackgroundColor(int color) { - mMoreBgColor = color; - return this; + fun setUnderline(height: Int, color: Int): LineLayout { + mMoreUnderlineHeight = height + mMoreUnderlineColor = color + return this } - public LineLayout setUnderline(int height, int color) { - mMoreUnderlineHeight = height; - mMoreUnderlineColor = color; - return this; + fun setTypeModel(typeModel: TypeModel?): LineLayout { + this.typeModel = typeModel + return this } - public LineLayout setTypeModel(TypeModel typeModel) { - mTypeModel = typeModel; - return this; - } - - public TypeModel getTypeModel() { - return mTypeModel; - } - - public void measureAndLayout() { - mTypeEnvironment.clear(); - release(); - if (mTypeModel == null) { - return; + fun measureAndLayout() { + mTypeEnvironment.clear() + release() + if (typeModel == null) { + return } - Element element = mTypeModel.firstElement(); - if (element == null) { - return; - } - Line line = Line.acquire(); - int y = 0; - line.init(0, y, mTypeEnvironment.getWidthLimit()); + var element: Element? = typeModel!!.firstElement() ?: return + var line = Line.acquire() + var y = 0 + line.init(0, y, mTypeEnvironment.widthLimit) while (element != null) { - element.measure(mTypeEnvironment); - if (element instanceof NextParagraphElement) { - line.add(element); - line.layout(mTypeEnvironment, mDropLastIfSpace, false); - mLines.add(line); + element.measure(mTypeEnvironment) + if (element is NextParagraphElement) { + line.add(element) + line.layout(mTypeEnvironment, mDropLastIfSpace, false) + mLines.add(line) if (canInterrupt()) { - return; + return } - y += line.getContentHeight() + mTypeEnvironment.getParagraphSpace(); - line = createNewLine(y); - } else if (line.getContentWidth() + element.getMeasureWidth() > mTypeEnvironment.getWidthLimit()) { - if (mLines.size() == 0 && line.getSize() == 0) { + y += line.contentHeight + mTypeEnvironment.paragraphSpace + line = createNewLine(y) + } else if (line.contentWidth + element.measureWidth > mTypeEnvironment.widthLimit) { + if (mLines.size == 0 && line.size == 0) { // the width is too small. - line.release(); - return; + line.release() + return } - List back = line.handleWordBreak(mTypeEnvironment); - line.layout(mTypeEnvironment, mDropLastIfSpace, false); - mLines.add(line); + val back = line.handleWordBreak(mTypeEnvironment) + line.layout(mTypeEnvironment, mDropLastIfSpace, false) + mLines.add(line) if (canInterrupt()) { - handleEllipse(true); - return; + handleEllipse(true) + return } - y += line.getContentHeight() + mTypeEnvironment.getLineSpace(); - line = createNewLine(y); + y += line.contentHeight + mTypeEnvironment.lineSpace + line = createNewLine(y) if (back != null && !back.isEmpty()) { - for (Element el : back) { - line.add(el); + for (el in back) { + line.add(el) } } - line.add(element); + line.add(element) } else { - line.add(element); + line.add(element) } - element = element.getNext(); + element = element.next } - if (line.getSize() > 0) { - line.layout(mTypeEnvironment, mDropLastIfSpace, true); - mLines.add(line); + if (line.size > 0) { + line.layout(mTypeEnvironment, mDropLastIfSpace, true) + mLines.add(line) } else { - line.release(); + line.release() } - mTotalLineCount = mLines.size(); - handleEllipse(false); + mTotalLineCount = mLines.size + handleEllipse(false) } - private Line createNewLine(int y) { - Line line = Line.acquire(); - line.init(0, y, mTypeEnvironment.getWidthLimit()); - return line; + private fun createNewLine(y: Int): Line { + val line = Line.acquire() + line.init(0, y, mTypeEnvironment.widthLimit) + return line } - private void handleEllipse(boolean fromInterrupt) { - if (mLines.isEmpty() || mLines.size() < mMaxLines || (mLines.size() == mMaxLines && !fromInterrupt)) { - return; + private fun handleEllipse(fromInterrupt: Boolean) { + if (mLines.isEmpty() || mLines.size < mMaxLines || mLines.size == mMaxLines && !fromInterrupt) { + return } - - if (mEllipsize == TextUtils.TruncateAt.END) { - handleEllipseEnd(); - } else if (mEllipsize == TextUtils.TruncateAt.START) { - handleEllipseStart(); - } else if (mEllipsize == TextUtils.TruncateAt.MIDDLE) { - handleEllipseMiddle(); + if (mEllipsize == TruncateAt.END) { + handleEllipseEnd() + } else if (mEllipsize == TruncateAt.START) { + handleEllipseStart() + } else if (mEllipsize == TruncateAt.MIDDLE) { + handleEllipseMiddle() } } - private void handleEllipseEnd() { - for (int i = mLines.size() - 1; i >= mMaxLines; i--) { - mLines.remove(mLines.get(i)); + private fun handleEllipseEnd() { + for (i in mLines.size - 1 downTo mMaxLines) { + mLines.remove(mLines[i]) } - Line lastLine = mLines.get(mLines.size() - 1); - int limitWidth = lastLine.getWidthLimit(); - Element ellipseElement = new CharOrPhraseElement("...", -1, -1); - ellipseElement.addSingleEnvironmentUpdater(null, new EnvironmentUpdater() { - @Override - public void update(TypeEnvironment env) { - env.clear(); + val lastLine = mLines[mLines.size - 1] + var limitWidth = lastLine.widthLimit + val ellipseElement: Element = TextElement("...", -1, -1) + ellipseElement.addSingleEnvironmentUpdater(null, object : EnvironmentUpdater { + override fun update(env: TypeEnvironment) { + env.clear() } - }); - ellipseElement.measure(mTypeEnvironment); - limitWidth -= ellipseElement.getMeasureWidth(); - - Element moreElement = null; - if (mMoreText != null && !mMoreText.isEmpty()) { - moreElement = new CharOrPhraseElement(mMoreText, -1, -1); - List changeTypes = new ArrayList<>(); - changeTypes.add(TypeEnvironment.TYPE_TEXT_COLOR); - changeTypes.add(TypeEnvironment.TYPE_BG_COLOR); - changeTypes.add(TypeEnvironment.TYPE_TYPEFACE); - changeTypes.add(TypeEnvironment.TYPE_BORDER_BOTTOM_COLOR); - changeTypes.add(TypeEnvironment.TYPE_BORDER_BOTTOM_WIDTH); - moreElement.addSingleEnvironmentUpdater(changeTypes, new EnvironmentUpdater() { - @Override - public void update(TypeEnvironment env) { + }) + ellipseElement.measure(mTypeEnvironment) + limitWidth = (limitWidth - ellipseElement.measureWidth).toInt() + var moreElement: Element? = null + if (mMoreText != null && !mMoreText!!.isEmpty()) { + moreElement = TextElement(mMoreText!!, -1, -1) + val changeTypes: MutableList = ArrayList() + changeTypes.add(TypeEnvironment.TYPE_TEXT_COLOR) + changeTypes.add(TypeEnvironment.TYPE_BG_COLOR) + changeTypes.add(TypeEnvironment.TYPE_TYPEFACE) + changeTypes.add(TypeEnvironment.TYPE_BORDER_BOTTOM_COLOR) + changeTypes.add(TypeEnvironment.TYPE_BORDER_BOTTOM_WIDTH) + moreElement.addSingleEnvironmentUpdater(changeTypes, object : EnvironmentUpdater { + override fun update(env: TypeEnvironment) { if (mMoreTextColor != 0) { - env.setTextColor(mMoreTextColor); + env.textColor = mMoreTextColor } if (mMoreBgColor != 0) { - env.setBackgroundColor(mMoreBgColor); + env.backgroundColor = mMoreBgColor } if (mMoreTextTypeface != null) { - env.setTypeface(mMoreTextTypeface); + env.typeface = mMoreTextTypeface } - if (mMoreUnderlineHeight > 0) { - env.setBorderBottom(mMoreUnderlineHeight, mMoreUnderlineColor); + env.setBorderBottom(mMoreUnderlineHeight, mMoreUnderlineColor) } } - }); - moreElement.measure(mTypeEnvironment); - limitWidth -= moreElement.getMeasureWidth(); + }) + moreElement.measure(mTypeEnvironment) + limitWidth = (limitWidth - moreElement.measureWidth).toInt() } - - int contentWidth = lastLine.getContentWidth(); + val contentWidth = lastLine.contentWidth if (contentWidth < limitWidth) { - lastLine.restoreVisibleChange(); + lastLine.restoreVisibleChange() } else { - List elements = lastLine.popAll(); - for (Element el : elements) { - if (el.getMeasureWidth() <= limitWidth) { - lastLine.add(el); - limitWidth -= el.getMeasureWidth(); + val elements = lastLine.popAll() + for (el in elements) { + if (el.measureWidth <= limitWidth) { + lastLine.add(el) + limitWidth -= (limitWidth - el.measureWidth).toInt() } else { - break; + break } } } - lastLine.add(ellipseElement); + lastLine.add(ellipseElement) if (moreElement != null) { - lastLine.add(moreElement); + lastLine.add(moreElement) } - lastLine.layout(mTypeEnvironment, mDropLastIfSpace, true); + lastLine.layout(mTypeEnvironment, mDropLastIfSpace, true) } - private void handleEllipseStart() { - mTypeEnvironment.clear(); - for (int i = mLines.size() - 1; i >= mMaxLines; i--) { - mLines.remove(mLines.get(i)); + private fun handleEllipseStart() { + mTypeEnvironment.clear() + for (i in mLines.size - 1 downTo mMaxLines) { + mLines.remove(mLines[i]) } - Element ellipseElement = new CharOrPhraseElement("...", -1, -1); - ellipseElement.addSingleEnvironmentUpdater(null, new EnvironmentUpdater() { - @Override - public void update(TypeEnvironment env) { - env.clear(); + val ellipseElement: Element = TextElement("...", -1, -1) + ellipseElement.addSingleEnvironmentUpdater(null, object : EnvironmentUpdater { + override fun update(env: TypeEnvironment) { + env.clear() } - }); - ellipseElement.measure(mTypeEnvironment); - Queue elements = new LinkedList<>(); - elements.add(ellipseElement); - for (int i = 0; i < mLines.size(); i++) { - Line line = mLines.get(i); - int limitWidth = line.getWidthLimit(); - elements.addAll(line.popAll()); + }) + ellipseElement.measure(mTypeEnvironment) + val elements: Queue = LinkedList() + elements.add(ellipseElement) + for (i in mLines.indices) { + val line = mLines[i] + val limitWidth = line.widthLimit + elements.addAll(line.popAll()) while (!elements.isEmpty()) { - Element el = elements.peek(); + val el = elements.peek() if (el != null) { - if (el instanceof NextParagraphElement) { - elements.poll(); - line.add(el); - el.move(mTypeEnvironment); - break; + if (el is NextParagraphElement) { + elements.poll() + line.add(el) + el.move(mTypeEnvironment) + break } - - if (el instanceof BreakWordLineElement) { - elements.poll(); - continue; + if (el is BreakWordLineElement) { + elements.poll() + continue } - if (line.getContentWidth() + el.getMeasureWidth() <= limitWidth) { - elements.poll(); - line.add(el); - el.move(mTypeEnvironment); - + if (line.contentWidth + el.measureWidth <= limitWidth) { + elements.poll() + line.add(el) + el.move(mTypeEnvironment) } else { - break; + break } } else { - elements.poll(); + elements.poll() } } - line.handleWordBreak(mTypeEnvironment); - line.layout(mTypeEnvironment, mDropLastIfSpace, false); + line.handleWordBreak(mTypeEnvironment) + line.layout(mTypeEnvironment, mDropLastIfSpace, false) if (elements.isEmpty()) { - return; + return } } } - private void handleEllipseMiddle() { - mTypeEnvironment.clear(); - List lines = new ArrayList<>(mLines); - mLines.clear(); - Element ellipseElement = new CharOrPhraseElement("...", -1, -1); - ellipseElement.measure(mTypeEnvironment); - int ellipseLine = mMaxLines % 2 == 0 ? mMaxLines / 2 : (mMaxLines + 1) / 2; - - for (int i = 0; i < ellipseLine; i++) { - mLines.add(lines.get(i)); + private fun handleEllipseMiddle() { + mTypeEnvironment.clear() + val lines: List = ArrayList(mLines) + mLines.clear() + val ellipseElement: Element = TextElement("...", -1, -1) + ellipseElement.measure(mTypeEnvironment) + val ellipseLine = if (mMaxLines % 2 == 0) mMaxLines / 2 else (mMaxLines + 1) / 2 + for (i in 0 until ellipseLine) { + mLines.add(lines[i]) } - Line handleLine = lines.get(ellipseLine - 1); - int limitWidth = handleLine.getWidthLimit(); - Deque unHandled = new LinkedList<>(handleLine.popAll()); + val handleLine = lines[ellipseLine - 1] + val limitWidth = handleLine.widthLimit + val unHandled: Deque = LinkedList(handleLine.popAll()) while (!unHandled.isEmpty()) { - Element el = unHandled.peek(); + val el = unHandled.peek() if (el != null) { - if (handleLine.getContentWidth() + el.getMeasureWidth() <= limitWidth / 2f - ellipseElement.getMeasureWidth() / 2) { - unHandled.poll(); - handleLine.add(el); - el.move(mTypeEnvironment); + if (handleLine.contentWidth + el.measureWidth <= limitWidth / 2f - ellipseElement.measureWidth / 2) { + unHandled.poll() + handleLine.add(el) + el.move(mTypeEnvironment) } else { - break; + break } } else { - unHandled.poll(); + unHandled.poll() } } - ellipseElement.measure(mTypeEnvironment); - handleLine.add(ellipseElement); - - int nextFullShowLine = lines.size() - mMaxLines + ellipseLine; - int startLine = lines.size() - 1; + ellipseElement.measure(mTypeEnvironment) + handleLine.add(ellipseElement) + val nextFullShowLine = lines.size - mMaxLines + ellipseLine + var startLine = lines.size - 1 // find the latest paragraph end line. - for (int i = lines.size() - 2; i > nextFullShowLine; i--) { - if (lines.get(i).isMiddleParagraphEndLine()) { - startLine = i; + for (i in lines.size - 2 downTo nextFullShowLine + 1) { + if (lines[i].isMiddleParagraphEndLine) { + startLine = i } } - for (int i = ellipseLine; i <= startLine; i++) { - unHandled.addAll(lines.get(i).popAll()); + for (i in ellipseLine..startLine) { + unHandled.addAll(lines[i].popAll()) } - - for (int i = startLine; i >= nextFullShowLine; i--) { - Line line = lines.get(i); + for (i in startLine downTo nextFullShowLine) { + val line = lines[i] while (!unHandled.isEmpty()) { - Element element = unHandled.peekLast(); + val element = unHandled.peekLast() if (element != null) { - if (element instanceof NextParagraphElement) { - unHandled.pollLast(); - continue; + if (element is NextParagraphElement) { + unHandled.pollLast() + continue } - if (element instanceof BreakWordLineElement) { - unHandled.pollLast(); - continue; + if (element is BreakWordLineElement) { + unHandled.pollLast() + continue } - if (line.getContentWidth() + element.getMeasureWidth() <= line.getWidthLimit()) { - unHandled.pollLast(); - line.addFirst(element); + if (line.contentWidth + element.measureWidth <= line.widthLimit) { + unHandled.pollLast() + line.addFirst(element) } else { - break; + break } } else { - unHandled.pollLast(); + unHandled.pollLast() } } } - - List toAdd = new LinkedList<>(); - int toAddWidth = 0; + val toAdd = LinkedList() + var toAddWidth = 0 while (!unHandled.isEmpty()) { - Element element = unHandled.peekLast(); + val element = unHandled.peekLast() if (element != null) { - if (element instanceof NextParagraphElement) { - unHandled.pollLast(); - continue; + if (element is NextParagraphElement) { + unHandled.pollLast() + continue } - if (element instanceof BreakWordLineElement) { - unHandled.pollLast(); - continue; + if (element is BreakWordLineElement) { + unHandled.pollLast() + continue } - if (handleLine.getContentWidth() + toAddWidth + element.getMeasureWidth() <= handleLine.getWidthLimit()) { - unHandled.pollLast(); - toAdd.add(0, element); - toAddWidth += element.getMeasureWidth(); + if (handleLine.contentWidth + toAddWidth + element.measureWidth <= handleLine.widthLimit) { + unHandled.pollLast() + toAdd.add(0, element) + toAddWidth = (toAddWidth + element.measureWidth).toInt() } else { - break; + break } } else { - unHandled.pollLast(); + unHandled.pollLast() } } - - Element firstUnHandle = unHandled.peekFirst(); - Element lastUnHandle = unHandled.peekLast(); - Element effect = mTypeModel.getFirstEffect(); + val firstUnHandle = unHandled.peekFirst() + val lastUnHandle = unHandled.peekLast() + var effect = typeModel!!.firstEffect if (firstUnHandle != null && lastUnHandle != null) { - List ellipseEffect = new ArrayList<>(); - while (effect != null && effect.getIndex() <= lastUnHandle.getIndex()) { - if (effect.getIndex() >= firstUnHandle.getIndex()) { - ellipseEffect.add(effect); + val ellipseEffect: MutableList = ArrayList() + while (effect != null && effect.index <= lastUnHandle.index) { + if (effect.index >= firstUnHandle.index) { + ellipseEffect.add(effect) } - effect = effect.getNext(); + effect = effect.next } - if (ellipseEffect.size() > 0) { - IgnoreEffectElement ignoreEffectElement = new IgnoreEffectElement(ellipseEffect); - ignoreEffectElement.move(mTypeEnvironment); - handleLine.add(ignoreEffectElement); + if (ellipseEffect.size > 0) { + val ignoreEffectElement = IgnoreEffectElement(ellipseEffect) + ignoreEffectElement.move(mTypeEnvironment) + handleLine.add(ignoreEffectElement) } } - for (Element el : toAdd) { - el.move(mTypeEnvironment); - handleLine.add(el); + for (el in toAdd) { + el.move(mTypeEnvironment) + handleLine.add(el) } - handleLine.handleWordBreak(mTypeEnvironment); - handleLine.layout(mTypeEnvironment, mDropLastIfSpace, ellipseLine == lines.size()); - int lastEnd = handleLine.getY() + handleLine.getContentHeight(); - for (int i = nextFullShowLine; i < lines.size(); i++) { - Line line = lines.get(i); - Line prev = lines.get(i - 1); - if (prev.isMiddleParagraphEndLine()) { - line.setY(lastEnd + mTypeEnvironment.getParagraphSpace()); + handleLine.handleWordBreak(mTypeEnvironment) + handleLine.layout(mTypeEnvironment, mDropLastIfSpace, ellipseLine == lines.size) + var lastEnd = handleLine.y + handleLine.contentHeight + for (i in nextFullShowLine until lines.size) { + val line = lines[i] + val prev = lines[i - 1] + if (prev.isMiddleParagraphEndLine) { + line.y = lastEnd + mTypeEnvironment.paragraphSpace } else { - line.setY(lastEnd + mTypeEnvironment.getLineSpace()); + line.y = lastEnd + mTypeEnvironment.lineSpace } - lastEnd = line.getY() + line.getContentHeight(); - line.move(mTypeEnvironment); - line.handleWordBreak(mTypeEnvironment); - line.layout(mTypeEnvironment, mDropLastIfSpace, i == lines.size() - 1); - mLines.add(line); + lastEnd = line.y + line.contentHeight + line.move(mTypeEnvironment) + line.handleWordBreak(mTypeEnvironment) + line.layout(mTypeEnvironment, mDropLastIfSpace, i == lines.size - 1) + mLines.add(line) } } - public int getMaxLayoutWidth() { - int maxWidth = 0; - for (Line line : mLines) { - maxWidth = Math.max(maxWidth, line.getLayoutWidth()); + val maxLayoutWidth: Int + get() { + var maxWidth = 0 + for (line in mLines) { + maxWidth = Math.max(maxWidth, line.layoutWidth) + } + return maxWidth } - return maxWidth; - } - - public int getContentHeight() { - if (mLines.isEmpty()) { - return 0; + val contentHeight: Int + get() { + if (mLines.isEmpty()) { + return 0 + } + val last = mLines[mLines.size - 1] + return last.y + last.contentHeight } - Line last = mLines.get(mLines.size() - 1); - return last.getY() + last.getContentHeight(); - } - public void draw(Canvas canvas) { - mTypeEnvironment.clear(); - for (Line line : mLines) { - line.draw(mTypeEnvironment, canvas); + fun draw(canvas: Canvas) { + mTypeEnvironment.clear() + for (line in mLines) { + line.draw(mTypeEnvironment, canvas) } } - private boolean canInterrupt() { - return mLines.size() == mMaxLines && !mCalculateWholeLines && - (mEllipsize == null || mEllipsize == TextUtils.TruncateAt.END); + private fun canInterrupt(): Boolean { + return mLines.size == mMaxLines && !mCalculateWholeLines && + (mEllipsize == null || mEllipsize == TruncateAt.END) } - public void release() { - for (Line line : mLines) { - line.release(); + fun release() { + for (line in mLines) { + line.release() } - mLines.clear(); + mLines.clear() } -} +} \ No newline at end of file diff --git a/type/src/main/java/com/qmuiteam/qmui/type/TypeEnvironment.kt b/type/src/main/java/com/qmuiteam/qmui/type/TypeEnvironment.kt index 2a0bbc86..3159b0b6 100644 --- a/type/src/main/java/com/qmuiteam/qmui/type/TypeEnvironment.kt +++ b/type/src/main/java/com/qmuiteam/qmui/type/TypeEnvironment.kt @@ -13,335 +13,248 @@ * either express or implied. See the License for the specific language governing permissions and * limitations under the License. */ +package com.qmuiteam.qmui.type -package com.qmuiteam.qmui.type; +import android.content.res.Resources +import android.graphics.Color +import android.graphics.Paint +import android.graphics.Typeface +import android.util.Log +import android.util.SparseArray +import java.util.* -import android.content.res.Resources; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Typeface; -import android.util.Log; -import android.util.SparseArray; +class TypeEnvironment { + companion object { + private const val TAG = "TypeEnvironment" + const val TYPE_TEXT_COLOR = -1 + const val TYPE_BG_COLOR = -2 + const val TYPE_TYPEFACE = -3 + const val TYPE_TEXT_SIZE = -4 + const val TYPE_ALIGNMENT = -5 + const val TYPE_LINE_SPACE = -6 + const val TYPE_PARAGRAPH_SPACE = -7 + const val TYPE_BORDER_TOP_WIDTH = -8 + const val TYPE_BORDER_TOP_COLOR = -9 + const val TYPE_BORDER_RIGHT_WIDTH = -10 + const val TYPE_BORDER_RIGHT_COLOR = -11 + const val TYPE_BORDER_BOTTOM_WIDTH = -12 + const val TYPE_BORDER_BOTTOM_COLOR = -13 + const val TYPE_BORDER_LEFT_WIDTH = -14 + const val TYPE_BORDER_LEFT_COLOR = -15 + const val TYPE_BORDER_PAINT = -16 -import com.qmuiteam.qmui.type.element.Element; - -import java.util.Stack; - -public class TypeEnvironment { - private static final String TAG = "TypeEnvironment"; - public static final int TYPE_TEXT_COLOR = -1; - public static final int TYPE_BG_COLOR = -2; - public static final int TYPE_TYPEFACE = -3; - public static final int TYPE_TEXT_SIZE = -4; - public static final int TYPE_ALIGNMENT = -5; - public static final int TYPE_LINE_SPACE = -6; - public static final int TYPE_PARAGRAPH_SPACE = -7; - public static final int TYPE_BORDER_TOP_WIDTH = -8; - public static final int TYPE_BORDER_TOP_COLOR = -9; - public static final int TYPE_BORDER_RIGHT_WIDTH = -10; - public static final int TYPE_BORDER_RIGHT_COLOR = -11; - public static final int TYPE_BORDER_BOTTOM_WIDTH = -12; - public static final int TYPE_BORDER_BOTTOM_COLOR = -13; - public static final int TYPE_BORDER_LEFT_WIDTH = -14; - public static final int TYPE_BORDER_LEFT_COLOR = -15; - public static final int TYPE_BORDER_PAINT = -16; - - public enum Alignment { - LEFT, - RIGHT, - CENTER, - JUSTIFY + val DEFAULT_LAST_LINE_JUSTIFY_MAX_WIDTH = (Resources.getSystem().displayMetrics.density * 36).toInt() } - private int mWidthLimit; - private int mHeightLimit; - - private Typeface mTypeface; - private float mTextSize; - private int mLineSpace; - private int mParagraphSpace; - private Alignment mAlignment = Alignment.JUSTIFY; - private int mLastLineJustifyMaxWidth = (int) (Resources.getSystem().getDisplayMetrics().density * 36); - - private int mTextColor = Color.BLACK; - private int mBackgroundColor = Color.TRANSPARENT; - - private Paint mPaint = new Paint(); - private Paint mBgPaint = new Paint(); - - private SparseArray mCustomProp = new SparseArray<>(); - - private SparseArray> mStack = new SparseArray<>(); - private Element mLastRunElement = null; - - - public TypeEnvironment() { - mPaint.setAntiAlias(true); - mBgPaint.setAntiAlias(true); + enum class Alignment { + LEFT, RIGHT, CENTER, JUSTIFY } + var widthLimit = 0 + private set + var heightLimit = 0 + private set - public void setMeasureLimit(int widthLimit, int heightLimit) { - mWidthLimit = widthLimit; - mHeightLimit = heightLimit; + + var alignment: Alignment = Alignment.JUSTIFY + + var lastLineJustifyMaxWidth = DEFAULT_LAST_LINE_JUSTIFY_MAX_WIDTH + + val paint = Paint().apply { + isAntiAlias = true } - - public int getWidthLimit() { - return mWidthLimit; + val bgPaint = Paint().apply { + isAntiAlias = true } + private val mCustomProp: SparseArray = SparseArray() + private val mStack = SparseArray>() - public int getHeightLimit() { - return mHeightLimit; - } - public void setLastLineJustifyMaxWidth(int lastLineJustifyMaxWidth) { - mLastLineJustifyMaxWidth = lastLineJustifyMaxWidth; - } + var lineSpace = 0 - public int getLastLineJustifyMaxWidth() { - return mLastLineJustifyMaxWidth; - } + var paragraphSpace: Int = 0 + get() = field.coerceAtLeast(lineSpace) - public void setTypeface(Typeface typeface) { - mTypeface = typeface; - mPaint.setTypeface(typeface); - } - - public void setTextColor(int textColor) { - mTextColor = textColor; - mPaint.setColor(textColor); - } - - public void setTextSize(float textSize) { - mTextSize = textSize; - mPaint.setTextSize(textSize); - } - - public void setBackgroundColor(int backgroundColor) { - mBackgroundColor = backgroundColor; - mBgPaint.setColor(backgroundColor); - } - - public void setAlignment(Alignment alignment) { - mAlignment = alignment; - } - - public void setLineSpace(int lineSpace) { - mLineSpace = lineSpace; - } - - public void setParagraphSpace(int paragraphSpace) { - mParagraphSpace = paragraphSpace; - } - - public int getParagraphSpace() { - return Math.max(mParagraphSpace, mLineSpace); - } - - public Alignment getAlignment() { - return mAlignment; - } - - public int getLineSpace() { - return mLineSpace; - } - - public float getTextSize() { - return mTextSize; - } - - public int getTextColor() { - return mTextColor; - } - - public int getBackgroundColor() { - return mBackgroundColor; - } - - public Paint getBgPaint() { - return mBgPaint; - } - - public Paint getPaint() { - return mPaint; - } - - public void setCustomProp(int type, Object value) { - mCustomProp.put(type, value); - } - - public void setBorderTop(int width, int color) { - setCustomProp(TYPE_BORDER_TOP_WIDTH, width); - setCustomProp(TYPE_BORDER_TOP_COLOR, color); - } - - public int getBorderTopWidth() { - return getIntCustomProp(TYPE_BORDER_TOP_WIDTH); - } - - public int getBorderTopColor() { - return getIntCustomProp(TYPE_BORDER_TOP_COLOR); - } - - public void setBorderRight(int width, int color) { - setCustomProp(TYPE_BORDER_RIGHT_WIDTH, width); - setCustomProp(TYPE_BORDER_RIGHT_COLOR, color); - } - - public int getBorderRightWidth() { - return getIntCustomProp(TYPE_BORDER_RIGHT_WIDTH); - } - - public int getBorderRightColor() { - return getIntCustomProp(TYPE_BORDER_RIGHT_COLOR); - } - - public void setBorderBottom(int width, int color) { - setCustomProp(TYPE_BORDER_BOTTOM_WIDTH, width); - setCustomProp(TYPE_BORDER_BOTTOM_COLOR, color); - } - - public int getBorderBottomWidth() { - return getIntCustomProp(TYPE_BORDER_BOTTOM_WIDTH); - } - - public int getBorderBottomColor() { - return getIntCustomProp(TYPE_BORDER_BOTTOM_COLOR); - } - - public void setBorderLeft(int width, int color) { - setCustomProp(TYPE_BORDER_LEFT_WIDTH, width); - setCustomProp(TYPE_BORDER_LEFT_COLOR, color); - } - - public int getBorderLeftWidth() { - return getIntCustomProp(TYPE_BORDER_LEFT_WIDTH); - } - - public int getBorderLeftColor() { - return getIntCustomProp(TYPE_BORDER_LEFT_COLOR); - } - - public Paint getBorderPaint() { - Object obj = getCustomProp(TYPE_BORDER_PAINT); - Paint paint; - if (obj == null) { - paint = new Paint(); - paint.setAntiAlias(true); - setCustomProp(TYPE_BORDER_PAINT, paint); - } else { - paint = (Paint) obj; - } - return paint; - } - - public Object getCustomProp(int type) { - return mCustomProp.get(type); - } - - public int getIntCustomProp(int type) { - Object obj = mCustomProp.get(type); - if (!(obj instanceof Integer)) { - return 0; - } - return (int) obj; - } - - public TypeEnvironment snapshot() { - TypeEnvironment env = new TypeEnvironment(); - env.setMeasureLimit(mWidthLimit, mHeightLimit); - env.setAlignment(mAlignment); - env.setLineSpace(mLineSpace); - env.setParagraphSpace(mParagraphSpace); - env.setTextSize(mTextSize); - env.setTypeface(mTypeface); - - env.setTextColor(mTextColor); - env.setBackgroundColor(mBackgroundColor); - for(int i =0; i< mStack.size(); i++){ - env.mStack.put(mStack.keyAt(i), (Stack) mStack.valueAt(i).clone()); + var typeface: Typeface? = null + set(value) { + field = value + paint.typeface = value } + var textSize: Float = 0f + set(value) { + field = value + paint.textSize = value + } + var textColor: Int = Color.BLACK + set(value) { + field = value + paint.color = value + } + var backgroundColor: Int = Color.TRANSPARENT + set(value) { + field = value + bgPaint.color = value + } + + fun setCustomProp(type: Int, value: Any?) { + mCustomProp!!.put(type, value) + } + + fun setBorderTop(width: Int, color: Int) { + setCustomProp(TYPE_BORDER_TOP_WIDTH, width) + setCustomProp(TYPE_BORDER_TOP_COLOR, color) + } + + val borderTopWidth: Int + get() = getIntCustomProp(TYPE_BORDER_TOP_WIDTH) + val borderTopColor: Int + get() = getIntCustomProp(TYPE_BORDER_TOP_COLOR) + + fun setBorderRight(width: Int, color: Int) { + setCustomProp(TYPE_BORDER_RIGHT_WIDTH, width) + setCustomProp(TYPE_BORDER_RIGHT_COLOR, color) + } + + val borderRightWidth: Int + get() = getIntCustomProp(TYPE_BORDER_RIGHT_WIDTH) + val borderRightColor: Int + get() = getIntCustomProp(TYPE_BORDER_RIGHT_COLOR) + + fun setBorderBottom(width: Int, color: Int) { + setCustomProp(TYPE_BORDER_BOTTOM_WIDTH, width) + setCustomProp(TYPE_BORDER_BOTTOM_COLOR, color) + } + + val borderBottomWidth: Int + get() = getIntCustomProp(TYPE_BORDER_BOTTOM_WIDTH) + val borderBottomColor: Int + get() = getIntCustomProp(TYPE_BORDER_BOTTOM_COLOR) + + fun setBorderLeft(width: Int, color: Int) { + setCustomProp(TYPE_BORDER_LEFT_WIDTH, width) + setCustomProp(TYPE_BORDER_LEFT_COLOR, color) + } + + val borderLeftWidth: Int + get() = getIntCustomProp(TYPE_BORDER_LEFT_WIDTH) + val borderLeftColor: Int + get() = getIntCustomProp(TYPE_BORDER_LEFT_COLOR) + val borderPaint: Paint + get() { + val obj = getCustomProp(TYPE_BORDER_PAINT) + val paint: Paint + if (obj == null) { + paint = Paint() + paint.isAntiAlias = true + setCustomProp(TYPE_BORDER_PAINT, paint) + } else { + paint = obj as Paint + } + return paint + } + + fun getCustomProp(type: Int): Any? { + return mCustomProp!![type] + } + + fun getIntCustomProp(type: Int): Int { + val obj = mCustomProp!![type] + return if (obj !is Int) { + 0 + } else obj + } + + fun setMeasureLimit(widthLimit: Int, heightLimit: Int) { + this.widthLimit = widthLimit + this.heightLimit = heightLimit + } + + fun snapshot(): TypeEnvironment { + val env = TypeEnvironment() + env.setMeasureLimit(widthLimit, heightLimit) + env.alignment = alignment + env.lineSpace = lineSpace + env.paragraphSpace = paragraphSpace + env.textSize = textSize + env.typeface = typeface + env.textColor = textColor + env.backgroundColor = backgroundColor + for (i in 0 until mStack.size()) { + env.mStack.put(mStack.keyAt(i), mStack.valueAt(i).clone() as Stack) + } if (mCustomProp != null) { - for (int i = 0; i < mCustomProp.size(); i++) { - env.setCustomProp(mCustomProp.keyAt(i), mCustomProp.valueAt(i)); + for (i in 0 until mCustomProp.size()) { + env.setCustomProp(mCustomProp.keyAt(i), mCustomProp.valueAt(i)) } } - return env; + return env } - void setLastRunElement(Element lastRunElement) { - mLastRunElement = lastRunElement; - } - - Element getLastRunElement() { - return mLastRunElement; - } - - public void save(int type) { - Stack stack = mStack.get(type); + fun save(type: Int) { + var stack = mStack[type] if (stack == null) { - stack = new Stack<>(); - mStack.put(type, stack); + stack = Stack() + mStack.put(type, stack) } if (type == TYPE_TEXT_COLOR) { - stack.push(mTextColor); + stack.push(textColor) } else if (type == TYPE_BG_COLOR) { - stack.push(mBackgroundColor); + stack.push(backgroundColor) } else if (type == TYPE_TYPEFACE) { - stack.push(mTypeface); + stack.push(typeface) } else if (type == TYPE_TEXT_SIZE) { - stack.push(mTextSize); + stack.push(textSize) } else if (type == TYPE_ALIGNMENT) { - stack.push(mAlignment); + stack.push(alignment) } else if (type == TYPE_LINE_SPACE) { - stack.push(mLineSpace); + stack.push(lineSpace) } else if (type == TYPE_PARAGRAPH_SPACE) { - stack.push(mParagraphSpace); + stack.push(paragraphSpace) } else { - stack.push(mCustomProp.get(type)); + stack.push(mCustomProp[type]) } } - public void restore(int type) { - Stack stack = mStack.get(type); + fun restore(type: Int) { + val stack = mStack[type] if (stack == null || stack.isEmpty()) { - Log.d(TAG, "restore (type = " + type + ")with a empty stack."); - return; + Log.d(TAG, "restore (type = $type)with a empty stack.") + return } - Object v = stack.pop(); - restore(type, v); + val v = stack.pop() + restore(type, v) } - private void restore(int type, Object v){ + private fun restore(type: Int, v: Any?) { if (type == TYPE_TEXT_COLOR) { - setTextColor((Integer) v); + textColor = v as Int } else if (type == TYPE_BG_COLOR) { - setBackgroundColor((Integer) v); + backgroundColor = v as Int } else if (type == TYPE_TYPEFACE) { - setTypeface((Typeface) v); + typeface = v as? Typeface } else if (type == TYPE_TEXT_SIZE) { - setTextSize((Float) v); + textSize = v as Float } else if (type == TYPE_ALIGNMENT) { - setAlignment((Alignment) v); + alignment = v as Alignment } else if (type == TYPE_LINE_SPACE) { - setLineSpace((Integer) v); + lineSpace = v as Int } else if (type == TYPE_PARAGRAPH_SPACE) { - setParagraphSpace((Integer) v); + paragraphSpace = v as Int } else { - setCustomProp(type, v); + setCustomProp(type, v) } } - public void clear() { - for (int i = 0; i < mStack.size(); i++) { - Stack stack = mStack.valueAt(i); - if (stack != null && stack.size() > 0) { - while (stack.size() > 1){ - stack.pop(); + fun clear() { + for (i in 0 until mStack.size()) { + val stack = mStack.valueAt(i) + if (stack != null && stack.size > 0) { + while (stack.size > 1) { + stack.pop() } - restore(mStack.keyAt(i), stack.pop()); + restore(mStack.keyAt(i), stack.pop()) } } } -} +} \ No newline at end of file diff --git a/type/src/main/java/com/qmuiteam/qmui/type/TypeModel.kt b/type/src/main/java/com/qmuiteam/qmui/type/TypeModel.kt index dfa6ba43..ebe7acc5 100644 --- a/type/src/main/java/com/qmuiteam/qmui/type/TypeModel.kt +++ b/type/src/main/java/com/qmuiteam/qmui/type/TypeModel.kt @@ -13,162 +13,110 @@ * either express or implied. See the License for the specific language governing permissions and * limitations under the License. */ +package com.qmuiteam.qmui.type -package com.qmuiteam.qmui.type; +import com.qmuiteam.qmui.type.element.Element +import java.util.* -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; +class TypeModel( + val origin: CharSequence, + private val mElementMap: Map, + private val mFirstElement: Element, + private val mLastElement: Element) { -import com.qmuiteam.qmui.type.element.Element; + var firstEffect: Element? = null -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -public class TypeModel { - private CharSequence mOrigin; - private final Map mElementMap; - private Element mFirstElement; - private Element mLastElement; - @Nullable - private Element mFirstEffect; - - public TypeModel( - CharSequence origin, - @NonNull Map elementMap, - Element firstElement, - Element lastElement, - @Nullable Element firstEffect) { - mOrigin = origin; - mElementMap = elementMap; - mFirstElement = firstElement; - mLastElement = lastElement; - mFirstEffect = firstEffect; - } - - @Nullable - public Element getFirstEffect() { - return mFirstEffect; - } - - public CharSequence getOrigin() { - return mOrigin; - } - - - public EffectRemover addBgEffect(int start, int end, final int bgColor){ - List types = new ArrayList<>(); - types.add(TypeEnvironment.TYPE_BG_COLOR); - return unsafeAddEffect(start, end, types, new EnvironmentUpdater() { - @Override - public void update(TypeEnvironment env) { - env.setBackgroundColor(bgColor); + fun addBgEffect(start: Int, end: Int, bgColor: Int): EffectRemover? { + val types: MutableList = ArrayList() + types.add(TypeEnvironment.TYPE_BG_COLOR) + return unsafeAddEffect(start, end, types, object : EnvironmentUpdater { + override fun update(env: TypeEnvironment) { + env.backgroundColor = bgColor } - }); + }) } - public EffectRemover addTextColorEffect(int start, int end, final int textColor){ - List types = new ArrayList<>(); - types.add(TypeEnvironment.TYPE_TEXT_COLOR); - return unsafeAddEffect(start, end, types, new EnvironmentUpdater() { - @Override - public void update(TypeEnvironment env) { - env.setTextColor(textColor); + fun addTextColorEffect(start: Int, end: Int, textColor: Int): EffectRemover? { + val types: MutableList = ArrayList() + types.add(TypeEnvironment.TYPE_TEXT_COLOR) + return unsafeAddEffect(start, end, types, object : EnvironmentUpdater { + override fun update(env: TypeEnvironment) { + env.textColor = textColor } - }); + }) } - public EffectRemover addUnderLineEffect(int start, int end, final int underLineColor, final int underLineHeight){ - List types = new ArrayList<>(); - types.add(TypeEnvironment.TYPE_BORDER_BOTTOM_WIDTH); - types.add(TypeEnvironment.TYPE_BORDER_BOTTOM_COLOR); - return unsafeAddEffect(start, end, types, new EnvironmentUpdater() { - @Override - public void update(TypeEnvironment env) { - env.setBorderBottom(underLineHeight, underLineColor); + fun addUnderLineEffect(start: Int, end: Int, underLineColor: Int, underLineHeight: Int): EffectRemover? { + val types: MutableList = ArrayList() + types.add(TypeEnvironment.TYPE_BORDER_BOTTOM_WIDTH) + types.add(TypeEnvironment.TYPE_BORDER_BOTTOM_COLOR) + return unsafeAddEffect(start, end, types, object : EnvironmentUpdater { + override fun update(env: TypeEnvironment) { + env.setBorderBottom(underLineHeight, underLineColor) } - }); + }) } - - public EffectRemover unsafeAddEffect(int start, int end, List types, EnvironmentUpdater environmentUpdater){ - Element elementStart = mElementMap.get(start); - Element elementEnd = mElementMap.get(end); - if(elementStart == null || elementEnd == null){ - return null; + fun unsafeAddEffect(start: Int, end: Int, types: List, environmentUpdater: EnvironmentUpdater): EffectRemover? { + val elementStart = mElementMap[start] + val elementEnd = mElementMap[end] + if (elementStart == null || elementEnd == null) { + return null } - for(Integer type: types){ - elementStart.addSaveType(type); - elementEnd.addRestoreType(type); + for (type in types) { + elementStart.addSaveType(type) + elementEnd.addRestoreType(type) } - elementStart.addEnvironmentUpdater(environmentUpdater); - if(mFirstEffect == null){ - mFirstEffect = elementStart; + elementStart.addEnvironmentUpdater(environmentUpdater) + firstEffect = if (firstEffect == null) { + elementStart } else { - mFirstEffect = elementStart.insertTo(mFirstElement); + elementStart.insertEffectTo(firstEffect!!) } - mFirstEffect = elementEnd.insertTo(mFirstElement); - return new DefaultEffectRemove(this, start, end, types, environmentUpdater); + firstEffect = elementEnd.insertEffectTo(firstEffect!!) + return DefaultEffectRemove(this, start, end, types, environmentUpdater) } - public boolean unsafeRemoveEffect(int start, int end, List types, EnvironmentUpdater environmentUpdater){ - Element elementStart = mElementMap.get(start); - Element elementEnd = mElementMap.get(end); - if(elementStart == null || elementEnd == null){ - return false; + fun unsafeRemoveEffect(start: Int, end: Int, types: List, environmentUpdater: EnvironmentUpdater): Boolean { + val elementStart = mElementMap[start] + val elementEnd = mElementMap[end] + if (elementStart == null || elementEnd == null) { + return false } - for(Integer type: types){ - elementStart.removeSaveType(type); - elementEnd.removeStoreType(type); + for (type in types) { + elementStart.removeSaveType(type) + elementEnd.removeStoreType(type) } - elementStart.removeEnvironmentUpdater(environmentUpdater); - - mFirstEffect = elementStart.removeFromEffectListIfNeeded(mFirstEffect); - mFirstEffect = elementEnd.removeFromEffectListIfNeeded(mFirstEffect); - return true; + elementStart.removeEnvironmentUpdater(environmentUpdater) + firstEffect = elementStart.removeFromEffectListIfNeeded(firstEffect) + firstEffect = elementEnd.removeFromEffectListIfNeeded(firstEffect) + return true } - public Element firstElement() { - return mFirstElement; + fun firstElement(): Element { + return mFirstElement } - public Element lastElement() { - return mLastElement; + fun lastElement(): Element { + return mLastElement } - @Nullable - public Element get(int pos){ - return mElementMap.get(pos); + operator fun get(pos: Int): Element? { + return mElementMap[pos] } - public interface EffectRemover { - void remove(); + interface EffectRemover { + fun remove() } +} - static class DefaultEffectRemove implements EffectRemover{ - - private final int mStart; - private final int mEnd; - private final List mTypes; - private final EnvironmentUpdater mEnvironmentUpdater; - private final TypeModel mTypeModel; - - public DefaultEffectRemove( - TypeModel typeModel, - int start, - int end, - List types, - EnvironmentUpdater environmentUpdater) { - mTypeModel = typeModel; - mStart = start; - mEnd = end; - mTypes = types; - mEnvironmentUpdater = environmentUpdater; - } - - @Override - public void remove() { - mTypeModel.unsafeRemoveEffect(mStart, mEnd, mTypes, mEnvironmentUpdater); - } +class DefaultEffectRemove( + private val typeModel: TypeModel, + private val start: Int, + private val end: Int, + private val types: List, + private val environmentUpdater: EnvironmentUpdater) : TypeModel.EffectRemover { + override fun remove() { + typeModel.unsafeRemoveEffect(start, end, types, environmentUpdater) } } \ No newline at end of file diff --git a/type/src/main/java/com/qmuiteam/qmui/type/element/BreakWordLineElement.kt b/type/src/main/java/com/qmuiteam/qmui/type/element/BreakWordLineElement.kt index 628b5b77..f728441c 100644 --- a/type/src/main/java/com/qmuiteam/qmui/type/element/BreakWordLineElement.kt +++ b/type/src/main/java/com/qmuiteam/qmui/type/element/BreakWordLineElement.kt @@ -13,13 +13,10 @@ * either express or implied. See the License for the specific language governing permissions and * limitations under the License. */ +package com.qmuiteam.qmui.type.element -package com.qmuiteam.qmui.type.element; - -public class BreakWordLineElement extends CharOrPhraseElement { - - public BreakWordLineElement() { - super('-', -1, -1); - setWordPart(WORD_PART_MIDDLE); +class BreakWordLineElement : TextElement("-", -1, -1) { + init { + wordPart = WORD_PART_MIDDLE } -} +} \ No newline at end of file diff --git a/type/src/main/java/com/qmuiteam/qmui/type/element/DrawableElement.kt b/type/src/main/java/com/qmuiteam/qmui/type/element/DrawableElement.kt index 89c96780..cfec7d73 100644 --- a/type/src/main/java/com/qmuiteam/qmui/type/element/DrawableElement.kt +++ b/type/src/main/java/com/qmuiteam/qmui/type/element/DrawableElement.kt @@ -1,44 +1,43 @@ -package com.qmuiteam.qmui.type.element; +/* + * Tencent is pleased to support the open source community by making QMUI_Android available. + * + * Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the MIT License (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://opensource.org/licenses/MIT + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.qmuiteam.qmui.type.element -import android.graphics.Canvas; -import android.graphics.drawable.Drawable; +import android.graphics.Canvas +import android.graphics.drawable.Drawable +import com.qmuiteam.qmui.type.TypeEnvironment -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; +class DrawableElement( + drawable: Drawable, + text: CharSequence, + index: Int, start: Int) : Element(text, index, start) { -import com.qmuiteam.qmui.type.TypeEnvironment; - -public class DrawableElement extends Element { - - private final Drawable mDrawable; - - public DrawableElement( - @NonNull Drawable drawable, - Character singleChar, - @Nullable CharSequence text, - int index, int originIndex) { - super(singleChar, text, index, originIndex, - text != null && text.length() > 2 && text.charAt(0) == '[' - ? text.subSequence(1, text.length() - 1).toString() : null); - mDrawable = drawable.mutate(); - mDrawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); + val drawable = drawable.mutate().apply { + setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight) } - @Override - protected void onMeasure(TypeEnvironment env) { - setMeasureDimen( - mDrawable.getIntrinsicWidth(), - mDrawable.getIntrinsicHeight(), - 0); + override fun onMeasure(env: TypeEnvironment) { + setMeasureDimen(drawable.intrinsicWidth.toFloat(), drawable.intrinsicHeight.toFloat(), 0f) } - @Override - protected void onDraw(TypeEnvironment env, Canvas canvas) { - drawBg(env, canvas); - canvas.save(); - canvas.translate(getX(), getY()); - mDrawable.draw(canvas); - canvas.restore(); - drawBorder(env, canvas); + override fun onDraw(env: TypeEnvironment, canvas: Canvas) { + drawBg(env, canvas) + canvas.save() + canvas.translate(x, y) + drawable.draw(canvas) + canvas.restore() + drawBorder(env, canvas) } -} +} \ No newline at end of file diff --git a/type/src/main/java/com/qmuiteam/qmui/type/element/Element.kt b/type/src/main/java/com/qmuiteam/qmui/type/element/Element.kt index 6634998f..13730fca 100644 --- a/type/src/main/java/com/qmuiteam/qmui/type/element/Element.kt +++ b/type/src/main/java/com/qmuiteam/qmui/type/element/Element.kt @@ -13,424 +13,291 @@ * either express or implied. See the License for the specific language governing permissions and * limitations under the License. */ +package com.qmuiteam.qmui.type.element -package com.qmuiteam.qmui.type.element; +import android.graphics.Canvas +import android.graphics.Color +import com.qmuiteam.qmui.type.EnvironmentUpdater +import com.qmuiteam.qmui.type.TypeEnvironment +import java.util.* +import kotlin.collections.ArrayList -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; +abstract class Element(val text: CharSequence, val index: Int, val start: Int) { + companion object { + const val VISIBLE = 0 + const val GONE = 1 + const val WORD_PART_WHOLE = 0 + const val WORD_PART_START = 1 + const val WORD_PART_MIDDLE = 2 + const val WORD_PART_END = 3 + const val LINE_BREAK_TYPE_NORMAL = 0 + const val LINE_BREAK_TYPE_NOT_START = 1 + const val LINE_BREAK_TYPE_NOT_END = 2 + const val LINE_BREAK_WORD_BREAK_ALLOWED = 3 + private val NOT_START_CHARS = charArrayOf( + ',', '.', ';', ']', '>', ')', '?', '"', '\'', '!', ':', '}', '」', + ',', '。', ';', '、', '】', '》', ')', '?', '”', '!', ':', '』') + private val NOT_END_CHARS = charArrayOf( + '(', '<', '[', '{', '“', '「', '『', '(', '《' + ) -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.qmuiteam.qmui.type.EnvironmentUpdater; -import com.qmuiteam.qmui.type.TypeEnvironment; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -public abstract class Element { - public static final int VISIBLE = 0; - public static final int INVISIBLE = 1; - public static final int GONE = 2; - - public static final int WORD_PART_WHOLE = 0; - public static final int WORD_PART_START = 1; - public static final int WORD_PART_MIDDLE = 2; - public static final int WORD_PART_END = 3; - - - public static final int LINE_BREAK_TYPE_NORMAL = 0; - public static final int LINE_BREAK_TYPE_NOT_START = 1; - public static final int LINE_BREAK_TYPE_NOT_END = 2; - public static final int LINE_BREAK_WORD_BREAK_ALLOWED = 3; - - private static final char[] NOT_START_CHARS =new char[]{ - ',', '.', ';', ']', '>', ')', '?', '"', '\'', '!', ':', '}', '」', - ',', '。', ';', '、', '】', '》', ')', '?', '”', '!', ':', '』', - }; - private static final char[] NOT_END_CHARS = new char[]{ - '(', '<', '[', '{', '“', '「', '『', '(', '《' - }; - - static { - Arrays.sort(NOT_START_CHARS); - Arrays.sort(NOT_END_CHARS); - } - - private final char mChar; - private final CharSequence mText; - private final int mIndex; - private final int mOriginIndex; - private final String mDescription; - private Element mPrevEffect; - private Element mNextEffect; - private Element mPrev; - private Element mNext; - private int mWordPart = WORD_PART_WHOLE; - private int mLineBreakType = LINE_BREAK_TYPE_NORMAL; - private int mVisible = VISIBLE; - - - private List mSaveType; - private List mRestoreType; - @Nullable - private List mEnvironmentUpdater; - - private float mMeasureWidth; - private float mMeasureHeight; - private float mX; - private float mY; - private float mBaseLine; - private float mNextGapWidth; - private String mToStringCache; - - public Element(Character singleChar, @Nullable CharSequence text, int index, int originIndex) { - this(singleChar, text, index, originIndex, null); - } - - public Element(char singleChar, @Nullable CharSequence text, int index, int originIndex, @Nullable String description) { - mChar = singleChar; - mText = text; - mIndex = index; - mOriginIndex = originIndex; - mDescription = description; - if(Arrays.binarySearch(NOT_START_CHARS, singleChar) >= 0){ - mLineBreakType = LINE_BREAK_TYPE_NOT_START; - } else if(Arrays.binarySearch(NOT_END_CHARS, singleChar) >= 0){ - mLineBreakType = LINE_BREAK_TYPE_NOT_END; + init { + Arrays.sort(NOT_START_CHARS) + Arrays.sort(NOT_END_CHARS) } } - public Element insertTo(Element head){ - if(head == null){ - return this; + var prevEffect: Element? = null + private set + var nextEffect: Element? = null + private set + + var wordPart = WORD_PART_WHOLE + var lineBreakType = LINE_BREAK_TYPE_NORMAL + var visible = VISIBLE + + + var measureWidth = 0f + private set + var measureHeight = 0f + private set + var x = 0f + var y = 0f + var baseLine = 0f + var nextGapWidth = 0f + + private var saveTypeList: MutableList? = null + private var restoreTypeList: MutableList? = null + private var environmentUpdaterList: MutableList? = null + + val length: Int = text.length + + private var _prev: Element? = null + private var _next: Element? = null + + var next: Element? + get() = _next + set(element) { + _next = element + if (element != null) { + element._prev = this + } } - if(head == this){ - return head; + var prev: Element? + get() = _prev + set(element) { + _prev = element + if (element != null) { + element._next = this + } } - if(mIndex < head.mIndex){ - head.setPrev(this); - this.setNext(head); - return this; + + private val rightWithGap: Float + get() = x + measureWidth + nextGapWidth + 0.5f + + init { + if(text.length == 1){ + if (Arrays.binarySearch(NOT_START_CHARS, text[0]) >= 0) { + lineBreakType = LINE_BREAK_TYPE_NOT_START + } else if (Arrays.binarySearch(NOT_END_CHARS, text[0]) >= 0) { + lineBreakType = LINE_BREAK_TYPE_NOT_END + } } - Element current = head; - Element next = head.mNext; - while (next != null){ - if(next == this){ + } + + fun insertEffectTo(head: Element): Element { + if (head === this) { + return head + } + if (index < head.index) { + head.prevEffect = this + nextEffect = head + return this + } + var current: Element = head + var next = head.nextEffect + while (next != null) { + if (next === this) { // already in list - return head; + return head } - if(next.mIndex > mIndex){ - current.setNext(this); - next.setPrev(this); - this.setPrev(current); - this.setNext(next); - return head; + if (next.index > index) { + current.nextEffect = this + next.prevEffect = this + prevEffect = current + nextEffect = next + return head } - current = next; - next = next.mNext; + current = next + next = next.nextEffect } - current.setNext(this); - this.setPrev(current); - this.setNext(null); - return head; + current.nextEffect = this + prevEffect = current + nextEffect = null + return head } - public Element removeFromEffectListIfNeeded(Element head){ - boolean noSaveType = mSaveType == null || mSaveType.isEmpty(); - boolean noRestoreType = mRestoreType == null || mRestoreType.isEmpty(); - if(noSaveType && noRestoreType){ - Element prev = mPrevEffect; - Element next = mNextEffect; - if(prev != null){ - prev.mNextEffect = next; - mPrevEffect = null; + fun removeFromEffectListIfNeeded(head: Element?): Element? { + if(head == null){ + return null + } + val noSaveType = saveTypeList.isNullOrEmpty() + val noRestoreType = restoreTypeList.isNullOrEmpty() + if (noSaveType && noRestoreType) { + val prev = prevEffect + val next = nextEffect + if (prev != null) { + prev.nextEffect = next + prevEffect = null } - if(next != null){ - next.mPrevEffect = prev; - mNextEffect = null; + if (next != null) { + next.prevEffect = prev + nextEffect = null } - if(head == this){ - return next; + if (head === this) { + return next } } - return head; + return head } - public Element getNextEffect() { - return mNextEffect; + fun addSaveType(type: Int) { + val list = saveTypeList ?: ArrayList().also { saveTypeList = it} + list.add(type) } - public Element getPrevEffect() { - return mPrevEffect; - } - - public int getLineBreakType() { - return mLineBreakType; - } - - public void setLineBreakType(int lineBreakType) { - mLineBreakType = lineBreakType; - } - - public void setPrev(Element element) { - this.mPrev = element; - if (element != null) { - element.mNext = this; - } - } - - public void setNext(Element element) { - this.mNext = element; - if (element != null) { - element.mPrev = this; - } - } - - public void setWordPart(int wordPart) { - this.mWordPart = wordPart; - } - - public int getWordPart() { - return mWordPart; - } - - public void addSaveType(int type) { - if (mSaveType == null) { - mSaveType = new ArrayList<>(); - } - mSaveType.add(type); - } - - public void removeSaveType(int type) { - if (mSaveType != null) { - for (int i = 0; i < mSaveType.size(); i++) { - if (mSaveType.get(i) == type) { - mSaveType.remove(i); - break; - } + fun removeSaveType(type: Int) { + val list = saveTypeList ?: return + for (i in list.indices) { + if (list[i] == type) { + list.removeAt(i) + break } } } - public void addRestoreType(int type) { - if (mRestoreType == null) { - mRestoreType = new ArrayList<>(); - } - mRestoreType.add(type); + fun addRestoreType(type: Int) { + val list = restoreTypeList ?: ArrayList().also { restoreTypeList = it} + list.add(type) } - public void removeStoreType(int type) { - if (mRestoreType != null) { - for (int i = 0; i < mRestoreType.size(); i++) { - if (mRestoreType.get(i) == type) { - mRestoreType.remove(i); - break; - } + fun removeStoreType(type: Int) { + val list = restoreTypeList ?: return + for (i in list.indices) { + if (list[i] == type) { + list.removeAt(i) + break } } } - public boolean hasEnvironmentUpdater() { - return mEnvironmentUpdater != null && mEnvironmentUpdater.size() > 0; + fun hasEnvironmentUpdater(): Boolean { + return (environmentUpdaterList?.size ?: 0) > 0 } - public void addEnvironmentUpdater(@NonNull EnvironmentUpdater environmentUpdater) { - if (mEnvironmentUpdater == null) { - mEnvironmentUpdater = new ArrayList<>(); - } - mEnvironmentUpdater.add(environmentUpdater); + fun hasSaveType(): Boolean { + return !saveTypeList.isNullOrEmpty() } - public void removeEnvironmentUpdater(@NonNull EnvironmentUpdater environmentUpdater) { - if (mEnvironmentUpdater != null) { - mEnvironmentUpdater.remove(environmentUpdater); - } + fun hasRestoreType(): Boolean { + return !restoreTypeList.isNullOrEmpty() } - public void addSingleEnvironmentUpdater(@Nullable List changedTypes, @NonNull EnvironmentUpdater environmentUpdater) { + fun addEnvironmentUpdater(environmentUpdater: EnvironmentUpdater) { + val list = environmentUpdaterList ?: ArrayList().also { environmentUpdaterList = it } + list.add(environmentUpdater) + } + + fun removeEnvironmentUpdater(environmentUpdater: EnvironmentUpdater) { + val list = environmentUpdaterList ?: return + list.remove(environmentUpdater) + } + + fun addSingleEnvironmentUpdater(changedTypes: List?, environmentUpdater: EnvironmentUpdater) { if (changedTypes != null) { - for (Integer type : changedTypes) { - addRestoreType(type); - addSaveType(type); + for (type in changedTypes) { + addSaveType(type) + addRestoreType(type) } } - addEnvironmentUpdater(environmentUpdater); + addEnvironmentUpdater(environmentUpdater) } - public void move(TypeEnvironment environment) { + fun move(environment: TypeEnvironment) { if (hasEnvironmentUpdater()) { - updateEnv(environment); - restoreEnv(environment); + updateEnv(environment) + restoreEnv(environment) } } - public int getIndex() { - return mIndex; + override fun toString(): String { + return text.toString() } - public int getOriginIndex() { - return mOriginIndex; + + protected fun setMeasureDimen(measureWidth: Float, measureHeight: Float, baseline: Float) { + this.measureWidth = measureWidth + this.measureHeight = measureHeight + baseLine = baseline } - public CharSequence getText() { - return mText; + + fun measure(env: TypeEnvironment) { + updateEnv(env) + onMeasure(env) + restoreEnv(env) } - public char getChar() { - return mChar; - } - - public boolean isSingleChar() { - return mText == null; - } - - @NonNull - @Override - public String toString() { - if(mToStringCache != null){ - return mToStringCache; + fun draw(env: TypeEnvironment, canvas: Canvas) { + updateEnv(env) + if (visible == VISIBLE) { + onDraw(env, canvas) } - mToStringCache = mText != null ? mText.toString() : String.valueOf(mChar); - return mToStringCache; + restoreEnv(env) } - public int getLength() { - return mText != null ? mText.length() : 1; - } - - public String getDescription() { - return mDescription != null ? mDescription : toString(); - } - - protected void setMeasureDimen(float measureWidth, float measureHeight, float baseline) { - mMeasureWidth = measureWidth; - mMeasureHeight = measureHeight; - mBaseLine = baseline; - } - - public void setVisible(int visible) { - mVisible = visible; - } - - public int getVisible() { - return mVisible; - } - - public void setX(float x) { - mX = x; - } - - public void setY(float y) { - mY = y; - } - - public void setNextGapWidth(float nextGapWidth) { - mNextGapWidth = nextGapWidth; - } - - public float getBaseLine() { - return mBaseLine; - } - - public float getMeasureWidth() { - return mMeasureWidth; - } - - public float getMeasureHeight() { - return mMeasureHeight; - } - - public float getX() { - return mX; - } - - public float getY() { - return mY; - } - - public Element getNext() { - return mNext; - } - - public Element getPrev() { - return mPrev; - } - - public final void measure(TypeEnvironment env) { - updateEnv(env); - onMeasure(env); - restoreEnv(env); - } - - public final void draw(TypeEnvironment env, Canvas canvas) { - updateEnv(env); - if (mVisible == VISIBLE) { - onDraw(env, canvas); + fun updateEnv(env: TypeEnvironment) { + saveTypeList?.forEach { + env.save(it) } - restoreEnv(env); +// environmentUpdaterList?.forEach { +// it.update(env) +// } } - void updateEnv(TypeEnvironment env) { - if (mSaveType != null) { - for (Integer type : mSaveType) { - env.save(type); - } - } - if (mEnvironmentUpdater != null) { - for (EnvironmentUpdater updater : mEnvironmentUpdater) { - updater.update(env); - } + fun restoreEnv(env: TypeEnvironment) { + restoreTypeList?.forEach { + env.restore(it) } } - void restoreEnv(TypeEnvironment env) { - if (mRestoreType != null) { - for (Integer type : mRestoreType) { - env.restore(type); - } + protected abstract fun onMeasure(env: TypeEnvironment) + protected abstract fun onDraw(env: TypeEnvironment, canvas: Canvas) + protected fun drawBg(env: TypeEnvironment, canvas: Canvas) { + if (env.backgroundColor != Color.TRANSPARENT) { + canvas.drawRect(x, y, rightWithGap, y + measureHeight, env.bgPaint) } } - protected abstract void onMeasure(TypeEnvironment env); - - protected abstract void onDraw(TypeEnvironment env, Canvas canvas); - - protected void drawBg(TypeEnvironment env, Canvas canvas){ - if(env.getBackgroundColor() != Color.TRANSPARENT){ - canvas.drawRect(mX, mY, getRightWithGap(), mY + mMeasureHeight, env.getBgPaint()); + protected fun drawBorder(env: TypeEnvironment, canvas: Canvas) { + val paint = env.borderPaint + if (env.borderLeftWidth > 0) { + paint.color = env.borderLeftColor + canvas.drawRect(x, y, x + env.borderLeftWidth, y + measureHeight, paint) + } + if (env.borderTopWidth > 0) { + paint.color = env.borderTopColor + canvas.drawRect(x, y, rightWithGap, y + env.borderTopWidth, paint) + } + if (env.borderRightWidth > 0) { + paint.color = env.borderRightColor + canvas.drawRect(x + measureWidth - env.borderRightWidth, y, + x + measureWidth, y + measureHeight, paint) + } + if (env.borderBottomWidth > 0) { + paint.color = env.borderBottomColor + canvas.drawRect(x, y + measureHeight - env.borderBottomWidth, + rightWithGap, y + measureHeight, paint) } } - - protected float getRightWithGap(){ - return mX + mMeasureWidth + mNextGapWidth + 0.5f; - } - - protected void drawBorder(TypeEnvironment env, Canvas canvas){ - Paint paint = env.getBorderPaint(); - - if(env.getBorderLeftWidth() > 0){ - paint.setColor(env.getBorderLeftColor()); - canvas.drawRect(mX, mY, mX + env.getBorderLeftWidth(), mY + mMeasureHeight, paint); - } - - if(env.getBorderTopWidth() > 0) { - paint.setColor(env.getBorderTopColor()); - canvas.drawRect(mX, mY, getRightWithGap(), mY + env.getBorderTopWidth(), paint); - } - - if(env.getBorderRightWidth() > 0){ - paint.setColor(env.getBorderRightColor()); - canvas.drawRect(mX + mMeasureWidth - env.getBorderRightWidth(), mY, - mX + mMeasureWidth, mY + mMeasureHeight, paint); - } - - if(env.getBorderBottomWidth() > 0){ - paint.setColor(env.getBorderBottomColor()); - canvas.drawRect(mX, mY + mMeasureHeight - env.getBorderBottomWidth(), - getRightWithGap(), mY + mMeasureHeight, paint); - } - } -} +} \ No newline at end of file diff --git a/type/src/main/java/com/qmuiteam/qmui/type/element/EmojiElement.kt b/type/src/main/java/com/qmuiteam/qmui/type/element/EmojiElement.kt index 0f1de7a1..bd4668a1 100644 --- a/type/src/main/java/com/qmuiteam/qmui/type/element/EmojiElement.kt +++ b/type/src/main/java/com/qmuiteam/qmui/type/element/EmojiElement.kt @@ -1,44 +1,39 @@ -package com.qmuiteam.qmui.type.element; +/* + * Tencent is pleased to support the open source community by making QMUI_Android available. + * + * Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the MIT License (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://opensource.org/licenses/MIT + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.qmuiteam.qmui.type.element -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.drawable.Drawable; +import android.graphics.Canvas +import android.graphics.drawable.Drawable +import com.qmuiteam.qmui.type.TypeEnvironment -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; +class EmojiElement(val drawable: Drawable, text: CharSequence, index: Int, start: Int) : Element(text, index, start) { -import com.qmuiteam.qmui.type.TypeEnvironment; - -public class EmojiElement extends Element { - - private final Drawable mDrawable; - - public EmojiElement( - @NonNull Drawable drawable, - Character singleChar, - @Nullable CharSequence text, - int index, int originIndex) { - super(singleChar, text, index, originIndex, - text != null && text.length() > 2 && text.charAt(0) == '[' - ? text.subSequence(1, text.length() - 1).toString() : null); - mDrawable = drawable; + override fun onMeasure(env: TypeEnvironment) { + val paint = env.paint + val size = (paint.fontMetrics.descent - paint.fontMetrics.ascent).toInt() + drawable.setBounds(0, 0, size, size) + setMeasureDimen(size.toFloat(), size.toFloat(), 0f) } - @Override - protected void onMeasure(TypeEnvironment env) { - Paint paint = env.getPaint(); - int size = (int) (paint.getFontMetrics().descent - paint.getFontMetrics().ascent); - mDrawable.setBounds(0, 0, size, size); - setMeasureDimen(size, size, 0); + override fun onDraw(env: TypeEnvironment, canvas: Canvas) { + drawBg(env, canvas) + canvas.save() + canvas.translate(x, y) + drawable.draw(canvas) + canvas.restore() + drawBorder(env, canvas) } - - @Override - protected void onDraw(TypeEnvironment env, Canvas canvas) { - drawBg(env, canvas); - canvas.save(); - canvas.translate(getX(), getY()); - mDrawable.draw(canvas); - canvas.restore(); - drawBorder(env, canvas); - } -} +} \ No newline at end of file diff --git a/type/src/main/java/com/qmuiteam/qmui/type/element/IgnoreEffectElement.kt b/type/src/main/java/com/qmuiteam/qmui/type/element/IgnoreEffectElement.kt index ac3d8297..ef5b8d96 100644 --- a/type/src/main/java/com/qmuiteam/qmui/type/element/IgnoreEffectElement.kt +++ b/type/src/main/java/com/qmuiteam/qmui/type/element/IgnoreEffectElement.kt @@ -13,37 +13,29 @@ * either express or implied. See the License for the specific language governing permissions and * limitations under the License. */ +package com.qmuiteam.qmui.type.element -package com.qmuiteam.qmui.type.element; +import android.graphics.Canvas +import com.qmuiteam.qmui.type.EnvironmentUpdater +import com.qmuiteam.qmui.type.TypeEnvironment -import android.graphics.Canvas; +class IgnoreEffectElement(list: List) : Element("", -1, -1) { -import com.qmuiteam.qmui.type.EnvironmentUpdater; -import com.qmuiteam.qmui.type.TypeEnvironment; - -import java.util.List; - -public class IgnoreEffectElement extends Element { - - public IgnoreEffectElement(final List list) { - super(' ', null, -1, -1, ""); - addEnvironmentUpdater(new EnvironmentUpdater() { - @Override - public void update(TypeEnvironment env) { - for (Element element : list) { - element.move(env); + init { + addEnvironmentUpdater(object: EnvironmentUpdater { + override fun update(env: TypeEnvironment) { + for (element in list) { + element.move(env) } } - }); + + }) } - @Override - protected void onMeasure(TypeEnvironment env) { - setMeasureDimen(0, 0, 0); + override fun onMeasure(env: TypeEnvironment) { + setMeasureDimen(0f, 0f, 0f) } - @Override - protected void onDraw(TypeEnvironment env, Canvas canvas) { + override fun onDraw(env: TypeEnvironment, canvas: Canvas) {} - } -} +} \ No newline at end of file diff --git a/type/src/main/java/com/qmuiteam/qmui/type/element/NextParagraphElement.kt b/type/src/main/java/com/qmuiteam/qmui/type/element/NextParagraphElement.kt index 91daecc6..ed302113 100644 --- a/type/src/main/java/com/qmuiteam/qmui/type/element/NextParagraphElement.kt +++ b/type/src/main/java/com/qmuiteam/qmui/type/element/NextParagraphElement.kt @@ -13,38 +13,16 @@ * either express or implied. See the License for the specific language governing permissions and * limitations under the License. */ +package com.qmuiteam.qmui.type.element -package com.qmuiteam.qmui.type.element; +import android.graphics.Canvas +import com.qmuiteam.qmui.type.TypeEnvironment -import android.graphics.Canvas; +class NextParagraphElement(text: CharSequence, index: Int, start: Int) : Element(text, index, start) { -import androidx.annotation.Nullable; - -import com.qmuiteam.qmui.type.TypeEnvironment; - -public class NextParagraphElement extends Element { - - public NextParagraphElement(int index, int originIndex) { - this('\n', null, index, originIndex, "\n"); + override fun onMeasure(env: TypeEnvironment) { + setMeasureDimen(0f, 0f, 0f) } - public NextParagraphElement(char singleChar, @Nullable String text, int index, int originIndex) { - super(singleChar, null, index, originIndex); - } - - public NextParagraphElement(char singleChar, @Nullable CharSequence text, int index, int originIndex, @Nullable String description) { - super(singleChar, text, index, originIndex, description); - } - - - - @Override - protected void onMeasure(TypeEnvironment env) { - setMeasureDimen(0, 0, 0); - } - - @Override - protected void onDraw(TypeEnvironment env, Canvas canvas) { - - } -} + override fun onDraw(env: TypeEnvironment, canvas: Canvas) {} +} \ No newline at end of file diff --git a/type/src/main/java/com/qmuiteam/qmui/type/element/TextElement.kt b/type/src/main/java/com/qmuiteam/qmui/type/element/TextElement.kt index c21d47f4..a4979413 100644 --- a/type/src/main/java/com/qmuiteam/qmui/type/element/TextElement.kt +++ b/type/src/main/java/com/qmuiteam/qmui/type/element/TextElement.kt @@ -13,42 +13,23 @@ * either express or implied. See the License for the specific language governing permissions and * limitations under the License. */ +package com.qmuiteam.qmui.type.element -package com.qmuiteam.qmui.type.element; +import android.graphics.Canvas +import com.qmuiteam.qmui.type.TypeEnvironment -import android.graphics.Canvas; -import android.graphics.Paint; +open class TextElement(text: CharSequence, index: Int, start: Int) : Element(text, index, start) { -import androidx.annotation.Nullable; - -import com.qmuiteam.qmui.type.TypeEnvironment; - -public class CharOrPhraseElement extends Element { - - public CharOrPhraseElement(char singleChar, int index, int originIndex) { - super(singleChar, null, index, originIndex); + override fun onMeasure(env: TypeEnvironment) { + val paint = env.paint + setMeasureDimen(paint.measureText(text, 0, text.length), + paint.fontMetrics.descent - paint.fontMetrics.ascent, + -paint.fontMetrics.ascent) } - public CharOrPhraseElement(char singleChar, int index, int originIndex, @Nullable String description) { - super(singleChar, null, index, originIndex, description); + override fun onDraw(env: TypeEnvironment, canvas: Canvas) { + drawBg(env, canvas) + canvas.drawText(text, 0, text.length, x, y + baseLine, env.paint) + drawBorder(env, canvas) } - - public CharOrPhraseElement(String text, int index, int originIndex) { - super('\u0000', text, index, originIndex); - } - - @Override - protected void onMeasure(TypeEnvironment env) { - Paint paint = env.getPaint(); - setMeasureDimen(paint.measureText(toString()), - paint.getFontMetrics().descent - paint.getFontMetrics().ascent, - -paint.getFontMetrics().ascent); - } - - @Override - protected void onDraw(TypeEnvironment env, Canvas canvas) { - drawBg(env, canvas); - canvas.drawText(toString(), getX(), getY() + getBaseLine(), env.getPaint()); - drawBorder(env, canvas); - } -} +} \ No newline at end of file diff --git a/type/src/main/java/com/qmuiteam/qmui/type/parser/EmojiResourceProvider.kt b/type/src/main/java/com/qmuiteam/qmui/type/parser/EmojiResourceProvider.kt index 8c736e21..7ea6dc5d 100644 --- a/type/src/main/java/com/qmuiteam/qmui/type/parser/EmojiResourceProvider.kt +++ b/type/src/main/java/com/qmuiteam/qmui/type/parser/EmojiResourceProvider.kt @@ -13,26 +13,13 @@ * either express or implied. See the License for the specific language governing permissions and * limitations under the License. */ +package com.qmuiteam.qmui.type.parser -package com.qmuiteam.qmui.type.parser; +import android.graphics.drawable.Drawable -import android.graphics.drawable.Drawable; - -import androidx.annotation.Nullable; - -public interface EmojiResourceProvider { - - @Nullable - Drawable queryForDrawable(CharSequence text); - - @Nullable - Drawable queryForDrawable(char c); - - @Nullable - Drawable queryForDrawable(int codePoint); - - @Nullable - Drawable queryForDrawable(int firstCodePoint, int secondCodePint); - - -} +interface EmojiResourceProvider { + fun queryForDrawable(text: CharSequence): Drawable? + fun queryForDrawable(c: Char): Drawable? + fun queryForDrawable(codePoint: Int): Drawable? + fun queryForDrawable(firstCodePoint: Int, secondCodePint: Int): Drawable? +} \ No newline at end of file diff --git a/type/src/main/java/com/qmuiteam/qmui/type/parser/EmojiTextParser.kt b/type/src/main/java/com/qmuiteam/qmui/type/parser/EmojiTextParser.kt index e1edb472..8d488506 100644 --- a/type/src/main/java/com/qmuiteam/qmui/type/parser/EmojiTextParser.kt +++ b/type/src/main/java/com/qmuiteam/qmui/type/parser/EmojiTextParser.kt @@ -13,116 +13,101 @@ * either express or implied. See the License for the specific language governing permissions and * limitations under the License. */ +package com.qmuiteam.qmui.type.parser -package com.qmuiteam.qmui.type.parser; +import com.qmuiteam.qmui.type.TypeModel +import com.qmuiteam.qmui.type.element.* +import java.util.* -import android.graphics.drawable.Drawable; +class EmojiTextParser(private val emojiProvider: EmojiResourceProvider) : TextParser { -import com.qmuiteam.qmui.type.TypeModel; -import com.qmuiteam.qmui.type.element.CharOrPhraseElement; -import com.qmuiteam.qmui.type.element.DrawableElement; -import com.qmuiteam.qmui.type.element.Element; -import com.qmuiteam.qmui.type.element.EmojiElement; -import com.qmuiteam.qmui.type.element.NextParagraphElement; - -import java.util.HashMap; - -public class EmojiTextParser implements TextParser { - - private final EmojiResourceProvider mEmojiProvider; - - public EmojiTextParser(EmojiResourceProvider provider) { - mEmojiProvider = provider; - } - - @Override - public TypeModel parse(CharSequence text) { - int size = text.length(); - if (size == 0) { - return null; + override fun parse(text: CharSequence?): TypeModel? { + if(text == null || text.isEmpty()){ + return null } - HashMap map = new HashMap<>(text.length()); - Element first = null, last = null, tmp = null; - int index = 0; - for (int i = 0; i < size; i++) { - char c = text.charAt(i); + + val size = text.length + val map = HashMap(size) + var first: Element? = null + var last: Element? = null + var tmp: Element? = null + var index = 0 + var i = 0 + while (i < size) { + val c = text[i] if (c == '\n') { - tmp = new NextParagraphElement(c, null, index, i); + tmp = NextParagraphElement(text.subSequence(i, i + 1), index, i) } else if (c == '\r') { - if (i + 1 < text.length() && text.charAt(i + 1) == '\n') { - tmp = new NextParagraphElement('\u0000', "\r\n", index, i); - i++; + if (i + 1 < text.length && text[i + 1] == '\n') { + tmp = NextParagraphElement(text.subSequence(i, i + 2), index, i) + i++ } else { - tmp = new NextParagraphElement(c, null, index, i); + tmp = NextParagraphElement(text.subSequence(i, i + 1), index, i) } } else if (c == '[') { - int j = i + 1; - boolean find = false; - int end = Math.min(i + 30, size); + var j = i + 1 + var find = false + val end = Math.min(i + 30, size) while (j < end) { - if (text.charAt(j) == ']') { - CharSequence sub = text.subSequence(i, j + 1); - Drawable emoji = mEmojiProvider.queryForDrawable(sub); + if (text[j] == ']') { + val sub = text.subSequence(i, j + 1) + val emoji = emojiProvider.queryForDrawable(sub) if (emoji != null) { - tmp = new EmojiElement(emoji, '\u0000', sub, index, i); - i = j; - find = true; - break; + tmp = EmojiElement(emoji, text.subSequence(i, j + 1), index, i) + i = j + find = true + break } } - j++; + j++ } if (!find) { - tmp = new CharOrPhraseElement(c, index, i); + tmp = TextElement(text.subSequence(i, i + 1), index, i) } } else { - boolean handled = false; - Drawable emoji = mEmojiProvider.queryForDrawable(c); + var handled = false + var emoji = emojiProvider.queryForDrawable(c) if (emoji != null) { - handled = true; - tmp = new DrawableElement(emoji, c, null, index, i); + handled = true + tmp = DrawableElement(emoji, text.subSequence(i, i + 1), index, i) } - if (!handled) { - int unicode = Character.codePointAt(text, i); - int codeCount = Character.charCount(unicode); - emoji = mEmojiProvider.queryForDrawable(unicode); + val unicode = Character.codePointAt(text, i) + val codeCount = Character.charCount(unicode) + emoji = emojiProvider.queryForDrawable(unicode) if (emoji != null) { - handled = true; - tmp = new DrawableElement(emoji, c, text.subSequence(i, i + codeCount), index, i); - i += codeCount - 1; + handled = true + tmp = DrawableElement(emoji, text.subSequence(i, i + codeCount), index, i) + i += codeCount - 1 } - - int nextStart = i + codeCount; + val nextStart = i + codeCount if (!handled && nextStart < size) { - int nextUnicode = Character.codePointAt(text, nextStart); - emoji = mEmojiProvider.queryForDrawable(unicode, nextUnicode); + val nextUnicode = Character.codePointAt(text, nextStart) + emoji = emojiProvider.queryForDrawable(unicode, nextUnicode) if (emoji != null) { - handled = true; - int nextCodeCount = Character.charCount(nextUnicode); - tmp = new DrawableElement(emoji, c, text.subSequence(i, nextStart + nextCodeCount), index, i); - i = nextStart + nextCodeCount - 1; + handled = true + val nextCodeCount = Character.charCount(nextUnicode) + tmp = DrawableElement(emoji, text.subSequence(i, nextStart + nextCodeCount), index, i) + i = nextStart + nextCodeCount - 1 } } } - if (!handled) { - tmp = new CharOrPhraseElement(c, index, i); + tmp = TextElement(text.subSequence(i, i + 1), index, i) } } - - ParserHelper.handleWordPart(c, last, tmp); - - index++; + ParserHelper.handleWordPart(c, last, tmp!!) + index++ if (first == null) { - first = tmp; - last = tmp; + first = tmp + last = tmp } else { - last.setNext(tmp); - last = tmp; + last!!.next = tmp + last = tmp } - map.put(tmp.getIndex(), tmp); + map[tmp.index] = tmp + i++ } - return new TypeModel(text, map, first, last, null); + return TypeModel(text, map, first!!, last!!) } -} +} \ No newline at end of file diff --git a/type/src/main/java/com/qmuiteam/qmui/type/parser/ParserHelper.kt b/type/src/main/java/com/qmuiteam/qmui/type/parser/ParserHelper.kt index a76521a7..b1820800 100644 --- a/type/src/main/java/com/qmuiteam/qmui/type/parser/ParserHelper.kt +++ b/type/src/main/java/com/qmuiteam/qmui/type/parser/ParserHelper.kt @@ -13,31 +13,28 @@ * either express or implied. See the License for the specific language governing permissions and * limitations under the License. */ +package com.qmuiteam.qmui.type.parser -package com.qmuiteam.qmui.type.parser; +import com.qmuiteam.qmui.type.element.Element -import com.qmuiteam.qmui.type.element.Element; +object ParserHelper { -public class ParserHelper { - - public static boolean isEnglishLetterOrNumber(char c){ - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); + fun isEnglishLetterOrNumber(c: Char): Boolean { + return c in 'a'..'z' || c in 'A'..'Z' || c in '0'..'9' } - public static void handleWordPart(char c, Element prev, Element curr){ - if(ParserHelper.isEnglishLetterOrNumber(c)){ - if(prev == null || - prev.getWordPart() == Element.WORD_PART_WHOLE || - prev.getWordPart() == Element.WORD_PART_END){ - curr.setWordPart(Element.WORD_PART_START); - }else{ - curr.setWordPart(Element.WORD_PART_MIDDLE); + fun handleWordPart(c: Char, prev: Element?, curr: Element) { + if (isEnglishLetterOrNumber(c)) { + if (prev == null || prev.wordPart == Element.WORD_PART_WHOLE || prev.wordPart == Element.WORD_PART_END) { + curr.wordPart = Element.WORD_PART_START + } else { + curr.wordPart = Element.WORD_PART_MIDDLE } - }else{ - if(prev != null && prev.getWordPart() == Element.WORD_PART_MIDDLE){ - prev.setWordPart(Element.WORD_PART_END); + } else { + if (prev != null && prev.wordPart == Element.WORD_PART_MIDDLE) { + prev.wordPart = Element.WORD_PART_END } - curr.setWordPart(Element.WORD_PART_WHOLE); + curr.wordPart = Element.WORD_PART_WHOLE } } -} +} \ No newline at end of file diff --git a/type/src/main/java/com/qmuiteam/qmui/type/parser/PlainTextParser.kt b/type/src/main/java/com/qmuiteam/qmui/type/parser/PlainTextParser.kt index 3920e272..66233929 100644 --- a/type/src/main/java/com/qmuiteam/qmui/type/parser/PlainTextParser.kt +++ b/type/src/main/java/com/qmuiteam/qmui/type/parser/PlainTextParser.kt @@ -13,52 +13,53 @@ * either express or implied. See the License for the specific language governing permissions and * limitations under the License. */ +package com.qmuiteam.qmui.type.parser -package com.qmuiteam.qmui.type.parser; +import com.qmuiteam.qmui.type.TypeModel +import com.qmuiteam.qmui.type.element.Element +import com.qmuiteam.qmui.type.element.NextParagraphElement +import com.qmuiteam.qmui.type.element.TextElement +import com.qmuiteam.qmui.type.parser.ParserHelper.handleWordPart +import java.util.* -import com.qmuiteam.qmui.type.TypeModel; -import com.qmuiteam.qmui.type.element.CharOrPhraseElement; -import com.qmuiteam.qmui.type.element.Element; -import com.qmuiteam.qmui.type.element.NextParagraphElement; - -import java.util.HashMap; - -public class PlainTextParser implements TextParser { - @Override - public TypeModel parse(CharSequence text) { - if (text.length() == 0) { - return null; +class PlainTextParser : TextParser { + override fun parse(text: CharSequence?): TypeModel? { + if (text == null || text.isEmpty()) { + return null } - HashMap map = new HashMap<>(text.length()); - Element first = null, last = null, tmp; - int index = 0; - for (int i = 0; i < text.length(); i++) { - char c = text.charAt(i); + val size = text.length + val map = HashMap(size) + var first: Element? = null + var last: Element? = null + var tmp: Element + var index = 0 + var i = 0 + while (i < size) { + val c = text[i] if (c == '\n') { - tmp = new NextParagraphElement(c, null, index, i); + tmp = NextParagraphElement(text.subSequence(i, i+1), index, i) } else if (c == '\r') { - if (i + 1 < text.length() && text.charAt(i + 1) == '\n') { - tmp = new NextParagraphElement('\u0000', "\r\n", index, i); - i++; + if (i + 1 < text.length && text[i + 1] == '\n') { + tmp = NextParagraphElement(text.subSequence(i, i+2), index, i) + i++ } else { - tmp = new NextParagraphElement(c, null, index, i); + tmp = NextParagraphElement(text.subSequence(i, i+1), index, i) } } else { - tmp = new CharOrPhraseElement(c, index, i); + tmp = TextElement(text.subSequence(i, i+1), index, i) } - - ParserHelper.handleWordPart(c, last, tmp); - - index++; + handleWordPart(c, last, tmp) + index++ if (first == null) { - first = tmp; - last = tmp; + first = tmp + last = tmp } else { - last.setNext(tmp); - last = tmp; + last!!.next = tmp + last = tmp } - map.put(tmp.getIndex(), tmp); + map[tmp.index] = tmp + i++ } - return new TypeModel(text, map, first, last, null); + return TypeModel(text, map, first!!, last!!) } -} +} \ No newline at end of file diff --git a/type/src/main/java/com/qmuiteam/qmui/type/parser/TextParser.kt b/type/src/main/java/com/qmuiteam/qmui/type/parser/TextParser.kt index 61167d59..89c7eec1 100644 --- a/type/src/main/java/com/qmuiteam/qmui/type/parser/TextParser.kt +++ b/type/src/main/java/com/qmuiteam/qmui/type/parser/TextParser.kt @@ -13,11 +13,10 @@ * either express or implied. See the License for the specific language governing permissions and * limitations under the License. */ +package com.qmuiteam.qmui.type.parser -package com.qmuiteam.qmui.type.parser; +import com.qmuiteam.qmui.type.TypeModel -import com.qmuiteam.qmui.type.TypeModel; - -public interface TextParser { - TypeModel parse(CharSequence text); -} +interface TextParser { + fun parse(text: CharSequence?): TypeModel? +} \ No newline at end of file