Эх сурвалжийг харах

Rename Download into Transfer

Extending Download into more generic Transfer that
can support both downloads and uploads.

Upload functionality is not provided in this PR - it's
only a rename.

Signed-off-by: Chris Narkiewicz <hello@ezaquarii.com>
Chris Narkiewicz 4 жил өмнө
parent
commit
67e6c3402c

+ 8 - 8
src/androidTest/java/com/nextcloud/client/files/downloader/DownloaderConnectionTest.kt

@@ -42,10 +42,10 @@ class DownloaderConnectionTest {
     lateinit var context: Context
 
     @MockK
-    lateinit var firstDownloadListener: (Download) -> Unit
+    lateinit var firstDownloadListener: (Transfer) -> Unit
 
     @MockK
-    lateinit var secondDownloadListener: (Download) -> Unit
+    lateinit var secondDownloadListener: (Transfer) -> Unit
 
     @MockK
     lateinit var firstStatusListener: (Downloader.Status) -> Unit
@@ -80,7 +80,7 @@ class DownloaderConnectionTest {
 
         // THEN
         //      all listeners are passed to the service
-        val listeners = mutableListOf<(Download) -> Unit>()
+        val listeners = mutableListOf<(Transfer) -> Unit>()
         verify { binder.registerDownloadListener(capture(listeners)) }
         assertEquals(listOf(firstDownloadListener, secondDownloadListener), listeners)
     }
@@ -130,11 +130,11 @@ class DownloaderConnectionTest {
 
         val request1 = Request(user, file)
         connection.download(request1)
-        val download1 = Download(request1.uuid, DownloadState.RUNNING, 50, request1.file, request1)
+        val download1 = Transfer(request1.uuid, TransferState.RUNNING, 50, request1.file, request1)
 
         val request2 = Request(user, file)
         connection.download(request2)
-        val download2 = Download(request2.uuid, DownloadState.RUNNING, 50, request2.file, request1)
+        val download2 = Transfer(request2.uuid, TransferState.RUNNING, 50, request2.file, request1)
 
         every { binder.getDownload(request1.uuid) } returns download1
         every { binder.getDownload(request2.uuid) } returns download2
@@ -145,11 +145,11 @@ class DownloaderConnectionTest {
 
         // THEN
         //      listeners receive current download state for pending downloads
-        val firstListenerNotifications = mutableListOf<Download>()
+        val firstListenerNotifications = mutableListOf<Transfer>()
         verify { firstDownloadListener(capture(firstListenerNotifications)) }
         assertEquals(listOf(download1, download2), firstListenerNotifications)
 
-        val secondListenerNotifications = mutableListOf<Download>()
+        val secondListenerNotifications = mutableListOf<Transfer>()
         verify { secondDownloadListener(capture(secondListenerNotifications)) }
         assertEquals(listOf(download1, download2), secondListenerNotifications)
     }
@@ -225,7 +225,7 @@ class DownloaderConnectionTest {
         //      some downloads requested without listener
         val request = Request(user, file)
         connection.download(request)
-        val download = Download(request.uuid, DownloadState.RUNNING, 50, request.file, request)
+        val download = Transfer(request.uuid, TransferState.RUNNING, 50, request.file, request)
         connection.registerDownloadListener(firstDownloadListener)
         every { binder.getDownload(request.uuid) } returns download
 

+ 14 - 14
src/androidTest/java/com/nextcloud/client/files/downloader/DownloaderTest.kt

@@ -42,7 +42,7 @@ import org.mockito.MockitoAnnotations
 @RunWith(Suite::class)
 @Suite.SuiteClasses(
     DownloaderTest.Enqueue::class,
-    DownloaderTest.DownloadStatusUpdates::class
+    DownloaderTest.TransferStatusUpdates::class
 )
 class DownloaderTest {
 
@@ -125,7 +125,7 @@ class DownloaderTest {
             // THEN
             //      download is started immediately
             val download = downloader.getDownload(request.uuid)
-            assertEquals(DownloadState.RUNNING, download?.state)
+            assertEquals(TransferState.RUNNING, download?.state)
         }
 
         @Test
@@ -137,7 +137,7 @@ class DownloaderTest {
                 val request = Request(user, file)
                 downloader.download(request)
                 val runningDownload = downloader.getDownload(request.uuid)
-                assertEquals(runningDownload?.state, DownloadState.RUNNING)
+                assertEquals(runningDownload?.state, TransferState.RUNNING)
             }
 
             // WHEN
@@ -149,11 +149,11 @@ class DownloaderTest {
             // THEN
             //      download is pending
             val download = downloader.getDownload(request.uuid)
-            assertEquals(DownloadState.PENDING, download?.state)
+            assertEquals(TransferState.PENDING, download?.state)
         }
     }
 
-    class DownloadStatusUpdates : Base() {
+    class TransferStatusUpdates : Base() {
 
         @get:Rule
         val rule = InstantTaskExecutorRule()
@@ -165,7 +165,7 @@ class DownloaderTest {
             // GIVEN
             //      download is running
             //      download is being observed
-            val downloadUpdates = mutableListOf<Download>()
+            val downloadUpdates = mutableListOf<Transfer>()
             downloader.registerDownloadListener { downloadUpdates.add(it) }
             downloader.download(Request(user, file))
 
@@ -175,8 +175,8 @@ class DownloaderTest {
 
             // THEN
             //      listener is notified about status change
-            assertEquals(DownloadState.RUNNING, downloadUpdates[0].state)
-            assertEquals(DownloadState.COMPLETED, downloadUpdates[1].state)
+            assertEquals(TransferState.RUNNING, downloadUpdates[0].state)
+            assertEquals(TransferState.COMPLETED, downloadUpdates[1].state)
         }
 
         @Test
@@ -184,7 +184,7 @@ class DownloaderTest {
             // GIVEN
             //      download is running
             //      download is being observed
-            val downloadUpdates = mutableListOf<Download>()
+            val downloadUpdates = mutableListOf<Transfer>()
             downloader.registerDownloadListener { downloadUpdates.add(it) }
             downloader.download(Request(user, file))
 
@@ -195,15 +195,15 @@ class DownloaderTest {
 
             // THEN
             //      listener is notified about status change
-            assertEquals(DownloadState.RUNNING, downloadUpdates[0].state)
-            assertEquals(DownloadState.FAILED, downloadUpdates[1].state)
+            assertEquals(TransferState.RUNNING, downloadUpdates[0].state)
+            assertEquals(TransferState.FAILED, downloadUpdates[1].state)
         }
 
         @Test
         fun download_progress_is_updated() {
             // GIVEN
             //      download is running
-            val downloadUpdates = mutableListOf<Download>()
+            val downloadUpdates = mutableListOf<Transfer>()
             downloader.registerDownloadListener { downloadUpdates.add(it) }
             downloader.download(Request(user, file))
 
@@ -219,12 +219,12 @@ class DownloaderTest {
             //          completion
             assertEquals(6, downloadUpdates.size)
             if (downloadUpdates.size >= 6) {
-                assertEquals(DownloadState.RUNNING, downloadUpdates[0].state)
+                assertEquals(TransferState.RUNNING, downloadUpdates[0].state)
                 assertEquals(25, downloadUpdates[1].progress)
                 assertEquals(50, downloadUpdates[2].progress)
                 assertEquals(75, downloadUpdates[3].progress)
                 assertEquals(100, downloadUpdates[4].progress)
-                assertEquals(DownloadState.COMPLETED, downloadUpdates[5].state)
+                assertEquals(TransferState.COMPLETED, downloadUpdates[5].state)
             }
         }
 

+ 131 - 131
src/androidTest/java/com/nextcloud/client/files/downloader/RegistryTest.kt

@@ -45,14 +45,14 @@ import java.util.UUID
     RegistryTest.Start::class,
     RegistryTest.Progress::class,
     RegistryTest.Complete::class,
-    RegistryTest.GetDownloads::class,
+    RegistryTest.GetTransfers::class,
     RegistryTest.IsRunning::class
 )
 class RegistryTest {
 
     abstract class Base {
         companion object {
-            const val MAX_DOWNLOAD_THREADS = 4
+            const val MAX_TRANSFER_THREADS = 4
             const val PROGRESS_FULL = 100
             const val PROGRESS_HALF = 50
         }
@@ -63,10 +63,10 @@ class RegistryTest {
         lateinit var file: OCFile
 
         @MockK
-        lateinit var onDownloadStart: (UUID, Request) -> Unit
+        lateinit var onTransferStart: (UUID, Request) -> Unit
 
         @MockK
-        lateinit var onDownloadChanged: (Download) -> Unit
+        lateinit var onTransferChanged: (Transfer) -> Unit
 
         internal lateinit var registry: Registry
 
@@ -74,36 +74,36 @@ class RegistryTest {
         fun setUpBase() {
             MockKAnnotations.init(this, relaxed = true)
             file = OCFile("/test/path")
-            registry = Registry(onDownloadStart, onDownloadChanged, MAX_DOWNLOAD_THREADS)
+            registry = Registry(onTransferStart, onTransferChanged, MAX_TRANSFER_THREADS)
             resetMocks()
         }
 
         fun resetMocks() {
             clearAllMocks()
-            every { onDownloadStart(any(), any()) } answers {}
-            every { onDownloadChanged(any()) } answers {}
+            every { onTransferStart(any(), any()) } answers {}
+            every { onTransferChanged(any()) } answers {}
         }
     }
 
     class Pending : Base() {
 
         @Test
-        fun inserting_pending_download() {
+        fun inserting_pending_transfer() {
             // GIVEN
-            //      registry has no pending downloads
+            //      registry has no pending transfers
             assertEquals(0, registry.pending.size)
 
             // WHEN
-            //      new download requests added
-            val addedDownloadsCount = 10
-            for (i in 0 until addedDownloadsCount) {
+            //      new transfer requests added
+            val addedTransfersCount = 10
+            for (i in 0 until addedTransfersCount) {
                 val request = Request(user, file)
                 registry.add(request)
             }
 
             // THEN
-            //      download is added to the pending queue
-            assertEquals(addedDownloadsCount, registry.pending.size)
+            //      transfer is added to the pending queue
+            assertEquals(addedTransfersCount, registry.pending.size)
         }
     }
 
@@ -122,7 +122,7 @@ class RegistryTest {
         }
 
         @Test
-        fun starting_download() {
+        fun starting_transfer() {
             // WHEN
             //      started
             registry.startNext()
@@ -130,47 +130,47 @@ class RegistryTest {
             // THEN
             //      up to max threads requests are started
             //      start callback is triggered
-            //      update callback is triggered on download transition
-            //      started downloads are in running state
+            //      update callback is triggered on transfer transition
+            //      started transfers are in running state
             assertEquals(
-                "Downloads not moved to running queue",
-                MAX_DOWNLOAD_THREADS,
+                "Transfers not moved to running queue",
+                MAX_TRANSFER_THREADS,
                 registry.running.size
             )
             assertEquals(
-                "Downloads not moved from pending queue",
-                ENQUEUED_REQUESTS_COUNT - MAX_DOWNLOAD_THREADS,
+                "Transfers not moved from pending queue",
+                ENQUEUED_REQUESTS_COUNT - MAX_TRANSFER_THREADS,
                 registry.pending.size
             )
-            verify(exactly = MAX_DOWNLOAD_THREADS) { onDownloadStart(any(), any()) }
-            val startedDownloads = mutableListOf<Download>()
-            verify(exactly = MAX_DOWNLOAD_THREADS) { onDownloadChanged(capture(startedDownloads)) }
+            verify(exactly = MAX_TRANSFER_THREADS) { onTransferStart(any(), any()) }
+            val startedTransfers = mutableListOf<Transfer>()
+            verify(exactly = MAX_TRANSFER_THREADS) { onTransferChanged(capture(startedTransfers)) }
             assertEquals(
-                "Callbacks not invoked for running downloads",
-                MAX_DOWNLOAD_THREADS,
-                startedDownloads.size
+                "Callbacks not invoked for running transfers",
+                MAX_TRANSFER_THREADS,
+                startedTransfers.size
             )
-            startedDownloads.forEach {
-                assertEquals("Download not placed into running state", DownloadState.RUNNING, it.state)
+            startedTransfers.forEach {
+                assertEquals("Transfer not placed into running state", TransferState.RUNNING, it.state)
             }
         }
 
         @Test
         fun start_is_ignored_if_no_more_free_threads() {
             // WHEN
-            //      max number of running downloads
+            //      max number of running transfers
             registry.startNext()
-            assertEquals(MAX_DOWNLOAD_THREADS, registry.running.size)
+            assertEquals(MAX_TRANSFER_THREADS, registry.running.size)
             clearAllMocks()
 
             // WHEN
-            //      starting more downloads
+            //      starting more transfers
             registry.startNext()
 
             // THEN
-            //      no more downloads can be started
-            assertEquals(MAX_DOWNLOAD_THREADS, registry.running.size)
-            verify(exactly = 0) { onDownloadStart(any(), any()) }
+            //      no more transfers can be started
+            assertEquals(MAX_TRANSFER_THREADS, registry.running.size)
+            verify(exactly = 0) { onTransferStart(any(), any()) }
         }
     }
 
@@ -189,54 +189,54 @@ class RegistryTest {
         }
 
         @Test
-        fun download_progress_is_updated() {
+        fun transfer_progress_is_updated() {
             // GIVEN
-            //      a download is running
+            //      a transfer is running
 
             // WHEN
-            //      download progress is updated
+            //      transfer progress is updated
             val progressHalf = 50
             registry.progress(uuid, progressHalf)
 
             // THEN
             //      progress is updated
             //      update callback is invoked
-            val download = mutableListOf<Download>()
-            verify { onDownloadChanged(capture(download)) }
-            assertEquals(1, download.size)
-            assertEquals(progressHalf, download.first().progress)
+            val transfer = mutableListOf<Transfer>()
+            verify { onTransferChanged(capture(transfer)) }
+            assertEquals(1, transfer.size)
+            assertEquals(progressHalf, transfer.first().progress)
         }
 
         @Test
-        fun updates_for_non_running_downloads_are_ignored() {
+        fun updates_for_non_running_transfers_are_ignored() {
             // GIVEN
-            //      download is not running
+            //      transfer is not running
             registry.complete(uuid, true)
             assertEquals(0, registry.running.size)
             resetMocks()
 
             // WHEN
-            //      progress for a non-running download is updated
+            //      progress for a non-running transfer is updated
             registry.progress(uuid, PROGRESS_HALF)
 
             // THEN
             //      progress update is ignored
-            verify(exactly = 0) { onDownloadChanged(any()) }
+            verify(exactly = 0) { onTransferChanged(any()) }
         }
 
         @Test
-        fun updates_for_non_existing_downloads_are_ignored() {
+        fun updates_for_non_existing_transfers_are_ignored() {
             // GIVEN
-            //      some download is running
+            //      some transfer is running
 
             // WHEN
-            //      progress is updated for non-existing download
-            val nonExistingDownloadId = UUID.randomUUID()
-            registry.progress(nonExistingDownloadId, PROGRESS_HALF)
+            //      progress is updated for non-existing transfer
+            val nonExistingTransferId = UUID.randomUUID()
+            registry.progress(nonExistingTransferId, PROGRESS_HALF)
 
             // THEN
             //      progress uppdate is ignored
-            verify(exactly = 0) { onDownloadChanged(any()) }
+            verify(exactly = 0) { onTransferChanged(any()) }
         }
     }
 
@@ -253,81 +253,81 @@ class RegistryTest {
         }
 
         @Test
-        fun complete_successful_download_with_updated_file() {
+        fun complete_successful_transfer_with_updated_file() {
             // GIVEN
-            //      a download is running
+            //      a transfer is running
 
             // WHEN
-            //      download is completed
+            //      transfer is completed
             //      file has been updated
             val updatedFile = OCFile("/updated/file")
             registry.complete(uuid, true, updatedFile)
 
             // THEN
-            //      download is completed successfully
+            //      transfer is completed successfully
             //      status carries updated file
-            val slot = CapturingSlot<Download>()
-            verify { onDownloadChanged(capture(slot)) }
-            assertEquals(DownloadState.COMPLETED, slot.captured.state)
+            val slot = CapturingSlot<Transfer>()
+            verify { onTransferChanged(capture(slot)) }
+            assertEquals(TransferState.COMPLETED, slot.captured.state)
             assertSame(slot.captured.file, updatedFile)
         }
 
         @Test
-        fun complete_successful_download() {
+        fun complete_successful_transfer() {
             // GIVEN
-            //      a download is running
+            //      a transfer is running
 
             // WHEN
-            //      download is completed
+            //      transfer is completed
             //      file is not updated
             registry.complete(uuid = uuid, success = true, file = null)
 
             // THEN
-            //      download is completed successfully
+            //      transfer is completed successfully
             //      status carries previous file
-            val slot = CapturingSlot<Download>()
-            verify { onDownloadChanged(capture(slot)) }
-            assertEquals(DownloadState.COMPLETED, slot.captured.state)
+            val slot = CapturingSlot<Transfer>()
+            verify { onTransferChanged(capture(slot)) }
+            assertEquals(TransferState.COMPLETED, slot.captured.state)
             assertSame(slot.captured.file, file)
         }
 
         @Test
-        fun complete_failed_download() {
+        fun complete_failed_transfer() {
             // GIVEN
-            //      a download is running
+            //      a transfer is running
 
             // WHEN
-            //      download is failed
+            //      transfer is failed
             registry.complete(uuid, false)
 
             // THEN
-            //      download is completed successfully
-            val slot = CapturingSlot<Download>()
-            verify { onDownloadChanged(capture(slot)) }
-            assertEquals(DownloadState.FAILED, slot.captured.state)
+            //      transfer is completed successfully
+            val slot = CapturingSlot<Transfer>()
+            verify { onTransferChanged(capture(slot)) }
+            assertEquals(TransferState.FAILED, slot.captured.state)
         }
     }
 
-    class GetDownloads : Base() {
+    class GetTransfers : Base() {
 
-        val pendingDownloadFile = OCFile("/pending")
-        val runningDownloadFile = OCFile("/running")
-        val completedDownloadFile = OCFile("/completed")
+        val pendingTransferFile = OCFile("/pending")
+        val runningTransferFile = OCFile("/running")
+        val completedTransferFile = OCFile("/completed")
 
-        lateinit var pendingDownloadId: UUID
-        lateinit var runningDownloadId: UUID
-        lateinit var completedDownloadId: UUID
+        lateinit var pendingTransferId: UUID
+        lateinit var runningTransferId: UUID
+        lateinit var completedTransferId: UUID
 
         @Before
         fun setUp() {
-            completedDownloadId = registry.add(Request(user, completedDownloadFile))
+            completedTransferId = registry.add(Request(user, completedTransferFile))
             registry.startNext()
-            registry.complete(completedDownloadId, true)
+            registry.complete(completedTransferId, true)
 
-            runningDownloadId = registry.add(Request(user, runningDownloadFile))
+            runningTransferId = registry.add(Request(user, runningTransferFile))
             registry.startNext()
 
-            pendingDownloadId = registry.add(Request(user, pendingDownloadFile))
+            pendingTransferId = registry.add(Request(user, pendingTransferFile))
             resetMocks()
 
             assertEquals(1, registry.pending.size)
@@ -338,121 +338,121 @@ class RegistryTest {
         @Test
         fun get_by_path_searches_pending_queue() {
             // GIVEN
-            //      file download is pending
+            //      file transfer is pending
 
             // WHEN
-            //      download status is retrieved
-            val download = registry.getDownload(pendingDownloadFile)
+            //      transfer status is retrieved
+            val transfer = registry.getTransfer(pendingTransferFile)
 
             // THEN
-            //      download from pending queue is returned
-            assertNotNull(download)
-            assertEquals(pendingDownloadId, download?.uuid)
+            //      transfer from pending queue is returned
+            assertNotNull(transfer)
+            assertEquals(pendingTransferId, transfer?.uuid)
         }
 
         @Test
         fun get_by_id_searches_pending_queue() {
             // GIVEN
-            //      file download is pending
+            //      file transfer is pending
 
             // WHEN
-            //      download status is retrieved
-            val download = registry.getDownload(pendingDownloadId)
+            //      transfer status is retrieved
+            val transfer = registry.getTransfer(pendingTransferId)
 
             // THEN
-            //      download from pending queue is returned
-            assertNotNull(download)
-            assertEquals(pendingDownloadId, download?.uuid)
+            //      transfer from pending queue is returned
+            assertNotNull(transfer)
+            assertEquals(pendingTransferId, transfer?.uuid)
         }
 
         @Test
         fun get_by_path_searches_running_queue() {
             // GIVEN
-            //      file download is running
+            //      file transfer is running
 
             // WHEN
-            //      download status is retrieved
-            val download = registry.getDownload(runningDownloadFile)
+            //      transfer status is retrieved
+            val transfer = registry.getTransfer(runningTransferFile)
 
             // THEN
-            //      download from pending queue is returned
-            assertNotNull(download)
-            assertEquals(runningDownloadId, download?.uuid)
+            //      transfer from pending queue is returned
+            assertNotNull(transfer)
+            assertEquals(runningTransferId, transfer?.uuid)
         }
 
         @Test
         fun get_by_id_searches_running_queue() {
             // GIVEN
-            //      file download is running
+            //      file transfer is running
 
             // WHEN
-            //      download status is retrieved
-            val download = registry.getDownload(runningDownloadId)
+            //      transfer status is retrieved
+            val transfer = registry.getTransfer(runningTransferId)
 
             // THEN
-            //      download from pending queue is returned
-            assertNotNull(download)
-            assertEquals(runningDownloadId, download?.uuid)
+            //      transfer from pending queue is returned
+            assertNotNull(transfer)
+            assertEquals(runningTransferId, transfer?.uuid)
         }
 
         @Test
         fun get_by_path_searches_completed_queue() {
             // GIVEN
-            //      file download is pending
+            //      file transfer is pending
 
             // WHEN
-            //      download status is retrieved
-            val download = registry.getDownload(completedDownloadFile)
+            //      transfer status is retrieved
+            val transfer = registry.getTransfer(completedTransferFile)
 
             // THEN
-            //      download from pending queue is returned
-            assertNotNull(download)
-            assertEquals(completedDownloadId, download?.uuid)
+            //      transfer from pending queue is returned
+            assertNotNull(transfer)
+            assertEquals(completedTransferId, transfer?.uuid)
         }
 
         @Test
         fun get_by_id_searches_completed_queue() {
             // GIVEN
-            //      file download is pending
+            //      file transfer is pending
 
             // WHEN
-            //      download status is retrieved
-            val download = registry.getDownload(completedDownloadId)
+            //      transfer status is retrieved
+            val transfer = registry.getTransfer(completedTransferId)
 
             // THEN
-            //      download from pending queue is returned
-            assertNotNull(download)
-            assertEquals(completedDownloadId, download?.uuid)
+            //      transfer from pending queue is returned
+            assertNotNull(transfer)
+            assertEquals(completedTransferId, transfer?.uuid)
         }
 
         @Test
         fun not_found_by_path() {
             // GIVEN
-            //      no download for a file
-            val nonExistingDownloadFile = OCFile("/non-nexisting/download")
+            //      no transfer for a file
+            val nonExistingTransferFile = OCFile("/non-nexisting/transfer")
 
             // WHEN
-            //      download status is retrieved for a file
-            val download = registry.getDownload(nonExistingDownloadFile)
+            //      transfer status is retrieved for a file
+            val transfer = registry.getTransfer(nonExistingTransferFile)
 
             // THEN
-            //      no download is found
-            assertNull(download)
+            //      no transfer is found
+            assertNull(transfer)
         }
 
         @Test
         fun not_found_by_id() {
             // GIVEN
-            //      no download for an id
+            //      no transfer for an id
             val nonExistingId = UUID.randomUUID()
 
             // WHEN
-            //      download status is retrieved for a file
-            val download = registry.getDownload(nonExistingId)
+            //      transfer status is retrieved for a file
+            val transfer = registry.getTransfer(nonExistingId)
 
             // THEN
-            //      no download is found
-            assertNull(download)
+            //      no transfer is found
+            assertNull(transfer)
         }
     }
 

+ 9 - 3
src/main/java/com/nextcloud/client/etm/pages/EtmDownloaderFragment.kt

@@ -12,7 +12,8 @@ import androidx.recyclerview.widget.DividerItemDecoration
 import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.RecyclerView
 import com.nextcloud.client.etm.EtmBaseFragment
-import com.nextcloud.client.files.downloader.Download
+import com.nextcloud.client.files.downloader.Direction
+import com.nextcloud.client.files.downloader.Transfer
 import com.nextcloud.client.files.downloader.Downloader
 import com.nextcloud.client.files.downloader.Request
 import com.owncloud.android.R
@@ -48,7 +49,7 @@ class EtmDownloaderFragment : EtmBaseFragment() {
                 }
         }
 
-        private var downloads = listOf<Download>()
+        private var downloads = listOf<Transfer>()
 
         fun setStatus(status: Downloader.Status) {
             downloads = listOf(status.pending, status.running, status.completed).flatten().reversed()
@@ -123,7 +124,12 @@ class EtmDownloaderFragment : EtmBaseFragment() {
     }
 
     private fun scheduleTestDownload() {
-        val request = Request(user = vm.currentUser, file = OCFile(TEST_DOWNLOAD_DUMMY_PATH), test = true)
+        val request = Request(
+            vm.currentUser,
+            OCFile(TEST_DOWNLOAD_DUMMY_PATH),
+            Direction.DOWNLOAD,
+            true
+        )
         vm.downloaderConnection.download(request)
     }
 

+ 25 - 0
src/main/java/com/nextcloud/client/files/downloader/Direction.kt

@@ -0,0 +1,25 @@
+/*
+ * Nextcloud Android client application
+ *
+ * @author Chris Narkiewicz
+ * Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.nextcloud.client.files.downloader
+
+enum class Direction {
+    DOWNLOAD,
+    UPLOAD
+}

+ 7 - 7
src/main/java/com/nextcloud/client/files/downloader/Downloader.kt

@@ -28,9 +28,9 @@ interface Downloader {
      * Snapshot of downloader status. All data is immutable and can be safely shared.
      */
     data class Status(
-        val pending: List<Download>,
-        val running: List<Download>,
-        val completed: List<Download>
+        val pending: List<Transfer>,
+        val running: List<Transfer>,
+        val completed: List<Transfer>
     ) {
         companion object {
             val EMPTY = Status(emptyList(), emptyList(), emptyList())
@@ -50,12 +50,12 @@ interface Downloader {
     /**
      * Register download progress listener. Registration is idempotent - listener can be registered only once.
      */
-    fun registerDownloadListener(listener: (Download) -> Unit)
+    fun registerDownloadListener(listener: (Transfer) -> Unit)
 
     /**
      * Removes registered listener if exists.
      */
-    fun removeDownloadListener(listener: (Download) -> Unit)
+    fun removeDownloadListener(listener: (Transfer) -> Unit)
 
     /**
      * Register downloader status listener. Registration is idempotent - listener can be registered only once.
@@ -80,7 +80,7 @@ interface Downloader {
      * @param uuid Download process uuid
      * @return download status or null if not found
      */
-    fun getDownload(uuid: UUID): Download?
+    fun getDownload(uuid: UUID): Transfer?
 
     /**
      * Query user's downloader for a download status. It performs linear search
@@ -94,5 +94,5 @@ interface Downloader {
      * @param file Downloaded file
      * @return download status or null, if download does not exist
      */
-    fun getDownload(file: OCFile): Download?
+    fun getDownload(file: OCFile): Transfer?
 }

+ 5 - 5
src/main/java/com/nextcloud/client/files/downloader/DownloaderConnection.kt

@@ -29,7 +29,7 @@ import java.util.UUID
 
 class DownloaderConnection(context: Context, val user: User) : LocalConnection<DownloaderService>(context), Downloader {
 
-    private var downloadListeners: MutableSet<(Download) -> Unit> = mutableSetOf()
+    private var downloadListeners: MutableSet<(Transfer) -> Unit> = mutableSetOf()
     private var statusListeners: MutableSet<(Downloader.Status) -> Unit> = mutableSetOf()
     private var binder: DownloaderService.Binder? = null
     private val downloadsRequiringStatusRedelivery: MutableSet<UUID> = mutableSetOf()
@@ -40,9 +40,9 @@ class DownloaderConnection(context: Context, val user: User) : LocalConnection<D
     override val status: Downloader.Status
         get() = binder?.status ?: Downloader.Status.EMPTY
 
-    override fun getDownload(uuid: UUID): Download? = binder?.getDownload(uuid)
+    override fun getDownload(uuid: UUID): Transfer? = binder?.getDownload(uuid)
 
-    override fun getDownload(file: OCFile): Download? = binder?.getDownload(file)
+    override fun getDownload(file: OCFile): Transfer? = binder?.getDownload(file)
 
     override fun download(request: Request) {
         val intent = DownloaderService.createDownloadIntent(context, request)
@@ -52,12 +52,12 @@ class DownloaderConnection(context: Context, val user: User) : LocalConnection<D
         }
     }
 
-    override fun registerDownloadListener(listener: (Download) -> Unit) {
+    override fun registerDownloadListener(listener: (Transfer) -> Unit) {
         downloadListeners.add(listener)
         binder?.registerDownloadListener(listener)
     }
 
-    override fun removeDownloadListener(listener: (Download) -> Unit) {
+    override fun removeDownloadListener(listener: (Transfer) -> Unit) {
         downloadListeners.remove(listener)
         binder?.removeDownloadListener(listener)
     }

+ 9 - 9
src/main/java/com/nextcloud/client/files/downloader/DownloaderImpl.kt

@@ -50,11 +50,11 @@ class DownloaderImpl(
     }
 
     private val registry = Registry(
-        onStartDownload = this::onStartDownload,
-        onDownloadChanged = this::onDownloadUpdate,
+        onStartTransfer = this::onStartDownload,
+        onTransferChanged = this::onDownloadUpdate,
         maxRunning = threads
     )
-    private val downloadListeners: MutableSet<(Download) -> Unit> = mutableSetOf()
+    private val downloadListeners: MutableSet<(Transfer) -> Unit> = mutableSetOf()
     private val statusListeners: MutableSet<(Downloader.Status) -> Unit> = mutableSetOf()
 
     override val isRunning: Boolean get() = registry.isRunning
@@ -66,11 +66,11 @@ class DownloaderImpl(
             completed = registry.completed
         )
 
-    override fun registerDownloadListener(listener: (Download) -> Unit) {
+    override fun registerDownloadListener(listener: (Transfer) -> Unit) {
         downloadListeners.add(listener)
     }
 
-    override fun removeDownloadListener(listener: (Download) -> Unit) {
+    override fun removeDownloadListener(listener: (Transfer) -> Unit) {
         downloadListeners.remove(listener)
     }
 
@@ -87,9 +87,9 @@ class DownloaderImpl(
         registry.startNext()
     }
 
-    override fun getDownload(uuid: UUID): Download? = registry.getDownload(uuid)
+    override fun getDownload(uuid: UUID): Transfer? = registry.getTransfer(uuid)
 
-    override fun getDownload(file: OCFile): Download? = registry.getDownload(file)
+    override fun getDownload(file: OCFile): Transfer? = registry.getTransfer(file)
 
     private fun onStartDownload(uuid: UUID, request: Request) {
         val downloadTask = createDownloadTask(request)
@@ -115,8 +115,8 @@ class DownloaderImpl(
         }
     }
 
-    private fun onDownloadUpdate(download: Download) {
-        downloadListeners.forEach { it.invoke(download) }
+    private fun onDownloadUpdate(transfer: Transfer) {
+        downloadListeners.forEach { it.invoke(transfer) }
         if (statusListeners.isNotEmpty()) {
             val status = this.status
             statusListeners.forEach { it.invoke(status) }

+ 5 - 5
src/main/java/com/nextcloud/client/files/downloader/DownloaderService.kt

@@ -115,7 +115,7 @@ class DownloaderService : Service() {
         }
     }
 
-    private fun onDownloadUpdate(download: Download) {
+    private fun onDownloadUpdate(transfer: Transfer) {
         if (!isRunning) {
             logger.d(TAG, "All downloads completed")
             notificationsManager.cancelDownloadProgress()
@@ -123,10 +123,10 @@ class DownloaderService : Service() {
             stopSelf()
         } else {
             notificationsManager.postDownloadProgress(
-                fileOwner = download.request.user,
-                file = download.request.file,
-                progress = download.progress,
-                allowPreview = !download.request.test
+                fileOwner = transfer.request.user,
+                file = transfer.request.file,
+                progress = transfer.progress,
+                allowPreview = !transfer.request.test
             )
         }
     }

+ 55 - 55
src/main/java/com/nextcloud/client/files/downloader/Registry.kt

@@ -27,9 +27,9 @@ import kotlin.math.max
 import kotlin.math.min
 
 /**
- * This class tracks status of all downloads. It serves as a state
- * machine and drives the download background task scheduler via callbacks.
- * Download status updates are triggering change callbacks that should be used
+ * This class tracks status of file transfers. It serves as a state
+ * machine and drives the transfer background task scheduler via callbacks.
+ * Transfer status updates trigger change callbacks that should be used
  * to notify listeners.
  *
  * No listener registration mechanism is provided at this level.
@@ -37,106 +37,106 @@ import kotlin.math.min
  * This class is not thread-safe. All access from multiple threads shall
  * be lock protected.
  *
- * @property onStartDownload callback triggered when download is switched into running state
- * @property onDownloadChanged callback triggered whenever download status update
- * @property maxRunning maximum number of allowed simultaneous downloads
+ * @property onStartTransfer callback triggered when transfer is switched into running state
+ * @property onTransferChanged callback triggered whenever transfer status update
+ * @property maxRunning maximum number of allowed simultaneous transfers
  */
 internal class Registry(
-    private val onStartDownload: (UUID, Request) -> Unit,
-    private val onDownloadChanged: (Download) -> Unit,
+    private val onStartTransfer: (UUID, Request) -> Unit,
+    private val onTransferChanged: (Transfer) -> Unit,
     private val maxRunning: Int = 2
 ) {
-    private val pendingQueue = TreeMap<UUID, Download>()
-    private val runningQueue = TreeMap<UUID, Download>()
-    private val completedQueue = TreeMap<UUID, Download>()
+    private val pendingQueue = TreeMap<UUID, Transfer>()
+    private val runningQueue = TreeMap<UUID, Transfer>()
+    private val completedQueue = TreeMap<UUID, Transfer>()
 
     val isRunning: Boolean get() = pendingQueue.size > 0 || runningQueue.size > 0
 
-    val pending: List<Download> get() = pendingQueue.map { it.value }
-    val running: List<Download> get() = runningQueue.map { it.value }
-    val completed: List<Download> get() = completedQueue.map { it.value }
+    val pending: List<Transfer> get() = pendingQueue.map { it.value }
+    val running: List<Transfer> get() = runningQueue.map { it.value }
+    val completed: List<Transfer> get() = completedQueue.map { it.value }
 
     /**
-     * Insert new download into a pending queue.
+     * Insert new transfer into a pending queue.
      *
-     * @return scheduled download id
+     * @return scheduled transfer id
      */
     fun add(request: Request): UUID {
-        val download = Download(
+        val transfer = Transfer(
             uuid = request.uuid,
-            state = DownloadState.PENDING,
+            state = TransferState.PENDING,
             progress = 0,
             file = request.file,
             request = request
         )
-        pendingQueue[download.uuid] = download
-        return download.uuid
+        pendingQueue[transfer.uuid] = transfer
+        return transfer.uuid
     }
 
     /**
-     * Move pending downloads into a running queue up
-     * to max allowed simultaneous downloads.
+     * Move pending transfers into a running queue up
+     * to max allowed simultaneous transfers.
      */
     fun startNext() {
         val freeThreads = max(0, maxRunning - runningQueue.size)
         for (i in 0 until min(freeThreads, pendingQueue.size)) {
             val key = pendingQueue.firstKey()
-            val pendingDownload = pendingQueue.remove(key) ?: throw IllegalStateException("Download $key not exist.")
-            val runningDownload = pendingDownload.copy(state = DownloadState.RUNNING)
-            runningQueue[key] = runningDownload
-            onStartDownload.invoke(key, runningDownload.request)
-            onDownloadChanged(runningDownload)
+            val pendingTransfer = pendingQueue.remove(key) ?: throw IllegalStateException("Transfer $key not found")
+            val runningTransfer = pendingTransfer.copy(state = TransferState.RUNNING)
+            runningQueue[key] = runningTransfer
+            onStartTransfer.invoke(key, runningTransfer.request)
+            onTransferChanged(runningTransfer)
         }
     }
 
     /**
-     * Update progress for a given download. If no download of a given id is currently running,
+     * Update progress for a given transfer. If no transfer of a given id is currently running,
      * update is ignored.
      *
-     * @param uuid ID of the download to update
+     * @param uuid ID of the transfer to update
      * @param progress progress 0-100%
      */
     fun progress(uuid: UUID, progress: Int) {
-        val download = runningQueue[uuid]
-        if (download != null) {
-            val runningDownload = download.copy(progress = progress)
-            runningQueue[uuid] = runningDownload
-            onDownloadChanged(runningDownload)
+        val transfer = runningQueue[uuid]
+        if (transfer != null) {
+            val runningTransfer = transfer.copy(progress = progress)
+            runningQueue[uuid] = runningTransfer
+            onTransferChanged(runningTransfer)
         }
     }
 
     /**
-     * Complete currently running download. If no download of a given id is currently running,
+     * Complete currently running transfer. If no transfer of a given id is currently running,
      * update is ignored.
      *
-     * @param uuid of the download to complete
-     * @param success if true, download will be marked as completed; if false - as failed
-     * @param file if provided, update file in download status; if null, existing value is retained
+     * @param uuid of the transfer to complete
+     * @param success if true, transfer will be marked as completed; if false - as failed
+     * @param file if provided, update file in transfer status; if null, existing value is retained
      */
     fun complete(uuid: UUID, success: Boolean, file: OCFile? = null) {
-        val download = runningQueue.remove(uuid)
-        if (download != null) {
+        val transfer = runningQueue.remove(uuid)
+        if (transfer != null) {
             val status = if (success) {
-                DownloadState.COMPLETED
+                TransferState.COMPLETED
             } else {
-                DownloadState.FAILED
+                TransferState.FAILED
             }
-            val completedDownload = download.copy(state = status, file = file ?: download.file)
-            completedQueue[uuid] = completedDownload
-            onDownloadChanged(completedDownload)
+            val completedTransfer = transfer.copy(state = status, file = file ?: transfer.file)
+            completedQueue[uuid] = completedTransfer
+            onTransferChanged(completedTransfer)
         }
     }
 
     /**
-     * Search for a download by file path. It traverses
+     * Search for a transfer by file path. It traverses
      * through all queues in order of pending, running and completed
-     * downloads and returns first download status matching
+     * transfers and returns first transfer status matching
      * file path.
      *
-     * @param file Search for a file download
-     * @return download status if found, null otherwise
+     * @param file Search for a file transfer
+     * @return transfer status if found, null otherwise
      */
-    fun getDownload(file: OCFile): Download? {
+    fun getTransfer(file: OCFile): Transfer? {
         arrayOf(pendingQueue, runningQueue, completedQueue).forEach { queue ->
             queue.forEach { entry ->
                 if (entry.value.request.file.remotePath == file.remotePath) {
@@ -148,15 +148,15 @@ internal class Registry(
     }
 
     /**
-     * Get download status by id. It traverses
+     * Get transfer status by id. It traverses
      * through all queues in order of pending, running and completed
-     * downloads and returns first download status matching
+     * transfers and returns first transfer status matching
      * file path.
      *
-     * @param id download id
-     * @return download status if found, null otherwise
+     * @param id transfer id
+     * @return transfer status if found, null otherwise
      */
-    fun getDownload(uuid: UUID): Download? {
+    fun getTransfer(uuid: UUID): Transfer? {
         return pendingQueue[uuid] ?: runningQueue[uuid] ?: completedQueue[uuid]
     }
 }

+ 20 - 8
src/main/java/com/nextcloud/client/files/downloader/Request.kt

@@ -26,33 +26,44 @@ import com.owncloud.android.datamodel.OCFile
 import java.util.UUID
 
 /**
- * Download request. This class should collect all information
- * required to trigger download operation.
+ * Transfer request. This class should collect all information
+ * required to trigger transfer operation.
  *
  * Class is immutable by design, although [OCFile] or other
  * types might not be immutable. Clients should no modify
  * contents of this object.
  *
- * @property user Download will be triggered for a given user
- * @property file Remote file to download
- * @property uuid Unique request identifier; this identifier can be set in [Download]
- * @property dummy if true, this requests a dummy test download; no real file transfer will occur
+ * @property user Transfer will be triggered for a given user
+ * @property file File to transfer
+ * @property uuid Unique request identifier; this identifier can be set in [Transfer]
+ * @property dummy if true, this requests a dummy test transfer; no real file transfer will occur
  */
 class Request internal constructor(
     val user: User,
     val file: OCFile,
     val uuid: UUID,
+    val type: Direction = Direction.DOWNLOAD,
     val test: Boolean = false
 ) : Parcelable {
 
-    constructor(user: User, file: OCFile) : this(user, file, UUID.randomUUID())
+    constructor(
+        user: User,
+        file: OCFile,
+        type: Direction = Direction.DOWNLOAD
+    ) : this(user, file, UUID.randomUUID(), type)
 
-    constructor(user: User, file: OCFile, test: Boolean) : this(user, file, UUID.randomUUID(), test)
+    constructor(
+        user: User,
+        file: OCFile,
+        type: Direction,
+        test: Boolean
+    ) : this(user, file, UUID.randomUUID(), type, test)
 
     constructor(parcel: Parcel) : this(
         user = parcel.readParcelable<User>(User::class.java.classLoader) as User,
         file = parcel.readParcelable<OCFile>(OCFile::class.java.classLoader) as OCFile,
         uuid = parcel.readSerializable() as UUID,
+        type = parcel.readSerializable() as Direction,
         test = parcel.readInt() != 0
     )
 
@@ -60,6 +71,7 @@ class Request internal constructor(
         parcel.writeParcelable(user, flags)
         parcel.writeParcelable(file, flags)
         parcel.writeSerializable(uuid)
+        parcel.writeSerializable(type)
         parcel.writeInt(if (test) 1 else 0)
     }
 

+ 9 - 9
src/main/java/com/nextcloud/client/files/downloader/Download.kt → src/main/java/com/nextcloud/client/files/downloader/Transfer.kt

@@ -23,21 +23,21 @@ import com.owncloud.android.datamodel.OCFile
 import java.util.UUID
 
 /**
- * This class represents current download process state.
+ * This class represents current transfer (download or upload) process state.
  * This object is immutable by design.
  *
  * NOTE: Although [OCFile] object is mutable, it is caused by shortcomings
  * of legacy design; please behave like an adult and treat it as immutable value.
  *
- * @property uuid Unique download process id
- * @property state current download state
- * @property progress download progress, 0-100 percent
- * @property file downloaded file, if download is in progress or failed, it is remote; if finished successfully - local
- * @property request initial download request
+ * @property uuid Unique transfer id
+ * @property state current transfer state
+ * @property progress transfer progress, 0-100 percent
+ * @property file transferred file
+ * @property request initial transfer request
  */
-data class Download(
+data class Transfer(
     val uuid: UUID,
-    val state: DownloadState,
+    val state: TransferState,
     val progress: Int,
     val file: OCFile,
     val request: Request
@@ -45,5 +45,5 @@ data class Download(
     /**
      * True if download is no longer running, false if it is still being processed.
      */
-    val isFinished: Boolean get() = state == DownloadState.COMPLETED || state == DownloadState.FAILED
+    val isFinished: Boolean get() = state == TransferState.COMPLETED || state == TransferState.FAILED
 }

+ 1 - 1
src/main/java/com/nextcloud/client/files/downloader/DownloadState.kt → src/main/java/com/nextcloud/client/files/downloader/TransferState.kt

@@ -19,7 +19,7 @@
  */
 package com.nextcloud.client.files.downloader
 
-enum class DownloadState {
+enum class TransferState {
     PENDING,
     RUNNING,
     COMPLETED,

+ 6 - 6
src/main/java/com/owncloud/android/ui/fragment/contactsbackup/ContactListFragment.java

@@ -57,14 +57,14 @@ import com.google.android.material.snackbar.Snackbar;
 import com.nextcloud.client.account.User;
 import com.nextcloud.client.account.UserAccountManager;
 import com.nextcloud.client.di.Injectable;
-import com.nextcloud.client.files.downloader.Download;
-import com.nextcloud.client.files.downloader.DownloadState;
+import com.nextcloud.client.files.downloader.Direction;
+import com.nextcloud.client.files.downloader.Transfer;
+import com.nextcloud.client.files.downloader.TransferState;
 import com.nextcloud.client.files.downloader.DownloaderConnection;
 import com.nextcloud.client.files.downloader.Request;
 import com.nextcloud.client.jobs.BackgroundJobManager;
 import com.nextcloud.client.network.ClientFactory;
 import com.owncloud.android.R;
-import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.ui.TextDrawable;
@@ -217,7 +217,7 @@ public class ContactListFragment extends FileFragment implements Injectable {
         fileDownloader.registerDownloadListener(this::onDownloadUpdate);
         fileDownloader.bind();
         if (!ocFile.isDown()) {
-            Request request = new Request(user, ocFile);
+            Request request = new Request(user, ocFile, Direction.DOWNLOAD);
             fileDownloader.download(request);
         } else {
             loadContactsTask.execute();
@@ -503,9 +503,9 @@ public class ContactListFragment extends FileFragment implements Injectable {
         }
     }
 
-    private Unit onDownloadUpdate(Download download) {
+    private Unit onDownloadUpdate(Transfer download) {
         final Activity activity = getActivity();
-        if (download.getState() == DownloadState.COMPLETED && activity != null) {
+        if (download.getState() == TransferState.COMPLETED && activity != null) {
             ocFile = download.getFile();
             loadContactsTask.execute();
         }