mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-11-03 08:13:55 +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.R
|
||||||
import fr.free.nrw.commons.auth.SessionManager
|
import fr.free.nrw.commons.auth.SessionManager
|
||||||
import fr.free.nrw.commons.contributions.Contribution
|
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.databinding.FragmentFailedUploadsBinding
|
||||||
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment
|
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment
|
||||||
import fr.free.nrw.commons.media.MediaClient
|
import fr.free.nrw.commons.media.MediaClient
|
||||||
|
|
@ -43,7 +44,7 @@ class FailedUploadsFragment :
|
||||||
|
|
||||||
private lateinit var adapter: FailedUploadsAdapter
|
private lateinit var adapter: FailedUploadsAdapter
|
||||||
|
|
||||||
var contributionsList = ArrayList<Contribution>()
|
var contributionsList = mutableListOf<Contribution>()
|
||||||
|
|
||||||
private lateinit var uploadProgressActivity: UploadProgressActivity
|
private lateinit var uploadProgressActivity: UploadProgressActivity
|
||||||
|
|
||||||
|
|
@ -71,7 +72,7 @@ class FailedUploadsFragment :
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?,
|
savedInstanceState: Bundle?,
|
||||||
): View? {
|
): View {
|
||||||
binding = FragmentFailedUploadsBinding.inflate(layoutInflater)
|
binding = FragmentFailedUploadsBinding.inflate(layoutInflater)
|
||||||
pendingUploadsPresenter.onAttachView(this)
|
pendingUploadsPresenter.onAttachView(this)
|
||||||
initAdapter()
|
initAdapter()
|
||||||
|
|
@ -99,9 +100,9 @@ class FailedUploadsFragment :
|
||||||
pendingUploadsPresenter.getFailedContributions()
|
pendingUploadsPresenter.getFailedContributions()
|
||||||
pendingUploadsPresenter.failedContributionList.observe(
|
pendingUploadsPresenter.failedContributionList.observe(
|
||||||
viewLifecycleOwner,
|
viewLifecycleOwner,
|
||||||
) { list: PagedList<Contribution?> ->
|
) { list: PagedList<Contribution> ->
|
||||||
adapter.submitList(list)
|
adapter.submitList(list)
|
||||||
contributionsList = ArrayList()
|
contributionsList = mutableListOf()
|
||||||
list.forEach {
|
list.forEach {
|
||||||
if (it != null) {
|
if (it != null) {
|
||||||
contributionsList.add(it)
|
contributionsList.add(it)
|
||||||
|
|
@ -124,26 +125,22 @@ class FailedUploadsFragment :
|
||||||
* Restarts all the failed uploads.
|
* Restarts all the failed uploads.
|
||||||
*/
|
*/
|
||||||
fun restartUploads() {
|
fun restartUploads() {
|
||||||
if (contributionsList != null) {
|
pendingUploadsPresenter.restartUploads(
|
||||||
pendingUploadsPresenter.restartUploads(
|
contributionsList,
|
||||||
contributionsList,
|
0,
|
||||||
0,
|
requireContext().applicationContext,
|
||||||
this.requireContext().applicationContext,
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restarts a specific upload.
|
* Restarts a specific upload.
|
||||||
*/
|
*/
|
||||||
override fun restartUpload(index: Int) {
|
override fun restartUpload(index: Int) {
|
||||||
if (contributionsList != null) {
|
pendingUploadsPresenter.restartUpload(
|
||||||
pendingUploadsPresenter.restartUpload(
|
contributionsList,
|
||||||
contributionsList,
|
index,
|
||||||
index,
|
requireContext().applicationContext,
|
||||||
this.requireContext().applicationContext,
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -166,7 +163,7 @@ class FailedUploadsFragment :
|
||||||
ViewUtil.showShortToast(context, R.string.cancelling_upload)
|
ViewUtil.showShortToast(context, R.string.cancelling_upload)
|
||||||
pendingUploadsPresenter.deleteUpload(
|
pendingUploadsPresenter.deleteUpload(
|
||||||
contribution,
|
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.
|
* Deletes all the uploads after getting a confirmation from the user using Dialog.
|
||||||
*/
|
*/
|
||||||
fun deleteUploads() {
|
fun deleteUploads() {
|
||||||
if (contributionsList != null) {
|
DialogUtil.showAlertDialog(
|
||||||
DialogUtil.showAlertDialog(
|
requireActivity(),
|
||||||
requireActivity(),
|
String.format(
|
||||||
String.format(
|
Locale.getDefault(),
|
||||||
Locale.getDefault(),
|
requireActivity().getString(R.string.cancelling_all_the_uploads),
|
||||||
requireActivity().getString(R.string.cancelling_all_the_uploads),
|
),
|
||||||
),
|
String.format(
|
||||||
String.format(
|
Locale.getDefault(),
|
||||||
Locale.getDefault(),
|
requireActivity().getString(R.string.are_you_sure_that_you_want_cancel_all_the_uploads),
|
||||||
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.yes)),
|
String.format(Locale.getDefault(), requireActivity().getString(R.string.no)),
|
||||||
String.format(Locale.getDefault(), requireActivity().getString(R.string.no)),
|
{
|
||||||
{
|
ViewUtil.showShortToast(context, R.string.cancelling_upload)
|
||||||
ViewUtil.showShortToast(context, R.string.cancelling_upload)
|
uploadProgressActivity.hidePendingIcons()
|
||||||
uploadProgressActivity.hidePendingIcons()
|
pendingUploadsPresenter.deleteUploads(listOf(STATE_FAILED))
|
||||||
pendingUploadsPresenter.deleteUploads(
|
},
|
||||||
listOf(Contribution.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.CommonsApplication
|
||||||
import fr.free.nrw.commons.R
|
import fr.free.nrw.commons.R
|
||||||
import fr.free.nrw.commons.contributions.Contribution
|
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.databinding.FragmentPendingUploadsBinding
|
||||||
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment
|
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment
|
||||||
import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog
|
import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog
|
||||||
|
|
@ -35,7 +38,8 @@ class PendingUploadsFragment :
|
||||||
private lateinit var adapter: PendingUploadsAdapter
|
private lateinit var adapter: PendingUploadsAdapter
|
||||||
|
|
||||||
private var contributionsSize = 0
|
private var contributionsSize = 0
|
||||||
var contributionsList = ArrayList<Contribution>()
|
|
||||||
|
private var contributionsList = mutableListOf<Contribution>()
|
||||||
|
|
||||||
override fun onAttach(context: Context) {
|
override fun onAttach(context: Context) {
|
||||||
super.onAttach(context)
|
super.onAttach(context)
|
||||||
|
|
@ -48,7 +52,7 @@ class PendingUploadsFragment :
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?,
|
savedInstanceState: Bundle?,
|
||||||
): View? {
|
): View {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
binding = FragmentPendingUploadsBinding.inflate(inflater, container, false)
|
binding = FragmentPendingUploadsBinding.inflate(inflater, container, false)
|
||||||
pendingUploadsPresenter.onAttachView(this)
|
pendingUploadsPresenter.onAttachView(this)
|
||||||
|
|
@ -71,27 +75,24 @@ class PendingUploadsFragment :
|
||||||
/**
|
/**
|
||||||
* Initializes the recycler view.
|
* Initializes the recycler view.
|
||||||
*/
|
*/
|
||||||
fun initRecyclerView() {
|
private fun initRecyclerView() {
|
||||||
binding.pendingUploadsRecyclerView.setLayoutManager(LinearLayoutManager(this.context))
|
binding.pendingUploadsRecyclerView.setLayoutManager(LinearLayoutManager(this.context))
|
||||||
binding.pendingUploadsRecyclerView.adapter = adapter
|
binding.pendingUploadsRecyclerView.adapter = adapter
|
||||||
pendingUploadsPresenter.setup()
|
pendingUploadsPresenter.setup()
|
||||||
pendingUploadsPresenter.totalContributionList.observe(
|
pendingUploadsPresenter.totalContributionList
|
||||||
viewLifecycleOwner,
|
.observe(viewLifecycleOwner) { list: PagedList<Contribution> ->
|
||||||
) { list: PagedList<Contribution?> ->
|
|
||||||
contributionsSize = list.size
|
contributionsSize = list.size
|
||||||
contributionsList = ArrayList()
|
contributionsList = mutableListOf()
|
||||||
var pausedOrQueuedUploads = 0
|
var pausedOrQueuedUploads = 0
|
||||||
list.forEach {
|
list.forEach {
|
||||||
if (it != null) {
|
if (it != null) {
|
||||||
if (it.state == Contribution.STATE_PAUSED ||
|
if (it.state == STATE_PAUSED ||
|
||||||
it.state == Contribution.STATE_QUEUED ||
|
it.state == STATE_QUEUED ||
|
||||||
it.state == Contribution.STATE_IN_PROGRESS
|
it.state == STATE_IN_PROGRESS
|
||||||
) {
|
) {
|
||||||
contributionsList.add(it)
|
contributionsList.add(it)
|
||||||
}
|
}
|
||||||
if (it.state == Contribution.STATE_PAUSED ||
|
if (it.state == STATE_PAUSED || it.state == STATE_QUEUED) {
|
||||||
it.state == Contribution.STATE_QUEUED
|
|
||||||
) {
|
|
||||||
pausedOrQueuedUploads++
|
pausedOrQueuedUploads++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -104,7 +105,7 @@ class PendingUploadsFragment :
|
||||||
binding.nopendingTextView.visibility = View.GONE
|
binding.nopendingTextView.visibility = View.GONE
|
||||||
binding.pendingUplaodsLl.visibility = View.VISIBLE
|
binding.pendingUplaodsLl.visibility = View.VISIBLE
|
||||||
adapter.submitList(list)
|
adapter.submitList(list)
|
||||||
binding.progressTextView.setText(contributionsSize.toString() + " uploads left")
|
binding.progressTextView.setText("$contributionsSize uploads left")
|
||||||
if ((pausedOrQueuedUploads == contributionsSize) || CommonsApplication.isPaused) {
|
if ((pausedOrQueuedUploads == contributionsSize) || CommonsApplication.isPaused) {
|
||||||
uploadProgressActivity.setPausedIcon(true)
|
uploadProgressActivity.setPausedIcon(true)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -118,23 +119,18 @@ class PendingUploadsFragment :
|
||||||
* Cancels a specific upload after getting a confirmation from the user using Dialog.
|
* Cancels a specific upload after getting a confirmation from the user using Dialog.
|
||||||
*/
|
*/
|
||||||
override fun deleteUpload(contribution: Contribution?) {
|
override fun deleteUpload(contribution: Contribution?) {
|
||||||
|
val activity = requireActivity()
|
||||||
|
val locale = Locale.getDefault()
|
||||||
showAlertDialog(
|
showAlertDialog(
|
||||||
requireActivity(),
|
activity,
|
||||||
String.format(
|
String.format(locale, activity.getString(R.string.cancelling_upload)),
|
||||||
Locale.getDefault(),
|
String.format(locale, activity.getString(R.string.cancel_upload_dialog)),
|
||||||
requireActivity().getString(R.string.cancelling_upload),
|
String.format(locale, activity.getString(R.string.yes)),
|
||||||
),
|
String.format(locale, activity.getString(R.string.no)),
|
||||||
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)),
|
|
||||||
{
|
{
|
||||||
ViewUtil.showShortToast(context, R.string.cancelling_upload)
|
ViewUtil.showShortToast(context, R.string.cancelling_upload)
|
||||||
pendingUploadsPresenter.deleteUpload(
|
pendingUploadsPresenter.deleteUpload(
|
||||||
contribution,
|
contribution, requireContext().applicationContext,
|
||||||
this.requireContext().applicationContext,
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
{},
|
{},
|
||||||
|
|
@ -144,47 +140,35 @@ class PendingUploadsFragment :
|
||||||
/**
|
/**
|
||||||
* Restarts all the paused uploads.
|
* Restarts all the paused uploads.
|
||||||
*/
|
*/
|
||||||
fun restartUploads() {
|
fun restartUploads() = pendingUploadsPresenter.restartUploads(
|
||||||
if (contributionsList != null) {
|
contributionsList, 0, requireContext().applicationContext
|
||||||
pendingUploadsPresenter.restartUploads(
|
)
|
||||||
contributionsList,
|
|
||||||
0,
|
|
||||||
this.requireContext().applicationContext,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pauses all the ongoing uploads.
|
* Pauses all the ongoing uploads.
|
||||||
*/
|
*/
|
||||||
fun pauseUploads() {
|
fun pauseUploads() = pendingUploadsPresenter.pauseUploads()
|
||||||
pendingUploadsPresenter.pauseUploads()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancels all the uploads after getting a confirmation from the user using Dialog.
|
* Cancels all the uploads after getting a confirmation from the user using Dialog.
|
||||||
*/
|
*/
|
||||||
fun deleteUploads() {
|
fun deleteUploads() {
|
||||||
|
val activity = requireActivity()
|
||||||
|
val locale = Locale.getDefault()
|
||||||
showAlertDialog(
|
showAlertDialog(
|
||||||
requireActivity(),
|
activity,
|
||||||
String.format(
|
String.format(locale, activity.getString(R.string.cancelling_all_the_uploads)),
|
||||||
Locale.getDefault(),
|
String.format(locale, activity.getString(R.string.are_you_sure_that_you_want_cancel_all_the_uploads)),
|
||||||
requireActivity().getString(R.string.cancelling_all_the_uploads),
|
String.format(locale, activity.getString(R.string.yes)),
|
||||||
),
|
String.format(locale, activity.getString(R.string.no)),
|
||||||
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)
|
ViewUtil.showShortToast(context, R.string.cancelling_upload)
|
||||||
uploadProgressActivity.hidePendingIcons()
|
uploadProgressActivity.hidePendingIcons()
|
||||||
pendingUploadsPresenter.deleteUploads(
|
pendingUploadsPresenter.deleteUploads(
|
||||||
listOf(
|
listOf(
|
||||||
Contribution.STATE_QUEUED,
|
STATE_QUEUED,
|
||||||
Contribution.STATE_IN_PROGRESS,
|
STATE_IN_PROGRESS,
|
||||||
Contribution.STATE_PAUSED,
|
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