Skip to content

Commit 87fccb5

Browse files
authored
Add Multiple File Upload Support (#37)
- Add Multiple File Upload Support - Add Previews to Single File Upload - Improve WebView Handling in Previews
1 parent 31b9378 commit 87fccb5

25 files changed

+869
-183
lines changed

README.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,17 +96,15 @@ Additionally, the URL is copied to the clipboard and the preview show in the app
9696
### Planned
9797

9898
- Add Default Upload Options.
99-
- Add Custom Options to Preview page.
100-
- Option to Disable Preview Page on Open, Share, and for Links.
99+
- Add File Options to Preview page.
100+
- Option to Disable Preview Page on Open, Share, and/or for Links.
101101
- Ability to Authenticate if/when your session (cookie) is expired.
102102
- File List
103-
- Context Menu with Options
104-
- Multi-Select with Options
103+
- Multi-Select with File Options
105104
- Response Caching for Infinite Scroll
106105
- File Preview
107-
- File Options
108-
- Text/Code Previews
109106
- PDF Previews
107+
- File Options
110108

111109
### Known Issues
112110

TODO.md

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,36 @@
11
# TODO
22

3+
- [Authentication](#Authentication)
4+
- [Status](#Status)
5+
6+
## Authentication
7+
8+
Options for persistent authentication are:
9+
10+
1. Implement secure scoped token authentication.
11+
2. Dramatically increase session times and let users manage sessions.
12+
313
## Upload
414

515
- Add Upload Options to Previews
6-
- Add Support for Multiple Files
16+
- Enable Multi for Upload Shortcut
17+
- Enable Multi for Upload Menu Option
718

819
## File List
920

10-
- Add Context Menu
1121
- Add Multi-Select
1222
- Add Swiper to Preview
1323

1424
## File Preview
1525

16-
- Add PDF Previews
17-
- Add Options
26+
- Add PDF
27+
- Add File Options
1828

1929
## Settings
2030

2131
- Overhaul Server Selector
2232
- Add Default Upload Options
33+
- Add Fingerprint Authentication
2334

2435
## Retrofit
2536

@@ -28,3 +39,48 @@
2839
## Room
2940

3041
- Move Room to Directory
42+
- Implement Room Active Server
43+
44+
# Status
45+
46+
## Authentication
47+
48+
- Returns a Cookie
49+
- Uses Cookie to get Token
50+
51+
## File List
52+
53+
Total Cache Size: `700` MB
54+
55+
- Uses `/recent/`
56+
- Uses Token
57+
- No Caching
58+
59+
### Glide
60+
61+
**All Images**
62+
63+
- Uses `/raw/?view=gallery`
64+
- Uses Cookies
65+
- `250` MB LRU Cache
66+
- Small Preview Enabled
67+
68+
### ExoPlayer
69+
70+
**All Video and Audio**
71+
72+
- Uses `/raw/?view=gallery`
73+
- Uses Cookies
74+
- `350` MB LRU Cache
75+
- Small Preview Disabled
76+
77+
### Okhttp
78+
79+
**All Plain Text**
80+
81+
Loads the Content into a WebView with highlight.js
82+
83+
- Uses `/raw/?view=gallery`
84+
- Uses Cookies
85+
- `100` MB LRU Cache
86+
- No Small Preview

app/src/main/assets/preview/preview.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ document.addEventListener('DOMContentLoaded', () => {
77
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
88
applyTheme(mediaQuery)
99
mediaQuery.addEventListener('change', applyTheme)
10+
11+
if (typeof Android !== 'undefined') {
12+
console.log('Android')
13+
Android.notifyReady()
14+
}
1015
})
1116

1217
function applyTheme(mediaQuery) {

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

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class MainActivity : AppCompatActivity() {
6565

6666
val packageInfo = packageManager.getPackageInfo(this.packageName, 0)
6767
val versionName = packageInfo.versionName
68-
Log.d("Main[onCreate]", "versionName: $versionName")
68+
//Log.d("Main[onCreate]", "versionName: $versionName")
6969

7070
val headerView = binding.navigationView.getHeaderView(0)
7171
val versionTextView = headerView.findViewById<TextView>(R.id.header_version)
@@ -147,7 +147,15 @@ class MainActivity : AppCompatActivity() {
147147
}
148148
}
149149

150-
handleIntent(intent, savedInstanceState)
150+
// Only Handel Intent Once on Startup
151+
if (savedInstanceState?.getBoolean("intentHandled") != true) {
152+
handleIntent(intent)
153+
}
154+
}
155+
156+
override fun onSaveInstanceState(outState: Bundle) {
157+
super.onSaveInstanceState(outState)
158+
outState.putBoolean("intentHandled", true)
151159
}
152160

153161
// TODO: Update with a ViewModel...
@@ -162,11 +170,11 @@ class MainActivity : AppCompatActivity() {
162170
override fun onNewIntent(intent: Intent) {
163171
super.onNewIntent(intent)
164172
Log.d("onNewIntent", "intent: $intent")
165-
handleIntent(intent, null)
173+
handleIntent(intent)
166174
}
167175

168-
private fun handleIntent(intent: Intent, savedInstanceState: Bundle?) {
169-
Log.d("handleIntent", "intent: $intent")
176+
private fun handleIntent(intent: Intent) {
177+
//Log.d("handleIntent", "intent: $intent")
170178
val data = intent.data
171179
val type = intent.type
172180
val action = intent.action
@@ -180,11 +188,11 @@ class MainActivity : AppCompatActivity() {
180188
val sharedPreferences = getSharedPreferences("AppPreferences", MODE_PRIVATE)
181189
val savedUrl = sharedPreferences.getString("saved_url", null)
182190
Log.d("handleIntent", "savedUrl: $savedUrl")
183-
Log.d("handleIntent", "data?.host: ${data?.host}")
184191
//val authToken = sharedPreferences.getString("auth_token", null)
185192
//Log.d("handleIntent", "authToken: $authToken")
186193

187194
Log.d("handleIntent", "data?.host: ${data?.host}")
195+
188196
if (data?.host != "oauth" && savedUrl.isNullOrEmpty()) {
189197
Log.i("handleIntent", "Missing Saved URL or Token! Showing Login...")
190198

@@ -196,7 +204,7 @@ class MainActivity : AppCompatActivity() {
196204
)
197205

198206
} else if (Intent.ACTION_MAIN == action) {
199-
Log.d("handleIntent", "ACTION_MAIN: ${savedInstanceState?.size()}")
207+
Log.d("handleIntent", "ACTION_MAIN")
200208

201209
binding.drawerLayout.closeDrawers()
202210

@@ -285,11 +293,18 @@ class MainActivity : AppCompatActivity() {
285293
Log.w("handleIntent", "fileUris is null")
286294
return
287295
}
288-
for (fileUri in fileUris) {
289-
Log.d("handleIntent", "MULTI: fileUri: $fileUri")
290-
}
291-
Toast.makeText(this, "Not Yet Implemented!", Toast.LENGTH_LONG).show()
292-
Log.w("handleIntent", "NOT IMPLEMENTED")
296+
//fileUris.sort()
297+
//Log.d("handleIntent", "fileUris: $fileUris")
298+
val bundle = Bundle()
299+
bundle.putParcelableArrayList("fileUris", fileUris)
300+
301+
navController.popBackStack(R.id.nav_graph, true)
302+
navController.navigate(
303+
R.id.nav_item_upload_multi, bundle, NavOptions.Builder()
304+
.setPopUpTo(R.id.nav_item_home, true)
305+
.setLaunchSingleTop(true)
306+
.build()
307+
)
293308

294309
} else if (Intent.ACTION_VIEW == action) {
295310
Log.d("handleIntent", "ACTION_VIEW")
@@ -335,7 +350,7 @@ class MainActivity : AppCompatActivity() {
335350

336351
navController.popBackStack(R.id.nav_graph, true)
337352
navController.navigate(
338-
R.id.nav_item_preview, bundle, NavOptions.Builder()
353+
R.id.nav_item_upload, bundle, NavOptions.Builder()
339354
.setPopUpTo(R.id.nav_item_home, true)
340355
.setLaunchSingleTop(true)
341356
.build()
@@ -464,7 +479,7 @@ object MediaCache {
464479
if (!::simpleCache.isInitialized) {
465480
simpleCache = SimpleCache(
466481
File(context.cacheDir, "exoCache"),
467-
LeastRecentlyUsedCacheEvictor(500 * 1024 * 1024),
482+
LeastRecentlyUsedCacheEvictor(350 * 1024 * 1024),
468483
StandaloneDatabaseProvider(context)
469484
)
470485
cacheDataSourceFactory = CacheDataSource.Factory()

app/src/main/java/com/djangofiles/djangofiles/ui/files/FilesFragment.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ class FilesFragment : Fragment() {
7979
override fun onDestroyView() {
8080
Log.d("File[onDestroyView]", "ON DESTROY")
8181
super.onDestroyView()
82+
_binding = null
8283
}
8384

8485
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

app/src/main/java/com/djangofiles/djangofiles/ui/files/FilesPreviewFragment.kt

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class FilesPreviewFragment : Fragment() {
5656
private var currentPosition: Long = 0
5757

5858
private lateinit var player: ExoPlayer
59+
private lateinit var webView: WebView
5960

6061
override fun onCreate(savedInstanceState: Bundle?) {
6162
super.onCreate(savedInstanceState)
@@ -69,17 +70,31 @@ class FilesPreviewFragment : Fragment() {
6970
container: ViewGroup?,
7071
savedInstanceState: Bundle?
7172
): View {
72-
Log.d("FilesPre[onCreateView]", "savedInstanceState: ${savedInstanceState?.size()}")
73+
Log.d("FilesPreviewFragment", "onCreateView: ${savedInstanceState?.size()}")
7374
_binding = FragmentFilesPreviewBinding.inflate(inflater, container, false)
7475
val root: View = binding.root
7576
return root
7677
}
7778

79+
override fun onDestroyView() {
80+
Log.d("FilesPreviewFragment", "onDestroyView")
81+
super.onDestroyView()
82+
if (::player.isInitialized) {
83+
Log.d("FilesPreviewFragment", "player.release")
84+
player.release()
85+
}
86+
if (::webView.isInitialized) {
87+
Log.d("FilesPreviewFragment", "webView.destroy")
88+
webView.destroy()
89+
}
90+
_binding = null
91+
}
92+
7893
@SuppressLint("SetJavaScriptEnabled")
7994
@OptIn(UnstableApi::class)
8095
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
8196
super.onViewCreated(view, savedInstanceState)
82-
Log.d("FilesPre[onViewCreated]", "savedInstanceState: ${savedInstanceState?.size()}")
97+
Log.d("FilesPreviewFragment", "onViewCreated: ${savedInstanceState?.size()}")
8398

8499
binding.goBack.setOnClickListener {
85100
Log.d("FilesPreviewFragment", "GO BACK")
@@ -214,14 +229,16 @@ class FilesPreviewFragment : Fragment() {
214229

215230
} else if (mimeType?.startsWith("text/") == true || isCodeMime(mimeType!!)) {
216231
Log.d("FilesPreviewFragment", "WEB VIEW TIME")
232+
binding.copyText.visibility = View.VISIBLE
233+
webView = WebView(requireContext())
234+
binding.previewContainer.addView(webView)
235+
217236
val url = "file:///android_asset/preview/preview.html"
218237
Log.d("FilesPreviewFragment", "url: $url")
219-
binding.webView.visibility = View.VISIBLE
220-
binding.copyText.visibility = View.VISIBLE
221238

222239
//val cookieManager = CookieManager.getInstance()
223240
//cookieManager.setAcceptCookie(true)
224-
//cookieManager.setAcceptThirdPartyCookies(binding.webView, true)
241+
//cookieManager.setAcceptThirdPartyCookies(webView, true)
225242

226243
lifecycleScope.launch {
227244
val content = withContext(Dispatchers.IO) { getContent(viewUrl!!) }
@@ -242,7 +259,7 @@ class FilesPreviewFragment : Fragment() {
242259
val jsString = "addContent(${escapedContent});"
243260
//Log.d("FilesPreviewFragment", "jsString: $jsString")
244261
withContext(Dispatchers.Main) {
245-
binding.webView.apply {
262+
webView.apply {
246263
settings.javaScriptEnabled = true
247264
loadUrl(url)
248265
webViewClient = object : WebViewClient() {
@@ -302,17 +319,17 @@ class FilesPreviewFragment : Fragment() {
302319
}
303320

304321
//override fun onPause() {
305-
// Log.d("Home[onPause]", "0 - ON PAUSE")
322+
// Log.d("Files[onPause]", "0 - ON PAUSE")
306323
// super.onPause()
307-
// binding.webView?.onPause()
308-
// binding.webView?.pauseTimers()
324+
// webView.onPause()
325+
// webView.pauseTimers()
309326
//}
310327

311328
//override fun onResume() {
312329
// Log.d("Home[onResume]", "ON RESUME")
313330
// super.onResume()
314-
// binding.webView?.onResume()
315-
// binding.webView?.resumeTimers()
331+
// webView.onResume()
332+
// webView.resumeTimers()
316333
//}
317334

318335
override fun onStop() {
@@ -326,7 +343,7 @@ class FilesPreviewFragment : Fragment() {
326343
}
327344

328345
override fun onSaveInstanceState(outState: Bundle) {
329-
Log.d("Files[onSave]", "2 - ON SAVE")
346+
Log.d("Files[onSave]", "2 - ON SAVE: outState: ${outState.size()}")
330347
super.onSaveInstanceState(outState)
331348
if (::player.isInitialized) {
332349
Log.d("Files[onSave]", "isPlaying: $isPlaying")
@@ -338,15 +355,6 @@ class FilesPreviewFragment : Fragment() {
338355
}
339356
}
340357

341-
override fun onDestroyView() {
342-
Log.d("Files[onDestroy]", "3 - ON DESTROY")
343-
super.onDestroyView()
344-
if (::player.isInitialized) {
345-
player.release()
346-
}
347-
binding.webView.destroy()
348-
}
349-
350358
//override fun onStart() {
351359
// Log.d("FilesPreviewFragment", "ON START")
352360
// super.onStart()

0 commit comments

Comments
 (0)