diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt index 0200578253bb..bbb245602fed 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt @@ -436,9 +436,7 @@ class FileUploadHelper { * @param user Needed for creating client */ fun removeDuplicatedFile(duplicatedFile: OCFile, client: OwnCloudClient, user: User, onCompleted: () -> Unit) { - val job = CoroutineScope(Dispatchers.IO) - - job.launch { + ioScope.launch { val removeFileOperation = RemoveFileOperation( duplicatedFile, false, diff --git a/app/src/main/java/com/nextcloud/ui/ImageDetailFragment.kt b/app/src/main/java/com/nextcloud/ui/ImageDetailFragment.kt index a0c2f73cff17..766809e8247c 100644 --- a/app/src/main/java/com/nextcloud/ui/ImageDetailFragment.kt +++ b/app/src/main/java/com/nextcloud/ui/ImageDetailFragment.kt @@ -20,6 +20,7 @@ import androidx.annotation.VisibleForTesting import androidx.core.content.ContextCompat import androidx.core.net.toUri import androidx.fragment.app.Fragment +import androidx.lifecycle.lifecycleScope import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.client.NominatimClient import com.nextcloud.client.account.User @@ -154,7 +155,7 @@ class ImageDetailFragment : binding.imageLocation.visibility = View.VISIBLE // launch reverse geocoding request - CoroutineScope(Dispatchers.IO).launch { + lifecycleScope.launch(Dispatchers.IO) { val geocodingResult = nominatimClient.reverseGeocode(location.first, location.second) if (geocodingResult != null) { withContext(Dispatchers.Main) { diff --git a/app/src/main/java/com/owncloud/android/ui/activities/ActivitiesActivity.kt b/app/src/main/java/com/owncloud/android/ui/activities/ActivitiesActivity.kt index 446201e5fc58..d217eaafd5d5 100644 --- a/app/src/main/java/com/owncloud/android/ui/activities/ActivitiesActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activities/ActivitiesActivity.kt @@ -12,6 +12,7 @@ import android.os.Bundle import android.view.MenuItem import android.view.View import androidx.core.view.size +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.nextcloud.client.network.ConnectivityService @@ -75,7 +76,7 @@ class ActivitiesActivity : // We set lastGiven variable to undefined here since when manually refreshing // activities data we want to clear the list and reset the pagination. lastGiven = ActivitiesContract.ActionListener.UNDEFINED.toLong() - actionListener?.loadActivities(lastGiven) + actionListener?.loadActivities(lifecycleScope, lastGiven) } } @@ -101,7 +102,7 @@ class ActivitiesActivity : addOnScrollListener(getOnScrollListener(layoutManager)) } - actionListener?.loadActivities(ActivitiesContract.ActionListener.UNDEFINED.toLong()) + actionListener?.loadActivities(lifecycleScope, ActivitiesContract.ActionListener.UNDEFINED.toLong()) } private fun getOnScrollListener(layoutManager: LinearLayoutManager) = object : RecyclerView.OnScrollListener() { @@ -117,7 +118,7 @@ class ActivitiesActivity : lastGiven > 0 ) { // Almost reached the end, continue to load new activities - actionListener?.loadActivities(lastGiven) + actionListener?.loadActivities(lifecycleScope, lastGiven) } } } diff --git a/app/src/main/java/com/owncloud/android/ui/activities/ActivitiesContract.kt b/app/src/main/java/com/owncloud/android/ui/activities/ActivitiesContract.kt index 664cd0ceb6fe..991c08f430a8 100644 --- a/app/src/main/java/com/owncloud/android/ui/activities/ActivitiesContract.kt +++ b/app/src/main/java/com/owncloud/android/ui/activities/ActivitiesContract.kt @@ -10,6 +10,7 @@ package com.owncloud.android.ui.activities import com.nextcloud.common.NextcloudClient import com.owncloud.android.datamodel.OCFile import com.owncloud.android.ui.activity.BaseActivity +import kotlinx.coroutines.CoroutineScope interface ActivitiesContract { interface View { @@ -24,7 +25,7 @@ interface ActivitiesContract { } interface ActionListener { - fun loadActivities(lastGiven: Long) + fun loadActivities(lifecycleScope: CoroutineScope, lastGiven: Long) fun openActivity(fileUrl: String, baseActivity: BaseActivity) diff --git a/app/src/main/java/com/owncloud/android/ui/activities/ActivitiesPresenter.kt b/app/src/main/java/com/owncloud/android/ui/activities/ActivitiesPresenter.kt index cf35391ed1f4..5f0a0a073829 100644 --- a/app/src/main/java/com/owncloud/android/ui/activities/ActivitiesPresenter.kt +++ b/app/src/main/java/com/owncloud/android/ui/activities/ActivitiesPresenter.kt @@ -14,6 +14,7 @@ import com.owncloud.android.ui.activities.data.activities.ActivitiesRepository.L import com.owncloud.android.ui.activities.data.files.FilesRepository import com.owncloud.android.ui.activities.data.files.FilesRepository.ReadRemoteFileCallback import com.owncloud.android.ui.activity.BaseActivity +import kotlinx.coroutines.CoroutineScope class ActivitiesPresenter internal constructor( private val activitiesRepository: ActivitiesRepository, @@ -22,13 +23,14 @@ class ActivitiesPresenter internal constructor( ) : ActivitiesContract.ActionListener { private var activityStopped = false - override fun loadActivities(lastGiven: Long) { + override fun loadActivities(lifecycleScope: CoroutineScope, lastGiven: Long) { if (ActivitiesContract.ActionListener.UNDEFINED.toLong() == lastGiven) { activitiesView.showLoadingMessage() } else { activitiesView.setProgressIndicatorState(true) } activitiesRepository.getActivities( + lifecycleScope, lastGiven, object : LoadActivitiesCallback { override fun onActivitiesLoaded(activities: List, client: NextcloudClient, lastGiven: Long) { diff --git a/app/src/main/java/com/owncloud/android/ui/activities/data/activities/ActivitiesRepository.kt b/app/src/main/java/com/owncloud/android/ui/activities/data/activities/ActivitiesRepository.kt index a5130fd8fd31..59cd088a69b5 100644 --- a/app/src/main/java/com/owncloud/android/ui/activities/data/activities/ActivitiesRepository.kt +++ b/app/src/main/java/com/owncloud/android/ui/activities/data/activities/ActivitiesRepository.kt @@ -8,15 +8,13 @@ package com.owncloud.android.ui.activities.data.activities import com.nextcloud.common.NextcloudClient +import kotlinx.coroutines.CoroutineScope -/** - * Main entry point for accessing activities data. - */ interface ActivitiesRepository { interface LoadActivitiesCallback { fun onActivitiesLoaded(activities: List, client: NextcloudClient, lastGiven: Long) fun onActivitiesLoadedError(error: String) } - fun getActivities(lastGiven: Long, callback: LoadActivitiesCallback) + fun getActivities(lifecycleScope: CoroutineScope, lastGiven: Long, callback: LoadActivitiesCallback) } diff --git a/app/src/main/java/com/owncloud/android/ui/activities/data/activities/ActivitiesServiceApi.kt b/app/src/main/java/com/owncloud/android/ui/activities/data/activities/ActivitiesServiceApi.kt index 2cb054d5ab8f..0e3cc5817f02 100644 --- a/app/src/main/java/com/owncloud/android/ui/activities/data/activities/ActivitiesServiceApi.kt +++ b/app/src/main/java/com/owncloud/android/ui/activities/data/activities/ActivitiesServiceApi.kt @@ -8,6 +8,7 @@ package com.owncloud.android.ui.activities.data.activities import com.nextcloud.common.NextcloudClient +import kotlinx.coroutines.CoroutineScope /** * Defines an interface to the Activities service API. All ([Activity]) data requests should @@ -19,5 +20,9 @@ interface ActivitiesServiceApi { fun onError(error: String) } - fun getAllActivities(lastGiven: Long, callback: ActivitiesServiceCallback>) + fun getAllActivities( + lifecycleScope: CoroutineScope, + lastGiven: Long, + callback: ActivitiesServiceCallback> + ) } diff --git a/app/src/main/java/com/owncloud/android/ui/activities/data/activities/ActivitiesServiceApiImpl.kt b/app/src/main/java/com/owncloud/android/ui/activities/data/activities/ActivitiesServiceApiImpl.kt index 4b6ced59c0cc..cfec43c3420f 100644 --- a/app/src/main/java/com/owncloud/android/ui/activities/data/activities/ActivitiesServiceApiImpl.kt +++ b/app/src/main/java/com/owncloud/android/ui/activities/data/activities/ActivitiesServiceApiImpl.kt @@ -29,8 +29,12 @@ import org.apache.commons.httpclient.HttpStatus @Suppress("TooGenericExceptionThrown") class ActivitiesServiceApiImpl(private val accountManager: UserAccountManager) : ActivitiesServiceApi { - override fun getAllActivities(lastGiven: Long, callback: ActivitiesServiceCallback>) { - CoroutineScope(Dispatchers.Main).launch { + override fun getAllActivities( + lifecycleScope: CoroutineScope, + lastGiven: Long, + callback: ActivitiesServiceCallback> + ) { + lifecycleScope.launch(Dispatchers.Main) { val result = runCatching { withContext(Dispatchers.IO) { fetchActivities(lastGiven) } } diff --git a/app/src/main/java/com/owncloud/android/ui/activities/data/activities/RemoteActivitiesRepository.kt b/app/src/main/java/com/owncloud/android/ui/activities/data/activities/RemoteActivitiesRepository.kt index 1ab57f80fd83..cb1bc6436720 100644 --- a/app/src/main/java/com/owncloud/android/ui/activities/data/activities/RemoteActivitiesRepository.kt +++ b/app/src/main/java/com/owncloud/android/ui/activities/data/activities/RemoteActivitiesRepository.kt @@ -10,10 +10,12 @@ package com.owncloud.android.ui.activities.data.activities import com.nextcloud.common.NextcloudClient import com.owncloud.android.ui.activities.data.activities.ActivitiesRepository.LoadActivitiesCallback import com.owncloud.android.ui.activities.data.activities.ActivitiesServiceApi.ActivitiesServiceCallback +import kotlinx.coroutines.CoroutineScope class RemoteActivitiesRepository(private val activitiesServiceApi: ActivitiesServiceApi) : ActivitiesRepository { - override fun getActivities(lastGiven: Long, callback: LoadActivitiesCallback) { + override fun getActivities(lifecycleScope: CoroutineScope, lastGiven: Long, callback: LoadActivitiesCallback) { activitiesServiceApi.getAllActivities( + lifecycleScope, lastGiven, object : ActivitiesServiceCallback> { override fun onLoaded(activities: List, client: NextcloudClient, lastGiven: Long) { diff --git a/app/src/main/java/com/owncloud/android/ui/activities/data/files/FilesServiceApiImpl.kt b/app/src/main/java/com/owncloud/android/ui/activities/data/files/FilesServiceApiImpl.kt index a699f172583a..93236764450c 100644 --- a/app/src/main/java/com/owncloud/android/ui/activities/data/files/FilesServiceApiImpl.kt +++ b/app/src/main/java/com/owncloud/android/ui/activities/data/files/FilesServiceApiImpl.kt @@ -8,20 +8,20 @@ */ package com.owncloud.android.ui.activities.data.files +import androidx.lifecycle.lifecycleScope import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.network.ClientFactory import com.nextcloud.client.network.ClientFactory.CreationException import com.owncloud.android.MainApp import com.owncloud.android.R import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.lib.resources.files.ReadFileRemoteOperation import com.owncloud.android.lib.resources.files.model.RemoteFile -import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.operations.RefreshFolderOperation import com.owncloud.android.ui.activities.data.files.FilesServiceApi.FilesServiceCallback import com.owncloud.android.ui.activity.BaseActivity import com.owncloud.android.utils.FileStorageUtils -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -33,7 +33,7 @@ class FilesServiceApiImpl(private val accountManager: UserAccountManager, privat FilesServiceApi { override fun readRemoteFile(fileUrl: String, activity: BaseActivity, callback: FilesServiceCallback) { - CoroutineScope(Dispatchers.Main).launch { + activity.lifecycleScope.launch(Dispatchers.Main) { val result = runCatching { withContext(Dispatchers.IO) { fetchRemoteFile(fileUrl, activity) } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupListAdapter.kt b/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupListAdapter.kt index 65ce44374614..69d71a5872f8 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupListAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupListAdapter.kt @@ -20,6 +20,7 @@ import android.view.ViewGroup import android.widget.AdapterView import android.widget.CheckedTextView import android.widget.ImageView +import androidx.lifecycle.lifecycleScope import com.afollestad.sectionedrecyclerview.SectionedRecyclerViewAdapter import com.afollestad.sectionedrecyclerview.SectionedViewHolder import com.bumptech.glide.request.target.CustomTarget @@ -255,7 +256,7 @@ class BackupListAdapter( } } - CoroutineScope(Dispatchers.IO).launch { + backupListFragment.lifecycleScope.launch(Dispatchers.IO) { val client = OwnCloudClientManagerFactory.getDefaultSingleton() .getNextcloudClientFor(accountManager.currentOwnCloudAccount, context) diff --git a/app/src/main/java/com/owncloud/android/ui/unifiedsearch/UnifiedSearchRemoteRepository.kt b/app/src/main/java/com/owncloud/android/ui/unifiedsearch/UnifiedSearchRemoteRepository.kt index d9f91aa025fe..0f1ebc2fda0a 100644 --- a/app/src/main/java/com/owncloud/android/ui/unifiedsearch/UnifiedSearchRemoteRepository.kt +++ b/app/src/main/java/com/owncloud/android/ui/unifiedsearch/UnifiedSearchRemoteRepository.kt @@ -19,6 +19,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch class UnifiedSearchRemoteRepository( + private val viewModelScope: CoroutineScope, private val clientFactory: ClientFactory, private val currentAccountProvider: CurrentAccountProvider, private val asyncRunner: AsyncRunner @@ -32,7 +33,7 @@ class UnifiedSearchRemoteRepository( Log_OC.d(tag, "CoroutineExceptionHandler got at runAsyncWithNcClient $exception") } - CoroutineScope(Dispatchers.IO).launch(coroutineExceptionHandler) { + viewModelScope.launch(Dispatchers.IO + coroutineExceptionHandler) { val client = clientFactory.createNextcloudClient(currentAccountProvider.user) callback(client) } diff --git a/app/src/main/java/com/owncloud/android/ui/unifiedsearch/UnifiedSearchViewModel.kt b/app/src/main/java/com/owncloud/android/ui/unifiedsearch/UnifiedSearchViewModel.kt index a68756f86a72..a79628d0fc21 100644 --- a/app/src/main/java/com/owncloud/android/ui/unifiedsearch/UnifiedSearchViewModel.kt +++ b/app/src/main/java/com/owncloud/android/ui/unifiedsearch/UnifiedSearchViewModel.kt @@ -14,6 +14,7 @@ import androidx.annotation.VisibleForTesting import androidx.core.net.toUri import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.viewModelScope import com.nextcloud.client.account.CurrentAccountProvider import com.nextcloud.client.core.AsyncRunner import com.nextcloud.client.network.ClientFactory @@ -79,6 +80,7 @@ class UnifiedSearchViewModel(application: Application) : this.connectivityService = connectivityService repository = UnifiedSearchRemoteRepository( + viewModelScope, clientFactory, currentAccountProvider, runner diff --git a/app/src/test/java/com/owncloud/android/ui/activities/ActivitiesPresenterTest.java b/app/src/test/java/com/owncloud/android/ui/activities/ActivitiesPresenterTest.java deleted file mode 100644 index 38af0ad430d4..000000000000 --- a/app/src/test/java/com/owncloud/android/ui/activities/ActivitiesPresenterTest.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Nextcloud - Android Client - * - * SPDX-FileCopyrightText: 2018 Edvard Holst - * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only - */ -package com.owncloud.android.ui.activities; - -import com.nextcloud.common.NextcloudClient; -import com.owncloud.android.datamodel.OCFile; -import com.owncloud.android.lib.resources.activities.model.Activity; -import com.owncloud.android.lib.resources.activities.model.RichElement; -import com.owncloud.android.ui.activities.data.activities.ActivitiesRepository; -import com.owncloud.android.ui.activities.data.files.FilesRepository; -import com.owncloud.android.ui.activity.BaseActivity; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.verify; - -public class ActivitiesPresenterTest { - - @Mock - private FilesRepository filesRepository; - - @Mock - private ActivitiesContract.View view; - - @Mock - private ActivitiesRepository activitiesRepository; - - @Mock - private BaseActivity baseActivity; - - @Mock - private NextcloudClient nextcloudClient; - - @Mock - private OCFile ocFile; - - @Captor - private ArgumentCaptor readRemoteFileCallbackArgumentCaptor; - - @Captor - private ArgumentCaptor loadActivitiesCallbackArgumentCaptor; - - private ActivitiesPresenter activitiesPresenter; - - private List activitiesList; - - - @Before - public void setupActivitiesPresenter() { - MockitoAnnotations.initMocks(this); - activitiesPresenter = new ActivitiesPresenter(activitiesRepository, filesRepository, view); - - activitiesList = new ArrayList<>(); - activitiesList.add(new Activity( - 2, - new Date(), - new Date(), - "comments", - "comments", - "user1", - "user1", - "admin commented", - "test2", - "icon", - "link", - "files", - "1", - "/text.txt", - new ArrayList<>(), - new RichElement()) - ); - } - - @Test - public void loadInitialActivitiesFromRepositoryIntoView() { - long lastGiven = -1L; - - // When loading activities from repository is requested from presenter... - activitiesPresenter.loadActivities(lastGiven); - // empty list view is hidden in view - verify(view).showLoadingMessage(); - // Repository starts retrieving activities from server - verify(activitiesRepository).getActivities(eq(lastGiven), loadActivitiesCallbackArgumentCaptor.capture()); - // Repository returns data - loadActivitiesCallbackArgumentCaptor.getValue().onActivitiesLoaded(activitiesList, nextcloudClient, lastGiven); - // Progress indicator is hidden - verify(view).setProgressIndicatorState(eq(false)); - // List of activities is shown in view. - verify(view).showActivities(eq(activitiesList), eq(nextcloudClient), eq(lastGiven)); - } - - @Test - public void loadFollowUpActivitiesFromRepositoryIntoView() { - long lastGiven = 1L; - - // When loading activities from repository is requested from presenter... - activitiesPresenter.loadActivities(lastGiven); - // Progress indicator is shown in view - verify(view).setProgressIndicatorState(eq(true)); - // Repository starts retrieving activities from server - verify(activitiesRepository).getActivities(eq(lastGiven), loadActivitiesCallbackArgumentCaptor.capture()); - // Repository returns data - loadActivitiesCallbackArgumentCaptor.getValue().onActivitiesLoaded(activitiesList, nextcloudClient, lastGiven); - // Progress indicator is hidden - verify(view).setProgressIndicatorState(eq(false)); - // List of activities is shown in view. - verify(view).showActivities(eq(activitiesList), eq(nextcloudClient), eq(lastGiven)); - } - - @Test - public void loadActivitiesFromRepositoryShowError() { - long lastGiven = -1L; - - // When loading activities from repository is requested from presenter... - activitiesPresenter.loadActivities(lastGiven); - // Repository starts retrieving activities from server - verify(activitiesRepository).getActivities(eq(lastGiven), loadActivitiesCallbackArgumentCaptor.capture()); - // Repository returns data - loadActivitiesCallbackArgumentCaptor.getValue().onActivitiesLoadedError("error"); - // Correct error is shown in view - verify(view).showActivitiesLoadError(eq("error")); - } - - @Test - public void loadRemoteFileFromRepositoryShowDetailUI() { - // When retrieving remote file from repository... - activitiesPresenter.openActivity("null", baseActivity); - // Progress indicator is shown in view - verify(view).setProgressIndicatorState(eq(true)); - // Repository retrieves remote file - verify(filesRepository).readRemoteFile(eq("null"), eq(baseActivity), - readRemoteFileCallbackArgumentCaptor.capture()); - // Repository returns valid file object - readRemoteFileCallbackArgumentCaptor.getValue().onFileLoaded(ocFile); - // Progress indicator is hidden - verify(view).setProgressIndicatorState(eq(false)); - // File detail UI is shown - verify(view).showActivityDetailUI(eq(ocFile)); - } - - @Test - public void loadRemoteFileFromRepositoryShowEmptyFile() { - // When retrieving remote file from repository... - activitiesPresenter.openActivity("null", baseActivity); - // Progress indicator is shown in view - verify(view).setProgressIndicatorState(eq(true)); - // Repository retrieves remote file - verify(filesRepository).readRemoteFile(eq("null"), eq(baseActivity), - readRemoteFileCallbackArgumentCaptor.capture()); - // Repository returns an valid but Null value file object. - readRemoteFileCallbackArgumentCaptor.getValue().onFileLoaded(null); - // Progress indicator is hidden - verify(view).setProgressIndicatorState(eq(false)); - // Returned file is null. Inform user. - verify(view).showActivityDetailUIIsNull(); - } - - @Test - public void loadRemoteFileFromRepositoryShowError() { - // When retrieving remote file from repository... - activitiesPresenter.openActivity("null", baseActivity); - // Progress indicator is shown in view - verify(view).setProgressIndicatorState(eq(true)); - // Repository retrieves remote file - verify(filesRepository).readRemoteFile(eq("null"), eq(baseActivity), - readRemoteFileCallbackArgumentCaptor.capture()); - // Repository returns valid file object - readRemoteFileCallbackArgumentCaptor.getValue().onFileLoadError("error"); - // Progress indicator is hidden - verify(view).setProgressIndicatorState(eq(false)); - // Error message is shown to the user. - verify(view).showActivityDetailError(eq("error")); - } -} diff --git a/app/src/test/java/com/owncloud/android/ui/activities/ActivitiesPresenterTest.kt b/app/src/test/java/com/owncloud/android/ui/activities/ActivitiesPresenterTest.kt new file mode 100644 index 000000000000..6d878cb3eb3d --- /dev/null +++ b/app/src/test/java/com/owncloud/android/ui/activities/ActivitiesPresenterTest.kt @@ -0,0 +1,156 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-FileCopyrightText: 2018 Edvard Holst + * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only + */ +package com.owncloud.android.ui.activities + +import androidx.lifecycle.LifecycleCoroutineScope +import com.nextcloud.common.NextcloudClient +import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.lib.resources.activities.model.Activity +import com.owncloud.android.lib.resources.activities.model.RichElement +import com.owncloud.android.ui.activities.data.activities.ActivitiesRepository +import com.owncloud.android.ui.activities.data.activities.ActivitiesRepository.LoadActivitiesCallback +import com.owncloud.android.ui.activities.data.files.FilesRepository +import com.owncloud.android.ui.activities.data.files.FilesRepository.ReadRemoteFileCallback +import com.owncloud.android.ui.activity.BaseActivity +import org.junit.Before +import org.junit.Test +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.eq +import java.util.Date + +class ActivitiesPresenterTest { + + @Mock + private lateinit var filesRepository: FilesRepository + + @Mock + private lateinit var view: ActivitiesContract.View + + @Mock + private lateinit var activitiesRepository: ActivitiesRepository + + @Mock + private lateinit var baseActivity: BaseActivity + + @Mock + private lateinit var nextcloudClient: NextcloudClient + + @Mock + private lateinit var ocFile: OCFile + + @Mock + private lateinit var lifecycleScope: LifecycleCoroutineScope + + private lateinit var activitiesPresenter: ActivitiesPresenter + private lateinit var activitiesList: List + + @Before + fun setupActivitiesPresenter() { + MockitoAnnotations.openMocks(this) + activitiesPresenter = ActivitiesPresenter(activitiesRepository, filesRepository, view) + + activitiesList = mutableListOf( + Activity( + 2, Date(), Date(), + "comments", "comments", + "user1", "user1", + "admin commented", "test2", + "icon", "link", "files", "1", "/text.txt", + ArrayList(), RichElement() + ) + ) + } + + @Test + fun loadInitialActivitiesFromRepositoryIntoView() { + val lastGiven = -1L + val captor = argumentCaptor() + + activitiesPresenter.loadActivities(lifecycleScope, lastGiven) + verify(view).showLoadingMessage() + verify(activitiesRepository).getActivities( + eq(lifecycleScope), + eq(lastGiven), + captor.capture() + ) + captor.firstValue.onActivitiesLoaded(activitiesList, nextcloudClient, lastGiven) + verify(view).setProgressIndicatorState(eq(false)) + verify(view).showActivities(eq(activitiesList), eq(nextcloudClient), eq(lastGiven)) + } + + @Test + fun loadFollowUpActivitiesFromRepositoryIntoView() { + val lastGiven = 1L + val captor = argumentCaptor() + + activitiesPresenter.loadActivities(lifecycleScope, lastGiven) + verify(view).setProgressIndicatorState(eq(true)) + verify(activitiesRepository).getActivities( + eq(lifecycleScope), + eq(lastGiven), + captor.capture() + ) + captor.firstValue.onActivitiesLoaded(activitiesList, nextcloudClient, lastGiven) + verify(view).setProgressIndicatorState(eq(false)) + verify(view).showActivities(eq(activitiesList), eq(nextcloudClient), eq(lastGiven)) + } + + @Test + fun loadActivitiesFromRepositoryShowError() { + val lastGiven = -1L + val captor = argumentCaptor() + + activitiesPresenter.loadActivities(lifecycleScope, lastGiven) + verify(activitiesRepository).getActivities( + eq(lifecycleScope), + eq(lastGiven), + captor.capture() + ) + captor.firstValue.onActivitiesLoadedError("error") + verify(view).showActivitiesLoadError(eq("error")) + } + + @Test + fun loadRemoteFileFromRepositoryShowDetailUI() { + val captor = argumentCaptor() + + activitiesPresenter.openActivity("null", baseActivity) + verify(view).setProgressIndicatorState(eq(true)) + verify(filesRepository).readRemoteFile(eq("null"), eq(baseActivity), captor.capture()) + captor.firstValue.onFileLoaded(ocFile) + verify(view).setProgressIndicatorState(eq(false)) + verify(view).showActivityDetailUI(eq(ocFile)) + } + + @Test + fun loadRemoteFileFromRepositoryShowEmptyFile() { + val captor = argumentCaptor() + + activitiesPresenter.openActivity("null", baseActivity) + verify(view).setProgressIndicatorState(eq(true)) + verify(filesRepository).readRemoteFile(eq("null"), eq(baseActivity), captor.capture()) + captor.firstValue.onFileLoaded(null) + verify(view).setProgressIndicatorState(eq(false)) + verify(view).showActivityDetailUIIsNull() + } + + @Test + fun loadRemoteFileFromRepositoryShowError() { + val captor = argumentCaptor() + + activitiesPresenter.openActivity("null", baseActivity) + verify(view).setProgressIndicatorState(eq(true)) + verify(filesRepository).readRemoteFile(eq("null"), eq(baseActivity), captor.capture()) + captor.firstValue.onFileLoadError("error") + verify(view).setProgressIndicatorState(eq(false)) + verify(view).showActivityDetailError(eq("error")) + } +} diff --git a/app/src/test/java/com/owncloud/android/ui/activities/data/activities/RemoteActivitiesRepositoryTest.java b/app/src/test/java/com/owncloud/android/ui/activities/data/activities/RemoteActivitiesRepositoryTest.java deleted file mode 100644 index d6d35bfad55b..000000000000 --- a/app/src/test/java/com/owncloud/android/ui/activities/data/activities/RemoteActivitiesRepositoryTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Nextcloud - Android Client - * - * SPDX-FileCopyrightText: 2018 Edvard Holst - * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only - */ -package com.owncloud.android.ui.activities.data.activities; - -import com.nextcloud.common.NextcloudClient; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.util.ArrayList; -import java.util.List; - -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.verify; - -public class RemoteActivitiesRepositoryTest { - - @Mock - ActivitiesServiceApi serviceApi; - - @Mock - ActivitiesRepository.LoadActivitiesCallback mockedLoadActivitiesCallback; - - @Mock - NextcloudClient nextcloudClient; - - @Captor - private ArgumentCaptor activitiesServiceCallbackCaptor; - - private ActivitiesRepository mActivitiesRepository; - - private List activitiesList; - - @Before - public void setUpActivitiesRepository() { - MockitoAnnotations.initMocks(this); - mActivitiesRepository = new RemoteActivitiesRepository(serviceApi); - activitiesList = new ArrayList<>(); - } - - @Test - public void loadActivitiesReturnSuccess() { - long lastGiven = -1L; - - mActivitiesRepository.getActivities(lastGiven, mockedLoadActivitiesCallback); - verify(serviceApi).getAllActivities(eq(lastGiven), activitiesServiceCallbackCaptor.capture()); - activitiesServiceCallbackCaptor.getValue().onLoaded(activitiesList, nextcloudClient, lastGiven); - verify(mockedLoadActivitiesCallback).onActivitiesLoaded(eq(activitiesList), eq(nextcloudClient), eq(lastGiven)); - } - - @Test - public void loadActivitiesReturnError() { - long lastGiven = -1L; - - mActivitiesRepository.getActivities(lastGiven, mockedLoadActivitiesCallback); - verify(serviceApi).getAllActivities(eq(lastGiven), activitiesServiceCallbackCaptor.capture()); - activitiesServiceCallbackCaptor.getValue().onError("error"); - verify(mockedLoadActivitiesCallback).onActivitiesLoadedError(eq("error")); - } - -} diff --git a/app/src/test/java/com/owncloud/android/ui/activities/data/activities/RemoteActivitiesRepositoryTest.kt b/app/src/test/java/com/owncloud/android/ui/activities/data/activities/RemoteActivitiesRepositoryTest.kt new file mode 100644 index 000000000000..24fa8ecd5db3 --- /dev/null +++ b/app/src/test/java/com/owncloud/android/ui/activities/data/activities/RemoteActivitiesRepositoryTest.kt @@ -0,0 +1,76 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-FileCopyrightText: 2018 Edvard Holst + * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only + */ + +package com.owncloud.android.ui.activities.data.activities + +import androidx.lifecycle.LifecycleCoroutineScope +import com.nextcloud.common.NextcloudClient +import com.owncloud.android.ui.activities.data.activities.ActivitiesRepository.LoadActivitiesCallback +import com.owncloud.android.ui.activities.data.activities.ActivitiesServiceApi.ActivitiesServiceCallback +import org.junit.Before +import org.junit.Test +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.eq + +class RemoteActivitiesRepositoryTest { + + @Mock + private lateinit var serviceApi: ActivitiesServiceApi + + @Mock + private lateinit var mockedLoadActivitiesCallback: LoadActivitiesCallback + + @Mock + private lateinit var nextcloudClient: NextcloudClient + + @Mock + private lateinit var lifecycleScope: LifecycleCoroutineScope + + private lateinit var activitiesRepository: ActivitiesRepository + private lateinit var activitiesList: List + + @Before + fun setUpActivitiesRepository() { + MockitoAnnotations.openMocks(this) + activitiesRepository = RemoteActivitiesRepository(serviceApi) + activitiesList = mutableListOf() + } + + @Test + fun loadActivitiesReturnSuccess() { + val lastGiven = -1L + val captor = argumentCaptor>>() + + activitiesRepository.getActivities(lifecycleScope, lastGiven, mockedLoadActivitiesCallback) + verify(serviceApi).getAllActivities( + eq(lifecycleScope), + eq(lastGiven), + captor.capture() + ) + captor.firstValue.onLoaded(activitiesList, nextcloudClient, lastGiven) + verify(mockedLoadActivitiesCallback).onActivitiesLoaded(eq(activitiesList), eq(nextcloudClient), eq(lastGiven)) + } + + @Test + fun loadActivitiesReturnError() { + val lastGiven = -1L + val captor = argumentCaptor>>() + + activitiesRepository.getActivities(lifecycleScope, lastGiven, mockedLoadActivitiesCallback) + verify(serviceApi).getAllActivities( + eq(lifecycleScope), + eq(lastGiven), + captor.capture() + ) + captor.firstValue.onError("error") + verify(mockedLoadActivitiesCallback).onActivitiesLoadedError(eq("error")) + } +} diff --git a/app/src/test/java/com/owncloud/android/ui/activities/data/files/RemoteFilesRepositoryTest.java b/app/src/test/java/com/owncloud/android/ui/activities/data/files/RemoteFilesRepositoryTest.java deleted file mode 100644 index 5c71db74c19e..000000000000 --- a/app/src/test/java/com/owncloud/android/ui/activities/data/files/RemoteFilesRepositoryTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Nextcloud - Android Client - * - * SPDX-FileCopyrightText: 2018 Edvard Holst - * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only - */ -package com.owncloud.android.ui.activities.data.files; - -import com.owncloud.android.datamodel.OCFile; -import com.owncloud.android.ui.activity.BaseActivity; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.verify; - -public class RemoteFilesRepositoryTest { - - @Mock - private FilesServiceApi serviceApi; - - @Mock - private FilesRepository.ReadRemoteFileCallback mockedReadRemoteFileCallback; - - @Mock - private BaseActivity baseActivity; - - @Captor - private ArgumentCaptor filesServiceCallbackCaptor; - - private FilesRepository mFilesRepository; - - private OCFile mOCFile = null; - - @Before - public void setUpFilesRepository() { - MockitoAnnotations.initMocks(this); - mFilesRepository = new RemoteFilesRepository(serviceApi); - } - - @Test - public void readRemoteFileReturnSuccess() { - mFilesRepository.readRemoteFile("path", baseActivity, mockedReadRemoteFileCallback); - verify(serviceApi).readRemoteFile(eq("path"), eq(baseActivity), filesServiceCallbackCaptor.capture()); - filesServiceCallbackCaptor.getValue().onLoaded(mOCFile); - verify(mockedReadRemoteFileCallback).onFileLoaded(eq(mOCFile)); - } - - @Test - public void readRemoteFileReturnError() { - mFilesRepository.readRemoteFile("path", baseActivity, mockedReadRemoteFileCallback); - verify(serviceApi).readRemoteFile(eq("path"), eq(baseActivity), filesServiceCallbackCaptor.capture()); - filesServiceCallbackCaptor.getValue().onError("error"); - verify(mockedReadRemoteFileCallback).onFileLoadError(eq("error")); - } -} diff --git a/app/src/test/java/com/owncloud/android/ui/activities/data/files/RemoteFilesRepositoryTest.kt b/app/src/test/java/com/owncloud/android/ui/activities/data/files/RemoteFilesRepositoryTest.kt new file mode 100644 index 000000000000..abeb2c1c62fe --- /dev/null +++ b/app/src/test/java/com/owncloud/android/ui/activities/data/files/RemoteFilesRepositoryTest.kt @@ -0,0 +1,59 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-FileCopyrightText: 2018 Edvard Holst + * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only + */ +package com.owncloud.android.ui.activities.data.files + +import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.ui.activities.data.files.FilesRepository.ReadRemoteFileCallback +import com.owncloud.android.ui.activities.data.files.FilesServiceApi.FilesServiceCallback +import com.owncloud.android.ui.activity.BaseActivity +import org.junit.Before +import org.junit.Test +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.eq + +class RemoteFilesRepositoryTest { + + @Mock private lateinit var serviceApi: FilesServiceApi + + @Mock private lateinit var mockedReadRemoteFileCallback: ReadRemoteFileCallback + + @Mock private lateinit var baseActivity: BaseActivity + + @Mock private lateinit var ocFile: OCFile + + private lateinit var filesRepository: FilesRepository + + @Before + fun setUpFilesRepository() { + MockitoAnnotations.openMocks(this) + filesRepository = RemoteFilesRepository(serviceApi) + } + + @Test + fun readRemoteFileReturnSuccess() { + val captor = argumentCaptor>() + + filesRepository.readRemoteFile("path", baseActivity, mockedReadRemoteFileCallback) + verify(serviceApi).readRemoteFile(eq("path"), eq(baseActivity), captor.capture()) + captor.firstValue.onLoaded(ocFile) + verify(mockedReadRemoteFileCallback).onFileLoaded(eq(ocFile)) + } + + @Test + fun readRemoteFileReturnError() { + val captor = argumentCaptor>() + + filesRepository.readRemoteFile("path", baseActivity, mockedReadRemoteFileCallback) + verify(serviceApi).readRemoteFile(eq("path"), eq(baseActivity), captor.capture()) + captor.firstValue.onError("error") + verify(mockedReadRemoteFileCallback).onFileLoadError(eq("error")) + } +}