Rewrite: Complete Release Tweaks

This commit is contained in:
Daniel 2025-11-16 21:10:12 +03:00
parent 188bc459b1
commit 300fceae98
11 changed files with 45 additions and 51 deletions

View file

@ -4,11 +4,11 @@ plugins {
} }
android { android {
namespace = "com.example.vedroid" namespace = "com.example.androidsshclient"
compileSdk = 34 compileSdk = 34
defaultConfig { defaultConfig {
applicationId = "com.example.vedroid" applicationId = "com.example.androidsshclient"
minSdk = 21 minSdk = 21
targetSdk = 34 targetSdk = 34
versionCode = 1 versionCode = 1

View file

@ -9,7 +9,7 @@
<application <application
android:allowBackup="false" android:allowBackup="false"
android:icon="@drawable/ic_launcher" android:icon="@drawable/ic_launcher"
android:label="Vedroid SSH Client" android:label="Android SSH Client"
android:theme="@style/Theme.AppCompat.Light.DarkActionBar"> android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
<!-- Главный экран --> <!-- Главный экран -->

View file

@ -1,4 +1,4 @@
package com.example.vedroid package com.example.androidsshclient
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle import android.os.Bundle

View file

@ -1,7 +1,7 @@
package com.example.vedroid package com.example.androidsshclient
import android.content.SharedPreferences import android.content.SharedPreferences
import android.content.Intent // ✅ Добавляем этот импорт import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.widget.* import android.widget.*
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
@ -13,7 +13,7 @@ import com.jcraft.jsch.ChannelExec
import com.jcraft.jsch.JSch import com.jcraft.jsch.JSch
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONObject import org.json.JSONObject
import com.example.vedroid.model.SshProfile import com.example.androidsshclient.model.SshProfile
class SshActivity : AppCompatActivity() { class SshActivity : AppCompatActivity() {
@ -27,7 +27,7 @@ class SshActivity : AppCompatActivity() {
private lateinit var profilesSpinner: Spinner private lateinit var profilesSpinner: Spinner
private lateinit var saveProfileButton: Button private lateinit var saveProfileButton: Button
private lateinit var deleteProfileButton: Button private lateinit var deleteProfileButton: Button
private lateinit var terminalButton: Button // ✅ Добавляем terminalButton private lateinit var terminalButton: Button
private val jsch = JSch() private val jsch = JSch()
private lateinit var prefs: SharedPreferences private lateinit var prefs: SharedPreferences
@ -55,7 +55,7 @@ class SshActivity : AppCompatActivity() {
profilesSpinner = findViewById(R.id.profilesSpinner) profilesSpinner = findViewById(R.id.profilesSpinner)
saveProfileButton = findViewById(R.id.saveProfileButton) saveProfileButton = findViewById(R.id.saveProfileButton)
deleteProfileButton = findViewById(R.id.deleteProfileButton) deleteProfileButton = findViewById(R.id.deleteProfileButton)
terminalButton = findViewById(R.id.terminalButton) // ✅ Инициализируем terminalButton terminalButton = findViewById(R.id.terminalButton)
executeButton.isEnabled = false executeButton.isEnabled = false
@ -94,7 +94,7 @@ class SshActivity : AppCompatActivity() {
deleteCurrentProfile() deleteCurrentProfile()
} }
terminalButton.setOnClickListener { // ✅ Добавляем обработчик для terminalButton terminalButton.setOnClickListener {
val position = profilesSpinner.selectedItemPosition val position = profilesSpinner.selectedItemPosition
if (position > 0) { if (position > 0) {
val profile = profiles[position - 1] val profile = profiles[position - 1]
@ -160,14 +160,13 @@ class SshActivity : AppCompatActivity() {
} }
prefs.edit().putString("profiles", jsonArray.toString()).apply() prefs.edit().putString("profiles", jsonArray.toString()).apply()
loadProfiles() // Reload to update spinner loadProfiles()
} }
private fun showSaveProfileDialog() { private fun showSaveProfileDialog() {
val dialogView = layoutInflater.inflate(R.layout.dialog_save_profile, null) val dialogView = layoutInflater.inflate(R.layout.dialog_save_profile, null)
val nameInput = dialogView.findViewById<EditText>(R.id.profileNameInput) val nameInput = dialogView.findViewById<EditText>(R.id.profileNameInput)
// Pre-fill with current connection details
nameInput.setText("${usernameInput.text}@${hostInput.text}") nameInput.setText("${usernameInput.text}@${hostInput.text}")
AlertDialog.Builder(this) AlertDialog.Builder(this)
@ -192,14 +191,13 @@ class SshActivity : AppCompatActivity() {
password = passwordInput.text.toString() password = passwordInput.text.toString()
) )
profiles.removeAll { it.name == name } // Remove existing with same name profiles.removeAll { it.name == name }
profiles.add(profile) profiles.add(profile)
saveProfiles() saveProfiles()
// Select the newly saved profile
profilesSpinner.setSelection(adapter.getPosition(name)) profilesSpinner.setSelection(adapter.getPosition(name))
appendOutput("Profile '$name' saved") appendOutput("Profile '$name' saved")
} }
private fun deleteCurrentProfile() { private fun deleteCurrentProfile() {
@ -213,7 +211,7 @@ class SshActivity : AppCompatActivity() {
profiles.removeAt(position - 1) profiles.removeAt(position - 1)
saveProfiles() saveProfiles()
profilesSpinner.setSelection(0) // Select "New Profile" profilesSpinner.setSelection(0) // Select "New Profile"
appendOutput("🗑️ Profile '${profile.name}' deleted") appendOutput("Profile '${profile.name}' deleted")
} }
.setNegativeButton("Cancel", null) .setNegativeButton("Cancel", null)
.show() .show()
@ -226,7 +224,7 @@ class SshActivity : AppCompatActivity() {
usernameInput.setText(profile.username) usernameInput.setText(profile.username)
passwordInput.setText(profile.password) passwordInput.setText(profile.password)
appendOutput("📁 Loaded profile: ${profile.name}") appendOutput("Loaded profile: ${profile.name}")
} }
private fun connectSsh() { private fun connectSsh() {
@ -236,28 +234,28 @@ class SshActivity : AppCompatActivity() {
val password = passwordInput.text.toString() val password = passwordInput.text.toString()
if (host.isEmpty() || username.isEmpty() || password.isEmpty()) { if (host.isEmpty() || username.isEmpty() || password.isEmpty()) {
appendOutput("Please fill all fields") appendOutput("Please fill all fields")
return return
} }
GlobalScope.launch(Dispatchers.IO) { GlobalScope.launch(Dispatchers.IO) {
try { try {
appendOutput("🔌 Connecting to $host:$port...") appendOutput("Connecting to $host:$port...")
val session = jsch.getSession(username, host, port).apply { val session = jsch.getSession(username, host, port).apply {
setPassword(password) setPassword(password)
setConfig("StrictHostKeyChecking", "no") // ⚠️ Only for testing! setConfig("StrictHostKeyChecking", "no")
connect(30000) // 30 second timeout connect(30000) // 30 second timeout
} }
appendOutput("Connected successfully!") appendOutput("Connected successfully!")
runOnUiThread { runOnUiThread {
executeButton.isEnabled = true executeButton.isEnabled = true
} }
} catch (e: Exception) { } catch (e: Exception) {
appendOutput("Connection failed: ${e.message}") appendOutput("Connection failed: ${e.message}")
e.printStackTrace() e.printStackTrace()
} }
} }
@ -270,13 +268,13 @@ class SshActivity : AppCompatActivity() {
val password = passwordInput.text.toString() val password = passwordInput.text.toString()
if (host.isEmpty() || username.isEmpty() || password.isEmpty()) { if (host.isEmpty() || username.isEmpty() || password.isEmpty()) {
appendOutput("Please fill all fields") appendOutput("Please fill all fields")
return return
} }
GlobalScope.launch(Dispatchers.IO) { GlobalScope.launch(Dispatchers.IO) {
try { try {
appendOutput("💻 Executing: $command") appendOutput("Executing: $command")
val session = jsch.getSession(username, host, port).apply { val session = jsch.getSession(username, host, port).apply {
setPassword(password) setPassword(password)
@ -300,16 +298,16 @@ class SshActivity : AppCompatActivity() {
runOnUiThread { runOnUiThread {
if (output.isNotEmpty()) { if (output.isNotEmpty()) {
appendOutput("📄 Output:\n$output") appendOutput("Output:\n$output")
} }
if (error.isNotEmpty()) { if (error.isNotEmpty()) {
appendOutput("⚠️ Error:\n$error") appendOutput("Error:\n$error")
} }
appendOutput("🔚 Command completed") appendOutput("Command completed")
} }
} catch (e: Exception) { } catch (e: Exception) {
appendOutput("SSH operation failed: ${e.message}") appendOutput("SSH operation failed: ${e.message}")
e.printStackTrace() e.printStackTrace()
} }
} }
@ -323,7 +321,6 @@ class SshActivity : AppCompatActivity() {
} }
} }
// Простой data class для профилей
data class SshProfile( data class SshProfile(
val name: String, val name: String,
val host: String, val host: String,

View file

@ -1,4 +1,4 @@
package com.example.vedroid package com.example.androidsshclient
import android.os.Bundle import android.os.Bundle
import android.text.method.ScrollingMovementMethod import android.text.method.ScrollingMovementMethod
@ -113,7 +113,7 @@ class TerminalActivity : AppCompatActivity() {
private fun connectToTerminal(host: String, port: Int, username: String, password: String) { private fun connectToTerminal(host: String, port: Int, username: String, password: String) {
terminalScope.launch(Dispatchers.IO) { terminalScope.launch(Dispatchers.IO) {
try { try {
appendToTerminal("🔌 Connecting to $host:$port...\n") appendToTerminal("Connecting to $host:$port...\n")
val session = jsch.getSession(username, host, port).apply { val session = jsch.getSession(username, host, port).apply {
setPassword(password) setPassword(password)
@ -146,8 +146,8 @@ class TerminalActivity : AppCompatActivity() {
isConnected = true isConnected = true
appendToTerminal("Connected to SSH terminal\n") appendToTerminal("Connected to SSH terminal\n")
appendToTerminal("💡 Type commands in the input field below\n\n") appendToTerminal("Type commands in the input field below\n\n")
// Запускаем чтение вывода // Запускаем чтение вывода
launch(Dispatchers.IO) { launch(Dispatchers.IO) {
@ -155,7 +155,7 @@ class TerminalActivity : AppCompatActivity() {
} }
} catch (e: Exception) { } catch (e: Exception) {
appendToTerminal("Connection failed: ${e.message}\n") appendToTerminal("Connection failed: ${e.message}\n")
} }
} }
} }
@ -175,7 +175,7 @@ class TerminalActivity : AppCompatActivity() {
} }
} catch (e: Exception) { } catch (e: Exception) {
if (isConnected) { if (isConnected) {
appendToTerminal("\nConnection lost\n") appendToTerminal("\nConnection lost\n")
} }
} finally { } finally {
disconnect() disconnect()
@ -213,7 +213,7 @@ class TerminalActivity : AppCompatActivity() {
outputStream?.write("$command\n".toByteArray(StandardCharsets.UTF_8)) outputStream?.write("$command\n".toByteArray(StandardCharsets.UTF_8))
outputStream?.flush() outputStream?.flush()
} catch (e: Exception) { } catch (e: Exception) {
appendToTerminal("Error sending command\n") appendToTerminal("Error sending command\n")
} }
} }
@ -252,7 +252,7 @@ class TerminalActivity : AppCompatActivity() {
outputStream?.flush() outputStream?.flush()
appendToTerminal("^C\n") appendToTerminal("^C\n")
} catch (e: Exception) { } catch (e: Exception) {
appendToTerminal("Error sending Ctrl+C\n") appendToTerminal("Error sending Ctrl+C\n")
} }
} }
} }
@ -266,7 +266,7 @@ class TerminalActivity : AppCompatActivity() {
outputStream?.flush() outputStream?.flush()
appendToTerminal("^D\n") appendToTerminal("^D\n")
} catch (e: Exception) { } catch (e: Exception) {
appendToTerminal("Error sending Ctrl+D\n") appendToTerminal("Error sending Ctrl+D\n")
} }
} }
} }
@ -301,7 +301,7 @@ class TerminalActivity : AppCompatActivity() {
} catch (e: Exception) { } catch (e: Exception) {
// Ignore // Ignore
} }
appendToTerminal("\n🔌 Disconnected\n") appendToTerminal("\nDisconnected\n")
} }
override fun onDestroy() { override fun onDestroy() {

View file

@ -1,4 +1,4 @@
package com.example.vedroid.model package com.example.androidsshclient.model
// Теперь не нужно Serializable // Теперь не нужно Serializable
data class SshProfile( data class SshProfile(

View file

@ -8,7 +8,7 @@
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="SSH Client with Profiles" android:text="SSH Client"
android:textSize="24sp" android:textSize="24sp"
android:layout_gravity="center_horizontal" android:layout_gravity="center_horizontal"
android:layout_marginBottom="20dp" /> android:layout_marginBottom="20dp" />
@ -31,7 +31,7 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:text="💾" android:text="Save Profile"
android:layout_marginEnd="4dp" /> android:layout_marginEnd="4dp" />
<Button <Button
@ -39,7 +39,7 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:text="🗑️" android:text="Delete Profile"
android:layout_marginStart="4dp" /> android:layout_marginStart="4dp" />
</LinearLayout> </LinearLayout>
@ -106,12 +106,11 @@
android:text="Execute: ls -la" android:text="Execute: ls -la"
android:layout_marginTop="8dp" /> android:layout_marginTop="8dp" />
<!-- Добавляем после executeButton -->
<Button <Button
android:id="@+id/terminalButton" android:id="@+id/terminalButton"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="🖥️ Open Interactive Terminal" android:text="Open Interactive Terminal"
android:layout_marginBottom="8dp" android:layout_marginBottom="8dp"
android:backgroundTint="#4CAF50" /> android:backgroundTint="#4CAF50" />

View file

@ -111,7 +111,7 @@
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="💡 Use ↑↓ for command history" android:text="Use scroll for command history"
android:textSize="12sp" android:textSize="12sp"
android:textColor="#AAAAAA" android:textColor="#AAAAAA"
android:gravity="center" android:gravity="center"

View file

@ -1,4 +1,4 @@
<resources> <resources>
<string name="app_name">Vedroid</string> <string name="app_name">Android</string>
<string name="hello_world">Hello World!</string> <string name="hello_world">Hello World!</string>
</resources> </resources>

View file

@ -1,6 +1,6 @@
<resources xmlns:tools="http://schemas.android.com/tools"> <resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. --> <!-- Base application theme. -->
<style name="Theme.Vedroid" parent="Theme.AppCompat.Light.DarkActionBar"> <style name="Theme.Android" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Primary brand color. --> <!-- Primary brand color. -->
<item name="colorPrimary">#3F51B5</item> <item name="colorPrimary">#3F51B5</item>
<item name="colorPrimaryVariant">#303F9F</item> <item name="colorPrimaryVariant">#303F9F</item>

View file

@ -19,10 +19,8 @@ dependencyResolutionManagement {
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
maven { url = uri("https://dl.bintray.com/termux/termux-packages/") }
maven { url = uri("https://grimler.se/termux-packages/") }
} }
} }
rootProject.name = "vedroid" rootProject.name = "AndroidSSHClient"
include(":app") include(":app")