You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
150 lines
4.5 KiB
Kotlin
150 lines
4.5 KiB
Kotlin
/*
|
|
* Copyright (c) 2023 to present Androidacy and contributors. Names, logos, icons, and the Androidacy name are all trademarks of Androidacy and may not be used without license. See LICENSE for more information.
|
|
*/
|
|
|
|
@file:Suppress("unused")
|
|
|
|
package com.fox2code.mmm.installer
|
|
|
|
import android.graphics.Typeface
|
|
import android.text.Spannable
|
|
import android.view.ViewGroup
|
|
import android.widget.TextView
|
|
import androidx.recyclerview.widget.LinearLayoutManager
|
|
import androidx.recyclerview.widget.RecyclerView
|
|
import com.fox2code.androidansi.AnsiContext
|
|
import com.fox2code.mmm.installer.InstallerTerminal.TextViewHolder
|
|
|
|
class InstallerTerminal(
|
|
recyclerView: RecyclerView, isLightTheme: Boolean,
|
|
foreground: Int, mmtReborn: Boolean
|
|
) : RecyclerView.Adapter<TextViewHolder>() {
|
|
private val recyclerView: RecyclerView
|
|
private val terminal: ArrayList<ProcessedLine>
|
|
private val ansiContext: AnsiContext
|
|
private val lock = Any()
|
|
private val foreground: Int
|
|
private val mmtReborn: Boolean
|
|
var isAnsiEnabled = false
|
|
private set
|
|
|
|
init {
|
|
recyclerView.layoutManager = LinearLayoutManager(recyclerView.context)
|
|
this.recyclerView = recyclerView
|
|
this.foreground = foreground
|
|
this.mmtReborn = mmtReborn
|
|
terminal = ArrayList()
|
|
ansiContext = (if (isLightTheme) AnsiContext.LIGHT else AnsiContext.DARK).copy()
|
|
this.recyclerView.adapter = this
|
|
}
|
|
|
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TextViewHolder {
|
|
return TextViewHolder(TextView(parent.context), foreground)
|
|
}
|
|
|
|
override fun onBindViewHolder(holder: TextViewHolder, position: Int) {
|
|
terminal[position].setText(holder.textView)
|
|
}
|
|
|
|
override fun getItemCount(): Int {
|
|
return terminal.size
|
|
}
|
|
|
|
fun addLine(line: String) {
|
|
synchronized(lock) {
|
|
val bottom = !recyclerView.canScrollVertically(1)
|
|
val index = terminal.size
|
|
terminal.add(process(line))
|
|
notifyItemInserted(index)
|
|
if (bottom) recyclerView.scrollToPosition(index)
|
|
}
|
|
}
|
|
|
|
var lastLine: String
|
|
get() {
|
|
synchronized(lock) {
|
|
val size = terminal.size
|
|
return if (size == 0) "" else terminal[size - 1].line
|
|
}
|
|
}
|
|
set(line) {
|
|
synchronized(lock) {
|
|
val size = terminal.size
|
|
if (size == 0) {
|
|
terminal.add(process(line))
|
|
notifyItemInserted(0)
|
|
} else {
|
|
terminal[size - 1] = process(line)
|
|
this.notifyItemChanged(size - 1)
|
|
}
|
|
}
|
|
}
|
|
|
|
fun removeLastLine() {
|
|
synchronized(lock) {
|
|
val size = terminal.size
|
|
if (size != 0) {
|
|
terminal.removeAt(size - 1)
|
|
notifyItemRemoved(size - 1)
|
|
}
|
|
}
|
|
}
|
|
|
|
fun clearTerminal() {
|
|
synchronized(lock) {
|
|
val size = terminal.size
|
|
if (size != 0) {
|
|
terminal.clear()
|
|
notifyItemRangeRemoved(0, size)
|
|
}
|
|
}
|
|
}
|
|
|
|
fun scrollUp() {
|
|
synchronized(lock) { recyclerView.scrollToPosition(0) }
|
|
}
|
|
|
|
fun scrollDown() {
|
|
synchronized(lock) { recyclerView.scrollToPosition(terminal.size - 1) }
|
|
}
|
|
|
|
fun enableAnsi() {
|
|
isAnsiEnabled = true
|
|
}
|
|
|
|
fun disableAnsi() {
|
|
isAnsiEnabled = false
|
|
ansiContext.reset()
|
|
}
|
|
|
|
private fun process(line: String): ProcessedLine {
|
|
@Suppress("NAME_SHADOWING") var line = line
|
|
if (line.isEmpty()) return ProcessedLine(" ", null)
|
|
if (mmtReborn) {
|
|
if (line.startsWith("- ")) {
|
|
line = "[*] " + line.substring(2)
|
|
} else if (line.startsWith("! ")) {
|
|
line = "[!] " + line.substring(2)
|
|
}
|
|
}
|
|
return ProcessedLine(line, if (isAnsiEnabled) ansiContext.parseAsSpannable(line) else null)
|
|
}
|
|
|
|
class TextViewHolder(val textView: TextView, foreground: Int) : RecyclerView.ViewHolder(
|
|
textView
|
|
) {
|
|
init {
|
|
textView.typeface = Typeface.MONOSPACE
|
|
textView.setTextColor(foreground)
|
|
textView.textSize = 12f
|
|
textView.setLines(1)
|
|
textView.text = " "
|
|
}
|
|
}
|
|
|
|
private class ProcessedLine(val line: String, val spannable: Spannable?) {
|
|
fun setText(textView: TextView) {
|
|
textView.text = spannable ?: line
|
|
}
|
|
}
|
|
} |