@@ -18,6 +18,7 @@ import android.webkit.WebResourceResponse
18
18
import android.webkit.WebView
19
19
import android.webkit.WebViewClient
20
20
import android.widget.EditText
21
+ import android.widget.LinearLayout
21
22
import android.widget.Toast
22
23
import androidx.activity.enableEdgeToEdge
23
24
import androidx.appcompat.app.AlertDialog
@@ -26,6 +27,12 @@ import androidx.core.content.edit
26
27
import androidx.core.view.ViewCompat
27
28
import androidx.core.view.WindowInsetsCompat
28
29
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
29
36
import org.json.JSONObject
30
37
import java.io.BufferedReader
31
38
import java.io.DataOutputStream
@@ -45,6 +52,7 @@ class MainActivity : AppCompatActivity() {
45
52
46
53
private lateinit var binding: ActivityMainBinding
47
54
private lateinit var webView: WebView
55
+ private val client = OkHttpClient ()
48
56
49
57
@SuppressLint(" SetJavaScriptEnabled" )
50
58
override fun onCreate (savedInstanceState : Bundle ? ) {
@@ -57,7 +65,13 @@ class MainActivity : AppCompatActivity() {
57
65
webView = binding.webview
58
66
webView.settings.domStorageEnabled = true
59
67
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
61
75
webView.addJavascriptInterface(WebAppInterface (this ), " Android" )
62
76
webView.setWebViewClient(MyWebViewClient ())
63
77
@@ -70,9 +84,9 @@ class MainActivity : AppCompatActivity() {
70
84
}
71
85
72
86
// 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} " )
76
90
handleIntent(intent)
77
91
}
78
92
@@ -136,7 +150,7 @@ class MainActivity : AppCompatActivity() {
136
150
} else {
137
151
Toast .makeText(
138
152
this ,
139
- this . getString(R .string.tst_error) + " : Unknown DeepLink" ,
153
+ getString(R .string.tst_error) + " : Unknown DeepLink" ,
140
154
Toast .LENGTH_SHORT
141
155
).show()
142
156
Log .d(" handleIntent" , " Unknown DeepLink!" )
@@ -149,7 +163,7 @@ class MainActivity : AppCompatActivity() {
149
163
} else {
150
164
Toast .makeText(
151
165
this ,
152
- this . getString(R .string.tst_error) + " : Unknown Intent" ,
166
+ getString(R .string.tst_error) + " : Unknown Intent" ,
153
167
Toast .LENGTH_SHORT
154
168
).show()
155
169
Log .e(" IntentDebug" , " Unknown Intent!" )
@@ -218,7 +232,16 @@ class MainActivity : AppCompatActivity() {
218
232
val savedUrl = preferences.getString(URL_KEY , null )
219
233
Log .d(" showSettingsDialog" , " savedUrl: $savedUrl " )
220
234
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
+
221
241
val input = EditText (this )
242
+ input.inputType = android.text.InputType .TYPE_CLASS_TEXT
243
+ input.maxLines = 1
244
+ layout.addView(input)
222
245
input.hint = getString(R .string.settings_input_place)
223
246
if (savedUrl != null ) {
224
247
input.setText(savedUrl)
@@ -228,42 +251,69 @@ class MainActivity : AppCompatActivity() {
228
251
runOnUiThread {
229
252
AlertDialog .Builder (this )
230
253
.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
+ }
264
303
}
265
304
}
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
267
317
}
268
318
}
269
319
@@ -276,7 +326,7 @@ class MainActivity : AppCompatActivity() {
276
326
Log .d(" processSharedFile" , " authToken: $authToken " )
277
327
if (savedUrl == null || authToken == null ) {
278
328
// 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()
280
330
return
281
331
}
282
332
@@ -294,7 +344,7 @@ class MainActivity : AppCompatActivity() {
294
344
val contentType = URLConnection .guessContentTypeFromName(fileName)
295
345
Log .d(" processSharedFile" , " contentType: $contentType " )
296
346
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()
298
348
299
349
Thread {
300
350
try {
@@ -419,9 +469,9 @@ class MainActivity : AppCompatActivity() {
419
469
if (clipboard != null ) {
420
470
val clip = ClipData .newPlainText(" URL" , url)
421
471
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()
423
473
} 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 )
425
475
.show()
426
476
}
427
477
}
@@ -465,6 +515,8 @@ class MainActivity : AppCompatActivity() {
465
515
" HTTP error " + errorResponse.description,
466
516
Toast .LENGTH_LONG
467
517
).show()
518
+ // TODO: Now that we verify the URL this should not be needed...
519
+ // showSettingsDialog()
468
520
}
469
521
470
522
override fun onReceivedHttpError (
@@ -478,6 +530,8 @@ class MainActivity : AppCompatActivity() {
478
530
" HTTP error " + errorResponse.reasonPhrase,
479
531
Toast .LENGTH_LONG
480
532
).show()
533
+ // TODO: Now that we verify the URL this should not be needed...
534
+ // showSettingsDialog()
481
535
}
482
536
}
483
537
}
0 commit comments