MISC: enhance code step 1
This commit is contained in:
parent
2dbc16cc68
commit
cc1fe9de00
@ -44,6 +44,9 @@ android {
|
||||
targetCompatibility 1.8
|
||||
sourceCompatibility 1.8
|
||||
}
|
||||
kotlinOptions {
|
||||
freeCompilerArgs = ["-Xallow-result-return-type"]
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
@ -9,10 +9,9 @@ import io.neoterm.frontend.component.ComponentManager
|
||||
import io.neoterm.frontend.component.helper.ConfigFileBasedComponent
|
||||
import io.neoterm.frontend.config.NeoPreference
|
||||
import io.neoterm.frontend.config.NeoTermPath
|
||||
import io.neoterm.frontend.logging.NLog
|
||||
import io.neoterm.frontend.terminal.TerminalView
|
||||
import io.neoterm.frontend.terminal.extrakey.ExtraKeysView
|
||||
import io.neoterm.utils.AssetsUtils
|
||||
import io.neoterm.utils.extractAssetsDir
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
|
||||
@ -103,15 +102,8 @@ class ColorSchemeComponent : ConfigFileBasedComponent<NeoColorScheme>(NeoTermPat
|
||||
setCurrentColorScheme(color.colorName)
|
||||
}
|
||||
|
||||
private fun extractDefaultColor(context: Context): Boolean {
|
||||
try {
|
||||
AssetsUtils.extractAssetsDir(context, "colors", baseDir)
|
||||
return true
|
||||
} catch (e: Exception) {
|
||||
NLog.e("ColorScheme", "Failed to extract default colors: ${e.localizedMessage}")
|
||||
return false
|
||||
}
|
||||
}
|
||||
private fun extractDefaultColor(context: Context) =
|
||||
kotlin.runCatching { context.extractAssetsDir("colors", baseDir) }.isSuccess
|
||||
|
||||
fun saveColorScheme(colorScheme: NeoColorScheme) {
|
||||
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.logging.NLog
|
||||
import io.neoterm.frontend.terminal.extrakey.ExtraKeysView
|
||||
import io.neoterm.utils.AssetsUtils
|
||||
import io.neoterm.utils.extractAssetsDir
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
@ -52,7 +52,7 @@ class ExtraKeyComponent : ConfigFileBasedComponent<NeoExtraKey>(NeoTermPath.EKS_
|
||||
|
||||
private fun extractDefaultConfig(context: Context) {
|
||||
try {
|
||||
AssetsUtils.extractAssetsDir(context, "eks", baseDir)
|
||||
context.extractAssetsDir("eks", baseDir)
|
||||
} catch (e: Exception) {
|
||||
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.terminal.TerminalView
|
||||
import io.neoterm.frontend.terminal.extrakey.ExtraKeysView
|
||||
import io.neoterm.utils.AssetsUtils
|
||||
import io.neoterm.utils.extractAssetsDir
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
@ -90,7 +90,7 @@ class FontComponent : NeoComponent {
|
||||
|
||||
private fun extractDefaultFont(context: Context): Boolean {
|
||||
try {
|
||||
AssetsUtils.extractAssetsDir(context, "fonts", NeoTermPath.FONT_PATH)
|
||||
context.extractAssetsDir( "fonts", NeoTermPath.FONT_PATH)
|
||||
return true
|
||||
} catch (e: Exception) {
|
||||
return false
|
||||
|
@ -6,7 +6,7 @@ import io.neoterm.App
|
||||
import io.neoterm.frontend.component.NeoComponent
|
||||
import io.neoterm.frontend.config.NeoTermPath
|
||||
import io.neoterm.frontend.logging.NLog
|
||||
import io.neoterm.utils.AssetsUtils
|
||||
import io.neoterm.utils.extractAssetsDir
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
@ -28,7 +28,7 @@ class UserScriptComponent : NeoComponent {
|
||||
|
||||
private fun extractDefaultScript(context: Context): Boolean {
|
||||
try {
|
||||
AssetsUtils.extractAssetsDir(context, "scripts", NeoTermPath.USER_SCRIPT_PATH)
|
||||
context.extractAssetsDir( "scripts", NeoTermPath.USER_SCRIPT_PATH)
|
||||
File(NeoTermPath.USER_SCRIPT_PATH)
|
||||
.listFiles().forEach {
|
||||
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.client.BasicSessionCallback
|
||||
import io.neoterm.frontend.session.shell.client.BasicViewClient
|
||||
import io.neoterm.utils.TerminalUtils
|
||||
import io.neoterm.utils.Terminals
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
@ -56,7 +56,7 @@ class TerminalDialog(val context: Context) {
|
||||
.arguments(arguments)
|
||||
.callback(terminalSessionCallback)
|
||||
.systemShell(false)
|
||||
terminalSession = TerminalUtils.createSession(context, parameter)
|
||||
terminalSession = Terminals.createSession(context, parameter)
|
||||
if (terminalSession is ShellTermSession) {
|
||||
(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.frontend.terminal.TerminalView
|
||||
import io.neoterm.frontend.terminal.TerminalViewClient
|
||||
import io.neoterm.utils.TerminalUtils
|
||||
import io.neoterm.utils.Terminals
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
@ -21,7 +21,7 @@ class WindowTermView(val context: Context) {
|
||||
private set
|
||||
|
||||
init {
|
||||
TerminalUtils.setupTerminalView(terminalView)
|
||||
Terminals.setupTerminalView(terminalView)
|
||||
}
|
||||
|
||||
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.XSession
|
||||
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 {
|
||||
val session = TerminalUtils.createSession(activity, parameter)
|
||||
val session = Terminals.createSession(activity, parameter)
|
||||
mXSessions.add(session)
|
||||
updateNotification()
|
||||
return session
|
||||
@ -112,7 +112,7 @@ class NeoTermService : Service() {
|
||||
private fun createOrFindSession(parameter: ShellParameter): TerminalSession {
|
||||
if (parameter.willCreateNewSession()) {
|
||||
NLog.d("createOrFindSession: creating new session")
|
||||
val session = TerminalUtils.createSession(this, parameter)
|
||||
val session = Terminals.createSession(this, parameter)
|
||||
mTerminalSessions.add(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.terminal.TerminalView
|
||||
import io.neoterm.frontend.terminal.extrakey.ExtraKeysView
|
||||
import io.neoterm.utils.TerminalUtils
|
||||
import io.neoterm.utils.Terminals
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
@ -36,8 +36,8 @@ open class BaseCustomizeActivity : AppCompatActivity() {
|
||||
extraKeysView = findViewById(R.id.custom_extra_keys)
|
||||
viewClient = BasicViewClient(terminalView)
|
||||
sessionCallback = BasicSessionCallback(terminalView)
|
||||
TerminalUtils.setupTerminalView(terminalView, viewClient)
|
||||
TerminalUtils.setupExtraKeysView(extraKeysView)
|
||||
Terminals.setupTerminalView(terminalView, viewClient)
|
||||
Terminals.setupExtraKeysView(extraKeysView)
|
||||
|
||||
val script = resources.getStringArray(R.array.custom_preview_script_colors)
|
||||
val parameter = ShellParameter()
|
||||
@ -46,7 +46,7 @@ open class BaseCustomizeActivity : AppCompatActivity() {
|
||||
.callback(sessionCallback)
|
||||
.systemShell(false)
|
||||
|
||||
session = TerminalUtils.createSession(this, parameter)
|
||||
session = Terminals.createSession(this, parameter)
|
||||
terminalView.attachSession(session)
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ import io.neoterm.frontend.component.ComponentManager
|
||||
import io.neoterm.frontend.terminal.TerminalView
|
||||
import io.neoterm.ui.customize.adapter.ColorItemAdapter
|
||||
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 = ""
|
||||
|
||||
val terminalView = findViewById<TerminalView>(R.id.terminal_view)
|
||||
TerminalUtils.setupTerminalView(terminalView, null)
|
||||
Terminals.setupTerminalView(terminalView, null)
|
||||
|
||||
adapter = ColorItemAdapter(this, editingColorScheme, COMPARATOR, object : ColorItemAdapter.Listener {
|
||||
override fun onModelClicked(model: ColorItem) {
|
||||
|
@ -13,7 +13,7 @@ import io.neoterm.component.colorscheme.ColorSchemeComponent
|
||||
import io.neoterm.component.font.FontComponent
|
||||
import io.neoterm.frontend.component.ComponentManager
|
||||
import io.neoterm.frontend.config.NeoTermPath
|
||||
import io.neoterm.utils.MediaUtils
|
||||
import io.neoterm.utils.getPathOfMediaUri
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Paths
|
||||
@ -114,7 +114,7 @@ class CustomizeActivity : BaseCustomizeActivity() {
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (resultCode == RESULT_OK && data != null) {
|
||||
val selected = MediaUtils.getPath(this, data.data)
|
||||
val selected = this.getPathOfMediaUri( data.data)
|
||||
if (selected != null && selected.isNotEmpty()) {
|
||||
when (requestCode) {
|
||||
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.model.PackageModel
|
||||
import io.neoterm.ui.pm.utils.StringDistance
|
||||
import io.neoterm.utils.PackageUtils
|
||||
import io.neoterm.utils.runApt
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
@ -178,67 +179,64 @@ class PackageManagerActivity : AppCompatActivity(), SearchView.OnQueryTextListen
|
||||
executeAptUpdate()
|
||||
}
|
||||
|
||||
private fun executeAptUpdate() {
|
||||
PackageUtils.apt(this, "update", null, { exitStatus, dialog ->
|
||||
if (exitStatus != 0) {
|
||||
dialog.setTitle(getString(R.string.error))
|
||||
return@apt
|
||||
}
|
||||
Toast.makeText(this, R.string.apt_update_ok, Toast.LENGTH_SHORT).show()
|
||||
dialog.dismiss()
|
||||
refreshPackageList()
|
||||
})
|
||||
private fun executeAptUpdate() = runApt("update", null) { exitStatus, dialog ->
|
||||
if (exitStatus != 0) {
|
||||
dialog.setTitle(getString(R.string.error))
|
||||
return@runApt
|
||||
}
|
||||
Toast.makeText(this, R.string.apt_update_ok, Toast.LENGTH_SHORT).show()
|
||||
dialog.dismiss()
|
||||
refreshPackageList()
|
||||
}
|
||||
|
||||
private fun executeAptUpgrade() {
|
||||
PackageUtils.apt(this, "update", null, { exitStatus, dialog ->
|
||||
private fun executeAptUpgrade() = runApt("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) {
|
||||
dialog.setTitle(getString(R.string.error))
|
||||
return@apt
|
||||
return@aptUpgrade
|
||||
}
|
||||
Toast.makeText(this, R.string.apt_upgrade_ok, Toast.LENGTH_SHORT).show()
|
||||
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()
|
||||
Thread {
|
||||
val pm = ComponentManager.getComponent<PackageComponent>()
|
||||
val sourceFiles = SourceHelper.detectSourceFiles()
|
||||
val pm = ComponentManager.getComponent<PackageComponent>()
|
||||
val sourceFiles = SourceHelper.detectSourceFiles()
|
||||
|
||||
pm.clearPackages()
|
||||
sourceFiles.forEach { pm.reloadPackages(it, false) }
|
||||
pm.packages.values.mapTo(models, { PackageModel(it) })
|
||||
pm.clearPackages()
|
||||
sourceFiles.forEach { pm.reloadPackages(it, false) }
|
||||
pm.packages.values.mapTo(models, { PackageModel(it) })
|
||||
|
||||
this@PackageManagerActivity.runOnUiThread {
|
||||
adapter.edit()
|
||||
.replaceAll(models)
|
||||
.commit()
|
||||
if (models.isEmpty()) {
|
||||
Toast.makeText(this@PackageManagerActivity, R.string.package_list_empty, Toast.LENGTH_SHORT).show()
|
||||
changeSource()
|
||||
}
|
||||
this@PackageManagerActivity.runOnUiThread {
|
||||
adapter.edit()
|
||||
.replaceAll(models)
|
||||
.commit()
|
||||
if (models.isEmpty()) {
|
||||
Toast.makeText(this@PackageManagerActivity, R.string.package_list_empty, Toast.LENGTH_SHORT).show()
|
||||
changeSource()
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
|
||||
private fun sortDistance(
|
||||
models: List<PackageModel>, query: String,
|
||||
mapper: (NeoPackageInfo) -> String
|
||||
): List<Pair<PackageModel, Int>> {
|
||||
return models
|
||||
.map({
|
||||
Pair(it, StringDistance.distance(mapper(it.packageInfo).toLowerCase(), query.toLowerCase()))
|
||||
})
|
||||
.map {
|
||||
Pair(
|
||||
it,
|
||||
StringDistance.distance(mapper(it.packageInfo).toLowerCase(Locale.ROOT), query.toLowerCase(Locale.ROOT))
|
||||
)
|
||||
}
|
||||
.sortedWith(Comparator { l, r -> r.second.compareTo(l.second) })
|
||||
.toList()
|
||||
}
|
||||
@ -255,17 +253,10 @@ class PackageManagerActivity : AppCompatActivity(), SearchView.OnQueryTextListen
|
||||
return filteredModelList
|
||||
}
|
||||
|
||||
override fun onQueryTextSubmit(text: String?): Boolean {
|
||||
return false
|
||||
}
|
||||
override fun onQueryTextSubmit(text: String?) = false
|
||||
|
||||
override fun onQueryTextChange(text: String?): Boolean {
|
||||
if (text != null) {
|
||||
val filteredModelList = filter(models, text)
|
||||
adapter.edit()
|
||||
.replaceAll(filteredModelList)
|
||||
.commit()
|
||||
}
|
||||
text?.let { adapter.edit().replaceAll(filter(models, it)).commit() }
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ import com.github.wrdlbrnft.sortedlistadapter.SortedListAdapter
|
||||
import io.neoterm.R
|
||||
|
||||
import io.neoterm.component.pm.NeoPackageInfo
|
||||
import io.neoterm.utils.FileUtils
|
||||
import io.neoterm.utils.formatSizeInKB
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
@ -28,7 +28,7 @@ class PackageModel(val packageInfo: NeoPackageInfo) : SortedListAdapter.ViewMode
|
||||
R.string.package_details,
|
||||
packageInfo.packageName, packageInfo.version,
|
||||
packageInfo.dependenciesString,
|
||||
FileUtils.formatSizeInKB(packageInfo.installedSizeInBytes),
|
||||
packageInfo.installedSizeInBytes.formatSizeInKB(),
|
||||
packageInfo.description, packageInfo.homePage
|
||||
)
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import android.view.MenuItem
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import io.neoterm.R
|
||||
import io.neoterm.frontend.config.NeoPreference
|
||||
import io.neoterm.utils.PackageUtils
|
||||
import io.neoterm.utils.runApt
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
@ -39,16 +39,14 @@ class GeneralSettingsActivity : BasePreferenceActivity() {
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle(getString(R.string.shell_not_found, shellName))
|
||||
.setMessage(R.string.shell_not_found_message)
|
||||
.setPositiveButton(R.string.install, { _, _ ->
|
||||
PackageUtils.apt(this, "install", arrayOf("-y", shellName), { exitStatus, dialog ->
|
||||
.setPositiveButton(R.string.install) { _, _ ->
|
||||
runApt("install", arrayOf("-y", shellName)) { exitStatus, dialog ->
|
||||
if (exitStatus == 0) {
|
||||
dialog.dismiss()
|
||||
postChangeShell(shellName)
|
||||
} else {
|
||||
dialog.setTitle(getString(R.string.error))
|
||||
}
|
||||
})
|
||||
})
|
||||
} else dialog.setTitle(getString(R.string.error))
|
||||
}
|
||||
}
|
||||
.setNegativeButton(android.R.string.no, null)
|
||||
.setOnDismissListener {
|
||||
postChangeShell(currentShell)
|
||||
|
@ -19,8 +19,8 @@ import io.neoterm.setup.SourceConnection
|
||||
import io.neoterm.setup.connections.BackupFileConnection
|
||||
import io.neoterm.setup.connections.LocalFileConnection
|
||||
import io.neoterm.setup.connections.NetworkConnection
|
||||
import io.neoterm.utils.MediaUtils
|
||||
import io.neoterm.utils.PackageUtils
|
||||
import io.neoterm.utils.getPathOfMediaUri
|
||||
import io.neoterm.utils.runApt
|
||||
import java.io.File
|
||||
|
||||
|
||||
@ -32,7 +32,6 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener
|
||||
private const val REQUEST_SELECT_PARAMETER = 520;
|
||||
}
|
||||
|
||||
private var aptUpdated = false
|
||||
private var setupParameter = ""
|
||||
private var setupParameterUri: Uri? = null
|
||||
|
||||
@ -83,8 +82,7 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
|
||||
if (requestCode == REQUEST_SELECT_PARAMETER && resultCode == RESULT_OK) {
|
||||
if (resultData != null) {
|
||||
setupParameterUri = resultData.data
|
||||
val path = MediaUtils.getPath(this, setupParameterUri!!)
|
||||
val path = this.getPathOfMediaUri(resultData.data)
|
||||
findViewById<EditText>(R.id.setup_source_parameter).setText(path)
|
||||
return
|
||||
}
|
||||
@ -236,26 +234,11 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener
|
||||
}
|
||||
}
|
||||
|
||||
private fun executeAptUpdate() {
|
||||
PackageUtils.apt(this, "update", null) { exitStatus, dialog ->
|
||||
if (exitStatus == 0) {
|
||||
dialog.dismiss()
|
||||
aptUpdated = true
|
||||
executeAptUpgrade()
|
||||
} else {
|
||||
dialog.setTitle(getString(R.string.error))
|
||||
}
|
||||
}
|
||||
}
|
||||
private fun executeAptUpdate() = runApt("update")
|
||||
.onSuccess { executeAptUpgrade() }
|
||||
.onFailure { Toast.makeText(this, R.string.error, Toast.LENGTH_SHORT).show() }
|
||||
|
||||
private fun executeAptUpgrade() {
|
||||
PackageUtils.apt(this, "upgrade", arrayOf("-y")) { exitStatus, dialog ->
|
||||
if (exitStatus == 0) {
|
||||
dialog.dismiss()
|
||||
finish()
|
||||
} else {
|
||||
dialog.setTitle(getString(R.string.error))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private fun executeAptUpgrade() = runApt("upgrade", "-y")
|
||||
.onSuccess { finish() }
|
||||
.onFailure { Toast.makeText(this, R.string.error, Toast.LENGTH_SHORT).show() }
|
||||
}
|
||||
|
@ -777,9 +777,7 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
|
||||
}
|
||||
|
||||
val rangedInt = RangedInt(tabSwitcher.selectedTabIndex, (0 until tabSwitcher.count))
|
||||
val nextIndex = if (switchSessionEvent.toNext)
|
||||
rangedInt.increaseOne()
|
||||
else rangedInt.decreaseOne()
|
||||
val nextIndex = if (switchSessionEvent.toNext) rangedInt.inc() else rangedInt.dec()
|
||||
if (!tabSwitcher.isSwitcherShown) {
|
||||
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.client.TermSessionCallback
|
||||
import io.neoterm.services.NeoTermService
|
||||
import io.neoterm.utils.MediaUtils
|
||||
import io.neoterm.utils.TerminalUtils
|
||||
import io.neoterm.utils.Terminals
|
||||
import io.neoterm.utils.getPathOfMediaUri
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
@ -67,13 +67,10 @@ class NeoTermRemoteInterface : AppCompatActivity(), ServiceConnection {
|
||||
handleIntent()
|
||||
}
|
||||
|
||||
private fun handleIntent() {
|
||||
val className = intent.component.className.substringAfterLast('.')
|
||||
when (className) {
|
||||
"TermHere" -> handleTermHere()
|
||||
"UserScript" -> handleUserScript()
|
||||
else -> handleNormal()
|
||||
}
|
||||
private fun handleIntent() = when (intent.component?.className?.substringAfterLast('.')) {
|
||||
"TermHere" -> handleTermHere()
|
||||
"UserScript" -> handleUserScript()
|
||||
else -> handleNormal()
|
||||
}
|
||||
|
||||
private fun handleNormal() {
|
||||
@ -98,12 +95,12 @@ class NeoTermRemoteInterface : AppCompatActivity(), ServiceConnection {
|
||||
|
||||
private fun handleTermHere() {
|
||||
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) {
|
||||
val path = MediaUtils.getPath(this, extra)
|
||||
val path = this.getPathOfMediaUri(extra)
|
||||
val file = File(path)
|
||||
val dirPath = if (file.isDirectory) path else file.parent
|
||||
val command = "cd " + TerminalUtils.escapeString(dirPath)
|
||||
val command = "cd " + Terminals.escapeString(dirPath)
|
||||
openTerm(command, null)
|
||||
}
|
||||
finish()
|
||||
@ -128,23 +125,23 @@ class NeoTermRemoteInterface : AppCompatActivity(), ServiceConnection {
|
||||
|
||||
if (intent.hasExtra(Intent.EXTRA_STREAM)) {
|
||||
// action send
|
||||
val extra = intent.extras.get(Intent.EXTRA_STREAM)
|
||||
val extra = intent.extras?.get(Intent.EXTRA_STREAM)
|
||||
|
||||
when (extra) {
|
||||
is ArrayList<*> -> {
|
||||
extra.takeWhile { it is Uri }
|
||||
.mapTo(filesToHandle) {
|
||||
val uri = it as Uri
|
||||
File(MediaUtils.getPath(this, uri)).absolutePath
|
||||
File(this.getPathOfMediaUri(uri)).absolutePath
|
||||
}
|
||||
}
|
||||
is Uri -> {
|
||||
filesToHandle.add(File(MediaUtils.getPath(this, extra)).absolutePath)
|
||||
filesToHandle.add(File(this.getPathOfMediaUri(extra)).absolutePath)
|
||||
}
|
||||
}
|
||||
} else if (intent.data != null) {
|
||||
// action view
|
||||
filesToHandle.add(File(intent.data.path).absolutePath)
|
||||
filesToHandle.add(File(intent.data?.path).absolutePath)
|
||||
}
|
||||
|
||||
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.extrakey.ExtraKeysView
|
||||
import io.neoterm.ui.term.NeoTermActivity
|
||||
import io.neoterm.utils.TerminalUtils
|
||||
import io.neoterm.utils.Terminals
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
@ -43,8 +43,8 @@ class NeoTabDecorator(val context: NeoTermActivity) : TabSwitcherDecorator() {
|
||||
val view = inflater.inflate(R.layout.ui_term, parent, false)
|
||||
val terminalView = view.findViewById<TerminalView>(R.id.terminal_view)
|
||||
val extraKeysView = view.findViewById<ExtraKeysView>(R.id.extra_keys)
|
||||
TerminalUtils.setupTerminalView(terminalView)
|
||||
TerminalUtils.setupExtraKeysView(extraKeysView)
|
||||
Terminals.setupTerminalView(terminalView)
|
||||
Terminals.setupExtraKeysView(extraKeysView)
|
||||
|
||||
val colorSchemeManager = ComponentManager.getComponent<ColorSchemeComponent>()
|
||||
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
|
||||
*/
|
||||
object TerminalUtils {
|
||||
object Terminals {
|
||||
fun setupTerminalView(terminalView: TerminalView?, terminalViewClient: TerminalViewClient? = null) {
|
||||
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…
Reference in New Issue
Block a user