Skip to content

Commit 05039a0

Browse files
authored
Add URL Check to Settings (#2)
- Add checkUrl to verify url before saving - Update User Agent - Cleanup Code
1 parent 0578d4c commit 05039a0

File tree

3 files changed

+101
-45
lines changed

3 files changed

+101
-45
lines changed

app/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ android {
3939
}
4040

4141
dependencies {
42-
4342
implementation(libs.androidx.core.ktx)
4443
implementation(libs.androidx.appcompat)
4544
implementation(libs.material)
45+
implementation(libs.okhttp)
4646
testImplementation(libs.junit)
4747
androidTestImplementation(libs.androidx.junit)
4848
androidTestImplementation(libs.androidx.espresso.core)

app/src/main/java/com/djangofiles/djangofiles/MainActivity.kt

Lines changed: 98 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import android.webkit.WebResourceResponse
1818
import android.webkit.WebView
1919
import android.webkit.WebViewClient
2020
import android.widget.EditText
21+
import android.widget.LinearLayout
2122
import android.widget.Toast
2223
import androidx.activity.enableEdgeToEdge
2324
import androidx.appcompat.app.AlertDialog
@@ -26,6 +27,12 @@ import androidx.core.content.edit
2627
import androidx.core.view.ViewCompat
2728
import androidx.core.view.WindowInsetsCompat
2829
import com.djangofiles.djangofiles.databinding.ActivityMainBinding
30+
import kotlinx.coroutines.CoroutineScope
31+
import kotlinx.coroutines.Dispatchers
32+
import kotlinx.coroutines.launch
33+
import kotlinx.coroutines.withContext
34+
import okhttp3.OkHttpClient
35+
import okhttp3.Request
2936
import org.json.JSONObject
3037
import java.io.BufferedReader
3138
import java.io.DataOutputStream
@@ -45,6 +52,7 @@ class MainActivity : AppCompatActivity() {
4552

4653
private lateinit var binding: ActivityMainBinding
4754
private lateinit var webView: WebView
55+
private val client = OkHttpClient()
4856

4957
@SuppressLint("SetJavaScriptEnabled")
5058
override fun onCreate(savedInstanceState: Bundle?) {
@@ -57,7 +65,13 @@ class MainActivity : AppCompatActivity() {
5765
webView = binding.webview
5866
webView.settings.domStorageEnabled = true
5967
webView.settings.javaScriptEnabled = true
60-
webView.settings.userAgentString = "DjangoFiles Android"
68+
69+
val packageInfo = packageManager.getPackageInfo(this.packageName, 0)
70+
Log.d("MY_APP_TAG", "versionName: ${packageInfo.versionName}")
71+
val userAgent = "${webView.settings.userAgentString} DjangoFiles Android/${packageInfo.versionName}"
72+
Log.d("onCreate", "UA: $userAgent")
73+
74+
webView.settings.userAgentString = userAgent
6175
webView.addJavascriptInterface(WebAppInterface(this), "Android")
6276
webView.setWebViewClient(MyWebViewClient())
6377

@@ -70,9 +84,9 @@ class MainActivity : AppCompatActivity() {
7084
}
7185

7286
// Handle Intent
73-
Log.d("onCreate", "getAction: " + intent.action)
74-
Log.d("onCreate", "getData: " + intent.data)
75-
Log.d("onCreate", "getExtras: " + intent.extras)
87+
Log.d("onCreate", "getAction: ${intent.action}")
88+
Log.d("onCreate", "getData: ${intent.data}")
89+
Log.d("onCreate", "getExtras: ${intent.extras}")
7690
handleIntent(intent)
7791
}
7892

@@ -136,7 +150,7 @@ class MainActivity : AppCompatActivity() {
136150
} else {
137151
Toast.makeText(
138152
this,
139-
this.getString(R.string.tst_error) + ": Unknown DeepLink",
153+
getString(R.string.tst_error) + ": Unknown DeepLink",
140154
Toast.LENGTH_SHORT
141155
).show()
142156
Log.d("handleIntent", "Unknown DeepLink!")
@@ -149,7 +163,7 @@ class MainActivity : AppCompatActivity() {
149163
} else {
150164
Toast.makeText(
151165
this,
152-
this.getString(R.string.tst_error) + ": Unknown Intent",
166+
getString(R.string.tst_error) + ": Unknown Intent",
153167
Toast.LENGTH_SHORT
154168
).show()
155169
Log.e("IntentDebug", "Unknown Intent!")
@@ -218,7 +232,16 @@ class MainActivity : AppCompatActivity() {
218232
val savedUrl = preferences.getString(URL_KEY, null)
219233
Log.d("showSettingsDialog", "savedUrl: $savedUrl")
220234

235+
236+
// Inflate custom layout with padding
237+
val layout = LinearLayout(this)
238+
layout.orientation = LinearLayout.VERTICAL
239+
layout.setPadding(5, 0, 5, 120)
240+
221241
val input = EditText(this)
242+
input.inputType = android.text.InputType.TYPE_CLASS_TEXT
243+
input.maxLines = 1
244+
layout.addView(input)
222245
input.hint = getString(R.string.settings_input_place)
223246
if (savedUrl != null) {
224247
input.setText(savedUrl)
@@ -228,42 +251,69 @@ class MainActivity : AppCompatActivity() {
228251
runOnUiThread {
229252
AlertDialog.Builder(this)
230253
.setCancelable(false)
231-
.setTitle(this.getString(R.string.settings_title))
232-
.setMessage(this.getString(R.string.settings_message))
233-
.setView(input)
234-
.setNegativeButton(
235-
"Exit"
236-
) { dialog: DialogInterface?, which: Int -> finish() }
237-
.setPositiveButton("OK") { dialog: DialogInterface, which: Int ->
238-
var url = input.text.toString().trim { it <= ' ' }
239-
Log.d("showSettingsDialog", "setPositiveButton: url: $url")
240-
if (url.isEmpty()) {
241-
// TODO: Need to add verification here and keep dialog open...
242-
Toast.makeText(
243-
this,
244-
getString(R.string.tst_invalid_url),
245-
Toast.LENGTH_SHORT
246-
).show()
247-
finish()
248-
return@setPositiveButton
249-
}
250-
if (!url.startsWith("http://") && !url.startsWith("https://")) {
251-
url = "https://$url"
252-
}
253-
if (url.endsWith("/")) {
254-
url = url.substring(0, url.length - 1)
255-
}
256-
if (savedUrl != url) {
257-
Log.d("showSettingsDialog", "Saving New URL.")
258-
preferences.edit { putString(URL_KEY, url) }
259-
webView.loadUrl(url)
260-
dialog.dismiss()
261-
} else {
262-
Log.d("showSettingsDialog", "URL NOT Changed!")
263-
finish()
254+
.setTitle(getString(R.string.settings_title))
255+
.setMessage(getString(R.string.settings_message))
256+
.setView(layout)
257+
.setNegativeButton("Exit") { dialog: DialogInterface?, which: Int -> finish() }
258+
.setPositiveButton("OK", null)
259+
.show().apply {
260+
getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
261+
var url = input.text.toString().trim { it <= ' ' }
262+
Log.d("showSettingsDialog", "setPositiveButton: url: $url")
263+
264+
if (url.isEmpty()) {
265+
Log.d("showSettingsDialog", "URL is Empty")
266+
input.error = "This field is required."
267+
} else {
268+
if (!url.startsWith("http://") && !url.startsWith("https://")) {
269+
url = "https://$url"
270+
}
271+
if (url.endsWith("/")) {
272+
url = url.substring(0, url.length - 1)
273+
}
274+
275+
Log.d("showSettingsDialog", "Processed URL: $url")
276+
if (savedUrl != url) {
277+
Log.d("showSettingsDialog", "Saving New URL...")
278+
CoroutineScope(Dispatchers.IO).launch {
279+
val authUrl = "${url}/api/auth/methods/"
280+
Log.d("showSettingsDialog", "Auth URL: $authUrl")
281+
val response = checkUrl(authUrl)
282+
Log.d("showSettingsDialog", "response: $response")
283+
withContext(Dispatchers.Main) {
284+
if (response) {
285+
Log.d("showSettingsDialog", "SUCCESS")
286+
preferences.edit { putString(URL_KEY, url) }
287+
webView.loadUrl(url)
288+
dismiss()
289+
} else {
290+
Log.d("showSettingsDialog", "FAILURE")
291+
input.error = "Invalid URL"
292+
}
293+
}
294+
}
295+
//preferences.edit { putString(URL_KEY, url) }
296+
//webView.loadUrl(url)
297+
//dismiss()
298+
} else {
299+
Log.d("showSettingsDialog", "URL NOT Changed!")
300+
finish()
301+
}
302+
}
264303
}
265304
}
266-
.show()
305+
}
306+
}
307+
308+
private fun checkUrl(url: String): Boolean {
309+
Log.d("checkUrl", "url: $url")
310+
// TODO: Change this to HEAD or use response data...
311+
val request = Request.Builder().url(url).get().build()
312+
return try {
313+
val response = client.newCall(request).execute()
314+
response.isSuccessful
315+
} catch (e: Exception) {
316+
false
267317
}
268318
}
269319

@@ -276,7 +326,7 @@ class MainActivity : AppCompatActivity() {
276326
Log.d("processSharedFile", "authToken: $authToken")
277327
if (savedUrl == null || authToken == null) {
278328
// TODO: Show settings dialog here...
279-
Toast.makeText(this, this.getString(R.string.tst_no_url), Toast.LENGTH_SHORT).show()
329+
Toast.makeText(this, getString(R.string.tst_no_url), Toast.LENGTH_SHORT).show()
280330
return
281331
}
282332

@@ -294,7 +344,7 @@ class MainActivity : AppCompatActivity() {
294344
val contentType = URLConnection.guessContentTypeFromName(fileName)
295345
Log.d("processSharedFile", "contentType: $contentType")
296346

297-
Toast.makeText(this, this.getString(R.string.tst_uploading_file), Toast.LENGTH_SHORT).show()
347+
Toast.makeText(this, getString(R.string.tst_uploading_file), Toast.LENGTH_SHORT).show()
298348

299349
Thread {
300350
try {
@@ -419,9 +469,9 @@ class MainActivity : AppCompatActivity() {
419469
if (clipboard != null) {
420470
val clip = ClipData.newPlainText("URL", url)
421471
clipboard.setPrimaryClip(clip)
422-
Toast.makeText(this, this.getString(R.string.tst_url_copied), Toast.LENGTH_SHORT).show()
472+
Toast.makeText(this, getString(R.string.tst_url_copied), Toast.LENGTH_SHORT).show()
423473
} else {
424-
Toast.makeText(this, this.getString(R.string.tst_no_clipboard), Toast.LENGTH_SHORT)
474+
Toast.makeText(this, getString(R.string.tst_no_clipboard), Toast.LENGTH_SHORT)
425475
.show()
426476
}
427477
}
@@ -465,6 +515,8 @@ class MainActivity : AppCompatActivity() {
465515
"HTTP error " + errorResponse.description,
466516
Toast.LENGTH_LONG
467517
).show()
518+
// TODO: Now that we verify the URL this should not be needed...
519+
// showSettingsDialog()
468520
}
469521

470522
override fun onReceivedHttpError(
@@ -478,6 +530,8 @@ class MainActivity : AppCompatActivity() {
478530
"HTTP error " + errorResponse.reasonPhrase,
479531
Toast.LENGTH_LONG
480532
).show()
533+
// TODO: Now that we verify the URL this should not be needed...
534+
// showSettingsDialog()
481535
}
482536
}
483537
}

gradle/libs.versions.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ junitVersion = "1.2.1"
77
espressoCore = "3.6.1"
88
appcompat = "1.7.0"
99
material = "1.12.0"
10+
okhttp = "4.12.0"
1011

1112
[libraries]
1213
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@@ -15,6 +16,7 @@ androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "j
1516
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
1617
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
1718
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
19+
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
1820

1921
[plugins]
2022
android-application = { id = "com.android.application", version.ref = "agp" }

0 commit comments

Comments
 (0)