Skip to content
Closed
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class PendingUploadsFragment :
CommonsDaggerSupportFragment(),
PendingUploadsContract.View,
PendingUploadsAdapter.Callback {
@Inject
@Inject
lateinit var pendingUploadsPresenter: PendingUploadsPresenter

private lateinit var binding: FragmentPendingUploadsBinding
Expand Down Expand Up @@ -60,10 +60,6 @@ class PendingUploadsFragment :
return binding.root
}

fun initAdapter() {
adapter = PendingUploadsAdapter(this)
}

override fun onViewCreated(
view: View,
savedInstanceState: Bundle?,
Expand All @@ -72,6 +68,10 @@ class PendingUploadsFragment :
initRecyclerView()
}

fun initAdapter() {
adapter = PendingUploadsAdapter(this)
}

/**
* Initializes the recycler view.
*/
Expand All @@ -81,38 +81,38 @@ class PendingUploadsFragment :
pendingUploadsPresenter.setup()
pendingUploadsPresenter.totalContributionList
.observe(viewLifecycleOwner) { list: PagedList<Contribution> ->
contributionsSize = list.size
contributionsList = mutableListOf()
var pausedOrQueuedUploads = 0
list.forEach {
if (it != null) {
if (it.state == STATE_PAUSED ||
it.state == STATE_QUEUED ||
it.state == STATE_IN_PROGRESS
) {
contributionsList.add(it)
}
if (it.state == STATE_PAUSED || it.state == STATE_QUEUED) {
pausedOrQueuedUploads++
contributionsSize = list.size
contributionsList = mutableListOf()
var pausedOrQueuedUploads = 0
list.forEach {
if (it != null) {
if (it.state == STATE_PAUSED ||
it.state == STATE_QUEUED ||
it.state == STATE_IN_PROGRESS
) {
contributionsList.add(it)
}
if (it.state == STATE_PAUSED || it.state == STATE_QUEUED) {
pausedOrQueuedUploads++
}
}
}
}
if (contributionsSize == 0) {
binding.nopendingTextView.visibility = View.VISIBLE
binding.pendingUplaodsLl.visibility = View.GONE
uploadProgressActivity.hidePendingIcons()
} else {
binding.nopendingTextView.visibility = View.GONE
binding.pendingUplaodsLl.visibility = View.VISIBLE
adapter.submitList(list)
binding.progressTextView.setText("$contributionsSize uploads left")
if ((pausedOrQueuedUploads == contributionsSize) || CommonsApplication.isPaused) {
uploadProgressActivity.setPausedIcon(true)
if (contributionsSize == 0) {
binding.nopendingTextView.visibility = View.VISIBLE
binding.pendingUplaodsLl.visibility = View.GONE
uploadProgressActivity.hidePendingIcons()
} else {
uploadProgressActivity.setPausedIcon(false)
binding.nopendingTextView.visibility = View.GONE
binding.pendingUplaodsLl.visibility = View.VISIBLE
adapter.submitList(list)
binding.progressTextView.setText("$contributionsSize uploads left")
if ((pausedOrQueuedUploads == contributionsSize) || CommonsApplication.isPaused) {
uploadProgressActivity.setPausedIcon(true)
} else {
uploadProgressActivity.setPausedIcon(false)
}
}
}
}
}

/**
Expand Down Expand Up @@ -140,19 +140,26 @@ class PendingUploadsFragment :
/**
* Restarts all the paused uploads.
*/
fun restartUploads() = pendingUploadsPresenter.restartUploads(
contributionsList, 0, requireContext().applicationContext
)
fun restartUploads() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding was that we don't need any changes in this entire file, is there anything that I'm missing out?😕

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() {
// the check below is no longer needed but kept for original logic
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the changes in this file really required? If not, could you please checkout to the original state as on main?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The check is no longer required. The logs confirmed the Presenter is always initialized, making the check redundant. I willl revert this file to the cleanest state by removing that check.

if (!::pendingUploadsPresenter.isInitialized) return

val activity = requireActivity()
val locale = Locale.getDefault()
showAlertDialog(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ import javax.inject.Inject
*/
class UploadProgressActivity : BaseActivity() {
private lateinit var binding: ActivityUploadProgressBinding
private var pendingUploadsFragment: PendingUploadsFragment? = null
private var failedUploadsFragment: FailedUploadsFragment? = null
// fields for the fragments are removed as retrieval is done via FragmentManager
var viewPagerAdapter: ViewPagerAdapter? = null
var menu: Menu? = null

Expand Down Expand Up @@ -68,18 +67,36 @@ class UploadProgressActivity : BaseActivity() {
setTabs()
}

// FIX: the helelper to retrieve the current, non-stale PendingUploadsFragment instance.
private fun getPendingUploadsFragment(): PendingUploadsFragment? {
return supportFragmentManager.findFragmentByTag(
"android:switcher:${R.id.upload_progress_view_pager}:${0}",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do we know these positions will remain the same? Indexing is risky - any developer new to the project can introduce a new tab in the middle. How will this code behave in that case?

) as? PendingUploadsFragment
}


// FIX: helper to retrieve the current, non-stale FailedUploadsFragment instance.
private fun getFailedUploadsFragment(): FailedUploadsFragment? {
return supportFragmentManager.findFragmentByTag(
"android:switcher:${R.id.upload_progress_view_pager}:${1}",
) as? FailedUploadsFragment
}

/**
* Initializes and sets up the tabs data by creating instances of `PendingUploadsFragment`
* and `FailedUploadsFragment`, adds them to the `fragmentList`, and assigns corresponding
* titles from resources to the `titleList`.
*/
fun setTabs() {
pendingUploadsFragment = PendingUploadsFragment()
failedUploadsFragment = FailedUploadsFragment()
val pendingUploadsFragment: Fragment
val failedUploadsFragment: Fragment
// using the FragmentManager lookup to get the correct, current instances after the rotation
pendingUploadsFragment = getPendingUploadsFragment() ?: PendingUploadsFragment()
failedUploadsFragment = getFailedUploadsFragment() ?: FailedUploadsFragment()

viewPagerAdapter!!.setTabs(
R.string.pending to pendingUploadsFragment!!,
R.string.failed to failedUploadsFragment!!
R.string.pending to pendingUploadsFragment,
R.string.failed to failedUploadsFragment
)
viewPagerAdapter!!.notifyDataSetChanged()
}
Expand Down Expand Up @@ -119,7 +136,8 @@ class UploadProgressActivity : BaseActivity() {
getString(R.string.pause),
).setIcon(R.drawable.pause_icon)
.setOnMenuItemClickListener {
pendingUploadsFragment!!.pauseUploads()
// FIX: retrive and use the current fragment instance with safe call to avoid the NPE if retrieval fails
getPendingUploadsFragment()?.pauseUploads()
setPausedIcon(true)
true
}.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
Expand All @@ -133,7 +151,8 @@ class UploadProgressActivity : BaseActivity() {
getString(R.string.cancel),
).setIcon(R.drawable.ic_cancel_upload)
.setOnMenuItemClickListener {
pendingUploadsFragment!!.deleteUploads()
// FIX: retrive and use the current fragment instance
getPendingUploadsFragment()?.deleteUploads()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will we evaluate this for every operation? Could you please elaborate if there are any use cases apart from configuration changes that need this? I thought adding it to setTabs() would suffice. Please check my previous comment for that approach and share the pros and cons of both the approaches.

true
}.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
}
Expand All @@ -147,7 +166,8 @@ class UploadProgressActivity : BaseActivity() {
getString(R.string.resume),
).setIcon(R.drawable.play_icon)
.setOnMenuItemClickListener {
pendingUploadsFragment!!.restartUploads()
// FIX: retrive and use the current fragment instance
getPendingUploadsFragment()?.restartUploads()
setPausedIcon(false)
true
}.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
Expand All @@ -161,7 +181,7 @@ class UploadProgressActivity : BaseActivity() {
.add(Menu.NONE, R.id.retry_icon, Menu.NONE, getString(R.string.retry))
.setIcon(R.drawable.ic_refresh_24dp)
.setOnMenuItemClickListener {
failedUploadsFragment!!.restartUploads()
getFailedUploadsFragment()?.restartUploads()
true
}.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
}
Expand All @@ -174,7 +194,7 @@ class UploadProgressActivity : BaseActivity() {
getString(R.string.cancel),
).setIcon(R.drawable.ic_cancel_upload)
.setOnMenuItemClickListener {
failedUploadsFragment!!.deleteUploads()
getFailedUploadsFragment()?.deleteUploads()
true
}.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
}
Expand Down