mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-11-03 00:03:53 +01:00
Convert PendingUploadsPresenter and contract to Kotlin with some code-cleanup
This commit is contained in:
parent
9160f2fe63
commit
a8740c4df8
6 changed files with 354 additions and 389 deletions
|
|
@ -10,6 +10,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.auth.SessionManager
|
||||
import fr.free.nrw.commons.contributions.Contribution
|
||||
import fr.free.nrw.commons.contributions.Contribution.Companion.STATE_FAILED
|
||||
import fr.free.nrw.commons.databinding.FragmentFailedUploadsBinding
|
||||
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment
|
||||
import fr.free.nrw.commons.media.MediaClient
|
||||
|
|
@ -43,7 +44,7 @@ class FailedUploadsFragment :
|
|||
|
||||
private lateinit var adapter: FailedUploadsAdapter
|
||||
|
||||
var contributionsList = ArrayList<Contribution>()
|
||||
var contributionsList = mutableListOf<Contribution>()
|
||||
|
||||
private lateinit var uploadProgressActivity: UploadProgressActivity
|
||||
|
||||
|
|
@ -71,7 +72,7 @@ class FailedUploadsFragment :
|
|||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?,
|
||||
): View? {
|
||||
): View {
|
||||
binding = FragmentFailedUploadsBinding.inflate(layoutInflater)
|
||||
pendingUploadsPresenter.onAttachView(this)
|
||||
initAdapter()
|
||||
|
|
@ -99,9 +100,9 @@ class FailedUploadsFragment :
|
|||
pendingUploadsPresenter.getFailedContributions()
|
||||
pendingUploadsPresenter.failedContributionList.observe(
|
||||
viewLifecycleOwner,
|
||||
) { list: PagedList<Contribution?> ->
|
||||
) { list: PagedList<Contribution> ->
|
||||
adapter.submitList(list)
|
||||
contributionsList = ArrayList()
|
||||
contributionsList = mutableListOf()
|
||||
list.forEach {
|
||||
if (it != null) {
|
||||
contributionsList.add(it)
|
||||
|
|
@ -124,26 +125,22 @@ class FailedUploadsFragment :
|
|||
* Restarts all the failed uploads.
|
||||
*/
|
||||
fun restartUploads() {
|
||||
if (contributionsList != null) {
|
||||
pendingUploadsPresenter.restartUploads(
|
||||
contributionsList,
|
||||
0,
|
||||
this.requireContext().applicationContext,
|
||||
)
|
||||
}
|
||||
pendingUploadsPresenter.restartUploads(
|
||||
contributionsList,
|
||||
0,
|
||||
requireContext().applicationContext,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Restarts a specific upload.
|
||||
*/
|
||||
override fun restartUpload(index: Int) {
|
||||
if (contributionsList != null) {
|
||||
pendingUploadsPresenter.restartUpload(
|
||||
contributionsList,
|
||||
index,
|
||||
this.requireContext().applicationContext,
|
||||
)
|
||||
}
|
||||
pendingUploadsPresenter.restartUpload(
|
||||
contributionsList,
|
||||
index,
|
||||
requireContext().applicationContext,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -166,7 +163,7 @@ class FailedUploadsFragment :
|
|||
ViewUtil.showShortToast(context, R.string.cancelling_upload)
|
||||
pendingUploadsPresenter.deleteUpload(
|
||||
contribution,
|
||||
this.requireContext().applicationContext,
|
||||
requireContext().applicationContext,
|
||||
)
|
||||
},
|
||||
{},
|
||||
|
|
@ -177,28 +174,24 @@ class FailedUploadsFragment :
|
|||
* Deletes all the uploads after getting a confirmation from the user using Dialog.
|
||||
*/
|
||||
fun deleteUploads() {
|
||||
if (contributionsList != null) {
|
||||
DialogUtil.showAlertDialog(
|
||||
requireActivity(),
|
||||
String.format(
|
||||
Locale.getDefault(),
|
||||
requireActivity().getString(R.string.cancelling_all_the_uploads),
|
||||
),
|
||||
String.format(
|
||||
Locale.getDefault(),
|
||||
requireActivity().getString(R.string.are_you_sure_that_you_want_cancel_all_the_uploads),
|
||||
),
|
||||
String.format(Locale.getDefault(), requireActivity().getString(R.string.yes)),
|
||||
String.format(Locale.getDefault(), requireActivity().getString(R.string.no)),
|
||||
{
|
||||
ViewUtil.showShortToast(context, R.string.cancelling_upload)
|
||||
uploadProgressActivity.hidePendingIcons()
|
||||
pendingUploadsPresenter.deleteUploads(
|
||||
listOf(Contribution.STATE_FAILED),
|
||||
)
|
||||
},
|
||||
{},
|
||||
)
|
||||
}
|
||||
DialogUtil.showAlertDialog(
|
||||
requireActivity(),
|
||||
String.format(
|
||||
Locale.getDefault(),
|
||||
requireActivity().getString(R.string.cancelling_all_the_uploads),
|
||||
),
|
||||
String.format(
|
||||
Locale.getDefault(),
|
||||
requireActivity().getString(R.string.are_you_sure_that_you_want_cancel_all_the_uploads),
|
||||
),
|
||||
String.format(Locale.getDefault(), requireActivity().getString(R.string.yes)),
|
||||
String.format(Locale.getDefault(), requireActivity().getString(R.string.no)),
|
||||
{
|
||||
ViewUtil.showShortToast(context, R.string.cancelling_upload)
|
||||
uploadProgressActivity.hidePendingIcons()
|
||||
pendingUploadsPresenter.deleteUploads(listOf(STATE_FAILED))
|
||||
},
|
||||
{},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,31 +0,0 @@
|
|||
package fr.free.nrw.commons.upload;
|
||||
|
||||
import android.content.Context;
|
||||
import fr.free.nrw.commons.BasePresenter;
|
||||
import fr.free.nrw.commons.contributions.Contribution;
|
||||
import fr.free.nrw.commons.nearby.contract.NearbyParentFragmentContract;
|
||||
import fr.free.nrw.commons.nearby.contract.NearbyParentFragmentContract.View;
|
||||
|
||||
/**
|
||||
* The contract using which the PendingUploadsFragment or FailedUploadsFragment would communicate
|
||||
* with its PendingUploadsPresenter
|
||||
*/
|
||||
public class PendingUploadsContract {
|
||||
|
||||
/**
|
||||
* Interface representing the view for uploads.
|
||||
*/
|
||||
public interface View { }
|
||||
|
||||
/**
|
||||
* Interface representing the user actions related to uploads.
|
||||
*/
|
||||
public interface UserActionListener extends
|
||||
BasePresenter<fr.free.nrw.commons.upload.PendingUploadsContract.View> {
|
||||
|
||||
/**
|
||||
* Deletes a upload.
|
||||
*/
|
||||
void deleteUpload(Contribution contribution, Context context);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package fr.free.nrw.commons.upload
|
||||
|
||||
import android.content.Context
|
||||
import fr.free.nrw.commons.BasePresenter
|
||||
import fr.free.nrw.commons.contributions.Contribution
|
||||
|
||||
/**
|
||||
* The contract using which the PendingUploadsFragment or FailedUploadsFragment would communicate
|
||||
* with its PendingUploadsPresenter
|
||||
*/
|
||||
class PendingUploadsContract {
|
||||
/**
|
||||
* Interface representing the view for uploads.
|
||||
*/
|
||||
interface View
|
||||
|
||||
/**
|
||||
* Interface representing the user actions related to uploads.
|
||||
*/
|
||||
interface UserActionListener : BasePresenter<View> {
|
||||
/**
|
||||
* Deletes a upload.
|
||||
*/
|
||||
fun deleteUpload(contribution: Contribution?, context: Context?)
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,9 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||
import fr.free.nrw.commons.CommonsApplication
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.contributions.Contribution
|
||||
import fr.free.nrw.commons.contributions.Contribution.Companion.STATE_IN_PROGRESS
|
||||
import fr.free.nrw.commons.contributions.Contribution.Companion.STATE_PAUSED
|
||||
import fr.free.nrw.commons.contributions.Contribution.Companion.STATE_QUEUED
|
||||
import fr.free.nrw.commons.databinding.FragmentPendingUploadsBinding
|
||||
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment
|
||||
import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog
|
||||
|
|
@ -35,7 +38,8 @@ class PendingUploadsFragment :
|
|||
private lateinit var adapter: PendingUploadsAdapter
|
||||
|
||||
private var contributionsSize = 0
|
||||
var contributionsList = ArrayList<Contribution>()
|
||||
|
||||
private var contributionsList = mutableListOf<Contribution>()
|
||||
|
||||
override fun onAttach(context: Context) {
|
||||
super.onAttach(context)
|
||||
|
|
@ -48,7 +52,7 @@ class PendingUploadsFragment :
|
|||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?,
|
||||
): View? {
|
||||
): View {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = FragmentPendingUploadsBinding.inflate(inflater, container, false)
|
||||
pendingUploadsPresenter.onAttachView(this)
|
||||
|
|
@ -71,27 +75,24 @@ class PendingUploadsFragment :
|
|||
/**
|
||||
* Initializes the recycler view.
|
||||
*/
|
||||
fun initRecyclerView() {
|
||||
private fun initRecyclerView() {
|
||||
binding.pendingUploadsRecyclerView.setLayoutManager(LinearLayoutManager(this.context))
|
||||
binding.pendingUploadsRecyclerView.adapter = adapter
|
||||
pendingUploadsPresenter.setup()
|
||||
pendingUploadsPresenter.totalContributionList.observe(
|
||||
viewLifecycleOwner,
|
||||
) { list: PagedList<Contribution?> ->
|
||||
pendingUploadsPresenter.totalContributionList
|
||||
.observe(viewLifecycleOwner) { list: PagedList<Contribution> ->
|
||||
contributionsSize = list.size
|
||||
contributionsList = ArrayList()
|
||||
contributionsList = mutableListOf()
|
||||
var pausedOrQueuedUploads = 0
|
||||
list.forEach {
|
||||
if (it != null) {
|
||||
if (it.state == Contribution.STATE_PAUSED ||
|
||||
it.state == Contribution.STATE_QUEUED ||
|
||||
it.state == Contribution.STATE_IN_PROGRESS
|
||||
if (it.state == STATE_PAUSED ||
|
||||
it.state == STATE_QUEUED ||
|
||||
it.state == STATE_IN_PROGRESS
|
||||
) {
|
||||
contributionsList.add(it)
|
||||
}
|
||||
if (it.state == Contribution.STATE_PAUSED ||
|
||||
it.state == Contribution.STATE_QUEUED
|
||||
) {
|
||||
if (it.state == STATE_PAUSED || it.state == STATE_QUEUED) {
|
||||
pausedOrQueuedUploads++
|
||||
}
|
||||
}
|
||||
|
|
@ -104,7 +105,7 @@ class PendingUploadsFragment :
|
|||
binding.nopendingTextView.visibility = View.GONE
|
||||
binding.pendingUplaodsLl.visibility = View.VISIBLE
|
||||
adapter.submitList(list)
|
||||
binding.progressTextView.setText(contributionsSize.toString() + " uploads left")
|
||||
binding.progressTextView.setText("$contributionsSize uploads left")
|
||||
if ((pausedOrQueuedUploads == contributionsSize) || CommonsApplication.isPaused) {
|
||||
uploadProgressActivity.setPausedIcon(true)
|
||||
} else {
|
||||
|
|
@ -118,23 +119,18 @@ class PendingUploadsFragment :
|
|||
* Cancels a specific upload after getting a confirmation from the user using Dialog.
|
||||
*/
|
||||
override fun deleteUpload(contribution: Contribution?) {
|
||||
val activity = requireActivity()
|
||||
val locale = Locale.getDefault()
|
||||
showAlertDialog(
|
||||
requireActivity(),
|
||||
String.format(
|
||||
Locale.getDefault(),
|
||||
requireActivity().getString(R.string.cancelling_upload),
|
||||
),
|
||||
String.format(
|
||||
Locale.getDefault(),
|
||||
requireActivity().getString(R.string.cancel_upload_dialog),
|
||||
),
|
||||
String.format(Locale.getDefault(), requireActivity().getString(R.string.yes)),
|
||||
String.format(Locale.getDefault(), requireActivity().getString(R.string.no)),
|
||||
activity,
|
||||
String.format(locale, activity.getString(R.string.cancelling_upload)),
|
||||
String.format(locale, activity.getString(R.string.cancel_upload_dialog)),
|
||||
String.format(locale, activity.getString(R.string.yes)),
|
||||
String.format(locale, activity.getString(R.string.no)),
|
||||
{
|
||||
ViewUtil.showShortToast(context, R.string.cancelling_upload)
|
||||
pendingUploadsPresenter.deleteUpload(
|
||||
contribution,
|
||||
this.requireContext().applicationContext,
|
||||
contribution, requireContext().applicationContext,
|
||||
)
|
||||
},
|
||||
{},
|
||||
|
|
@ -144,47 +140,35 @@ class PendingUploadsFragment :
|
|||
/**
|
||||
* Restarts all the paused uploads.
|
||||
*/
|
||||
fun restartUploads() {
|
||||
if (contributionsList != null) {
|
||||
pendingUploadsPresenter.restartUploads(
|
||||
contributionsList,
|
||||
0,
|
||||
this.requireContext().applicationContext,
|
||||
)
|
||||
}
|
||||
}
|
||||
fun restartUploads() = pendingUploadsPresenter.restartUploads(
|
||||
contributionsList, 0, requireContext().applicationContext
|
||||
)
|
||||
|
||||
/**
|
||||
* Pauses all the ongoing uploads.
|
||||
*/
|
||||
fun pauseUploads() {
|
||||
pendingUploadsPresenter.pauseUploads()
|
||||
}
|
||||
fun pauseUploads() = pendingUploadsPresenter.pauseUploads()
|
||||
|
||||
/**
|
||||
* Cancels all the uploads after getting a confirmation from the user using Dialog.
|
||||
*/
|
||||
fun deleteUploads() {
|
||||
val activity = requireActivity()
|
||||
val locale = Locale.getDefault()
|
||||
showAlertDialog(
|
||||
requireActivity(),
|
||||
String.format(
|
||||
Locale.getDefault(),
|
||||
requireActivity().getString(R.string.cancelling_all_the_uploads),
|
||||
),
|
||||
String.format(
|
||||
Locale.getDefault(),
|
||||
requireActivity().getString(R.string.are_you_sure_that_you_want_cancel_all_the_uploads),
|
||||
),
|
||||
String.format(Locale.getDefault(), requireActivity().getString(R.string.yes)),
|
||||
String.format(Locale.getDefault(), requireActivity().getString(R.string.no)),
|
||||
activity,
|
||||
String.format(locale, activity.getString(R.string.cancelling_all_the_uploads)),
|
||||
String.format(locale, activity.getString(R.string.are_you_sure_that_you_want_cancel_all_the_uploads)),
|
||||
String.format(locale, activity.getString(R.string.yes)),
|
||||
String.format(locale, activity.getString(R.string.no)),
|
||||
{
|
||||
ViewUtil.showShortToast(context, R.string.cancelling_upload)
|
||||
uploadProgressActivity.hidePendingIcons()
|
||||
pendingUploadsPresenter.deleteUploads(
|
||||
listOf(
|
||||
Contribution.STATE_QUEUED,
|
||||
Contribution.STATE_IN_PROGRESS,
|
||||
Contribution.STATE_PAUSED,
|
||||
STATE_QUEUED,
|
||||
STATE_IN_PROGRESS,
|
||||
STATE_PAUSED,
|
||||
),
|
||||
)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,263 +0,0 @@
|
|||
package fr.free.nrw.commons.upload;
|
||||
|
||||
|
||||
import static fr.free.nrw.commons.di.CommonsApplicationModule.IO_THREAD;
|
||||
import static fr.free.nrw.commons.utils.ImageUtils.IMAGE_OK;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.paging.DataSource.Factory;
|
||||
import androidx.paging.LivePagedListBuilder;
|
||||
import androidx.paging.PagedList;
|
||||
import androidx.work.ExistingWorkPolicy;
|
||||
import fr.free.nrw.commons.CommonsApplication;
|
||||
import fr.free.nrw.commons.contributions.Contribution;
|
||||
import fr.free.nrw.commons.contributions.ContributionBoundaryCallback;
|
||||
import fr.free.nrw.commons.contributions.ContributionsRemoteDataSource;
|
||||
import fr.free.nrw.commons.contributions.ContributionsRepository;
|
||||
import fr.free.nrw.commons.di.CommonsApplicationModule;
|
||||
import fr.free.nrw.commons.repository.UploadRepository;
|
||||
import fr.free.nrw.commons.upload.PendingUploadsContract.UserActionListener;
|
||||
import fr.free.nrw.commons.upload.PendingUploadsContract.View;
|
||||
import fr.free.nrw.commons.upload.worker.WorkRequestHelper;
|
||||
import io.reactivex.Scheduler;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
* The presenter class for PendingUploadsFragment and FailedUploadsFragment
|
||||
*/
|
||||
public class PendingUploadsPresenter implements UserActionListener {
|
||||
|
||||
private final ContributionBoundaryCallback contributionBoundaryCallback;
|
||||
private final ContributionsRepository contributionsRepository;
|
||||
private final UploadRepository uploadRepository;
|
||||
private final Scheduler ioThreadScheduler;
|
||||
|
||||
private final CompositeDisposable compositeDisposable;
|
||||
private final ContributionsRemoteDataSource contributionsRemoteDataSource;
|
||||
|
||||
LiveData<PagedList<Contribution>> totalContributionList;
|
||||
LiveData<PagedList<Contribution>> failedContributionList;
|
||||
|
||||
@Inject
|
||||
PendingUploadsPresenter(
|
||||
final ContributionBoundaryCallback contributionBoundaryCallback,
|
||||
final ContributionsRemoteDataSource contributionsRemoteDataSource,
|
||||
final ContributionsRepository contributionsRepository,
|
||||
final UploadRepository uploadRepository,
|
||||
@Named(IO_THREAD) final Scheduler ioThreadScheduler) {
|
||||
this.contributionBoundaryCallback = contributionBoundaryCallback;
|
||||
this.contributionsRepository = contributionsRepository;
|
||||
this.uploadRepository = uploadRepository;
|
||||
this.ioThreadScheduler = ioThreadScheduler;
|
||||
this.contributionsRemoteDataSource = contributionsRemoteDataSource;
|
||||
compositeDisposable = new CompositeDisposable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setups the paged list of Pending Uploads. This method sets the configuration for paged list
|
||||
* and ties it up with the live data object. This method can be tweaked to update the lazy
|
||||
* loading behavior of the contributions list
|
||||
*/
|
||||
void setup() {
|
||||
final PagedList.Config pagedListConfig =
|
||||
(new PagedList.Config.Builder())
|
||||
.setPrefetchDistance(50)
|
||||
.setPageSize(10).build();
|
||||
Factory<Integer, Contribution> factory;
|
||||
|
||||
factory = contributionsRepository.fetchContributionsWithStatesSortedByDateUploadStarted(
|
||||
Arrays.asList(Contribution.STATE_QUEUED, Contribution.STATE_IN_PROGRESS,
|
||||
Contribution.STATE_PAUSED));
|
||||
LivePagedListBuilder livePagedListBuilder = new LivePagedListBuilder(factory,
|
||||
pagedListConfig);
|
||||
totalContributionList = livePagedListBuilder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setups the paged list of Failed Uploads. This method sets the configuration for paged list
|
||||
* and ties it up with the live data object. This method can be tweaked to update the lazy
|
||||
* loading behavior of the contributions list
|
||||
*/
|
||||
void getFailedContributions() {
|
||||
final PagedList.Config pagedListConfig =
|
||||
(new PagedList.Config.Builder())
|
||||
.setPrefetchDistance(50)
|
||||
.setPageSize(10).build();
|
||||
Factory<Integer, Contribution> factory;
|
||||
factory = contributionsRepository.fetchContributionsWithStatesSortedByDateUploadStarted(
|
||||
Collections.singletonList(Contribution.STATE_FAILED));
|
||||
LivePagedListBuilder livePagedListBuilder = new LivePagedListBuilder(factory,
|
||||
pagedListConfig);
|
||||
failedContributionList = livePagedListBuilder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachView(@NonNull View view) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachView() {
|
||||
compositeDisposable.clear();
|
||||
contributionsRemoteDataSource.dispose();
|
||||
contributionBoundaryCallback.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the specified upload (contribution) from the database.
|
||||
*
|
||||
* @param contribution The contribution object representing the upload to be deleted.
|
||||
* @param context The context in which the operation is being performed.
|
||||
*/
|
||||
@Override
|
||||
public void deleteUpload(final Contribution contribution, Context context) {
|
||||
compositeDisposable.add(contributionsRepository
|
||||
.deleteContributionFromDB(contribution)
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.subscribe());
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses all the uploads by changing the state of contributions from STATE_QUEUED and
|
||||
* STATE_IN_PROGRESS to STATE_PAUSED in the database.
|
||||
*/
|
||||
public void pauseUploads() {
|
||||
CommonsApplication.isPaused = true;
|
||||
compositeDisposable.add(contributionsRepository
|
||||
.updateContributionsWithStates(
|
||||
List.of(Contribution.STATE_QUEUED, Contribution.STATE_IN_PROGRESS),
|
||||
Contribution.STATE_PAUSED)
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.subscribe());
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes contributions from the database that match the specified states.
|
||||
*
|
||||
* @param states A list of integers representing the states of the contributions to be deleted.
|
||||
*/
|
||||
public void deleteUploads(List<Integer> states) {
|
||||
compositeDisposable.add(contributionsRepository
|
||||
.deleteContributionsFromDBWithStates(states)
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.subscribe());
|
||||
}
|
||||
|
||||
/**
|
||||
* Restarts the uploads for the specified list of contributions starting from the given index.
|
||||
*
|
||||
* @param contributionList The list of contributions to be restarted.
|
||||
* @param index The starting index in the list from which to restart uploads.
|
||||
* @param context The context in which the operation is being performed.
|
||||
*/
|
||||
public void restartUploads(List<Contribution> contributionList, int index, Context context) {
|
||||
CommonsApplication.isPaused = false;
|
||||
if (index >= contributionList.size()) {
|
||||
return;
|
||||
}
|
||||
Contribution it = contributionList.get(index);
|
||||
if (it.getState() == Contribution.STATE_FAILED) {
|
||||
it.setDateUploadStarted(Calendar.getInstance().getTime());
|
||||
if (it.getErrorInfo() == null) {
|
||||
it.setChunkInfo(null);
|
||||
it.setTransferred(0);
|
||||
}
|
||||
compositeDisposable.add(uploadRepository
|
||||
.checkDuplicateImage(it.getLocalUriPath().getPath())
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.subscribe(imageCheckResult -> {
|
||||
if (imageCheckResult == IMAGE_OK) {
|
||||
it.setState(Contribution.STATE_QUEUED);
|
||||
compositeDisposable.add(contributionsRepository
|
||||
.save(it)
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.doOnComplete(() -> {
|
||||
restartUploads(contributionList, index + 1, context);
|
||||
})
|
||||
.subscribe(() -> WorkRequestHelper.Companion.makeOneTimeWorkRequest(
|
||||
context, ExistingWorkPolicy.KEEP)));
|
||||
} else {
|
||||
Timber.e("Contribution already exists");
|
||||
compositeDisposable.add(contributionsRepository
|
||||
.deleteContributionFromDB(it)
|
||||
.subscribeOn(ioThreadScheduler).doOnComplete(() -> {
|
||||
restartUploads(contributionList, index + 1, context);
|
||||
})
|
||||
.subscribe());
|
||||
}
|
||||
}, throwable -> {
|
||||
Timber.e(throwable);
|
||||
restartUploads(contributionList, index + 1, context);
|
||||
}));
|
||||
} else {
|
||||
it.setState(Contribution.STATE_QUEUED);
|
||||
compositeDisposable.add(contributionsRepository
|
||||
.save(it)
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.doOnComplete(() -> {
|
||||
restartUploads(contributionList, index + 1, context);
|
||||
})
|
||||
.subscribe(() -> WorkRequestHelper.Companion.makeOneTimeWorkRequest(
|
||||
context, ExistingWorkPolicy.KEEP)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restarts the upload for the specified list of contributions for the given index.
|
||||
*
|
||||
* @param contributionList The list of contributions.
|
||||
* @param index The index in the list which to be restarted.
|
||||
* @param context The context in which the operation is being performed.
|
||||
*/
|
||||
public void restartUpload(List<Contribution> contributionList, int index, Context context) {
|
||||
CommonsApplication.isPaused = false;
|
||||
if (index >= contributionList.size()) {
|
||||
return;
|
||||
}
|
||||
Contribution it = contributionList.get(index);
|
||||
if (it.getState() == Contribution.STATE_FAILED) {
|
||||
it.setDateUploadStarted(Calendar.getInstance().getTime());
|
||||
if (it.getErrorInfo() == null) {
|
||||
it.setChunkInfo(null);
|
||||
it.setTransferred(0);
|
||||
}
|
||||
compositeDisposable.add(uploadRepository
|
||||
.checkDuplicateImage(it.getLocalUriPath().getPath())
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.subscribe(imageCheckResult -> {
|
||||
if (imageCheckResult == IMAGE_OK) {
|
||||
it.setState(Contribution.STATE_QUEUED);
|
||||
compositeDisposable.add(contributionsRepository
|
||||
.save(it)
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.subscribe(() -> WorkRequestHelper.Companion.makeOneTimeWorkRequest(
|
||||
context, ExistingWorkPolicy.KEEP)));
|
||||
} else {
|
||||
Timber.e("Contribution already exists");
|
||||
compositeDisposable.add(contributionsRepository
|
||||
.deleteContributionFromDB(it)
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.subscribe());
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
it.setState(Contribution.STATE_QUEUED);
|
||||
compositeDisposable.add(contributionsRepository
|
||||
.save(it)
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.subscribe(() -> WorkRequestHelper.Companion.makeOneTimeWorkRequest(
|
||||
context, ExistingWorkPolicy.KEEP)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,256 @@
|
|||
package fr.free.nrw.commons.upload
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.paging.LivePagedListBuilder
|
||||
import androidx.paging.PagedList
|
||||
import androidx.work.ExistingWorkPolicy
|
||||
import fr.free.nrw.commons.CommonsApplication
|
||||
import fr.free.nrw.commons.contributions.Contribution
|
||||
import fr.free.nrw.commons.contributions.Contribution.Companion.STATE_FAILED
|
||||
import fr.free.nrw.commons.contributions.Contribution.Companion.STATE_IN_PROGRESS
|
||||
import fr.free.nrw.commons.contributions.Contribution.Companion.STATE_PAUSED
|
||||
import fr.free.nrw.commons.contributions.Contribution.Companion.STATE_QUEUED
|
||||
import fr.free.nrw.commons.contributions.ContributionBoundaryCallback
|
||||
import fr.free.nrw.commons.contributions.ContributionsRemoteDataSource
|
||||
import fr.free.nrw.commons.contributions.ContributionsRepository
|
||||
import fr.free.nrw.commons.di.CommonsApplicationModule
|
||||
import fr.free.nrw.commons.repository.UploadRepository
|
||||
import fr.free.nrw.commons.upload.worker.WorkRequestHelper.Companion.makeOneTimeWorkRequest
|
||||
import fr.free.nrw.commons.utils.ImageUtils.IMAGE_OK
|
||||
import io.reactivex.Scheduler
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import timber.log.Timber
|
||||
import java.util.Calendar
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Named
|
||||
|
||||
|
||||
/**
|
||||
* The presenter class for PendingUploadsFragment and FailedUploadsFragment
|
||||
*/
|
||||
class PendingUploadsPresenter @Inject internal constructor(
|
||||
private val contributionBoundaryCallback: ContributionBoundaryCallback,
|
||||
private val contributionsRemoteDataSource: ContributionsRemoteDataSource,
|
||||
private val contributionsRepository: ContributionsRepository,
|
||||
private val uploadRepository: UploadRepository,
|
||||
@param:Named(CommonsApplicationModule.IO_THREAD) private val ioThreadScheduler: Scheduler
|
||||
) : PendingUploadsContract.UserActionListener {
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
|
||||
lateinit var totalContributionList: LiveData<PagedList<Contribution>>
|
||||
lateinit var failedContributionList: LiveData<PagedList<Contribution>>
|
||||
|
||||
/**
|
||||
* Setups the paged list of Pending Uploads. This method sets the configuration for paged list
|
||||
* and ties it up with the live data object. This method can be tweaked to update the lazy
|
||||
* loading behavior of the contributions list
|
||||
*/
|
||||
fun setup() {
|
||||
val pagedListConfig = PagedList.Config.Builder()
|
||||
.setPrefetchDistance(50)
|
||||
.setPageSize(10).build()
|
||||
|
||||
val factory = contributionsRepository.fetchContributionsWithStatesSortedByDateUploadStarted(
|
||||
listOf(STATE_QUEUED, STATE_IN_PROGRESS, STATE_PAUSED)
|
||||
)
|
||||
totalContributionList = LivePagedListBuilder(factory, pagedListConfig).build()
|
||||
}
|
||||
|
||||
/**
|
||||
* Setups the paged list of Failed Uploads. This method sets the configuration for paged list
|
||||
* and ties it up with the live data object. This method can be tweaked to update the lazy
|
||||
* loading behavior of the contributions list
|
||||
*/
|
||||
fun getFailedContributions() {
|
||||
val pagedListConfig = PagedList.Config.Builder()
|
||||
.setPrefetchDistance(50)
|
||||
.setPageSize(10).build()
|
||||
|
||||
val factory = contributionsRepository.fetchContributionsWithStatesSortedByDateUploadStarted(
|
||||
listOf(STATE_FAILED)
|
||||
)
|
||||
failedContributionList = LivePagedListBuilder(factory, pagedListConfig).build()
|
||||
}
|
||||
|
||||
override fun onAttachView(view: PendingUploadsContract.View) {
|
||||
}
|
||||
|
||||
override fun onDetachView() {
|
||||
compositeDisposable.clear()
|
||||
contributionsRemoteDataSource.dispose()
|
||||
contributionBoundaryCallback.dispose()
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the specified upload (contribution) from the database.
|
||||
*
|
||||
* @param contribution The contribution object representing the upload to be deleted.
|
||||
* @param context The context in which the operation is being performed.
|
||||
*/
|
||||
override fun deleteUpload(contribution: Contribution?, context: Context?) {
|
||||
compositeDisposable.add(
|
||||
contributionsRepository
|
||||
.deleteContributionFromDB(contribution)
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.subscribe()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses all the uploads by changing the state of contributions from STATE_QUEUED and
|
||||
* STATE_IN_PROGRESS to STATE_PAUSED in the database.
|
||||
*/
|
||||
fun pauseUploads() {
|
||||
CommonsApplication.isPaused = true
|
||||
compositeDisposable.add(
|
||||
contributionsRepository
|
||||
.updateContributionsWithStates(
|
||||
listOf(STATE_QUEUED, STATE_IN_PROGRESS),
|
||||
STATE_PAUSED
|
||||
)
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.subscribe()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes contributions from the database that match the specified states.
|
||||
*
|
||||
* @param states A list of integers representing the states of the contributions to be deleted.
|
||||
*/
|
||||
fun deleteUploads(states: List<Int>) {
|
||||
compositeDisposable.add(
|
||||
contributionsRepository
|
||||
.deleteContributionsFromDBWithStates(states)
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.subscribe()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Restarts the uploads for the specified list of contributions starting from the given index.
|
||||
*
|
||||
* @param contributionList The list of contributions to be restarted.
|
||||
* @param index The starting index in the list from which to restart uploads.
|
||||
* @param context The context in which the operation is being performed.
|
||||
*/
|
||||
fun restartUploads(contributionList: List<Contribution>, index: Int, context: Context) {
|
||||
CommonsApplication.isPaused = false
|
||||
if (index >= contributionList.size) {
|
||||
return
|
||||
}
|
||||
val contribution = contributionList[index]
|
||||
if (contribution.state == STATE_FAILED) {
|
||||
contribution.dateUploadStarted = Calendar.getInstance().time
|
||||
if (contribution.errorInfo == null) {
|
||||
contribution.chunkInfo = null
|
||||
contribution.transferred = 0
|
||||
}
|
||||
compositeDisposable.add(
|
||||
uploadRepository
|
||||
.checkDuplicateImage(contribution.localUriPath!!.path)
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.subscribe({ imageCheckResult: Int ->
|
||||
if (imageCheckResult == IMAGE_OK) {
|
||||
contribution.state = STATE_QUEUED
|
||||
compositeDisposable.add(
|
||||
contributionsRepository
|
||||
.save(contribution)
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.doOnComplete {
|
||||
restartUploads(contributionList, index + 1, context)
|
||||
}
|
||||
.subscribe {
|
||||
makeOneTimeWorkRequest(
|
||||
context, ExistingWorkPolicy.KEEP
|
||||
)
|
||||
})
|
||||
} else {
|
||||
Timber.e("Contribution already exists")
|
||||
compositeDisposable.add(
|
||||
contributionsRepository
|
||||
.deleteContributionFromDB(contribution)
|
||||
.subscribeOn(ioThreadScheduler).doOnComplete {
|
||||
restartUploads(contributionList, index + 1, context)
|
||||
}
|
||||
.subscribe())
|
||||
}
|
||||
}, { throwable: Throwable? ->
|
||||
Timber.e(throwable)
|
||||
restartUploads(contributionList, index + 1, context)
|
||||
})
|
||||
)
|
||||
} else {
|
||||
contribution.state = STATE_QUEUED
|
||||
compositeDisposable.add(
|
||||
contributionsRepository
|
||||
.save(contribution)
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.doOnComplete {
|
||||
restartUploads(contributionList, index + 1, context)
|
||||
}
|
||||
.subscribe {
|
||||
makeOneTimeWorkRequest(context, ExistingWorkPolicy.KEEP)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restarts the upload for the specified list of contributions for the given index.
|
||||
*
|
||||
* @param contributionList The list of contributions.
|
||||
* @param index The index in the list which to be restarted.
|
||||
* @param context The context in which the operation is being performed.
|
||||
*/
|
||||
fun restartUpload(contributionList: List<Contribution>, index: Int, context: Context) {
|
||||
CommonsApplication.isPaused = false
|
||||
if (index >= contributionList.size) {
|
||||
return
|
||||
}
|
||||
val contribution = contributionList[index]
|
||||
if (contribution.state == STATE_FAILED) {
|
||||
contribution.dateUploadStarted = Calendar.getInstance().time
|
||||
if (contribution.errorInfo == null) {
|
||||
contribution.chunkInfo = null
|
||||
contribution.transferred = 0
|
||||
}
|
||||
compositeDisposable.add(
|
||||
uploadRepository
|
||||
.checkDuplicateImage(contribution.localUriPath!!.path)
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.subscribe { imageCheckResult: Int ->
|
||||
if (imageCheckResult == IMAGE_OK) {
|
||||
contribution.state = STATE_QUEUED
|
||||
compositeDisposable.add(
|
||||
contributionsRepository
|
||||
.save(contribution)
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.subscribe {
|
||||
makeOneTimeWorkRequest(context, ExistingWorkPolicy.KEEP)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
Timber.e("Contribution already exists")
|
||||
compositeDisposable.add(
|
||||
contributionsRepository
|
||||
.deleteContributionFromDB(contribution)
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.subscribe()
|
||||
)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
contribution.state = STATE_QUEUED
|
||||
compositeDisposable.add(
|
||||
contributionsRepository
|
||||
.save(contribution)
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.subscribe {
|
||||
makeOneTimeWorkRequest(context, ExistingWorkPolicy.KEEP)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue