MISC: enhance code step 1
This commit is contained in:
parent
2dbc16cc68
commit
cc1fe9de00
@ -44,6 +44,9 @@ android {
|
|||||||
targetCompatibility 1.8
|
targetCompatibility 1.8
|
||||||
sourceCompatibility 1.8
|
sourceCompatibility 1.8
|
||||||
}
|
}
|
||||||
|
kotlinOptions {
|
||||||
|
freeCompilerArgs = ["-Xallow-result-return-type"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -9,10 +9,9 @@ import io.neoterm.frontend.component.ComponentManager
|
|||||||
import io.neoterm.frontend.component.helper.ConfigFileBasedComponent
|
import io.neoterm.frontend.component.helper.ConfigFileBasedComponent
|
||||||
import io.neoterm.frontend.config.NeoPreference
|
import io.neoterm.frontend.config.NeoPreference
|
||||||
import io.neoterm.frontend.config.NeoTermPath
|
import io.neoterm.frontend.config.NeoTermPath
|
||||||
import io.neoterm.frontend.logging.NLog
|
|
||||||
import io.neoterm.frontend.terminal.TerminalView
|
import io.neoterm.frontend.terminal.TerminalView
|
||||||
import io.neoterm.frontend.terminal.extrakey.ExtraKeysView
|
import io.neoterm.frontend.terminal.extrakey.ExtraKeysView
|
||||||
import io.neoterm.utils.AssetsUtils
|
import io.neoterm.utils.extractAssetsDir
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
|
|
||||||
@ -103,15 +102,8 @@ class ColorSchemeComponent : ConfigFileBasedComponent<NeoColorScheme>(NeoTermPat
|
|||||||
setCurrentColorScheme(color.colorName)
|
setCurrentColorScheme(color.colorName)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun extractDefaultColor(context: Context): Boolean {
|
private fun extractDefaultColor(context: Context) =
|
||||||
try {
|
kotlin.runCatching { context.extractAssetsDir("colors", baseDir) }.isSuccess
|
||||||
AssetsUtils.extractAssetsDir(context, "colors", baseDir)
|
|
||||||
return true
|
|
||||||
} catch (e: Exception) {
|
|
||||||
NLog.e("ColorScheme", "Failed to extract default colors: ${e.localizedMessage}")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun saveColorScheme(colorScheme: NeoColorScheme) {
|
fun saveColorScheme(colorScheme: NeoColorScheme) {
|
||||||
val colorFile = colorFile(colorScheme.colorName)
|
val colorFile = colorFile(colorScheme.colorName)
|
||||||
|
@ -7,7 +7,7 @@ import io.neoterm.frontend.component.helper.ConfigFileBasedComponent
|
|||||||
import io.neoterm.frontend.config.NeoTermPath
|
import io.neoterm.frontend.config.NeoTermPath
|
||||||
import io.neoterm.frontend.logging.NLog
|
import io.neoterm.frontend.logging.NLog
|
||||||
import io.neoterm.frontend.terminal.extrakey.ExtraKeysView
|
import io.neoterm.frontend.terminal.extrakey.ExtraKeysView
|
||||||
import io.neoterm.utils.AssetsUtils
|
import io.neoterm.utils.extractAssetsDir
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -52,7 +52,7 @@ class ExtraKeyComponent : ConfigFileBasedComponent<NeoExtraKey>(NeoTermPath.EKS_
|
|||||||
|
|
||||||
private fun extractDefaultConfig(context: Context) {
|
private fun extractDefaultConfig(context: Context) {
|
||||||
try {
|
try {
|
||||||
AssetsUtils.extractAssetsDir(context, "eks", baseDir)
|
context.extractAssetsDir("eks", baseDir)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
NLog.e("ExtraKey", "Failed to extract configure: ${e.localizedMessage}")
|
NLog.e("ExtraKey", "Failed to extract configure: ${e.localizedMessage}")
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ import io.neoterm.frontend.config.NeoPreference
|
|||||||
import io.neoterm.frontend.config.NeoTermPath
|
import io.neoterm.frontend.config.NeoTermPath
|
||||||
import io.neoterm.frontend.terminal.TerminalView
|
import io.neoterm.frontend.terminal.TerminalView
|
||||||
import io.neoterm.frontend.terminal.extrakey.ExtraKeysView
|
import io.neoterm.frontend.terminal.extrakey.ExtraKeysView
|
||||||
import io.neoterm.utils.AssetsUtils
|
import io.neoterm.utils.extractAssetsDir
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -90,7 +90,7 @@ class FontComponent : NeoComponent {
|
|||||||
|
|
||||||
private fun extractDefaultFont(context: Context): Boolean {
|
private fun extractDefaultFont(context: Context): Boolean {
|
||||||
try {
|
try {
|
||||||
AssetsUtils.extractAssetsDir(context, "fonts", NeoTermPath.FONT_PATH)
|
context.extractAssetsDir( "fonts", NeoTermPath.FONT_PATH)
|
||||||
return true
|
return true
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
return false
|
return false
|
||||||
|
@ -6,7 +6,7 @@ import io.neoterm.App
|
|||||||
import io.neoterm.frontend.component.NeoComponent
|
import io.neoterm.frontend.component.NeoComponent
|
||||||
import io.neoterm.frontend.config.NeoTermPath
|
import io.neoterm.frontend.config.NeoTermPath
|
||||||
import io.neoterm.frontend.logging.NLog
|
import io.neoterm.frontend.logging.NLog
|
||||||
import io.neoterm.utils.AssetsUtils
|
import io.neoterm.utils.extractAssetsDir
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -28,7 +28,7 @@ class UserScriptComponent : NeoComponent {
|
|||||||
|
|
||||||
private fun extractDefaultScript(context: Context): Boolean {
|
private fun extractDefaultScript(context: Context): Boolean {
|
||||||
try {
|
try {
|
||||||
AssetsUtils.extractAssetsDir(context, "scripts", NeoTermPath.USER_SCRIPT_PATH)
|
context.extractAssetsDir( "scripts", NeoTermPath.USER_SCRIPT_PATH)
|
||||||
File(NeoTermPath.USER_SCRIPT_PATH)
|
File(NeoTermPath.USER_SCRIPT_PATH)
|
||||||
.listFiles().forEach {
|
.listFiles().forEach {
|
||||||
Os.chmod(it.absolutePath, 448 /*Dec of 0700*/)
|
Os.chmod(it.absolutePath, 448 /*Dec of 0700*/)
|
||||||
|
@ -9,7 +9,7 @@ import io.neoterm.frontend.session.shell.ShellParameter
|
|||||||
import io.neoterm.frontend.session.shell.ShellTermSession
|
import io.neoterm.frontend.session.shell.ShellTermSession
|
||||||
import io.neoterm.frontend.session.shell.client.BasicSessionCallback
|
import io.neoterm.frontend.session.shell.client.BasicSessionCallback
|
||||||
import io.neoterm.frontend.session.shell.client.BasicViewClient
|
import io.neoterm.frontend.session.shell.client.BasicViewClient
|
||||||
import io.neoterm.utils.TerminalUtils
|
import io.neoterm.utils.Terminals
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author kiva
|
* @author kiva
|
||||||
@ -56,7 +56,7 @@ class TerminalDialog(val context: Context) {
|
|||||||
.arguments(arguments)
|
.arguments(arguments)
|
||||||
.callback(terminalSessionCallback)
|
.callback(terminalSessionCallback)
|
||||||
.systemShell(false)
|
.systemShell(false)
|
||||||
terminalSession = TerminalUtils.createSession(context, parameter)
|
terminalSession = Terminals.createSession(context, parameter)
|
||||||
if (terminalSession is ShellTermSession) {
|
if (terminalSession is ShellTermSession) {
|
||||||
(terminalSession as ShellTermSession).exitPrompt = context.getString(R.string.process_exit_prompt_press_back)
|
(terminalSession as ShellTermSession).exitPrompt = context.getString(R.string.process_exit_prompt_press_back)
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import io.neoterm.R
|
|||||||
import io.neoterm.backend.TerminalSession
|
import io.neoterm.backend.TerminalSession
|
||||||
import io.neoterm.frontend.terminal.TerminalView
|
import io.neoterm.frontend.terminal.TerminalView
|
||||||
import io.neoterm.frontend.terminal.TerminalViewClient
|
import io.neoterm.frontend.terminal.TerminalViewClient
|
||||||
import io.neoterm.utils.TerminalUtils
|
import io.neoterm.utils.Terminals
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author kiva
|
* @author kiva
|
||||||
@ -21,7 +21,7 @@ class WindowTermView(val context: Context) {
|
|||||||
private set
|
private set
|
||||||
|
|
||||||
init {
|
init {
|
||||||
TerminalUtils.setupTerminalView(terminalView)
|
Terminals.setupTerminalView(terminalView)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setTerminalViewClient(terminalViewClient: TerminalViewClient?) {
|
fun setTerminalViewClient(terminalViewClient: TerminalViewClient?) {
|
||||||
|
@ -19,7 +19,7 @@ import io.neoterm.frontend.session.shell.ShellParameter
|
|||||||
import io.neoterm.frontend.session.xorg.XParameter
|
import io.neoterm.frontend.session.xorg.XParameter
|
||||||
import io.neoterm.frontend.session.xorg.XSession
|
import io.neoterm.frontend.session.xorg.XSession
|
||||||
import io.neoterm.ui.term.NeoTermActivity
|
import io.neoterm.ui.term.NeoTermActivity
|
||||||
import io.neoterm.utils.TerminalUtils
|
import io.neoterm.utils.Terminals
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -94,7 +94,7 @@ class NeoTermService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createXSession(activity: AppCompatActivity, parameter: XParameter): XSession {
|
fun createXSession(activity: AppCompatActivity, parameter: XParameter): XSession {
|
||||||
val session = TerminalUtils.createSession(activity, parameter)
|
val session = Terminals.createSession(activity, parameter)
|
||||||
mXSessions.add(session)
|
mXSessions.add(session)
|
||||||
updateNotification()
|
updateNotification()
|
||||||
return session
|
return session
|
||||||
@ -112,7 +112,7 @@ class NeoTermService : Service() {
|
|||||||
private fun createOrFindSession(parameter: ShellParameter): TerminalSession {
|
private fun createOrFindSession(parameter: ShellParameter): TerminalSession {
|
||||||
if (parameter.willCreateNewSession()) {
|
if (parameter.willCreateNewSession()) {
|
||||||
NLog.d("createOrFindSession: creating new session")
|
NLog.d("createOrFindSession: creating new session")
|
||||||
val session = TerminalUtils.createSession(this, parameter)
|
val session = Terminals.createSession(this, parameter)
|
||||||
mTerminalSessions.add(session)
|
mTerminalSessions.add(session)
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ import io.neoterm.frontend.session.shell.client.BasicSessionCallback
|
|||||||
import io.neoterm.frontend.session.shell.client.BasicViewClient
|
import io.neoterm.frontend.session.shell.client.BasicViewClient
|
||||||
import io.neoterm.frontend.terminal.TerminalView
|
import io.neoterm.frontend.terminal.TerminalView
|
||||||
import io.neoterm.frontend.terminal.extrakey.ExtraKeysView
|
import io.neoterm.frontend.terminal.extrakey.ExtraKeysView
|
||||||
import io.neoterm.utils.TerminalUtils
|
import io.neoterm.utils.Terminals
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author kiva
|
* @author kiva
|
||||||
@ -36,8 +36,8 @@ open class BaseCustomizeActivity : AppCompatActivity() {
|
|||||||
extraKeysView = findViewById(R.id.custom_extra_keys)
|
extraKeysView = findViewById(R.id.custom_extra_keys)
|
||||||
viewClient = BasicViewClient(terminalView)
|
viewClient = BasicViewClient(terminalView)
|
||||||
sessionCallback = BasicSessionCallback(terminalView)
|
sessionCallback = BasicSessionCallback(terminalView)
|
||||||
TerminalUtils.setupTerminalView(terminalView, viewClient)
|
Terminals.setupTerminalView(terminalView, viewClient)
|
||||||
TerminalUtils.setupExtraKeysView(extraKeysView)
|
Terminals.setupExtraKeysView(extraKeysView)
|
||||||
|
|
||||||
val script = resources.getStringArray(R.array.custom_preview_script_colors)
|
val script = resources.getStringArray(R.array.custom_preview_script_colors)
|
||||||
val parameter = ShellParameter()
|
val parameter = ShellParameter()
|
||||||
@ -46,7 +46,7 @@ open class BaseCustomizeActivity : AppCompatActivity() {
|
|||||||
.callback(sessionCallback)
|
.callback(sessionCallback)
|
||||||
.systemShell(false)
|
.systemShell(false)
|
||||||
|
|
||||||
session = TerminalUtils.createSession(this, parameter)
|
session = Terminals.createSession(this, parameter)
|
||||||
terminalView.attachSession(session)
|
terminalView.attachSession(session)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ import io.neoterm.frontend.component.ComponentManager
|
|||||||
import io.neoterm.frontend.terminal.TerminalView
|
import io.neoterm.frontend.terminal.TerminalView
|
||||||
import io.neoterm.ui.customize.adapter.ColorItemAdapter
|
import io.neoterm.ui.customize.adapter.ColorItemAdapter
|
||||||
import io.neoterm.ui.customize.model.ColorItem
|
import io.neoterm.ui.customize.model.ColorItem
|
||||||
import io.neoterm.utils.TerminalUtils
|
import io.neoterm.utils.Terminals
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,7 +51,7 @@ class ColorSchemeActivity : BaseCustomizeActivity() {
|
|||||||
editingColorScheme.colorName = ""
|
editingColorScheme.colorName = ""
|
||||||
|
|
||||||
val terminalView = findViewById<TerminalView>(R.id.terminal_view)
|
val terminalView = findViewById<TerminalView>(R.id.terminal_view)
|
||||||
TerminalUtils.setupTerminalView(terminalView, null)
|
Terminals.setupTerminalView(terminalView, null)
|
||||||
|
|
||||||
adapter = ColorItemAdapter(this, editingColorScheme, COMPARATOR, object : ColorItemAdapter.Listener {
|
adapter = ColorItemAdapter(this, editingColorScheme, COMPARATOR, object : ColorItemAdapter.Listener {
|
||||||
override fun onModelClicked(model: ColorItem) {
|
override fun onModelClicked(model: ColorItem) {
|
||||||
|
@ -13,7 +13,7 @@ import io.neoterm.component.colorscheme.ColorSchemeComponent
|
|||||||
import io.neoterm.component.font.FontComponent
|
import io.neoterm.component.font.FontComponent
|
||||||
import io.neoterm.frontend.component.ComponentManager
|
import io.neoterm.frontend.component.ComponentManager
|
||||||
import io.neoterm.frontend.config.NeoTermPath
|
import io.neoterm.frontend.config.NeoTermPath
|
||||||
import io.neoterm.utils.MediaUtils
|
import io.neoterm.utils.getPathOfMediaUri
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
@ -114,7 +114,7 @@ class CustomizeActivity : BaseCustomizeActivity() {
|
|||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
if (resultCode == RESULT_OK && data != null) {
|
if (resultCode == RESULT_OK && data != null) {
|
||||||
val selected = MediaUtils.getPath(this, data.data)
|
val selected = this.getPathOfMediaUri( data.data)
|
||||||
if (selected != null && selected.isNotEmpty()) {
|
if (selected != null && selected.isNotEmpty()) {
|
||||||
when (requestCode) {
|
when (requestCode) {
|
||||||
REQUEST_SELECT_FONT -> installFont(selected)
|
REQUEST_SELECT_FONT -> installFont(selected)
|
||||||
|
@ -25,7 +25,8 @@ import io.neoterm.frontend.floating.TerminalDialog
|
|||||||
import io.neoterm.ui.pm.adapter.PackageAdapter
|
import io.neoterm.ui.pm.adapter.PackageAdapter
|
||||||
import io.neoterm.ui.pm.model.PackageModel
|
import io.neoterm.ui.pm.model.PackageModel
|
||||||
import io.neoterm.ui.pm.utils.StringDistance
|
import io.neoterm.ui.pm.utils.StringDistance
|
||||||
import io.neoterm.utils.PackageUtils
|
import io.neoterm.utils.runApt
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author kiva
|
* @author kiva
|
||||||
@ -178,67 +179,64 @@ class PackageManagerActivity : AppCompatActivity(), SearchView.OnQueryTextListen
|
|||||||
executeAptUpdate()
|
executeAptUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun executeAptUpdate() {
|
private fun executeAptUpdate() = runApt("update", null) { exitStatus, dialog ->
|
||||||
PackageUtils.apt(this, "update", null, { exitStatus, dialog ->
|
if (exitStatus != 0) {
|
||||||
if (exitStatus != 0) {
|
dialog.setTitle(getString(R.string.error))
|
||||||
dialog.setTitle(getString(R.string.error))
|
return@runApt
|
||||||
return@apt
|
}
|
||||||
}
|
Toast.makeText(this, R.string.apt_update_ok, Toast.LENGTH_SHORT).show()
|
||||||
Toast.makeText(this, R.string.apt_update_ok, Toast.LENGTH_SHORT).show()
|
dialog.dismiss()
|
||||||
dialog.dismiss()
|
refreshPackageList()
|
||||||
refreshPackageList()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun executeAptUpgrade() {
|
private fun executeAptUpgrade() = runApt("update", null) { exitStatus, dialog ->
|
||||||
PackageUtils.apt(this, "update", null, { exitStatus, dialog ->
|
if (exitStatus != 0) {
|
||||||
|
dialog.setTitle(getString(R.string.error))
|
||||||
|
return@runApt
|
||||||
|
}
|
||||||
|
dialog.dismiss()
|
||||||
|
|
||||||
|
runApt("upgrade", arrayOf("-y")) aptUpgrade@{ exitStatus, dialog ->
|
||||||
if (exitStatus != 0) {
|
if (exitStatus != 0) {
|
||||||
dialog.setTitle(getString(R.string.error))
|
dialog.setTitle(getString(R.string.error))
|
||||||
return@apt
|
return@aptUpgrade
|
||||||
}
|
}
|
||||||
|
Toast.makeText(this, R.string.apt_upgrade_ok, Toast.LENGTH_SHORT).show()
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
|
}
|
||||||
PackageUtils.apt(this, "upgrade", arrayOf("-y"), out@{ exitStatus, dialog ->
|
|
||||||
if (exitStatus != 0) {
|
|
||||||
dialog.setTitle(getString(R.string.error))
|
|
||||||
return@out
|
|
||||||
}
|
|
||||||
Toast.makeText(this, R.string.apt_upgrade_ok, Toast.LENGTH_SHORT).show()
|
|
||||||
dialog.dismiss()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun refreshPackageList() {
|
private fun refreshPackageList() = Thread {
|
||||||
models.clear()
|
models.clear()
|
||||||
Thread {
|
val pm = ComponentManager.getComponent<PackageComponent>()
|
||||||
val pm = ComponentManager.getComponent<PackageComponent>()
|
val sourceFiles = SourceHelper.detectSourceFiles()
|
||||||
val sourceFiles = SourceHelper.detectSourceFiles()
|
|
||||||
|
|
||||||
pm.clearPackages()
|
pm.clearPackages()
|
||||||
sourceFiles.forEach { pm.reloadPackages(it, false) }
|
sourceFiles.forEach { pm.reloadPackages(it, false) }
|
||||||
pm.packages.values.mapTo(models, { PackageModel(it) })
|
pm.packages.values.mapTo(models, { PackageModel(it) })
|
||||||
|
|
||||||
this@PackageManagerActivity.runOnUiThread {
|
this@PackageManagerActivity.runOnUiThread {
|
||||||
adapter.edit()
|
adapter.edit()
|
||||||
.replaceAll(models)
|
.replaceAll(models)
|
||||||
.commit()
|
.commit()
|
||||||
if (models.isEmpty()) {
|
if (models.isEmpty()) {
|
||||||
Toast.makeText(this@PackageManagerActivity, R.string.package_list_empty, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this@PackageManagerActivity, R.string.package_list_empty, Toast.LENGTH_SHORT).show()
|
||||||
changeSource()
|
changeSource()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}.start()
|
}
|
||||||
}
|
}.start()
|
||||||
|
|
||||||
private fun sortDistance(
|
private fun sortDistance(
|
||||||
models: List<PackageModel>, query: String,
|
models: List<PackageModel>, query: String,
|
||||||
mapper: (NeoPackageInfo) -> String
|
mapper: (NeoPackageInfo) -> String
|
||||||
): List<Pair<PackageModel, Int>> {
|
): List<Pair<PackageModel, Int>> {
|
||||||
return models
|
return models
|
||||||
.map({
|
.map {
|
||||||
Pair(it, StringDistance.distance(mapper(it.packageInfo).toLowerCase(), query.toLowerCase()))
|
Pair(
|
||||||
})
|
it,
|
||||||
|
StringDistance.distance(mapper(it.packageInfo).toLowerCase(Locale.ROOT), query.toLowerCase(Locale.ROOT))
|
||||||
|
)
|
||||||
|
}
|
||||||
.sortedWith(Comparator { l, r -> r.second.compareTo(l.second) })
|
.sortedWith(Comparator { l, r -> r.second.compareTo(l.second) })
|
||||||
.toList()
|
.toList()
|
||||||
}
|
}
|
||||||
@ -255,17 +253,10 @@ class PackageManagerActivity : AppCompatActivity(), SearchView.OnQueryTextListen
|
|||||||
return filteredModelList
|
return filteredModelList
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onQueryTextSubmit(text: String?): Boolean {
|
override fun onQueryTextSubmit(text: String?) = false
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onQueryTextChange(text: String?): Boolean {
|
override fun onQueryTextChange(text: String?): Boolean {
|
||||||
if (text != null) {
|
text?.let { adapter.edit().replaceAll(filter(models, it)).commit() }
|
||||||
val filteredModelList = filter(models, text)
|
|
||||||
adapter.edit()
|
|
||||||
.replaceAll(filteredModelList)
|
|
||||||
.commit()
|
|
||||||
}
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import com.github.wrdlbrnft.sortedlistadapter.SortedListAdapter
|
|||||||
import io.neoterm.R
|
import io.neoterm.R
|
||||||
|
|
||||||
import io.neoterm.component.pm.NeoPackageInfo
|
import io.neoterm.component.pm.NeoPackageInfo
|
||||||
import io.neoterm.utils.FileUtils
|
import io.neoterm.utils.formatSizeInKB
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author kiva
|
* @author kiva
|
||||||
@ -28,7 +28,7 @@ class PackageModel(val packageInfo: NeoPackageInfo) : SortedListAdapter.ViewMode
|
|||||||
R.string.package_details,
|
R.string.package_details,
|
||||||
packageInfo.packageName, packageInfo.version,
|
packageInfo.packageName, packageInfo.version,
|
||||||
packageInfo.dependenciesString,
|
packageInfo.dependenciesString,
|
||||||
FileUtils.formatSizeInKB(packageInfo.installedSizeInBytes),
|
packageInfo.installedSizeInBytes.formatSizeInKB(),
|
||||||
packageInfo.description, packageInfo.homePage
|
packageInfo.description, packageInfo.homePage
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import android.view.MenuItem
|
|||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import io.neoterm.R
|
import io.neoterm.R
|
||||||
import io.neoterm.frontend.config.NeoPreference
|
import io.neoterm.frontend.config.NeoPreference
|
||||||
import io.neoterm.utils.PackageUtils
|
import io.neoterm.utils.runApt
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author kiva
|
* @author kiva
|
||||||
@ -39,16 +39,14 @@ class GeneralSettingsActivity : BasePreferenceActivity() {
|
|||||||
AlertDialog.Builder(this)
|
AlertDialog.Builder(this)
|
||||||
.setTitle(getString(R.string.shell_not_found, shellName))
|
.setTitle(getString(R.string.shell_not_found, shellName))
|
||||||
.setMessage(R.string.shell_not_found_message)
|
.setMessage(R.string.shell_not_found_message)
|
||||||
.setPositiveButton(R.string.install, { _, _ ->
|
.setPositiveButton(R.string.install) { _, _ ->
|
||||||
PackageUtils.apt(this, "install", arrayOf("-y", shellName), { exitStatus, dialog ->
|
runApt("install", arrayOf("-y", shellName)) { exitStatus, dialog ->
|
||||||
if (exitStatus == 0) {
|
if (exitStatus == 0) {
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
postChangeShell(shellName)
|
postChangeShell(shellName)
|
||||||
} else {
|
} else dialog.setTitle(getString(R.string.error))
|
||||||
dialog.setTitle(getString(R.string.error))
|
}
|
||||||
}
|
}
|
||||||
})
|
|
||||||
})
|
|
||||||
.setNegativeButton(android.R.string.no, null)
|
.setNegativeButton(android.R.string.no, null)
|
||||||
.setOnDismissListener {
|
.setOnDismissListener {
|
||||||
postChangeShell(currentShell)
|
postChangeShell(currentShell)
|
||||||
|
@ -19,8 +19,8 @@ import io.neoterm.setup.SourceConnection
|
|||||||
import io.neoterm.setup.connections.BackupFileConnection
|
import io.neoterm.setup.connections.BackupFileConnection
|
||||||
import io.neoterm.setup.connections.LocalFileConnection
|
import io.neoterm.setup.connections.LocalFileConnection
|
||||||
import io.neoterm.setup.connections.NetworkConnection
|
import io.neoterm.setup.connections.NetworkConnection
|
||||||
import io.neoterm.utils.MediaUtils
|
import io.neoterm.utils.getPathOfMediaUri
|
||||||
import io.neoterm.utils.PackageUtils
|
import io.neoterm.utils.runApt
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
|
|
||||||
@ -32,7 +32,6 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener
|
|||||||
private const val REQUEST_SELECT_PARAMETER = 520;
|
private const val REQUEST_SELECT_PARAMETER = 520;
|
||||||
}
|
}
|
||||||
|
|
||||||
private var aptUpdated = false
|
|
||||||
private var setupParameter = ""
|
private var setupParameter = ""
|
||||||
private var setupParameterUri: Uri? = null
|
private var setupParameterUri: Uri? = null
|
||||||
|
|
||||||
@ -83,8 +82,7 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener
|
|||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
|
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
|
||||||
if (requestCode == REQUEST_SELECT_PARAMETER && resultCode == RESULT_OK) {
|
if (requestCode == REQUEST_SELECT_PARAMETER && resultCode == RESULT_OK) {
|
||||||
if (resultData != null) {
|
if (resultData != null) {
|
||||||
setupParameterUri = resultData.data
|
val path = this.getPathOfMediaUri(resultData.data)
|
||||||
val path = MediaUtils.getPath(this, setupParameterUri!!)
|
|
||||||
findViewById<EditText>(R.id.setup_source_parameter).setText(path)
|
findViewById<EditText>(R.id.setup_source_parameter).setText(path)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -236,26 +234,11 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun executeAptUpdate() {
|
private fun executeAptUpdate() = runApt("update")
|
||||||
PackageUtils.apt(this, "update", null) { exitStatus, dialog ->
|
.onSuccess { executeAptUpgrade() }
|
||||||
if (exitStatus == 0) {
|
.onFailure { Toast.makeText(this, R.string.error, Toast.LENGTH_SHORT).show() }
|
||||||
dialog.dismiss()
|
|
||||||
aptUpdated = true
|
|
||||||
executeAptUpgrade()
|
|
||||||
} else {
|
|
||||||
dialog.setTitle(getString(R.string.error))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun executeAptUpgrade() {
|
private fun executeAptUpgrade() = runApt("upgrade", "-y")
|
||||||
PackageUtils.apt(this, "upgrade", arrayOf("-y")) { exitStatus, dialog ->
|
.onSuccess { finish() }
|
||||||
if (exitStatus == 0) {
|
.onFailure { Toast.makeText(this, R.string.error, Toast.LENGTH_SHORT).show() }
|
||||||
dialog.dismiss()
|
|
||||||
finish()
|
|
||||||
} else {
|
|
||||||
dialog.setTitle(getString(R.string.error))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -777,9 +777,7 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
|
|||||||
}
|
}
|
||||||
|
|
||||||
val rangedInt = RangedInt(tabSwitcher.selectedTabIndex, (0 until tabSwitcher.count))
|
val rangedInt = RangedInt(tabSwitcher.selectedTabIndex, (0 until tabSwitcher.count))
|
||||||
val nextIndex = if (switchSessionEvent.toNext)
|
val nextIndex = if (switchSessionEvent.toNext) rangedInt.inc() else rangedInt.dec()
|
||||||
rangedInt.increaseOne()
|
|
||||||
else rangedInt.decreaseOne()
|
|
||||||
if (!tabSwitcher.isSwitcherShown) {
|
if (!tabSwitcher.isSwitcherShown) {
|
||||||
tabSwitcher.showSwitcher()
|
tabSwitcher.showSwitcher()
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,8 @@ import io.neoterm.frontend.config.NeoPreference
|
|||||||
import io.neoterm.frontend.session.shell.ShellParameter
|
import io.neoterm.frontend.session.shell.ShellParameter
|
||||||
import io.neoterm.frontend.session.shell.client.TermSessionCallback
|
import io.neoterm.frontend.session.shell.client.TermSessionCallback
|
||||||
import io.neoterm.services.NeoTermService
|
import io.neoterm.services.NeoTermService
|
||||||
import io.neoterm.utils.MediaUtils
|
import io.neoterm.utils.Terminals
|
||||||
import io.neoterm.utils.TerminalUtils
|
import io.neoterm.utils.getPathOfMediaUri
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -67,13 +67,10 @@ class NeoTermRemoteInterface : AppCompatActivity(), ServiceConnection {
|
|||||||
handleIntent()
|
handleIntent()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleIntent() {
|
private fun handleIntent() = when (intent.component?.className?.substringAfterLast('.')) {
|
||||||
val className = intent.component.className.substringAfterLast('.')
|
"TermHere" -> handleTermHere()
|
||||||
when (className) {
|
"UserScript" -> handleUserScript()
|
||||||
"TermHere" -> handleTermHere()
|
else -> handleNormal()
|
||||||
"UserScript" -> handleUserScript()
|
|
||||||
else -> handleNormal()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleNormal() {
|
private fun handleNormal() {
|
||||||
@ -98,12 +95,12 @@ class NeoTermRemoteInterface : AppCompatActivity(), ServiceConnection {
|
|||||||
|
|
||||||
private fun handleTermHere() {
|
private fun handleTermHere() {
|
||||||
if (intent.hasExtra(Intent.EXTRA_STREAM)) {
|
if (intent.hasExtra(Intent.EXTRA_STREAM)) {
|
||||||
val extra = intent.extras.get(Intent.EXTRA_STREAM)
|
val extra = intent.extras?.get(Intent.EXTRA_STREAM)
|
||||||
if (extra is Uri) {
|
if (extra is Uri) {
|
||||||
val path = MediaUtils.getPath(this, extra)
|
val path = this.getPathOfMediaUri(extra)
|
||||||
val file = File(path)
|
val file = File(path)
|
||||||
val dirPath = if (file.isDirectory) path else file.parent
|
val dirPath = if (file.isDirectory) path else file.parent
|
||||||
val command = "cd " + TerminalUtils.escapeString(dirPath)
|
val command = "cd " + Terminals.escapeString(dirPath)
|
||||||
openTerm(command, null)
|
openTerm(command, null)
|
||||||
}
|
}
|
||||||
finish()
|
finish()
|
||||||
@ -128,23 +125,23 @@ class NeoTermRemoteInterface : AppCompatActivity(), ServiceConnection {
|
|||||||
|
|
||||||
if (intent.hasExtra(Intent.EXTRA_STREAM)) {
|
if (intent.hasExtra(Intent.EXTRA_STREAM)) {
|
||||||
// action send
|
// action send
|
||||||
val extra = intent.extras.get(Intent.EXTRA_STREAM)
|
val extra = intent.extras?.get(Intent.EXTRA_STREAM)
|
||||||
|
|
||||||
when (extra) {
|
when (extra) {
|
||||||
is ArrayList<*> -> {
|
is ArrayList<*> -> {
|
||||||
extra.takeWhile { it is Uri }
|
extra.takeWhile { it is Uri }
|
||||||
.mapTo(filesToHandle) {
|
.mapTo(filesToHandle) {
|
||||||
val uri = it as Uri
|
val uri = it as Uri
|
||||||
File(MediaUtils.getPath(this, uri)).absolutePath
|
File(this.getPathOfMediaUri(uri)).absolutePath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is Uri -> {
|
is Uri -> {
|
||||||
filesToHandle.add(File(MediaUtils.getPath(this, extra)).absolutePath)
|
filesToHandle.add(File(this.getPathOfMediaUri(extra)).absolutePath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (intent.data != null) {
|
} else if (intent.data != null) {
|
||||||
// action view
|
// action view
|
||||||
filesToHandle.add(File(intent.data.path).absolutePath)
|
filesToHandle.add(File(intent.data?.path).absolutePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filesToHandle.isNotEmpty()) {
|
if (filesToHandle.isNotEmpty()) {
|
||||||
|
@ -23,7 +23,7 @@ import io.neoterm.frontend.session.shell.client.TermCompleteListener
|
|||||||
import io.neoterm.frontend.terminal.TerminalView
|
import io.neoterm.frontend.terminal.TerminalView
|
||||||
import io.neoterm.frontend.terminal.extrakey.ExtraKeysView
|
import io.neoterm.frontend.terminal.extrakey.ExtraKeysView
|
||||||
import io.neoterm.ui.term.NeoTermActivity
|
import io.neoterm.ui.term.NeoTermActivity
|
||||||
import io.neoterm.utils.TerminalUtils
|
import io.neoterm.utils.Terminals
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author kiva
|
* @author kiva
|
||||||
@ -43,8 +43,8 @@ class NeoTabDecorator(val context: NeoTermActivity) : TabSwitcherDecorator() {
|
|||||||
val view = inflater.inflate(R.layout.ui_term, parent, false)
|
val view = inflater.inflate(R.layout.ui_term, parent, false)
|
||||||
val terminalView = view.findViewById<TerminalView>(R.id.terminal_view)
|
val terminalView = view.findViewById<TerminalView>(R.id.terminal_view)
|
||||||
val extraKeysView = view.findViewById<ExtraKeysView>(R.id.extra_keys)
|
val extraKeysView = view.findViewById<ExtraKeysView>(R.id.extra_keys)
|
||||||
TerminalUtils.setupTerminalView(terminalView)
|
Terminals.setupTerminalView(terminalView)
|
||||||
TerminalUtils.setupExtraKeysView(extraKeysView)
|
Terminals.setupExtraKeysView(extraKeysView)
|
||||||
|
|
||||||
val colorSchemeManager = ComponentManager.getComponent<ColorSchemeComponent>()
|
val colorSchemeManager = ComponentManager.getComponent<ColorSchemeComponent>()
|
||||||
colorSchemeManager.applyColorScheme(
|
colorSchemeManager.applyColorScheme(
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
package io.neoterm.utils
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import java.io.File
|
|
||||||
import java.nio.file.Files
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author kiva
|
|
||||||
*/
|
|
||||||
object AssetsUtils {
|
|
||||||
fun extractAssetsDir(context: Context, dirName: String, extractDir: String) {
|
|
||||||
val assets = context.assets
|
|
||||||
assets.list(dirName)?.let {
|
|
||||||
it.map { File(extractDir, it) }
|
|
||||||
.takeWhile { !it.exists() }
|
|
||||||
.forEach { file ->
|
|
||||||
assets.open("$dirName/${file.name}").use {
|
|
||||||
kotlin.runCatching { Files.copy(it, file.toPath()) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
package io.neoterm.utils
|
|
||||||
|
|
||||||
import java.text.DecimalFormat
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author kiva
|
|
||||||
*/
|
|
||||||
object FileUtils {
|
|
||||||
fun formatSizeInKB(size: Long): String {
|
|
||||||
val decimalFormat = DecimalFormat("####.00");
|
|
||||||
if (size < 1024) {
|
|
||||||
return "$size KB"
|
|
||||||
} else if (size < 1024 * 1024) {
|
|
||||||
val parsedSize: Float = size / 1024f
|
|
||||||
return decimalFormat.format(parsedSize) + " MB"
|
|
||||||
} else if (size < 1024 * 1024 * 1024) {
|
|
||||||
val parsedSize: Float = size / 1024f / 1024f
|
|
||||||
return decimalFormat.format(parsedSize) + " GB"
|
|
||||||
} else if (size < 1024L * 1024 * 1024 * 1024) {
|
|
||||||
val parsedSize: Float = size / 1024f / 1024f / 1024f
|
|
||||||
return decimalFormat.format(parsedSize) + " TB"
|
|
||||||
} else {
|
|
||||||
return "$size KB"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,141 +0,0 @@
|
|||||||
package io.neoterm.utils
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.content.ContentUris
|
|
||||||
import android.content.Context
|
|
||||||
import android.database.Cursor
|
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.Environment
|
|
||||||
import android.provider.DocumentsContract
|
|
||||||
import android.provider.MediaStore
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author kiva
|
|
||||||
*/
|
|
||||||
|
|
||||||
object MediaUtils {
|
|
||||||
/**
|
|
||||||
* Get a file path from a Uri. This will get the the path for Storage Access
|
|
||||||
* Framework Documents, as well as the _data field for the MediaStore and
|
|
||||||
* other file-based ContentProviders.
|
|
||||||
|
|
||||||
* @param context The context.
|
|
||||||
* *
|
|
||||||
* @param uri The Uri to query.
|
|
||||||
*/
|
|
||||||
@SuppressLint("ObsoleteSdkInt")
|
|
||||||
fun getPath(context: Context, uri: Uri?): String? {
|
|
||||||
uri ?: return null
|
|
||||||
val isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
|
|
||||||
// DocumentProvider
|
|
||||||
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
|
|
||||||
// ExternalStorageProvider
|
|
||||||
if (isExternalStorageDocument(uri)) {
|
|
||||||
val docId = DocumentsContract.getDocumentId(uri)
|
|
||||||
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
|
||||||
val type = split[0]
|
|
||||||
|
|
||||||
if ("primary".equals(type, ignoreCase = true)) {
|
|
||||||
return Environment.getExternalStorageDirectory().toString() + "/" + split[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Temporary workaround for non-primary volumes
|
|
||||||
return "/storage/$type/${split[1]}"
|
|
||||||
|
|
||||||
} else if (isDownloadsDocument(uri)) {
|
|
||||||
val id = DocumentsContract.getDocumentId(uri)
|
|
||||||
val contentUri = ContentUris.withAppendedId(
|
|
||||||
Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id)!!
|
|
||||||
)
|
|
||||||
|
|
||||||
return getDataColumn(context, contentUri, null, null)
|
|
||||||
} else if (isMediaDocument(uri)) {
|
|
||||||
val docId = DocumentsContract.getDocumentId(uri)
|
|
||||||
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
|
||||||
|
|
||||||
val contentUri = when (split[0]) {
|
|
||||||
"image" -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI
|
|
||||||
"video" -> MediaStore.Video.Media.EXTERNAL_CONTENT_URI
|
|
||||||
"audio" -> MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
|
|
||||||
val selection = "_id=?"
|
|
||||||
val selectionArgs = arrayOf(split[1])
|
|
||||||
|
|
||||||
return getDataColumn(context, contentUri!!, selection, selectionArgs)
|
|
||||||
}
|
|
||||||
} else if ("content".equals(uri.scheme, ignoreCase = true)) {
|
|
||||||
return getDataColumn(context, uri, null, null)
|
|
||||||
} else if ("file".equals(uri.scheme, ignoreCase = true)) {
|
|
||||||
return uri.path
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the value of the data column for this Uri. This is useful for
|
|
||||||
* MediaStore Uris, and other file-based ContentProviders.
|
|
||||||
|
|
||||||
* @param context The context.
|
|
||||||
* *
|
|
||||||
* @param uri The Uri to query.
|
|
||||||
* *
|
|
||||||
* @param selection (Optional) Filter used in the query.
|
|
||||||
* *
|
|
||||||
* @param selectionArgs (Optional) Selection arguments used in the query.
|
|
||||||
* *
|
|
||||||
* @return The value of the _data column, which is typically a file path.
|
|
||||||
*/
|
|
||||||
private fun getDataColumn(
|
|
||||||
context: Context, uri: Uri, selection: String?,
|
|
||||||
selectionArgs: Array<String>?
|
|
||||||
): String? {
|
|
||||||
|
|
||||||
var cursor: Cursor? = null
|
|
||||||
val column = "_data"
|
|
||||||
val projection = arrayOf(column)
|
|
||||||
|
|
||||||
try {
|
|
||||||
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
|
||||||
val column_index = cursor.getColumnIndexOrThrow(column)
|
|
||||||
return cursor.getString(column_index)
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (cursor != null)
|
|
||||||
cursor.close()
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param uri The Uri to check.
|
|
||||||
* *
|
|
||||||
* @return Whether the Uri authority is ExternalStorageProvider.
|
|
||||||
*/
|
|
||||||
private fun isExternalStorageDocument(uri: Uri): Boolean {
|
|
||||||
return "com.android.externalstorage.documents" == uri.authority
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param uri The Uri to check.
|
|
||||||
* *
|
|
||||||
* @return Whether the Uri authority is DownloadsProvider.
|
|
||||||
*/
|
|
||||||
private fun isDownloadsDocument(uri: Uri): Boolean {
|
|
||||||
return "com.android.providers.downloads.documents" == uri.authority
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param uri The Uri to check.
|
|
||||||
* *
|
|
||||||
* @return Whether the Uri authority is MediaProvider.
|
|
||||||
*/
|
|
||||||
private fun isMediaDocument(uri: Uri): Boolean {
|
|
||||||
return "com.android.providers.media.documents" == uri.authority
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
package io.neoterm.utils
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import io.neoterm.backend.TerminalSession
|
|
||||||
import io.neoterm.frontend.config.NeoTermPath
|
|
||||||
import io.neoterm.frontend.floating.TerminalDialog
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author kiva
|
|
||||||
*/
|
|
||||||
object PackageUtils {
|
|
||||||
fun apt(context: Context, subCommand: String, extraArgs: Array<String>?, callback: (Int, TerminalDialog) -> Unit) {
|
|
||||||
val argArray =
|
|
||||||
if (extraArgs != null) arrayOf(NeoTermPath.APT_BIN_PATH, subCommand, *extraArgs)
|
|
||||||
else arrayOf(NeoTermPath.APT_BIN_PATH, subCommand)
|
|
||||||
|
|
||||||
TerminalDialog(context)
|
|
||||||
.onFinish(object : TerminalDialog.SessionFinishedCallback {
|
|
||||||
override fun onSessionFinished(dialog: TerminalDialog, finishedSession: TerminalSession?) {
|
|
||||||
val exit = finishedSession?.exitStatus ?: 1
|
|
||||||
callback(exit, dialog)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.imeEnabled(true)
|
|
||||||
.execute(NeoTermPath.APT_BIN_PATH, argArray)
|
|
||||||
.show("apt $subCommand")
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
package io.neoterm.utils
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author kiva
|
|
||||||
*/
|
|
||||||
class RangedInt(val number: Int, val range: IntRange) {
|
|
||||||
fun increaseOne(): Int {
|
|
||||||
var result = number + 1
|
|
||||||
if (result > range.last) {
|
|
||||||
result = 0
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
fun decreaseOne(): Int {
|
|
||||||
var result = number - 1
|
|
||||||
if (result < 0) {
|
|
||||||
result = range.last
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
@ -17,7 +17,7 @@ import io.neoterm.frontend.terminal.extrakey.ExtraKeysView
|
|||||||
/**
|
/**
|
||||||
* @author kiva
|
* @author kiva
|
||||||
*/
|
*/
|
||||||
object TerminalUtils {
|
object Terminals {
|
||||||
fun setupTerminalView(terminalView: TerminalView?, terminalViewClient: TerminalViewClient? = null) {
|
fun setupTerminalView(terminalView: TerminalView?, terminalViewClient: TerminalViewClient? = null) {
|
||||||
terminalView?.textSize = NeoPreference.getFontSize();
|
terminalView?.textSize = NeoPreference.getFontSize();
|
||||||
|
|
135
app/src/main/java/io/neoterm/utils/utils.kt
Normal file
135
app/src/main/java/io/neoterm/utils/utils.kt
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
package io.neoterm.utils
|
||||||
|
|
||||||
|
import android.content.ContentUris
|
||||||
|
import android.content.Context
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Environment
|
||||||
|
import android.provider.DocumentsContract
|
||||||
|
import android.provider.MediaStore
|
||||||
|
import io.neoterm.backend.TerminalSession
|
||||||
|
import io.neoterm.frontend.config.NeoTermPath
|
||||||
|
import io.neoterm.frontend.floating.TerminalDialog
|
||||||
|
import java.io.File
|
||||||
|
import java.nio.file.Files
|
||||||
|
import java.text.DecimalFormat
|
||||||
|
|
||||||
|
class RangedInt(private val number: Int, private val range: IntRange) {
|
||||||
|
fun inc() = (number + 1).takeIf { range.contains(it) } ?: 0
|
||||||
|
fun dec() = (number - 1).takeIf { range.contains(it) } ?: range.last
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Long.formatSizeInKB(): String {
|
||||||
|
val decimalFormat = DecimalFormat("####.00");
|
||||||
|
if (this < 1024) {
|
||||||
|
return "$this KB"
|
||||||
|
} else if (this < 1024 * 1024) {
|
||||||
|
val parsedSize: Float = this / 1024f
|
||||||
|
return decimalFormat.format(parsedSize) + " MB"
|
||||||
|
} else if (this < 1024 * 1024 * 1024) {
|
||||||
|
val parsedSize: Float = this / 1024f / 1024f
|
||||||
|
return decimalFormat.format(parsedSize) + " GB"
|
||||||
|
} else if (this < 1024L * 1024 * 1024 * 1024) {
|
||||||
|
val parsedSize: Float = this / 1024f / 1024f / 1024f
|
||||||
|
return decimalFormat.format(parsedSize) + " TB"
|
||||||
|
} else {
|
||||||
|
return "$this KB"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.extractAssetsDir(dirName: String, extractDir: String) {
|
||||||
|
val assets = this.assets
|
||||||
|
assets.list(dirName)?.let {
|
||||||
|
it.map { File(extractDir, it) }
|
||||||
|
.takeWhile { !it.exists() }
|
||||||
|
.forEach { file ->
|
||||||
|
assets.open("$dirName/${file.name}").use {
|
||||||
|
kotlin.runCatching { Files.copy(it, file.toPath()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.runApt(subCommand: String, vararg extraArgs: String): Result<TerminalDialog> = runAsyncCatching {
|
||||||
|
val args = arrayOf(NeoTermPath.APT_BIN_PATH, subCommand, *extraArgs)
|
||||||
|
TerminalDialog(this)
|
||||||
|
.onFinish(object : TerminalDialog.SessionFinishedCallback {
|
||||||
|
override fun onSessionFinished(dialog: TerminalDialog, finishedSession: TerminalSession?) {
|
||||||
|
val exit = finishedSession?.exitStatus ?: 1
|
||||||
|
if (exit == 0) {
|
||||||
|
dialog.dismiss()
|
||||||
|
throw SuccessResult(dialog)
|
||||||
|
}
|
||||||
|
else throw RuntimeException()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.imeEnabled(true)
|
||||||
|
.execute(NeoTermPath.APT_BIN_PATH, args)
|
||||||
|
.show("apt $subCommand")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a file path from a Uri. This will get the the path for Storage Access
|
||||||
|
* Framework Documents, as well as the _data field for the MediaStore and
|
||||||
|
* other file-based ContentProviders.
|
||||||
|
* @param context The context.
|
||||||
|
* @param inUri The Uri to query.
|
||||||
|
*/
|
||||||
|
fun Context.getPathOfMediaUri(inUri: Uri?) = inUri?.let {
|
||||||
|
when {
|
||||||
|
"content".equals(it.scheme, ignoreCase = true) -> getDataColumn(this, it, null, null)
|
||||||
|
"file".equals(it.scheme, ignoreCase = true) -> it.path
|
||||||
|
DocumentsContract.isDocumentUri(this, it) -> this.getPathOfDocumentUri(it)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Context.getPathOfDocumentUri(uri: Uri) = if (isExternalStorageDocument(uri)) {
|
||||||
|
val docId = DocumentsContract.getDocumentId(uri)
|
||||||
|
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||||
|
val type = split[0]
|
||||||
|
if ("primary".equals(type, ignoreCase = true)) Environment.getExternalStorageDirectory().toString() + "/" + split[1]
|
||||||
|
else "/storage/$type/${split[1]}" // Temporary workaround for non-primary volumes
|
||||||
|
} else if (isDownloadsDocument(uri)) {
|
||||||
|
val id = DocumentsContract.getDocumentId(uri)
|
||||||
|
val contentUri = ContentUris.withAppendedId(
|
||||||
|
Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id)
|
||||||
|
)
|
||||||
|
getDataColumn(this, contentUri, null, null)
|
||||||
|
} else if (isMediaDocument(uri)) {
|
||||||
|
val docId = DocumentsContract.getDocumentId(uri)
|
||||||
|
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||||
|
val contentUri = when (split[0]) {
|
||||||
|
"image" -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI
|
||||||
|
"video" -> MediaStore.Video.Media.EXTERNAL_CONTENT_URI
|
||||||
|
"audio" -> MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
getDataColumn(this, contentUri!!, "_id=?", arrayOf(split[1]))
|
||||||
|
} else null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of the data column for this Uri
|
||||||
|
*/
|
||||||
|
private fun getDataColumn(context: Context, uri: Uri, selection: String?, selectionArgs: Array<String>?) =
|
||||||
|
context.contentResolver.query(uri, arrayOf("_data"), selection, selectionArgs, null)?.use {
|
||||||
|
if (it.moveToFirst()) {
|
||||||
|
val columnIndex = it.getColumnIndex("_data").takeIf { it != -1 } ?: return@use null
|
||||||
|
it.getString(columnIndex)
|
||||||
|
} else null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isExternalStorageDocument(uri: Uri) = "com.android.externalstorage.documents" == uri.authority
|
||||||
|
private fun isDownloadsDocument(uri: Uri) = "com.android.providers.downloads.documents" == uri.authority
|
||||||
|
private fun isMediaDocument(uri: Uri) = "com.android.providers.media.documents" == uri.authority
|
||||||
|
|
||||||
|
data class SuccessResult(val data: Any) : RuntimeException()
|
||||||
|
|
||||||
|
inline fun <reified R> runAsyncCatching(block: () -> Unit): Result<R> = try {
|
||||||
|
block()
|
||||||
|
Result.failure(IllegalStateException())
|
||||||
|
} catch (s: SuccessResult) {
|
||||||
|
if (s.data is R) Result.success(s.data)
|
||||||
|
else Result.failure(ClassCastException())
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
Result.failure(e)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user