update browser extension and app
This commit is contained in:
42
android/app/src/main/java/com/fuggloader/app/Instance.kt
Normal file
42
android/app/src/main/java/com/fuggloader/app/Instance.kt
Normal file
@@ -0,0 +1,42 @@
|
||||
package com.fuggloader.app
|
||||
|
||||
import org.json.JSONObject
|
||||
import java.util.UUID
|
||||
|
||||
data class Instance(
|
||||
val id: String = UUID.randomUUID().toString(),
|
||||
var name: String,
|
||||
var apiUrl: String,
|
||||
var apiKey: String,
|
||||
var defaultRating: String = "none",
|
||||
var defaultTags: String = "",
|
||||
var defaultVisibility: String = "0"
|
||||
) {
|
||||
fun toJsonObject(): JSONObject {
|
||||
return JSONObject().apply {
|
||||
put("id", id)
|
||||
put("name", name)
|
||||
put("apiUrl", apiUrl)
|
||||
put("apiKey", apiKey)
|
||||
put("defaultRating", defaultRating)
|
||||
put("defaultTags", defaultTags)
|
||||
put("defaultVisibility", defaultVisibility)
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String = name
|
||||
|
||||
companion object {
|
||||
fun fromJsonObject(json: JSONObject): Instance {
|
||||
return Instance(
|
||||
id = json.optString("id", UUID.randomUUID().toString()),
|
||||
name = json.optString("name", "Default"),
|
||||
apiUrl = json.optString("apiUrl", ""),
|
||||
apiKey = json.optString("apiKey", ""),
|
||||
defaultRating = json.optString("defaultRating", "none"),
|
||||
defaultTags = json.optString("defaultTags", ""),
|
||||
defaultVisibility = json.optString("defaultVisibility", "0")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@ package com.fuggloader.app
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.AdapterView
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
@@ -9,13 +11,15 @@ import com.fuggloader.app.databinding.ActivityMainBinding
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
private lateinit var prefs: PreferencesManager
|
||||
private lateinit var uploader: UploaderService
|
||||
|
||||
private lateinit var instanceAdapter: ArrayAdapter<Instance>
|
||||
private var currentInstances: List<Instance> = emptyList()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -27,7 +31,7 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
setupRatingSpinner()
|
||||
setupVisibilitySpinner()
|
||||
loadSettings()
|
||||
setupInstanceSpinner()
|
||||
|
||||
binding.btnSave.setOnClickListener {
|
||||
saveSettings()
|
||||
@@ -35,9 +39,16 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
binding.btnTestConnection.setOnClickListener {
|
||||
saveSettings()
|
||||
testConnection()
|
||||
}
|
||||
|
||||
binding.btnAddInstance.setOnClickListener {
|
||||
addNewInstance()
|
||||
}
|
||||
|
||||
binding.btnDeleteInstance.setOnClickListener {
|
||||
deleteCurrentInstance()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupRatingSpinner() {
|
||||
@@ -52,19 +63,45 @@ class MainActivity : AppCompatActivity() {
|
||||
binding.spinnerVisibility.adapter = adapter
|
||||
}
|
||||
|
||||
private fun loadSettings() {
|
||||
binding.etApiUrl.setText(prefs.apiUrl)
|
||||
binding.etApiKey.setText(prefs.apiKey)
|
||||
binding.etTags.setText(prefs.defaultTags)
|
||||
private fun setupInstanceSpinner() {
|
||||
currentInstances = prefs.getInstances()
|
||||
if (currentInstances.isEmpty()) {
|
||||
val default = Instance(name = "Default", apiUrl = "", apiKey = "")
|
||||
prefs.addInstance(default)
|
||||
currentInstances = prefs.getInstances()
|
||||
}
|
||||
|
||||
when (prefs.defaultRating) {
|
||||
instanceAdapter = ArrayAdapter(this, android.R.layout.simple_spinner_dropdown_item, currentInstances)
|
||||
binding.spinnerInstances.adapter = instanceAdapter
|
||||
|
||||
val activeId = prefs.activeInstanceId
|
||||
val activeIndex = currentInstances.indexOfFirst { it.id == activeId }.coerceAtLeast(0)
|
||||
binding.spinnerInstances.setSelection(activeIndex)
|
||||
|
||||
binding.spinnerInstances.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||
val selected = currentInstances[position]
|
||||
prefs.activeInstanceId = selected.id
|
||||
loadInstanceData(selected)
|
||||
}
|
||||
override fun onNothingSelected(parent: AdapterView<*>?) {}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadInstanceData(instance: Instance) {
|
||||
binding.etInstanceName.setText(instance.name)
|
||||
binding.etApiUrl.setText(instance.apiUrl)
|
||||
binding.etApiKey.setText(instance.apiKey)
|
||||
binding.etTags.setText(instance.defaultTags)
|
||||
|
||||
when (instance.defaultRating) {
|
||||
"sfw" -> binding.spinnerRating.setSelection(1)
|
||||
"nsfw" -> binding.spinnerRating.setSelection(2)
|
||||
"nsfl" -> binding.spinnerRating.setSelection(3)
|
||||
else -> binding.spinnerRating.setSelection(0)
|
||||
}
|
||||
|
||||
when (prefs.defaultVisibility) {
|
||||
when (instance.defaultVisibility) {
|
||||
"1" -> binding.spinnerVisibility.setSelection(1)
|
||||
"2" -> binding.spinnerVisibility.setSelection(2)
|
||||
else -> binding.spinnerVisibility.setSelection(0)
|
||||
@@ -72,22 +109,54 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun saveSettings() {
|
||||
prefs.apiUrl = binding.etApiUrl.text.toString().trim()
|
||||
prefs.apiKey = binding.etApiKey.text.toString().trim()
|
||||
prefs.defaultTags = binding.etTags.text.toString().trim()
|
||||
val currentInstance = prefs.getActiveInstance() ?: return
|
||||
|
||||
currentInstance.name = binding.etInstanceName.text.toString().trim().ifBlank { "Untitled" }
|
||||
currentInstance.apiUrl = binding.etApiUrl.text.toString().trim()
|
||||
currentInstance.apiKey = binding.etApiKey.text.toString().trim()
|
||||
currentInstance.defaultTags = binding.etTags.text.toString().trim()
|
||||
|
||||
prefs.defaultRating = when (binding.spinnerRating.selectedItemPosition) {
|
||||
currentInstance.defaultRating = when (binding.spinnerRating.selectedItemPosition) {
|
||||
1 -> "sfw"
|
||||
2 -> "nsfw"
|
||||
3 -> "nsfl"
|
||||
else -> "none"
|
||||
}
|
||||
|
||||
prefs.defaultVisibility = binding.spinnerVisibility.selectedItemPosition.toString()
|
||||
currentInstance.defaultVisibility = binding.spinnerVisibility.selectedItemPosition.toString()
|
||||
|
||||
prefs.updateInstance(currentInstance)
|
||||
|
||||
// Refresh spinner to show updated name
|
||||
val pos = binding.spinnerInstances.selectedItemPosition
|
||||
currentInstances = prefs.getInstances()
|
||||
instanceAdapter = ArrayAdapter(this, android.R.layout.simple_spinner_dropdown_item, currentInstances)
|
||||
binding.spinnerInstances.adapter = instanceAdapter
|
||||
binding.spinnerInstances.setSelection(pos)
|
||||
}
|
||||
|
||||
private fun addNewInstance() {
|
||||
val newInstance = Instance(name = "New Instance", apiUrl = "", apiKey = "")
|
||||
prefs.addInstance(newInstance)
|
||||
prefs.activeInstanceId = newInstance.id
|
||||
setupInstanceSpinner()
|
||||
}
|
||||
|
||||
private fun deleteCurrentInstance() {
|
||||
val current = prefs.getActiveInstance() ?: return
|
||||
if (currentInstances.size <= 1) {
|
||||
Toast.makeText(this, "Cannot delete the only instance", Toast.LENGTH_SHORT).show()
|
||||
return
|
||||
}
|
||||
|
||||
prefs.deleteInstance(current.id)
|
||||
setupInstanceSpinner()
|
||||
Toast.makeText(this, "Instance deleted", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
private fun testConnection() {
|
||||
if (!prefs.isConfigured()) {
|
||||
val currentInstance = prefs.getActiveInstance()
|
||||
if (currentInstance == null || currentInstance.apiUrl.isBlank() || currentInstance.apiKey.isBlank()) {
|
||||
Toast.makeText(this, "Please enter both API URL and API Key", Toast.LENGTH_LONG).show()
|
||||
return
|
||||
}
|
||||
@@ -96,7 +165,7 @@ class MainActivity : AppCompatActivity() {
|
||||
binding.btnTestConnection.text = "Testing..."
|
||||
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
val result = uploader.testConnection()
|
||||
val result = uploader.testConnection(currentInstance)
|
||||
binding.btnTestConnection.isEnabled = true
|
||||
binding.btnTestConnection.text = "Test"
|
||||
|
||||
|
||||
@@ -2,31 +2,112 @@ package com.fuggloader.app
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import org.json.JSONArray
|
||||
|
||||
class PreferencesManager(context: Context) {
|
||||
private val prefs: SharedPreferences = context.getSharedPreferences("fuggloader_prefs", Context.MODE_PRIVATE)
|
||||
|
||||
var apiUrl: String
|
||||
get() = prefs.getString("api_url", "") ?: ""
|
||||
set(value) = prefs.edit().putString("api_url", value).apply()
|
||||
companion object {
|
||||
private const val KEY_INSTANCES = "instances_json"
|
||||
private const val KEY_ACTIVE_INSTANCE_ID = "active_instance_id"
|
||||
|
||||
var apiKey: String
|
||||
get() = prefs.getString("api_key", "") ?: ""
|
||||
set(value) = prefs.edit().putString("api_key", value).apply()
|
||||
// Old keys for migration
|
||||
private const val OLD_API_URL = "api_url"
|
||||
private const val OLD_API_KEY = "api_key"
|
||||
private const val OLD_RATING = "default_rating"
|
||||
private const val OLD_TAGS = "default_tags"
|
||||
private const val OLD_VISIBILITY = "default_visibility"
|
||||
}
|
||||
|
||||
var defaultRating: String
|
||||
get() = prefs.getString("default_rating", "none") ?: "none"
|
||||
set(value) = prefs.edit().putString("default_rating", value).apply()
|
||||
var activeInstanceId: String?
|
||||
get() = prefs.getString(KEY_ACTIVE_INSTANCE_ID, null)
|
||||
set(value) = prefs.edit().putString(KEY_ACTIVE_INSTANCE_ID, value).apply()
|
||||
|
||||
var defaultTags: String
|
||||
get() = prefs.getString("default_tags", "android,upload") ?: "android,upload"
|
||||
set(value) = prefs.edit().putString("default_tags", value).apply()
|
||||
fun getInstances(): List<Instance> {
|
||||
val jsonStr = prefs.getString(KEY_INSTANCES, null)
|
||||
if (jsonStr == null) {
|
||||
// Check for migration
|
||||
val oldUrl = prefs.getString(OLD_API_URL, null)
|
||||
if (oldUrl != null) {
|
||||
val instance = Instance(
|
||||
name = "Default",
|
||||
apiUrl = oldUrl,
|
||||
apiKey = prefs.getString(OLD_API_KEY, "") ?: "",
|
||||
defaultRating = prefs.getString(OLD_RATING, "none") ?: "none",
|
||||
defaultTags = prefs.getString(OLD_TAGS, "android,upload") ?: "android,upload",
|
||||
defaultVisibility = prefs.getString(OLD_VISIBILITY, "0") ?: "0"
|
||||
)
|
||||
val list = listOf(instance)
|
||||
saveInstances(list)
|
||||
activeInstanceId = instance.id
|
||||
|
||||
var defaultVisibility: String
|
||||
get() = prefs.getString("default_visibility", "0") ?: "0"
|
||||
set(value) = prefs.edit().putString("default_visibility", value).apply()
|
||||
// Clear old settings to avoid re-migration
|
||||
prefs.edit()
|
||||
.remove(OLD_API_URL)
|
||||
.remove(OLD_API_KEY)
|
||||
.remove(OLD_RATING)
|
||||
.remove(OLD_TAGS)
|
||||
.remove(OLD_VISIBILITY)
|
||||
.apply()
|
||||
|
||||
return list
|
||||
}
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
val list = mutableListOf<Instance>()
|
||||
try {
|
||||
val array = JSONArray(jsonStr)
|
||||
for (i in 0 until array.length()) {
|
||||
list.add(Instance.fromJsonObject(array.getJSONObject(i)))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
fun saveInstances(instances: List<Instance>) {
|
||||
val array = JSONArray()
|
||||
instances.forEach { array.put(it.toJsonObject()) }
|
||||
prefs.edit().putString(KEY_INSTANCES, array.toString()).apply()
|
||||
}
|
||||
|
||||
fun addInstance(instance: Instance) {
|
||||
val instances = getInstances().toMutableList()
|
||||
instances.add(instance)
|
||||
saveInstances(instances)
|
||||
}
|
||||
|
||||
fun updateInstance(instance: Instance) {
|
||||
val instances = getInstances().toMutableList()
|
||||
val index = instances.indexOfFirst { it.id == instance.id }
|
||||
if (index != -1) {
|
||||
instances[index] = instance
|
||||
saveInstances(instances)
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteInstance(id: String) {
|
||||
val instances = getInstances().toMutableList()
|
||||
instances.removeAll { it.id == id }
|
||||
saveInstances(instances)
|
||||
if (activeInstanceId == id) {
|
||||
activeInstanceId = instances.firstOrNull()?.id
|
||||
}
|
||||
}
|
||||
|
||||
fun getActiveInstance(): Instance? {
|
||||
val instances = getInstances()
|
||||
if (instances.isEmpty()) return null
|
||||
|
||||
val id = activeInstanceId ?: return instances.firstOrNull()
|
||||
return instances.find { it.id == id } ?: instances.firstOrNull()
|
||||
}
|
||||
|
||||
fun isConfigured(): Boolean {
|
||||
return apiUrl.isNotBlank() && apiKey.isNotBlank()
|
||||
return getActiveInstance()?.let {
|
||||
it.apiUrl.isNotBlank() && it.apiKey.isNotBlank()
|
||||
} ?: false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.fuggloader.app.databinding.ActivityShareBinding
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -57,10 +58,32 @@ class ShareActivity : AppCompatActivity() {
|
||||
finish()
|
||||
}
|
||||
|
||||
handleShareIntent(intent)
|
||||
prepareShare(intent)
|
||||
}
|
||||
|
||||
private fun handleShareIntent(intent: Intent) {
|
||||
private fun prepareShare(intent: Intent) {
|
||||
val instances = prefs.getInstances()
|
||||
if (instances.size > 1) {
|
||||
val names = instances.map { it.name }.toTypedArray()
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle("Select Instance")
|
||||
.setItems(names) { _, which ->
|
||||
handleShareIntent(instances[which], intent)
|
||||
}
|
||||
.setNegativeButton("Cancel") { _, _ -> finish() }
|
||||
.setCancelable(false)
|
||||
.show()
|
||||
} else {
|
||||
val target = instances.firstOrNull()
|
||||
if (target != null) {
|
||||
handleShareIntent(target, intent)
|
||||
} else {
|
||||
showError("No instance configured")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleShareIntent(instance: Instance, intent: Intent) {
|
||||
val action = intent.action
|
||||
val type = intent.type
|
||||
|
||||
@@ -69,11 +92,11 @@ class ShareActivity : AppCompatActivity() {
|
||||
val sharedText = intent.getStringExtra(Intent.EXTRA_TEXT)
|
||||
if (!sharedText.isNull_or_blank_url()) {
|
||||
val targetUrl = extractUrl(sharedText!!)
|
||||
processUrlUpload(targetUrl)
|
||||
processUrlUpload(instance, targetUrl)
|
||||
} else {
|
||||
val streamUri = intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)
|
||||
if (streamUri != null) {
|
||||
processFileUpload(streamUri)
|
||||
processFileUpload(instance, streamUri)
|
||||
} else {
|
||||
showError("No valid file or URL found in share intent")
|
||||
}
|
||||
@@ -81,7 +104,7 @@ class ShareActivity : AppCompatActivity() {
|
||||
} else {
|
||||
val streamUri = intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)
|
||||
if (streamUri != null) {
|
||||
processFileUpload(streamUri)
|
||||
processFileUpload(instance, streamUri)
|
||||
} else {
|
||||
showError("No stream URI found for file share")
|
||||
}
|
||||
@@ -90,7 +113,7 @@ class ShareActivity : AppCompatActivity() {
|
||||
val uris = intent.getParcelableArrayListExtra<Uri>(Intent.EXTRA_STREAM)
|
||||
if (!uris.isNullOrEmpty()) {
|
||||
// Upload first file in batch for now
|
||||
processFileUpload(uris[0])
|
||||
processFileUpload(instance, uris[0])
|
||||
} else {
|
||||
showError("No files found in multi-share intent")
|
||||
}
|
||||
@@ -116,8 +139,8 @@ class ShareActivity : AppCompatActivity() {
|
||||
return trimmed
|
||||
}
|
||||
|
||||
private fun processFileUpload(uri: Uri) {
|
||||
binding.tvStatus.text = "Uploading file..."
|
||||
private fun processFileUpload(instance: Instance, uri: Uri) {
|
||||
binding.tvStatus.text = "Uploading to ${instance.name}..."
|
||||
binding.progressBar.visibility = View.VISIBLE
|
||||
binding.progressBar.isIndeterminate = false
|
||||
binding.progressBar.progress = 0
|
||||
@@ -126,6 +149,7 @@ class ShareActivity : AppCompatActivity() {
|
||||
val result = uploader.uploadFile(
|
||||
contentResolver = contentResolver,
|
||||
uri = uri,
|
||||
instance = instance,
|
||||
onProgress = { pct ->
|
||||
runOnUiThread {
|
||||
binding.progressBar.progress = pct
|
||||
@@ -141,14 +165,14 @@ class ShareActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun processUrlUpload(url: String) {
|
||||
binding.tvStatus.text = "Uploading URL..."
|
||||
private fun processUrlUpload(instance: Instance, url: String) {
|
||||
binding.tvStatus.text = "Uploading to ${instance.name}..."
|
||||
binding.progressBar.visibility = View.VISIBLE
|
||||
binding.progressBar.isIndeterminate = true
|
||||
binding.tvPercent.text = ""
|
||||
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
val result = uploader.uploadUrl(url)
|
||||
val result = uploader.uploadUrl(url, instance)
|
||||
result.fold(
|
||||
onSuccess = { postUrl -> showSuccess(postUrl) },
|
||||
onFailure = { err -> showError(err.message ?: "URL Upload failed") }
|
||||
|
||||
@@ -29,12 +29,13 @@ class UploaderService(private val prefs: PreferencesManager) {
|
||||
suspend fun uploadFile(
|
||||
contentResolver: ContentResolver,
|
||||
uri: Uri,
|
||||
rating: String = prefs.defaultRating,
|
||||
tags: String = prefs.defaultTags,
|
||||
visibility: String = prefs.defaultVisibility,
|
||||
instance: Instance? = null,
|
||||
onProgress: (percent: Int) -> Unit
|
||||
): Result<String> = withContext(Dispatchers.IO) {
|
||||
Log.d("UploaderService", "Starting uploadFile for $uri")
|
||||
val targetInstance = instance ?: prefs.getActiveInstance()
|
||||
?: return@withContext Result.failure(Exception("No instance configured"))
|
||||
|
||||
Log.d("UploaderService", "Starting uploadFile for $uri to ${targetInstance.apiUrl}")
|
||||
try {
|
||||
val fileName = getFileName(contentResolver, uri) ?: "upload_${System.currentTimeMillis()}"
|
||||
val mimeType = contentResolver.getType(uri) ?: "application/octet-stream"
|
||||
@@ -69,16 +70,16 @@ class UploaderService(private val prefs: PreferencesManager) {
|
||||
.setType(MultipartBody.FORM)
|
||||
.addFormDataPart("file", fileName, requestBody)
|
||||
|
||||
if (rating != "none") {
|
||||
multipartBuilder.addFormDataPart("rating", rating)
|
||||
if (targetInstance.defaultRating != "none") {
|
||||
multipartBuilder.addFormDataPart("rating", targetInstance.defaultRating)
|
||||
}
|
||||
|
||||
multipartBuilder.addFormDataPart("tags", tags)
|
||||
.addFormDataPart("visibility", visibility)
|
||||
multipartBuilder.addFormDataPart("tags", targetInstance.defaultTags)
|
||||
.addFormDataPart("visibility", targetInstance.defaultVisibility)
|
||||
|
||||
val request = Request.Builder()
|
||||
.url(prefs.apiUrl)
|
||||
.addHeader("X-Api-Key", prefs.apiKey)
|
||||
.url(targetInstance.apiUrl)
|
||||
.addHeader("X-Api-Key", targetInstance.apiKey)
|
||||
.addHeader("User-Agent", "fuggloader-android/1.0")
|
||||
.post(multipartBuilder.build())
|
||||
.build()
|
||||
@@ -101,19 +102,20 @@ class UploaderService(private val prefs: PreferencesManager) {
|
||||
|
||||
suspend fun uploadUrl(
|
||||
url: String,
|
||||
rating: String = prefs.defaultRating,
|
||||
tags: String = prefs.defaultTags,
|
||||
visibility: String = prefs.defaultVisibility
|
||||
instance: Instance? = null
|
||||
): Result<String> = withContext(Dispatchers.IO) {
|
||||
Log.d("UploaderService", "Starting uploadUrl for $url")
|
||||
val targetInstance = instance ?: prefs.getActiveInstance()
|
||||
?: return@withContext Result.failure(Exception("No instance configured"))
|
||||
|
||||
Log.d("UploaderService", "Starting uploadUrl for $url to ${targetInstance.apiUrl}")
|
||||
try {
|
||||
val json = JSONObject().apply {
|
||||
put("url", url)
|
||||
if (rating != "none") {
|
||||
put("rating", rating)
|
||||
if (targetInstance.defaultRating != "none") {
|
||||
put("rating", targetInstance.defaultRating)
|
||||
}
|
||||
put("tags", tags)
|
||||
put("visibility", visibility)
|
||||
put("tags", targetInstance.defaultTags)
|
||||
put("visibility", targetInstance.defaultVisibility)
|
||||
}
|
||||
|
||||
val requestBody = RequestBody.create(
|
||||
@@ -122,8 +124,8 @@ class UploaderService(private val prefs: PreferencesManager) {
|
||||
)
|
||||
|
||||
val request = Request.Builder()
|
||||
.url(prefs.apiUrl)
|
||||
.addHeader("X-Api-Key", prefs.apiKey)
|
||||
.url(targetInstance.apiUrl)
|
||||
.addHeader("X-Api-Key", targetInstance.apiKey)
|
||||
.addHeader("User-Agent", "fuggloader-android/1.0")
|
||||
.post(requestBody)
|
||||
.build()
|
||||
@@ -143,12 +145,15 @@ class UploaderService(private val prefs: PreferencesManager) {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun testConnection(): Result<String> = withContext(Dispatchers.IO) {
|
||||
Log.d("UploaderService", "Starting testConnection ping")
|
||||
suspend fun testConnection(instance: Instance? = null): Result<String> = withContext(Dispatchers.IO) {
|
||||
val targetInstance = instance ?: prefs.getActiveInstance()
|
||||
?: return@withContext Result.failure(Exception("No instance configured"))
|
||||
|
||||
Log.d("UploaderService", "Starting testConnection ping for ${targetInstance.apiUrl}")
|
||||
try {
|
||||
val request = Request.Builder()
|
||||
.url(prefs.apiUrl)
|
||||
.addHeader("X-Api-Key", prefs.apiKey)
|
||||
.url(targetInstance.apiUrl)
|
||||
.addHeader("X-Api-Key", targetInstance.apiKey)
|
||||
.addHeader("User-Agent", "fuggloader-android/1.0")
|
||||
.post(ByteArray(0).toRequestBody(null))
|
||||
.build()
|
||||
|
||||
@@ -28,11 +28,76 @@
|
||||
android:textColor="#A0A0B0"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<!-- Instance Selection -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:text="Select Instance"
|
||||
android:textColor="#E0E0E0"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinnerInstances"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_weight="1"
|
||||
android:background="#1E1E24" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btnAddInstance"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:background="#1E1E24"
|
||||
android:contentDescription="Add Instance"
|
||||
android:src="@android:drawable/ic_input_add"
|
||||
app:tint="#FFFFFF" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btnDeleteInstance"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:background="#1E1E24"
|
||||
android:contentDescription="Delete Instance"
|
||||
android:src="@android:drawable/ic_menu_delete"
|
||||
app:tint="#FF4444" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Instance Name -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="Instance Name"
|
||||
android:textColor="#E0E0E0"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etInstanceName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:background="#1E1E24"
|
||||
android:hint="My Server"
|
||||
android:inputType="text"
|
||||
android:padding="12dp"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textColorHint="#606070" />
|
||||
|
||||
<!-- API Endpoint URL -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="API Endpoint URL"
|
||||
android:textColor="#E0E0E0"
|
||||
android:textStyle="bold" />
|
||||
|
||||
Reference in New Issue
Block a user