MISC: improve code quality

- use nio apis
- remove unnecessary utilities
- apply idea suggestions
- remove some unused parameters and imports
This commit is contained in:
imkiva 2021-05-08 00:05:28 +08:00 committed by Kiva Oyama
parent 31bbf3f1c0
commit b517d68e9e
14 changed files with 236 additions and 382 deletions

View File

@ -1,13 +1,13 @@
package io.neoterm
import android.annotation.SuppressLint
import androidx.appcompat.app.AlertDialog
import android.app.Application
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.view.Gravity
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import io.neoterm.component.NeoInitializer
import io.neoterm.frontend.config.NeoPreference
import io.neoterm.ui.bonus.BonusActivity
@ -31,16 +31,16 @@ class App : Application() {
fun errorDialog(context: Context, message: String, dismissCallback: (() -> Unit)?) {
AlertDialog.Builder(context)
.setTitle(R.string.error)
.setMessage(message)
.setNegativeButton(android.R.string.no, null)
.setPositiveButton(R.string.show_help, { _, _ ->
openHelpLink()
})
.setOnDismissListener {
dismissCallback?.invoke()
}
.show()
.setTitle(R.string.error)
.setMessage(message)
.setNegativeButton(android.R.string.no, null)
.setPositiveButton(R.string.show_help) { _, _ ->
openHelpLink()
}
.setOnDismissListener {
dismissCallback?.invoke()
}
.show()
}
fun openHelpLink() {
@ -72,6 +72,5 @@ class App : Application() {
fun get(): App {
return app!!
}
}
}

View File

@ -13,8 +13,8 @@ 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.FileUtils
import java.io.File
import java.nio.file.Files
/**
* @author kiva
@ -121,7 +121,9 @@ class ColorSchemeComponent : ConfigFileBasedComponent<NeoColorScheme>(NeoTermPat
val component = ComponentManager.getComponent<CodeGenComponent>()
val content = component.newGenerator(colorScheme).generateCode(colorScheme)
if (!FileUtils.writeFile(colorFile, content.toByteArray())) {
kotlin.runCatching {
Files.write(colorFile.toPath(), content.toByteArray())
}.onFailure {
throw RuntimeException("Failed to save file ${colorFile.absolutePath}")
}
}

View File

@ -3,9 +3,10 @@ package io.neoterm.component.pm
import io.neoterm.frontend.component.ComponentManager
import io.neoterm.frontend.config.NeoTermPath
import io.neoterm.frontend.logging.NLog
import io.neoterm.utils.FileUtils
import java.io.File
import java.net.URL
import java.nio.file.Files
import java.nio.file.Paths
/**
* @author kiva
@ -17,13 +18,14 @@ object SourceHelper {
}
fun syncSource(sourceManager: SourceManager) {
val sourceFile = File(NeoTermPath.SOURCE_FILE)
val content = buildString {
this.append("# Generated by NeoTerm-Preference\n")
sourceManager.getEnabledSources()
.joinTo(this, "\n") { "deb [trusted=yes] ${it.url} ${it.repo}\n" }
}
FileUtils.writeFile(sourceFile, content.toByteArray())
kotlin.runCatching {
Files.write(Paths.get(NeoTermPath.SOURCE_FILE), content.toByteArray())
}
}
fun detectSourceFiles(): List<File> {
@ -36,10 +38,10 @@ object SourceHelper {
File(NeoTermPath.PACKAGE_LIST_DIR)
.listFiles()
.filterTo(sourceFiles, { file ->
.filterTo(sourceFiles) { file ->
prefixes.filter { file.name.startsWith(it) }
.count() > 0
})
.count() > 0
}
} catch (e: Exception) {
sourceFiles.clear()
NLog.e("PM", "Failed to detect source files: ${e.localizedMessage}")
@ -59,8 +61,7 @@ object SourceHelper {
val path = url.path
if (path != null && path.isNotEmpty()) {
builder.append("_")
val fixedPath = path.replace("/", "_")
.substring(1) // skip the last '/'
val fixedPath = path.replace("/", "_").substring(1) // skip the last '/'
builder.append(fixedPath)
}
builder.append("_dists_${source.repo.replace(" ".toRegex(), "_")}_binary-")

View File

@ -2,9 +2,8 @@ package io.neoterm.frontend.config
import io.neolang.parser.NeoLangParser
import io.neolang.visitor.ConfigVisitor
import io.neoterm.frontend.logging.NLog
import io.neoterm.utils.FileUtils
import java.io.File
import java.nio.file.Files
/**
* @author kiva
@ -13,30 +12,15 @@ open class NeoConfigureFile(val configureFile: File) {
private val configParser = NeoLangParser()
open protected var configVisitor : ConfigVisitor? = null
fun getVisitor(): ConfigVisitor {
checkParsed()
return configVisitor!!
}
fun getVisitor() = configVisitor ?: throw IllegalStateException("Configure file not loaded or parse failed.")
open fun parseConfigure(): Boolean {
val configContent = FileUtils.readFile(configureFile)
if (configContent == null) {
NLog.e("ConfigureFile", "Cannot read file $configureFile")
return false
}
val programCode = String(configContent)
open fun parseConfigure() = kotlin.runCatching {
val programCode = String(Files.readAllBytes(configureFile.toPath()))
configParser.setInputSource(programCode)
val ast = configParser.parse()
val astVisitor = ast.visit().getVisitor(ConfigVisitor::class.java) ?: return false
astVisitor.start()
configVisitor = astVisitor.getCallback()
return true
}
private fun checkParsed() {
if (configVisitor == null) {
throw IllegalStateException("Configure file not loaded or parse failed.")
}
}
}.isSuccess
}

View File

@ -11,8 +11,8 @@ import io.neoterm.R
import io.neoterm.backend.TerminalSession
import io.neoterm.frontend.logging.NLog
import io.neoterm.services.NeoTermService
import io.neoterm.utils.FileUtils
import java.io.File
import java.nio.file.Files
/**
@ -46,12 +46,13 @@ object NeoPreference {
// load apt source
val sourceFile = File(NeoTermPath.SOURCE_FILE)
val bytes = FileUtils.readFile(sourceFile)
if (bytes != null) {
val source = String(FileUtils.readFile(sourceFile)!!).trim().trimEnd()
val array = source.split(" ")
if (array.size >= 2 && array[0] == "deb") {
store(R.string.key_package_source, array[1])
kotlin.runCatching {
Files.readAllBytes(sourceFile.toPath())?.let {
val source = String(it).trim().trimEnd()
val array = source.split(" ")
if (array.size >= 2 && array[0] == "deb") {
store(R.string.key_package_source, array[1])
}
}
}
}
@ -94,16 +95,16 @@ object NeoPreference {
fun storeCurrentSession(session: TerminalSession) {
preference!!.edit()
.putString(KEY_CURRENT_SESSION, session.mHandle)
.apply()
.putString(KEY_CURRENT_SESSION, session.mHandle)
.apply()
}
fun getCurrentSession(termService: NeoTermService?): TerminalSession? {
val sessionHandle = PreferenceManager.getDefaultSharedPreferences(termService!!)
.getString(KEY_CURRENT_SESSION, "")
.getString(KEY_CURRENT_SESSION, "")
return termService.sessions
.singleOrNull { it.mHandle == sessionHandle }
.singleOrNull { it.mHandle == sessionHandle }
}
fun setLoginShellName(loginProgramName: String?): Boolean {
@ -164,73 +165,101 @@ object NeoPreference {
}
fun getFontSize(): Int {
return loadInt(KEY_FONT_SIZE,
DefaultValues.fontSize)
return loadInt(
KEY_FONT_SIZE,
DefaultValues.fontSize
)
}
fun getInitialCommand(): String {
return loadString(R.string.key_general_initial_command,
DefaultValues.initialCommand)
return loadString(
R.string.key_general_initial_command,
DefaultValues.initialCommand
)
}
fun isBellEnabled(): Boolean {
return loadBoolean(R.string.key_general_bell,
DefaultValues.enableBell)
return loadBoolean(
R.string.key_general_bell,
DefaultValues.enableBell
)
}
fun isVibrateEnabled(): Boolean {
return loadBoolean(R.string.key_general_vibrate,
DefaultValues.enableVibrate)
return loadBoolean(
R.string.key_general_vibrate,
DefaultValues.enableVibrate
)
}
fun isExecveWrapperEnabled() : Boolean {
return loadBoolean(R.string.key_general_use_execve_wrapper,
DefaultValues.enableExecveWrapper)
fun isExecveWrapperEnabled(): Boolean {
return loadBoolean(
R.string.key_general_use_execve_wrapper,
DefaultValues.enableExecveWrapper
)
}
fun isSpecialVolumeKeysEnabled() : Boolean {
return loadBoolean(R.string.key_general_volume_as_control,
DefaultValues.enableSpecialVolumeKeys)
fun isSpecialVolumeKeysEnabled(): Boolean {
return loadBoolean(
R.string.key_general_volume_as_control,
DefaultValues.enableSpecialVolumeKeys
)
}
fun isAutoCompletionEnabled() : Boolean {
return loadBoolean(R.string.key_general_auto_completion,
DefaultValues.enableAutoCompletion)
fun isAutoCompletionEnabled(): Boolean {
return loadBoolean(
R.string.key_general_auto_completion,
DefaultValues.enableAutoCompletion
)
}
fun isBackButtonBeMappedToEscapeEnabled(): Boolean {
return loadBoolean(R.string.key_generaL_backspace_map_to_esc,
DefaultValues.enableBackButtonBeMappedToEscape)
return loadBoolean(
R.string.key_generaL_backspace_map_to_esc,
DefaultValues.enableBackButtonBeMappedToEscape
)
}
fun isExtraKeysEnabled(): Boolean {
return loadBoolean(R.string.key_ui_eks_enabled,
DefaultValues.enableExtraKeys)
return loadBoolean(
R.string.key_ui_eks_enabled,
DefaultValues.enableExtraKeys
)
}
fun isExplicitExtraKeysWeightEnabled() :Boolean {
return loadBoolean(R.string.key_ui_eks_weight_explicit,
DefaultValues.enableExplicitExtraKeysWeight)
fun isExplicitExtraKeysWeightEnabled(): Boolean {
return loadBoolean(
R.string.key_ui_eks_weight_explicit,
DefaultValues.enableExplicitExtraKeysWeight
)
}
fun isFullScreenEnabled() : Boolean {
return loadBoolean(R.string.key_ui_fullscreen,
DefaultValues.enableFullScreen)
fun isFullScreenEnabled(): Boolean {
return loadBoolean(
R.string.key_ui_fullscreen,
DefaultValues.enableFullScreen
)
}
fun isHideToolbarEnabled() :Boolean {
return loadBoolean(R.string.key_ui_hide_toolbar,
DefaultValues.enableAutoHideToolbar)
fun isHideToolbarEnabled(): Boolean {
return loadBoolean(
R.string.key_ui_hide_toolbar,
DefaultValues.enableAutoHideToolbar
)
}
fun isNextTabEnabled() :Boolean {
return loadBoolean(R.string.key_ui_next_tab_anim,
DefaultValues.enableSwitchNextTab)
fun isNextTabEnabled(): Boolean {
return loadBoolean(
R.string.key_ui_next_tab_anim,
DefaultValues.enableSwitchNextTab
)
}
fun isWordBasedImeEnabled() : Boolean {
return loadBoolean(R.string.key_general_enable_word_based_ime,
DefaultValues.enableWordBasedIme)
fun isWordBasedImeEnabled(): Boolean {
return loadBoolean(
R.string.key_general_enable_word_based_ime,
DefaultValues.enableWordBasedIme
)
}
/**

View File

@ -1,43 +0,0 @@
package io.neoterm.setup.helper;
import android.content.Context;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import io.neoterm.utils.NetworkUtils;
/**
* @author kiva
*/
public final class URLAvailability {
public enum ResultCode {
URL_OK,
URL_CONNECTION_FAILED,
URL_INVALID,
URL_NO_INTERNET,
}
public static ResultCode checkUrlAvailability(Context context, String urlString) {
if (!NetworkUtils.INSTANCE.isNetworkAvailable(context)) {
return ResultCode.URL_NO_INTERNET;
}
try {
URL url = new URL(urlString);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.disconnect();
} catch (MalformedURLException e) {
return ResultCode.URL_INVALID;
} catch (IOException | ClassCastException e) {
return ResultCode.URL_CONNECTION_FAILED;
}
return ResultCode.URL_OK;
}
}

View File

@ -1,6 +1,5 @@
package io.neoterm.ui.customize
import androidx.appcompat.app.AppCompatActivity
import android.content.Intent
import android.os.Bundle
import android.view.MenuItem
@ -14,10 +13,10 @@ 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.FileUtils
import io.neoterm.utils.MediaUtils
import java.io.File
import java.io.FileInputStream
import java.nio.file.Files
import java.nio.file.Paths
/**
* @author kiva
@ -41,7 +40,10 @@ class CustomizeActivity : BaseCustomizeActivity() {
val intent = Intent()
intent.action = Intent.ACTION_GET_CONTENT
intent.type = "*/*"
startActivityForResult(Intent.createChooser(intent, getString(R.string.install_color)), REQUEST_SELECT_COLOR)
startActivityForResult(
Intent.createChooser(intent, getString(R.string.install_color)),
REQUEST_SELECT_COLOR
)
}
}
@ -50,40 +52,47 @@ class CustomizeActivity : BaseCustomizeActivity() {
val colorSchemeComponent = ComponentManager.getComponent<ColorSchemeComponent>()
setupSpinner(R.id.custom_font_spinner, fontComponent.getFontNames(),
fontComponent.getCurrentFontName(), object : AdapterView.OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) {
}
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
val fontName = parent!!.adapter!!.getItem(position) as String
val font = fontComponent.getFont(fontName)
fontComponent.applyFont(terminalView, extraKeysView, font)
fontComponent.setCurrentFont(fontName)
}
})
val colorData = listOf(getString(R.string.new_color_scheme),
*colorSchemeComponent.getColorSchemeNames().toTypedArray())
setupSpinner(R.id.custom_color_spinner, colorData,
colorSchemeComponent.getCurrentColorSchemeName(), object : AdapterView.OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) {
}
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
if (position == 0) {
val intent = Intent(this@CustomizeActivity, ColorSchemeActivity::class.java)
startActivity(intent)
return
fontComponent.getCurrentFontName(), object : AdapterView.OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) {
}
val colorName = parent!!.adapter!!.getItem(position) as String
val color = colorSchemeComponent.getColorScheme(colorName)
colorSchemeComponent.applyColorScheme(terminalView, extraKeysView, color)
colorSchemeComponent.setCurrentColorScheme(colorName)
}
})
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
val fontName = parent!!.adapter!!.getItem(position) as String
val font = fontComponent.getFont(fontName)
fontComponent.applyFont(terminalView, extraKeysView, font)
fontComponent.setCurrentFont(fontName)
}
})
val colorData = listOf(
getString(R.string.new_color_scheme),
*colorSchemeComponent.getColorSchemeNames().toTypedArray()
)
setupSpinner(R.id.custom_color_spinner, colorData,
colorSchemeComponent.getCurrentColorSchemeName(), object : AdapterView.OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) {
}
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
if (position == 0) {
val intent = Intent(this@CustomizeActivity, ColorSchemeActivity::class.java)
startActivity(intent)
return
}
val colorName = parent!!.adapter!!.getItem(position) as String
val color = colorSchemeComponent.getColorScheme(colorName)
colorSchemeComponent.applyColorScheme(terminalView, extraKeysView, color)
colorSchemeComponent.setCurrentColorScheme(colorName)
}
})
}
private fun setupSpinner(id: Int, data: List<String>, selected: String, listener: AdapterView.OnItemSelectedListener) : Spinner {
private fun setupSpinner(
id: Int,
data: List<String>,
selected: String,
listener: AdapterView.OnItemSelectedListener
): Spinner {
val spinner = findViewById<Spinner>(id)
val adapter = ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, data)
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
@ -104,7 +113,7 @@ class CustomizeActivity : BaseCustomizeActivity() {
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (resultCode == AppCompatActivity.RESULT_OK && data != null) {
if (resultCode == RESULT_OK && data != null) {
val selected = MediaUtils.getPath(this, data.data)
if (selected != null && selected.isNotEmpty()) {
when (requestCode) {
@ -127,15 +136,11 @@ class CustomizeActivity : BaseCustomizeActivity() {
}
private fun installFileTo(file: String, targetDir: String) {
try {
val fileObject = File(file)
val input = FileInputStream(fileObject.absolutePath)
val targetFile = File(targetDir, fileObject.name)
input.use {
FileUtils.writeFile(targetFile, it)
}
} catch (e: Exception) {
Toast.makeText(this, getString(R.string.error) + ": ${e.localizedMessage}", Toast.LENGTH_LONG).show()
kotlin.runCatching {
val source = File(file)
Files.copy(source.toPath(), Paths.get(targetDir, source.name))
}.onFailure {
Toast.makeText(this, getString(R.string.error) + ": ${it.localizedMessage}", Toast.LENGTH_LONG).show()
}
}

View File

@ -1,14 +1,14 @@
package io.neoterm.ui.setup
import androidx.appcompat.app.AlertDialog
import android.content.ActivityNotFoundException
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import android.view.LayoutInflater
import android.view.View
import android.widget.*
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import io.neoterm.App
import io.neoterm.R
import io.neoterm.component.pm.SourceHelper
@ -19,11 +19,9 @@ 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.setup.helper.URLAvailability
import io.neoterm.utils.MediaUtils
import io.neoterm.utils.PackageUtils
import java.io.File
import java.lang.Exception
/**
@ -39,9 +37,9 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener
private var setupParameterUri: Uri? = null
private val hintMapping = arrayOf(
R.id.setup_method_online, R.string.setup_hint_online,
R.id.setup_method_local, R.string.setup_hint_local,
R.id.setup_method_backup, R.string.setup_hint_backup
R.id.setup_method_online, R.string.setup_hint_online,
R.id.setup_method_local, R.string.setup_hint_local,
R.id.setup_method_backup, R.string.setup_hint_backup
)
override fun onCreate(savedInstanceState: Bundle?) {
@ -103,7 +101,7 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener
R.id.setup_method_backup,
R.id.setup_method_local -> {
SetupHelper.makeErrorDialog(this, R.string.setup_error_parameter_null)
.show()
.show()
return
}
}
@ -137,8 +135,10 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "*/*"
try {
startActivityForResult( Intent.createChooser(intent, getString(R.string.setup_local)),
REQUEST_SELECT_PARAMETER)
startActivityForResult(
Intent.createChooser(intent, getString(R.string.setup_local)),
REQUEST_SELECT_PARAMETER
)
} catch (ignore: ActivityNotFoundException) {
Toast.makeText(this, R.string.no_file_picker, Toast.LENGTH_SHORT).show()
}
@ -151,15 +151,15 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener
val edit = view.findViewById<EditText>(R.id.dialog_edit_text_editor)
AlertDialog.Builder(this)
.setTitle(R.string.new_source)
.setView(view)
.setPositiveButton(android.R.string.yes, { _, _ ->
val newURL = edit.text.toString()
val parameterEditor = findViewById<EditText>(R.id.setup_source_parameter)
parameterEditor.setText(newURL)
})
.setNegativeButton(android.R.string.no, null)
.show()
.setTitle(R.string.new_source)
.setView(view)
.setPositiveButton(android.R.string.yes) { _, _ ->
val newURL = edit.text.toString()
val parameterEditor = findViewById<EditText>(R.id.setup_source_parameter)
parameterEditor.setText(newURL)
}
.setNegativeButton(android.R.string.no, null)
.show()
}
}
}
@ -175,26 +175,14 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener
private fun validateParameter(id: Int, parameter: String): String? {
return when (id) {
R.id.setup_method_online -> {
val result = URLAvailability.checkUrlAvailability(this, parameter)
return when (result) {
URLAvailability.ResultCode.URL_NO_INTERNET -> {
getString(R.string.setup_error_no_internet)
}
URLAvailability.ResultCode.URL_CONNECTION_FAILED -> {
getString(R.string.setup_error_connection_failed)
}
URLAvailability.ResultCode.URL_INVALID -> {
getString(R.string.setup_error_invalid_url)
}
else -> null
}
R.id.setup_method_online -> try {
java.net.URI.create(parameter)
null
} catch (e: IllegalArgumentException) {
getString(R.string.setup_error_invalid_url)
}
R.id.setup_method_local,
R.id.setup_method_backup -> {
if (File(parameter).exists()) null
else getString(R.string.setup_error_file_not_found)
}
R.id.setup_method_backup -> if (File(parameter).exists()) null else getString(R.string.setup_error_file_not_found)
else -> null
}
}
@ -213,13 +201,13 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener
val messageId = if (needSetup) R.string.setup_confirm_text else R.string.setup_reset_confirm_text
AlertDialog.Builder(this)
.setTitle(titleId)
.setMessage(messageId)
.setPositiveButton(android.R.string.yes, { _, _ ->
doSetup(connection)
})
.setNegativeButton(android.R.string.no, null)
.show()
.setTitle(titleId)
.setMessage(messageId)
.setPositiveButton(android.R.string.yes) { _, _ ->
doSetup(connection)
}
.setNegativeButton(android.R.string.no, null)
.show()
}
private fun doSetup(connection: SourceConnection) {
@ -234,22 +222,22 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener
} else {
AlertDialog.Builder(this)
.setTitle(R.string.error)
.setMessage(error.toString())
.setNegativeButton(R.string.use_system_shell, { _, _ ->
setResult(RESULT_CANCELED)
finish()
})
.setNeutralButton(R.string.show_help, { _, _ ->
App.get().openHelpLink()
})
.setPositiveButton(android.R.string.yes, null)
.show()
.setTitle(R.string.error)
.setMessage(error.toString())
.setNegativeButton(R.string.use_system_shell) { _, _ ->
setResult(RESULT_CANCELED)
finish()
}
.setNeutralButton(R.string.show_help) { _, _ ->
App.get().openHelpLink()
}
.setPositiveButton(android.R.string.yes, null)
.show()
}
}
private fun executeAptUpdate() {
PackageUtils.apt(this, "update", null, { exitStatus, dialog ->
PackageUtils.apt(this, "update", null) { exitStatus, dialog ->
if (exitStatus == 0) {
dialog.dismiss()
aptUpdated = true
@ -257,17 +245,17 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener
} else {
dialog.setTitle(getString(R.string.error))
}
})
}
}
private fun executeAptUpgrade() {
PackageUtils.apt(this, "upgrade", arrayOf("-y"), { exitStatus, dialog ->
PackageUtils.apt(this, "upgrade", arrayOf("-y")) { exitStatus, dialog ->
if (exitStatus == 0) {
dialog.dismiss()
finish()
} else {
dialog.setTitle(getString(R.string.error))
}
})
}
}
}

View File

@ -2,7 +2,7 @@ package io.neoterm.utils
import android.content.Context
import java.io.File
import java.io.InputStream
import java.nio.file.Files
/**
* @author kiva
@ -10,18 +10,14 @@ import java.io.InputStream
object AssetsUtils {
fun extractAssetsDir(context: Context, dirName: String, extractDir: String) {
val assets = context.assets
assets.list(dirName)
.map { File(extractDir, it) }
assets.list(dirName)?.let {
it.map { File(extractDir, it) }
.takeWhile { !it.exists() }
.forEach { file ->
assets.open("$dirName/${file.name}").use {
FileUtils.writeFile(file, it)
kotlin.runCatching { Files.copy(it, file.toPath()) }
}
}
}
fun openAssetsFile(context: Context, fileName: String) : InputStream {
val assets = context.assets
return assets.open(fileName)
}
}
}

View File

@ -1,47 +1,11 @@
package io.neoterm.utils
import io.neoterm.frontend.logging.NLog
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.InputStream
import java.text.DecimalFormat
/**
* @author kiva
*/
object FileUtils {
fun writeFile(path: File, bytes: ByteArray): Boolean {
try {
return FileOutputStream(path).use {
it.write(bytes)
it.flush()
true
}
} catch (e: Exception) {
NLog.e("FileUtils", "Failed to write file: ${e.localizedMessage}")
return false
}
}
fun writeFile(path: File, inputStream: InputStream): Boolean {
val bytes = ByteArray(inputStream.available())
inputStream.read(bytes)
return writeFile(path, bytes)
}
fun readFile(path: File): ByteArray? {
if (!path.canRead()) {
return null
}
return FileInputStream(path).use {
val bytes = ByteArray(it.available())
it.read(bytes)
bytes
}
}
fun formatSizeInKB(size: Long): String {
val decimalFormat = DecimalFormat("####.00");
if (size < 1024) {

View File

@ -15,8 +15,7 @@ import android.provider.MediaStore
*/
object MediaUtils {
@SuppressLint("ObsoleteSdkInt")
/**
/**
* 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.
@ -25,9 +24,10 @@ object MediaUtils {
* *
* @param uri The Uri to query.
*/
fun getPath(context: Context, uri: Uri): String? {
@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
@ -44,37 +44,30 @@ object MediaUtils {
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)!!)
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 type = split[0]
var contentUri: Uri? = null
if ("image" == type) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
} else if ("video" == type) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
} else if ("audio" == type) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
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)
}// MediaProvider
// DownloadsProvider
}
} 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
}
@ -96,8 +89,10 @@ object MediaUtils {
* *
* @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? {
private fun getDataColumn(
context: Context, uri: Uri, selection: String?,
selectionArgs: Array<String>?
): String? {
var cursor: Cursor? = null
val column = "_data"

View File

@ -1,62 +0,0 @@
package io.neoterm.utils
import android.content.Context
import android.net.ConnectivityManager
import android.telephony.TelephonyManager
/**
* @author kiva
*/
object NetworkUtils {
fun isNetworkAvailable(context: Context): Boolean {
return getNetworkType(context) != null
}
private fun getNetworkType(context: Context): String? {
var networkType: String? = null
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager ?: return null
val networkInfo = connectivityManager.activeNetworkInfo
if (networkInfo != null && networkInfo.isConnected) {
if (networkInfo.type == ConnectivityManager.TYPE_WIFI) {
networkType = "WIFI"
} else if (networkInfo.type == ConnectivityManager.TYPE_MOBILE) {
when (networkInfo.subtype) {
TelephonyManager.NETWORK_TYPE_GPRS,
TelephonyManager.NETWORK_TYPE_EDGE,
TelephonyManager.NETWORK_TYPE_CDMA,
TelephonyManager.NETWORK_TYPE_1xRTT,
TelephonyManager.NETWORK_TYPE_IDEN -> networkType = "2G"
TelephonyManager.NETWORK_TYPE_UMTS,
TelephonyManager.NETWORK_TYPE_EVDO_0,
TelephonyManager.NETWORK_TYPE_EVDO_A,
TelephonyManager.NETWORK_TYPE_HSDPA,
TelephonyManager.NETWORK_TYPE_HSUPA,
TelephonyManager.NETWORK_TYPE_HSPA,
TelephonyManager.NETWORK_TYPE_EVDO_B,
TelephonyManager.NETWORK_TYPE_EHRPD,
TelephonyManager.NETWORK_TYPE_HSPAP -> networkType = "3G"
TelephonyManager.NETWORK_TYPE_LTE -> networkType = "4G"
else -> {
val subtypeName = networkInfo.subtypeName
if (subtypeName.equals("TD-SCDMA", ignoreCase = true)
|| subtypeName.equals("WCDMA", ignoreCase = true)
|| subtypeName.equals("CDMA2000", ignoreCase = true)) {
networkType = "3G"
} else {
networkType = subtypeName
}
}
}
}
}
return networkType
}
}

View File

@ -2,12 +2,8 @@ package io.neoterm.utils
import android.content.Context
import io.neoterm.backend.TerminalSession
import io.neoterm.component.pm.PackageComponent
import io.neoterm.component.pm.SourceManager
import io.neoterm.frontend.component.ComponentManager
import io.neoterm.frontend.config.NeoTermPath
import io.neoterm.frontend.floating.TerminalDialog
import java.io.File
/**
* @author kiva
@ -15,18 +11,18 @@ import java.io.File
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)
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")
.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")
}
}

View File

@ -1,7 +1,7 @@
package io.neoterm.utils
import androidx.appcompat.app.AppCompatActivity
import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import io.neoterm.backend.TerminalSession
import io.neoterm.component.font.FontComponent
import io.neoterm.component.session.SessionComponent
@ -54,7 +54,7 @@ object TerminalUtils {
val specialChars = "\"\\$`!"
builder.append('"')
val length = s.length
for (i in 0..length - 1) {
for (i in 0 until length) {
val c = s[i]
if (specialChars.indexOf(c) >= 0) {
builder.append('\\')