|
|
|
@ -43,6 +43,7 @@ class RecyclerViewThreadLines(context: Context, private val lineInfoList: List<L
|
|
|
|
|
|
|
|
|
|
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
|
|
|
|
|
val position = parent.getChildAdapterPosition(view)
|
|
|
|
|
if (position < 0) return
|
|
|
|
|
val level = lineInfoList[position].level
|
|
|
|
|
val startMargin = margin * level + margin * fontScale
|
|
|
|
|
if (parent.layoutDirection == View.LAYOUT_DIRECTION_LTR) outRect.left = startMargin else outRect.right = startMargin
|
|
|
|
@ -53,6 +54,7 @@ class RecyclerViewThreadLines(context: Context, private val lineInfoList: List<L
|
|
|
|
|
for (i in 0 until childCount) {
|
|
|
|
|
val view = parent.getChildAt(i)
|
|
|
|
|
val position = parent.getChildAdapterPosition(view)
|
|
|
|
|
if (position < 0) return
|
|
|
|
|
val lineInfo = lineInfoList[position]
|
|
|
|
|
val level = lineInfo.level
|
|
|
|
|
|
|
|
|
@ -64,11 +66,11 @@ class RecyclerViewThreadLines(context: Context, private val lineInfoList: List<L
|
|
|
|
|
paint.color = if (j > 0) lineColors[j - 1] else Color.GRAY
|
|
|
|
|
|
|
|
|
|
// draw lines for below statuses
|
|
|
|
|
if (j != level && j >= lineInfo.fullLinesStart && j <= lineInfo.fullLinesEnd)
|
|
|
|
|
if (j != level && lineInfo.lines.contains(j))
|
|
|
|
|
c.drawLine(lineStart, lineTop, lineStart, view.bottom.toFloat(), paint)
|
|
|
|
|
|
|
|
|
|
// draw vertical line for current statuses
|
|
|
|
|
if (j == level && i != 0) {
|
|
|
|
|
if (j == level && position != 0) {
|
|
|
|
|
// top the line starts at the middle of the above status
|
|
|
|
|
if (i > 0) lineTop -= parent.getChildAt(i - 1).height / 2 - 1 // '- 1' is to prevent overlapping with above horizontal line
|
|
|
|
|
|
|
|
|
@ -76,12 +78,8 @@ class RecyclerViewThreadLines(context: Context, private val lineInfoList: List<L
|
|
|
|
|
var lineBottom = view.bottom.toFloat() - view.height / 2
|
|
|
|
|
|
|
|
|
|
// if below status has a full line for current level, extend the line to the bottom
|
|
|
|
|
if (i < lineInfoList.lastIndex - 1) {
|
|
|
|
|
val nextLineInfo = lineInfoList[i + 1]
|
|
|
|
|
if (level >= nextLineInfo.fullLinesStart && level <= nextLineInfo.fullLinesEnd) {
|
|
|
|
|
lineBottom = view.bottom.toFloat()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (position < lineInfoList.lastIndex && lineInfoList[position + 1].lines.contains(level) && j != maxLevel)
|
|
|
|
|
lineBottom = view.bottom.toFloat()
|
|
|
|
|
|
|
|
|
|
// if level is max, use a dashed line
|
|
|
|
|
if (j == maxLevel) paint.pathEffect = dashPathEffect
|
|
|
|
@ -99,7 +97,7 @@ class RecyclerViewThreadLines(context: Context, private val lineInfoList: List<L
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data class LineInfo(var level: Int, var end: Boolean, var fullLinesStart: Int, var fullLinesEnd: Int)
|
|
|
|
|
data class LineInfo(var level: Int, var lines: List<Int>)
|
|
|
|
|
|
|
|
|
|
private val Int.dpToPx: Float
|
|
|
|
|
get() = this * Resources.getSystem().displayMetrics.density
|
|
|
|
@ -112,43 +110,33 @@ class RecyclerViewThreadLines(context: Context, private val lineInfoList: List<L
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun getThreadDecorationInfo(fediContext: StatusContext, selectedStatusId: String): MutableList<LineInfo> {
|
|
|
|
|
fun getThreadDecorationInfo(statusContext: StatusContext): MutableList<LineInfo> {
|
|
|
|
|
val lineInfoList = mutableListOf<LineInfo>()
|
|
|
|
|
repeat(fediContext.ancestors.size) { lineInfoList.add(LineInfo(0, true, 0, 0)) }
|
|
|
|
|
lineInfoList.add(LineInfo(0, fediContext.descendants.isNotEmpty(), 0, 0))
|
|
|
|
|
val descendantsLineInfoList = List(fediContext.descendants.size) { LineInfo(0, false, 0, 0) }
|
|
|
|
|
for (i in fediContext.descendants.indices) {
|
|
|
|
|
fediContext.descendants[i].let { status ->
|
|
|
|
|
repeat(statusContext.ancestors.size) { lineInfoList.add(LineInfo(0, listOf(0))) }
|
|
|
|
|
lineInfoList.add(LineInfo(0, listOf(0)))
|
|
|
|
|
val descendantsLineInfoList = List(statusContext.descendants.size) { LineInfo(0, listOf()) }
|
|
|
|
|
for (i in statusContext.descendants.indices) {
|
|
|
|
|
statusContext.descendants[i].let { status ->
|
|
|
|
|
var level = 0
|
|
|
|
|
if (status.in_reply_to_id != null) {
|
|
|
|
|
if (status.in_reply_to_id == selectedStatusId)
|
|
|
|
|
level = 1
|
|
|
|
|
else {
|
|
|
|
|
var replyToId: String? = status.in_reply_to_id
|
|
|
|
|
while (replyToId != null && level < RecyclerViewThreadLines.threadLineColors.size) {
|
|
|
|
|
level += 1
|
|
|
|
|
replyToId = fediContext.descendants.firstOrNull { it.id == replyToId }?.in_reply_to_id
|
|
|
|
|
}
|
|
|
|
|
var replyToId: String? = status.in_reply_to_id
|
|
|
|
|
while (replyToId != null && level < RecyclerViewThreadLines.threadLineColors.size) {
|
|
|
|
|
level += 1
|
|
|
|
|
replyToId = statusContext.descendants.firstOrNull { it.id == replyToId }?.in_reply_to_id
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
descendantsLineInfoList[i].level = level
|
|
|
|
|
val firstReply = fediContext.descendants.firstOrNull { it.in_reply_to_id == status.id }
|
|
|
|
|
if (firstReply == null) descendantsLineInfoList[i].end = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (i in descendantsLineInfoList.indices) {
|
|
|
|
|
var fullLinesStart = descendantsLineInfoList[i].level
|
|
|
|
|
var fullLinesEnd = descendantsLineInfoList[i].level
|
|
|
|
|
var fullLinesEndSet = false
|
|
|
|
|
for (j in i + 1 until descendantsLineInfoList.lastIndex) {
|
|
|
|
|
if (!fullLinesEndSet && descendantsLineInfoList[j].level < descendantsLineInfoList[i].level) {
|
|
|
|
|
fullLinesEnd = descendantsLineInfoList[j].level
|
|
|
|
|
fullLinesEndSet = true
|
|
|
|
|
}
|
|
|
|
|
fullLinesStart = descendantsLineInfoList[j].level.coerceAtMost(fullLinesStart)
|
|
|
|
|
for (i in descendantsLineInfoList.indices.reversed()) {
|
|
|
|
|
val lines: MutableList<Int> = mutableListOf()
|
|
|
|
|
val lineInfo = descendantsLineInfoList[i]
|
|
|
|
|
lines.add(lineInfo.level)
|
|
|
|
|
if (i < descendantsLineInfoList.lastIndex) {
|
|
|
|
|
val belowLineInfo = descendantsLineInfoList[i + 1]
|
|
|
|
|
lines.addAll(belowLineInfo.lines.filter { it < lineInfo.level })
|
|
|
|
|
}
|
|
|
|
|
descendantsLineInfoList[i].fullLinesStart = fullLinesStart
|
|
|
|
|
descendantsLineInfoList[i].fullLinesEnd = fullLinesEnd
|
|
|
|
|
descendantsLineInfoList[i].lines = lines
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lineInfoList.addAll(descendantsLineInfoList)
|
|
|
|
|