Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add option to specify a path for server #194

Merged
merged 3 commits into from
Dec 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ android {
applicationId = "dev.yashgarg.qbit"
minSdk = 24
targetSdk = 33
versionCode = 8
versionCode = 9
versionName = "v0.1.$versionCode-$commitHash"

multiDexEnabled = true
Expand Down
83 changes: 83 additions & 0 deletions app/schemas/dev.yashgarg.qbit.data.AppDatabase/3.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
{
"formatVersion": 1,
"database": {
"version": 3,
"identityHash": "fd3c97ded76419eef57c25570fef8bfb",
"entities": [
{
"tableName": "configs",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`config_id` INTEGER NOT NULL, `serverName` TEXT NOT NULL, `baseUrl` TEXT NOT NULL, `port` INTEGER, `path` TEXT, `username` TEXT NOT NULL, `password` TEXT NOT NULL, `connectionType` TEXT NOT NULL, `trustSelfSigned` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`config_id`))",
"fields": [
{
"fieldPath": "configId",
"columnName": "config_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "serverName",
"columnName": "serverName",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "baseUrl",
"columnName": "baseUrl",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "port",
"columnName": "port",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "path",
"columnName": "path",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "username",
"columnName": "username",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "password",
"columnName": "password",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "connectionType",
"columnName": "connectionType",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "trustSelfSigned",
"columnName": "trustSelfSigned",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"config_id"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'fd3c97ded76419eef57c25570fef8bfb')"
]
}
}
4 changes: 2 additions & 2 deletions app/src/main/kotlin/dev/yashgarg/qbit/data/AppDatabase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import dev.yashgarg.qbit.data.models.ServerConfig

@Database(
entities = [ServerConfig::class],
version = 2,
autoMigrations = [AutoMigration(from = 1, to = 2)],
version = 3,
autoMigrations = [AutoMigration(from = 1, to = 2), AutoMigration(from = 2, to = 3)],
exportSchema = true
)
abstract class AppDatabase : RoomDatabase() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,12 @@ constructor(
withContext(Dispatchers.IO) {
if (client == null) {
val config = configDao.getConfigAtIndex()!!
val port = if (config.port != null) ":${config.port}" else ""
val path = config.path ?: ""

client =
QBittorrentClient(
"${config.connectionType.toString().lowercase()}://${config.baseUrl}" +
if (config.port != null) ":${config.port}" else "",
"${config.connectionType.toString().lowercase()}://${config.baseUrl}$port$path",
config.username,
config.password,
syncInterval = ClientManager.syncInterval,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ data class ServerConfig(
val serverName: String,
val baseUrl: String,
val port: Int? = null,
val path: String? = null,
val username: String,
val password: String,
val connectionType: ConnectionType,
Expand Down
130 changes: 73 additions & 57 deletions app/src/main/kotlin/dev/yashgarg/qbit/ui/config/ConfigFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,20 @@ class ConfigFragment : Fragment(AppR.layout.config_fragment) {
setupActionbar()

val adapter = ArrayAdapter(requireContext(), AppR.layout.list_item, connectionTypes)
(binding.typeDropdown.editText as? AutoCompleteTextView)?.setAdapter(adapter)

binding.saveButton.setOnClickListener {
viewModel.validateForm(
binding.serverNameTil.editText?.text.toString(),
binding.serverHostTil.editText?.text.toString(),
binding.serverPortTil.editText?.text.toString(),
binding.typeDropdown.editText?.text.toString(),
binding.serverUsernameTil.editText?.text.toString(),
binding.serverPasswordTil.editText?.text.toString(),
)

with(binding) {
(typeDropdown.editText as? AutoCompleteTextView)?.setAdapter(adapter)

saveButton.setOnClickListener {
viewModel.validateForm(
serverNameTil.editText?.text.toString(),
serverHostTil.editText?.text.toString(),
serverPortTil.editText?.text.toString(),
typeDropdown.editText?.text.toString(),
serverUsernameTil.editText?.text.toString(),
serverPasswordTil.editText?.text.toString(),
)
}
}
}

Expand Down Expand Up @@ -112,13 +115,17 @@ class ConfigFragment : Fragment(AppR.layout.config_fragment) {
}

private fun enableFields(enabled: Boolean) {
binding.serverNameTiet.isEnabled = enabled
binding.serverHostTiet.isEnabled = enabled
binding.serverPortTiet.isEnabled = enabled
binding.typeDropdown.isEnabled = enabled
binding.serverUsernameTiet.isEnabled = enabled
binding.serverPasswordTiet.isEnabled = enabled
binding.saveButton.isEnabled = enabled
with(binding) {
enabled.apply {
serverNameTiet.isEnabled = this
serverHostTiet.isEnabled = this
serverPortTiet.isEnabled = this
typeDropdown.isEnabled = this
serverUsernameTiet.isEnabled = this
serverPasswordTiet.isEnabled = this
saveButton.isEnabled = this
}
}
}

private fun handleEvent(event: ConfigViewModel.ValidationEvent) {
Expand All @@ -133,50 +140,59 @@ class ConfigFragment : Fragment(AppR.layout.config_fragment) {
)
checkSnackbar.show()

viewLifecycleOwner.lifecycleScope.launch {
val port = binding.serverPortTil.editText?.text
val connectionResponse =
viewModel.testConfig(
"${binding.typeDropdown.editText?.text.toString().lowercase()}://${binding.serverHostTil.editText?.text}" +
if (!port.isNullOrEmpty()) ":$port" else "",
binding.serverUsernameTil.editText?.text.toString(),
binding.serverPasswordTil.editText?.text.toString(),
binding.trustCert.isChecked
)

when (connectionResponse) {
is Ok -> {
checkSnackbar.dismiss()
Toast.makeText(
context,
"Success! Client app version is ${connectionResponse.value}",
Toast.LENGTH_LONG
)
.show()

viewModel.insert(
binding.serverNameTil.editText?.text.toString(),
binding.serverHostTil.editText?.text.toString(),
binding.serverPortTil.editText?.text.toString(),
binding.typeDropdown.editText?.text.toString(),
binding.serverUsernameTil.editText?.text.toString(),
binding.serverPasswordTil.editText?.text.toString(),
binding.trustCert.isChecked
with(binding) {
viewLifecycleOwner.lifecycleScope.launch {
val connectionType = typeDropdown.editText?.text.toString().lowercase()
val serverHost = serverHostTil.editText?.text.toString()
val username = serverUsernameTil.editText?.text.toString()
val password = serverPasswordTil.editText?.text.toString()
val path = serverPathTil.editText?.text.toString()
val port = serverPortTil.editText?.text

val connectionResponse =
viewModel.testConfig(
"$connectionType://$serverHost${if (!port.isNullOrEmpty()) ":$port" else ""}" +
if (path.isNotEmpty()) "/$path" else "",
username,
password,
trustCert.isChecked
)

findNavController().navigateUp()
}
is Err -> {
Log.e(ClientManager.tag, connectionResponse.error.toString())
Snackbar.make(
requireView(),
"Failed! ${connectionResponse.error.message}",
Snackbar.LENGTH_LONG
when (connectionResponse) {
is Ok -> {
checkSnackbar.dismiss()
Toast.makeText(
context,
"Success! Client app version is ${connectionResponse.value}",
Toast.LENGTH_LONG
)
.show()

viewModel.insert(
serverNameTil.editText?.text.toString(),
serverHost,
port.toString(),
path,
connectionType,
username,
password,
trustCert.isChecked
)
.show()

findNavController().navigateUp()
}
is Err -> {
Log.e(ClientManager.tag, connectionResponse.error.toString())
Snackbar.make(
requireView(),
"Failed! ${connectionResponse.error.message}",
Snackbar.LENGTH_LONG
)
.show()
}
}
enableFields(true)
}
enableFields(true)
}
}
}
Expand Down
20 changes: 12 additions & 8 deletions app/src/main/kotlin/dev/yashgarg/qbit/ui/config/ConfigViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -166,21 +166,25 @@ class ConfigViewModel @Inject constructor(private val configDao: ConfigDao) : Vi
serverName: String,
serverHost: String,
port: String,
path: String,
connectionType: String,
username: String,
password: String,
trustSelfSigned: Boolean
) {
val config =
ServerConfig(
0,
serverName.trim(),
serverHost.trim(),
if (port.isEmpty()) null else port.trim().toInt(),
username.trim(),
password.trim(),
if (connectionType.trim() == "HTTP") ConnectionType.HTTP else ConnectionType.HTTPS,
trustSelfSigned
configId = 0,
serverName = serverName.trim(),
baseUrl = serverHost.trim(),
port = if (port.isEmpty()) null else port.trim().toInt(),
path = if (path.isEmpty()) null else "/$path",
username = username.trim(),
password = password.trim(),
connectionType =
if (connectionType.trim() == "http") ConnectionType.HTTP
else ConnectionType.HTTPS,
trustSelfSigned = trustSelfSigned
)

viewModelScope.launch { configDao.addConfig(config) }
Expand Down
36 changes: 31 additions & 5 deletions app/src/main/res/layout/config_fragment.xml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/server_host_til"
app:placeholderText="0 - 65535">
app:placeholderText="0 - 65535"
app:prefixText=":">

<com.google.android.material.textfield.TextInputEditText
android:id="@+id/server_port_tiet"
Expand All @@ -99,6 +100,30 @@

</com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.textfield.TextInputLayout
android:id="@+id/server_path_til"
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="15dp"
android:layout_marginVertical="5dp"
android:hint="@string/path"
app:errorEnabled="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/server_port_til"
app:placeholderText="your/path"
app:prefixText="/">

<com.google.android.material.textfield.TextInputEditText
android:id="@+id/server_path_tiet"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inputType="text"
android:maxLines="1" />

</com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.textfield.TextInputLayout
android:id="@+id/server_username_til"
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
Expand All @@ -108,9 +133,9 @@
android:layout_marginVertical="5dp"
android:hint="@string/username"
app:errorEnabled="true"
app:layout_constraintEnd_toEndOf="@id/server_port_til"
app:layout_constraintStart_toStartOf="@id/server_port_til"
app:layout_constraintTop_toBottomOf="@id/server_port_til"
app:layout_constraintEnd_toEndOf="@id/server_path_til"
app:layout_constraintStart_toStartOf="@id/server_path_til"
app:layout_constraintTop_toBottomOf="@id/server_path_til"
app:placeholderText="e.g. admin">

<com.google.android.material.textfield.TextInputEditText
Expand All @@ -134,7 +159,8 @@
app:errorEnabled="true"
app:layout_constraintEnd_toEndOf="@id/server_username_til"
app:layout_constraintStart_toStartOf="@id/server_username_til"
app:layout_constraintTop_toBottomOf="@id/server_username_til">
app:layout_constraintTop_toBottomOf="@id/server_username_til"
app:placeholderText="e.g. adminadmin">

<com.google.android.material.textfield.TextInputEditText
android:id="@+id/server_password_tiet"
Expand Down
1 change: 1 addition & 0 deletions common/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
<string name="password">Password</string>
<string name="username">Username</string>
<string name="port">Port (optional)</string>
<string name="path">Path (optional)</string>
<string name="host_or_ip">Host or IP</string>
<string name="server_name">Server name</string>
<string name="save_and_test_cfg">Save and test config</string>
Expand Down