MISC: improve code quality
- use nio apis - remove unnecessary utilities - apply idea suggestions - remove some unused parameters and imports
This commit is contained in:
parent
31bbf3f1c0
commit
b517d68e9e
@ -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!!
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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}")
|
||||
}
|
||||
}
|
||||
|
@ -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-")
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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) {
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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")
|
||||
}
|
||||
}
|
@ -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('\\')
|
||||
|
Loading…
Reference in New Issue
Block a user