mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-11-02 15:53:55 +01:00
Merge ba7ffc8051 into cdc4f89da5
This commit is contained in:
commit
c0a74ccb06
2 changed files with 284 additions and 268 deletions
|
|
@ -1,194 +1,203 @@
|
||||||
package fr.free.nrw.commons.upload
|
package fr.free.nrw.commons.upload
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.paging.PagedList
|
import androidx.paging.PagedList
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
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.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.upload.worker.WorkRequestHelper
|
||||||
import fr.free.nrw.commons.utils.ViewUtil
|
import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog
|
||||||
import java.util.Locale
|
import fr.free.nrw.commons.utils.ViewUtil
|
||||||
import javax.inject.Inject
|
import java.util.Locale
|
||||||
|
import javax.inject.Inject
|
||||||
/**
|
|
||||||
* Fragment for showing pending uploads in Upload Progress Activity. This fragment provides
|
/**
|
||||||
* functionality for the user to pause uploads.
|
* Fragment for showing pending uploads in Upload Progress Activity. This fragment provides
|
||||||
*/
|
* functionality for the user to pause uploads.
|
||||||
class PendingUploadsFragment :
|
*/
|
||||||
CommonsDaggerSupportFragment(),
|
class PendingUploadsFragment :
|
||||||
PendingUploadsContract.View,
|
CommonsDaggerSupportFragment(),
|
||||||
PendingUploadsAdapter.Callback {
|
PendingUploadsContract.View,
|
||||||
@Inject
|
PendingUploadsAdapter.Callback {
|
||||||
lateinit var pendingUploadsPresenter: PendingUploadsPresenter
|
@Inject
|
||||||
|
lateinit var pendingUploadsPresenter: PendingUploadsPresenter
|
||||||
private lateinit var binding: FragmentPendingUploadsBinding
|
|
||||||
|
private lateinit var binding: FragmentPendingUploadsBinding
|
||||||
private lateinit var uploadProgressActivity: UploadProgressActivity
|
|
||||||
|
private lateinit var uploadProgressActivity: UploadProgressActivity
|
||||||
private lateinit var adapter: PendingUploadsAdapter
|
|
||||||
|
private lateinit var adapter: PendingUploadsAdapter
|
||||||
private var contributionsSize = 0
|
|
||||||
var contributionsList = ArrayList<Contribution>()
|
private var contributionsSize = 0
|
||||||
|
var contributionsList = ArrayList<Contribution>()
|
||||||
override fun onAttach(context: Context) {
|
|
||||||
super.onAttach(context)
|
override fun onAttach(context: Context) {
|
||||||
if (context is UploadProgressActivity) {
|
super.onAttach(context)
|
||||||
uploadProgressActivity = context
|
if (context is UploadProgressActivity) {
|
||||||
}
|
uploadProgressActivity = context
|
||||||
}
|
}
|
||||||
|
}
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater,
|
override fun onCreateView(
|
||||||
container: ViewGroup?,
|
inflater: LayoutInflater,
|
||||||
savedInstanceState: Bundle?,
|
container: ViewGroup?,
|
||||||
): View? {
|
savedInstanceState: Bundle?,
|
||||||
super.onCreate(savedInstanceState)
|
): View? {
|
||||||
binding = FragmentPendingUploadsBinding.inflate(inflater, container, false)
|
super.onCreate(savedInstanceState)
|
||||||
pendingUploadsPresenter.onAttachView(this)
|
binding = FragmentPendingUploadsBinding.inflate(inflater, container, false)
|
||||||
initAdapter()
|
pendingUploadsPresenter.onAttachView(this)
|
||||||
return binding.root
|
initAdapter()
|
||||||
}
|
return binding.root
|
||||||
|
}
|
||||||
fun initAdapter() {
|
|
||||||
adapter = PendingUploadsAdapter(this)
|
fun initAdapter() {
|
||||||
}
|
adapter = PendingUploadsAdapter(this)
|
||||||
|
}
|
||||||
override fun onViewCreated(
|
|
||||||
view: View,
|
override fun onViewCreated(
|
||||||
savedInstanceState: Bundle?,
|
view: View,
|
||||||
) {
|
savedInstanceState: Bundle?,
|
||||||
super.onViewCreated(view, savedInstanceState)
|
) {
|
||||||
initRecyclerView()
|
super.onViewCreated(view, savedInstanceState)
|
||||||
}
|
initRecyclerView()
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Initializes the recycler view.
|
/**
|
||||||
*/
|
* Initializes the recycler view.
|
||||||
fun initRecyclerView() {
|
*/
|
||||||
binding.pendingUploadsRecyclerView.setLayoutManager(LinearLayoutManager(this.context))
|
fun initRecyclerView() {
|
||||||
binding.pendingUploadsRecyclerView.adapter = adapter
|
binding.pendingUploadsRecyclerView.setLayoutManager(LinearLayoutManager(this.context))
|
||||||
pendingUploadsPresenter!!.setup()
|
binding.pendingUploadsRecyclerView.adapter = adapter
|
||||||
pendingUploadsPresenter!!.totalContributionList.observe(
|
pendingUploadsPresenter!!.setup()
|
||||||
viewLifecycleOwner,
|
pendingUploadsPresenter!!.totalContributionList.observe(
|
||||||
) { list: PagedList<Contribution?> ->
|
viewLifecycleOwner,
|
||||||
contributionsSize = list.size
|
) { list: PagedList<Contribution?> ->
|
||||||
contributionsList = ArrayList()
|
contributionsSize = list.size
|
||||||
var pausedOrQueuedUploads = 0
|
contributionsList = ArrayList()
|
||||||
list.forEach {
|
var pausedOrQueuedUploads = 0
|
||||||
if (it != null) {
|
list.forEach {
|
||||||
if (it.state == Contribution.STATE_PAUSED ||
|
if (it != null) {
|
||||||
it.state == Contribution.STATE_QUEUED ||
|
if (it.state == Contribution.STATE_PAUSED ||
|
||||||
it.state == Contribution.STATE_IN_PROGRESS
|
it.state == Contribution.STATE_QUEUED ||
|
||||||
) {
|
it.state == Contribution.STATE_IN_PROGRESS
|
||||||
contributionsList.add(it)
|
) {
|
||||||
}
|
contributionsList.add(it)
|
||||||
if (it.state == Contribution.STATE_PAUSED ||
|
}
|
||||||
it.state == Contribution.STATE_QUEUED
|
if (it.state == Contribution.STATE_PAUSED ||
|
||||||
) {
|
it.state == Contribution.STATE_QUEUED
|
||||||
pausedOrQueuedUploads++
|
) {
|
||||||
}
|
pausedOrQueuedUploads++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (contributionsSize == 0) {
|
}
|
||||||
binding.nopendingTextView.visibility = View.VISIBLE
|
if (contributionsSize == 0) {
|
||||||
binding.pendingUplaodsLl.visibility = View.GONE
|
binding.nopendingTextView.visibility = View.VISIBLE
|
||||||
uploadProgressActivity.hidePendingIcons()
|
binding.pendingUplaodsLl.visibility = View.GONE
|
||||||
} else {
|
uploadProgressActivity.hidePendingIcons()
|
||||||
binding.nopendingTextView.visibility = View.GONE
|
} else {
|
||||||
binding.pendingUplaodsLl.visibility = View.VISIBLE
|
binding.nopendingTextView.visibility = View.GONE
|
||||||
adapter.submitList(list)
|
binding.pendingUplaodsLl.visibility = View.VISIBLE
|
||||||
binding.progressTextView.setText(contributionsSize.toString() + " uploads left")
|
adapter.submitList(list)
|
||||||
if ((pausedOrQueuedUploads == contributionsSize) || CommonsApplication.isPaused) {
|
binding.progressTextView.setText(contributionsSize.toString() + " uploads left")
|
||||||
uploadProgressActivity.setPausedIcon(true)
|
|
||||||
} else {
|
if ((pausedOrQueuedUploads == contributionsSize) || CommonsApplication.isPaused) {
|
||||||
uploadProgressActivity.setPausedIcon(false)
|
//As this function would be triggered multiple times by one tap
|
||||||
}
|
//Add new checking to enable/ disable the pause button for better UI
|
||||||
}
|
if (!WorkRequestHelper.Companion.getisUploadWorkerRunning()) {
|
||||||
}
|
uploadProgressActivity.setPausedIcon(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
} else {
|
||||||
* Cancels a specific upload after getting a confirmation from the user using Dialog.
|
if (WorkRequestHelper.Companion.getisUploadWorkerRunning()) {
|
||||||
*/
|
uploadProgressActivity.setPausedIcon(false)
|
||||||
override fun deleteUpload(contribution: Contribution?) {
|
}
|
||||||
showAlertDialog(
|
}
|
||||||
requireActivity(),
|
}
|
||||||
String.format(
|
}
|
||||||
Locale.getDefault(),
|
}
|
||||||
requireActivity().getString(R.string.cancelling_upload),
|
|
||||||
),
|
/**
|
||||||
String.format(
|
* Cancels a specific upload after getting a confirmation from the user using Dialog.
|
||||||
Locale.getDefault(),
|
*/
|
||||||
requireActivity().getString(R.string.cancel_upload_dialog),
|
override fun deleteUpload(contribution: Contribution?) {
|
||||||
),
|
showAlertDialog(
|
||||||
String.format(Locale.getDefault(), requireActivity().getString(R.string.yes)),
|
requireActivity(),
|
||||||
String.format(Locale.getDefault(), requireActivity().getString(R.string.no)),
|
String.format(
|
||||||
{
|
Locale.getDefault(),
|
||||||
ViewUtil.showShortToast(context, R.string.cancelling_upload)
|
requireActivity().getString(R.string.cancelling_upload),
|
||||||
pendingUploadsPresenter.deleteUpload(
|
),
|
||||||
contribution,
|
String.format(
|
||||||
this.requireContext().applicationContext,
|
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)
|
||||||
/**
|
pendingUploadsPresenter.deleteUpload(
|
||||||
* Restarts all the paused uploads.
|
contribution,
|
||||||
*/
|
this.requireContext().applicationContext,
|
||||||
fun restartUploads() {
|
)
|
||||||
if (contributionsList != null) {
|
},
|
||||||
pendingUploadsPresenter.restartUploads(
|
{},
|
||||||
contributionsList,
|
)
|
||||||
0,
|
}
|
||||||
this.requireContext().applicationContext,
|
|
||||||
)
|
/**
|
||||||
}
|
* Restarts all the paused uploads.
|
||||||
}
|
*/
|
||||||
|
fun restartUploads() {
|
||||||
/**
|
if (contributionsList != null) {
|
||||||
* Pauses all the ongoing uploads.
|
pendingUploadsPresenter.restartUploads(
|
||||||
*/
|
contributionsList,
|
||||||
fun pauseUploads() {
|
0,
|
||||||
pendingUploadsPresenter.pauseUploads()
|
this.requireContext().applicationContext,
|
||||||
}
|
)
|
||||||
|
}
|
||||||
/**
|
}
|
||||||
* Cancels all the uploads after getting a confirmation from the user using Dialog.
|
|
||||||
*/
|
/**
|
||||||
fun deleteUploads() {
|
* Pauses all the ongoing uploads.
|
||||||
showAlertDialog(
|
*/
|
||||||
requireActivity(),
|
fun pauseUploads() {
|
||||||
String.format(
|
pendingUploadsPresenter.pauseUploads()
|
||||||
Locale.getDefault(),
|
}
|
||||||
requireActivity().getString(R.string.cancelling_all_the_uploads),
|
|
||||||
),
|
/**
|
||||||
String.format(
|
* Cancels all the uploads after getting a confirmation from the user using Dialog.
|
||||||
Locale.getDefault(),
|
*/
|
||||||
requireActivity().getString(R.string.are_you_sure_that_you_want_cancel_all_the_uploads),
|
fun deleteUploads() {
|
||||||
),
|
showAlertDialog(
|
||||||
String.format(Locale.getDefault(), requireActivity().getString(R.string.yes)),
|
requireActivity(),
|
||||||
String.format(Locale.getDefault(), requireActivity().getString(R.string.no)),
|
String.format(
|
||||||
{
|
Locale.getDefault(),
|
||||||
ViewUtil.showShortToast(context, R.string.cancelling_upload)
|
requireActivity().getString(R.string.cancelling_all_the_uploads),
|
||||||
uploadProgressActivity.hidePendingIcons()
|
),
|
||||||
pendingUploadsPresenter.deleteUploads(
|
String.format(
|
||||||
listOf(
|
Locale.getDefault(),
|
||||||
Contribution.STATE_QUEUED,
|
requireActivity().getString(R.string.are_you_sure_that_you_want_cancel_all_the_uploads),
|
||||||
Contribution.STATE_IN_PROGRESS,
|
),
|
||||||
Contribution.STATE_PAUSED,
|
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_QUEUED,
|
||||||
|
Contribution.STATE_IN_PROGRESS,
|
||||||
|
Contribution.STATE_PAUSED,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,74 +1,81 @@
|
||||||
package fr.free.nrw.commons.upload.worker
|
package fr.free.nrw.commons.upload.worker
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.work.BackoffPolicy
|
import androidx.work.BackoffPolicy
|
||||||
import androidx.work.Constraints
|
import androidx.work.Constraints
|
||||||
import androidx.work.ExistingWorkPolicy
|
import androidx.work.ExistingWorkPolicy
|
||||||
import androidx.work.NetworkType
|
import androidx.work.NetworkType
|
||||||
import androidx.work.OneTimeWorkRequest
|
import androidx.work.OneTimeWorkRequest
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
import androidx.work.WorkRequest.Companion.MIN_BACKOFF_MILLIS
|
import androidx.work.WorkRequest.Companion.MIN_BACKOFF_MILLIS
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class for all the one time work requests
|
* Helper class for all the one time work requests
|
||||||
*/
|
*/
|
||||||
class WorkRequestHelper {
|
class WorkRequestHelper {
|
||||||
companion object {
|
companion object {
|
||||||
private var isUploadWorkerRunning = false
|
private var isUploadWorkerRunning = false
|
||||||
private val lock = Object()
|
private val lock = Object()
|
||||||
|
|
||||||
fun makeOneTimeWorkRequest(
|
fun makeOneTimeWorkRequest(
|
||||||
context: Context,
|
context: Context,
|
||||||
existingWorkPolicy: ExistingWorkPolicy,
|
existingWorkPolicy: ExistingWorkPolicy,
|
||||||
) {
|
) {
|
||||||
synchronized(lock) {
|
synchronized(lock) {
|
||||||
if (isUploadWorkerRunning) {
|
if (isUploadWorkerRunning) {
|
||||||
Timber.e("UploadWorker is already running. Cannot start another instance.")
|
Timber.e("UploadWorker is already running. Cannot start another instance.")
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
Timber.e("Setting isUploadWorkerRunning to true")
|
Timber.e("Setting isUploadWorkerRunning to true")
|
||||||
isUploadWorkerRunning = true
|
isUploadWorkerRunning = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set backoff criteria for the work request
|
/* Set backoff criteria for the work request
|
||||||
The default backoff policy is EXPONENTIAL, but while testing we found that it
|
The default backoff policy is EXPONENTIAL, but while testing we found that it
|
||||||
too long for the uploads to finish. So, set the backoff policy as LINEAR with the
|
too long for the uploads to finish. So, set the backoff policy as LINEAR with the
|
||||||
minimum backoff delay value of 10 seconds.
|
minimum backoff delay value of 10 seconds.
|
||||||
|
|
||||||
More details on when exactly it is retried:
|
More details on when exactly it is retried:
|
||||||
https://developer.android.com/guide/background/persistent/getting-started/define-work#retries_backoff
|
https://developer.android.com/guide/background/persistent/getting-started/define-work#retries_backoff
|
||||||
*/
|
*/
|
||||||
val constraints: Constraints =
|
val constraints: Constraints =
|
||||||
Constraints
|
Constraints
|
||||||
.Builder()
|
.Builder()
|
||||||
.setRequiredNetworkType(NetworkType.CONNECTED)
|
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||||
.build()
|
.build()
|
||||||
val uploadRequest: OneTimeWorkRequest =
|
val uploadRequest: OneTimeWorkRequest =
|
||||||
OneTimeWorkRequest
|
OneTimeWorkRequest
|
||||||
.Builder(UploadWorker::class.java)
|
.Builder(UploadWorker::class.java)
|
||||||
.setBackoffCriteria(
|
.setBackoffCriteria(
|
||||||
BackoffPolicy.LINEAR,
|
BackoffPolicy.LINEAR,
|
||||||
MIN_BACKOFF_MILLIS,
|
MIN_BACKOFF_MILLIS,
|
||||||
TimeUnit.MILLISECONDS,
|
TimeUnit.MILLISECONDS,
|
||||||
).setConstraints(constraints)
|
).setConstraints(constraints)
|
||||||
.build()
|
.build()
|
||||||
WorkManager.getInstance(context).enqueueUniqueWork(
|
WorkManager.getInstance(context).enqueueUniqueWork(
|
||||||
UploadWorker::class.java.simpleName,
|
UploadWorker::class.java.simpleName,
|
||||||
existingWorkPolicy,
|
existingWorkPolicy,
|
||||||
uploadRequest,
|
uploadRequest,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the flag isUploadWorkerRunning to`false` allowing new worker to be started.
|
* Sets the flag isUploadWorkerRunning to`false` allowing new worker to be started.
|
||||||
*/
|
*/
|
||||||
fun markUploadWorkerAsStopped() {
|
fun markUploadWorkerAsStopped() {
|
||||||
synchronized(lock) {
|
synchronized(lock) {
|
||||||
isUploadWorkerRunning = false
|
isUploadWorkerRunning = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
/**
|
||||||
|
* Provide a function for other class to get the flag isUploadWorkerRunning
|
||||||
|
*/
|
||||||
|
fun getisUploadWorkerRunning(): Boolean {
|
||||||
|
return isUploadWorkerRunning;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue