This commit is contained in:
Nishthajain7 2025-10-23 22:04:22 +09:00 committed by GitHub
commit 980b590022
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 354 additions and 235 deletions

View file

@ -362,9 +362,12 @@ class ContributionController @Inject constructor(@param:Named("default_preferenc
override fun onImagesPicked( override fun onImagesPicked(
imagesFiles: List<UploadableFile>, imagesFiles: List<UploadableFile>,
source: FilePicker.ImageSource, type: Int source: FilePicker.ImageSource,
type: Int
) { ) {
val intent = handleImagesPicked(activity, imagesFiles) val intent = handleImagesPicked(activity, imagesFiles).apply {
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
}
activity.startActivity(intent) activity.startActivity(intent)
} }
}) })
@ -385,27 +388,31 @@ class ContributionController @Inject constructor(@param:Named("default_preferenc
context: Context, context: Context,
imagesFiles: List<UploadableFile> imagesFiles: List<UploadableFile>
): Intent { ): Intent {
val shareIntent = Intent(context, UploadActivity::class.java) val shareIntent = Intent(context, UploadActivity::class.java).apply {
shareIntent.setAction(ACTION_INTERNAL_UPLOADS) action = ACTION_INTERNAL_UPLOADS
shareIntent putParcelableArrayListExtra(UploadActivity.EXTRA_FILES, ArrayList(imagesFiles))
.putParcelableArrayListExtra(UploadActivity.EXTRA_FILES, ArrayList(imagesFiles))
val place = defaultKvStore.getJson<Place>(PLACE_OBJECT, Place::class.java)
if (place != null) { val place = defaultKvStore.getJson<Place>(PLACE_OBJECT, Place::class.java)
shareIntent.putExtra(PLACE_OBJECT, place) if (place != null) {
} putExtra(PLACE_OBJECT, place)
}
if (locationBeforeImageCapture != null) { if (locationBeforeImageCapture != null) {
shareIntent.putExtra( putExtra(
UploadActivity.LOCATION_BEFORE_IMAGE_CAPTURE, UploadActivity.LOCATION_BEFORE_IMAGE_CAPTURE,
locationBeforeImageCapture locationBeforeImageCapture
)
}
putExtra(
UploadActivity.IN_APP_CAMERA_UPLOAD,
isInAppCameraUpload
) )
// ✅ Prevent multiple UploadActivity instances on backstack
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
} }
shareIntent.putExtra(
UploadActivity.IN_APP_CAMERA_UPLOAD,
isInAppCameraUpload
)
isInAppCameraUpload = false // reset the flag for next use isInAppCameraUpload = false // reset the flag for next use
return shareIntent return shareIntent
} }

View file

@ -1,9 +1,7 @@
package fr.free.nrw.commons.contributions package fr.free.nrw.commons.contributions
import android.Manifest.permission
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.Intent
import android.content.res.Configuration import android.content.res.Configuration
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
@ -12,13 +10,7 @@ import android.view.LayoutInflater
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.animation.Animation
import android.view.animation.AnimationUtils
import android.widget.LinearLayout import android.widget.LinearLayout
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting
import androidx.paging.PagedList import androidx.paging.PagedList
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
@ -34,9 +26,9 @@ import fr.free.nrw.commons.contributions.WikipediaInstructionsDialogFragment.Com
import fr.free.nrw.commons.databinding.FragmentContributionsListBinding import fr.free.nrw.commons.databinding.FragmentContributionsListBinding
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment import fr.free.nrw.commons.di.CommonsDaggerSupportFragment
import fr.free.nrw.commons.di.NetworkingModule import fr.free.nrw.commons.di.NetworkingModule
import fr.free.nrw.commons.filepicker.FilePicker
import fr.free.nrw.commons.media.MediaClient import fr.free.nrw.commons.media.MediaClient
import fr.free.nrw.commons.profile.ProfileActivity import fr.free.nrw.commons.profile.ProfileActivity
import fr.free.nrw.commons.ui.CustomFabController
import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog
import fr.free.nrw.commons.utils.SystemThemeUtils import fr.free.nrw.commons.utils.SystemThemeUtils
import fr.free.nrw.commons.utils.ViewUtil.showShortToast import fr.free.nrw.commons.utils.ViewUtil.showShortToast
@ -51,7 +43,7 @@ import javax.inject.Named
/** /**
* Created by root on 01.06.2018. * Created by root on 01.06.2018.
*/ */
class ContributionsListFragment : CommonsDaggerSupportFragment(), ContributionsListContract.View, open class ContributionsListFragment : CommonsDaggerSupportFragment(), ContributionsListContract.View,
ContributionsListAdapter.Callback, WikipediaInstructionsDialogFragment.Callback { ContributionsListAdapter.Callback, WikipediaInstructionsDialogFragment.Callback {
@JvmField @JvmField
@Inject @Inject
@ -83,13 +75,7 @@ class ContributionsListFragment : CommonsDaggerSupportFragment(), ContributionsL
var sessionManager: SessionManager? = null var sessionManager: SessionManager? = null
private var binding: FragmentContributionsListBinding? = null private var binding: FragmentContributionsListBinding? = null
private var fab_close: Animation? = null private lateinit var fabController: CustomFabController
private var fab_open: Animation? = null
private var rotate_forward: Animation? = null
private var rotate_backward: Animation? = null
private var isFabOpen = false
private lateinit var inAppCameraLocationPermissionLauncher: ActivityResultLauncher<Array<String>>
@VisibleForTesting @VisibleForTesting
var rvContributionsList: RecyclerView? = null var rvContributionsList: RecyclerView? = null
@ -106,46 +92,12 @@ class ContributionsListFragment : CommonsDaggerSupportFragment(), ContributionsL
private var contributionsSize = 0 private var contributionsSize = 0
private var userName: String? = null private var userName: String? = null
private val galleryPickLauncherForResult = registerForActivityResult<Intent, ActivityResult>(
StartActivityForResult()
) { result: ActivityResult? ->
controller!!.handleActivityResultWithCallback(requireActivity()
) { callbacks: FilePicker.Callbacks? ->
controller!!.onPictureReturnedFromGallery(
result!!, requireActivity(), callbacks!!
)
}
}
private val customSelectorLauncherForResult = registerForActivityResult<Intent, ActivityResult>(
StartActivityForResult()
) { result: ActivityResult? ->
controller!!.handleActivityResultWithCallback(requireActivity()
) { callbacks: FilePicker.Callbacks? ->
controller!!.onPictureReturnedFromCustomSelector(
result!!, requireActivity(), callbacks!!
)
}
}
private val cameraPickLauncherForResult = registerForActivityResult<Intent, ActivityResult>(
StartActivityForResult()
) { result: ActivityResult? ->
controller!!.handleActivityResultWithCallback(requireActivity()
) { callbacks: FilePicker.Callbacks? ->
controller!!.onPictureReturnedFromCamera(
result!!, requireActivity(), callbacks!!
)
}
}
@SuppressLint("NewApi") @SuppressLint("NewApi")
override fun onCreate( override fun onCreate(
savedInstanceState: Bundle? savedInstanceState: Bundle?
) { ) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
//Now that we are allowing this fragment to be started for
// any userName- we expect it to be passed as an argument
if (arguments != null) { if (arguments != null) {
userName = requireArguments().getString(ProfileActivity.KEY_USERNAME) userName = requireArguments().getString(ProfileActivity.KEY_USERNAME)
} }
@ -153,45 +105,18 @@ class ContributionsListFragment : CommonsDaggerSupportFragment(), ContributionsL
if (StringUtils.isEmpty(userName)) { if (StringUtils.isEmpty(userName)) {
userName = sessionManager!!.userName userName = sessionManager!!.userName
} }
inAppCameraLocationPermissionLauncher =
registerForActivityResult(RequestMultiplePermissions()) { result ->
val areAllGranted = result.values.all { it }
if (areAllGranted) {
controller?.locationPermissionCallback?.onLocationPermissionGranted()
} else {
activity?.let { currentActivity ->
if (currentActivity.shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) {
controller?.handleShowRationaleFlowCameraLocation(
currentActivity,
inAppCameraLocationPermissionLauncher, // Pass launcher
cameraPickLauncherForResult
)
} else {
controller?.locationPermissionCallback?.onLocationPermissionDenied(
currentActivity.getString(R.string.in_app_camera_location_permission_denied)
)
}
}
}
}
} }
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View {
binding = FragmentContributionsListBinding.inflate( binding = FragmentContributionsListBinding.inflate(
inflater, container, false inflater, container, false
) )
rvContributionsList = binding!!.contributionsList rvContributionsList = binding!!.contributionsList
contributionsListPresenter!!.onAttachView(this) contributionsListPresenter!!.onAttachView(this)
binding!!.fabCustomGallery.setOnClickListener { v: View? -> launchCustomSelector() }
binding!!.fabCustomGallery.setOnLongClickListener { view: View? ->
showShortToast(context, fr.free.nrw.commons.R.string.custom_selector_title)
true
}
if (sessionManager!!.userName == userName) { if (sessionManager!!.userName == userName) {
binding!!.tvContributionsOfUser.visibility = View.GONE binding!!.tvContributionsOfUser.visibility = View.GONE
@ -199,7 +124,7 @@ class ContributionsListFragment : CommonsDaggerSupportFragment(), ContributionsL
} else { } else {
binding!!.tvContributionsOfUser.visibility = View.VISIBLE binding!!.tvContributionsOfUser.visibility = View.VISIBLE
binding!!.tvContributionsOfUser.text = binding!!.tvContributionsOfUser.text =
getString(fr.free.nrw.commons.R.string.contributions_of_user, userName) getString(R.string.contributions_of_user, userName)
binding!!.fabLayout.visibility = View.GONE binding!!.fabLayout.visibility = View.GONE
} }
@ -242,9 +167,18 @@ class ContributionsListFragment : CommonsDaggerSupportFragment(), ContributionsL
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
fabController = CustomFabController(
this,
requireContext(),
binding!!.fabPlus,
binding!!.fabCamera,
binding!!.fabGallery,
binding!!.fabCustomGallery,
controller!!
)
fabController.initializeLaunchers()
initRecyclerView() initRecyclerView()
initializeAnimations() fabController.setListeners(controller!!, requireActivity())
setListeners()
} }
private fun initRecyclerView() { private fun initRecyclerView() {
@ -311,9 +245,7 @@ class ContributionsListFragment : CommonsDaggerSupportFragment(), ContributionsL
*/ */
override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean { override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean {
if (e.action == MotionEvent.ACTION_DOWN) { if (e.action == MotionEvent.ACTION_DOWN) {
if (isFabOpen) { fabController.closeFabMenuIfOpen()
animateFAB(isFabOpen)
}
} }
return false return false
} }
@ -358,85 +290,20 @@ class ContributionsListFragment : CommonsDaggerSupportFragment(), ContributionsL
) )
} }
private fun initializeAnimations() {
fab_open = AnimationUtils.loadAnimation(activity, fr.free.nrw.commons.R.anim.fab_open)
fab_close = AnimationUtils.loadAnimation(activity, fr.free.nrw.commons.R.anim.fab_close)
rotate_forward = AnimationUtils.loadAnimation(activity, fr.free.nrw.commons.R.anim.rotate_forward)
rotate_backward = AnimationUtils.loadAnimation(activity, fr.free.nrw.commons.R.anim.rotate_backward)
}
private fun setListeners() {
binding!!.fabPlus.setOnClickListener { view: View? -> animateFAB(isFabOpen) }
binding!!.fabCamera.setOnClickListener { view: View? ->
controller!!.initiateCameraPick(
requireActivity(),
inAppCameraLocationPermissionLauncher,
cameraPickLauncherForResult
)
animateFAB(isFabOpen)
}
binding!!.fabCamera.setOnLongClickListener { view: View? ->
showShortToast(
context,
fr.free.nrw.commons.R.string.add_contribution_from_camera
)
true
}
binding!!.fabGallery.setOnClickListener { view: View? ->
controller!!.initiateGalleryPick(requireActivity(), galleryPickLauncherForResult, true)
animateFAB(isFabOpen)
}
binding!!.fabGallery.setOnLongClickListener { view: View? ->
showShortToast(context, fr.free.nrw.commons.R.string.menu_from_gallery)
true
}
}
/** /**
* Launch Custom Selector. * Launch Custom Selector.
*/ */
protected fun launchCustomSelector() {
controller!!.initiateCustomGalleryPickWithPermission(
requireActivity(),
customSelectorLauncherForResult
)
animateFAB(isFabOpen)
}
fun scrollToTop() { fun scrollToTop() {
rvContributionsList!!.smoothScrollToPosition(0) rvContributionsList!!.smoothScrollToPosition(0)
} }
private fun animateFAB(isFabOpen: Boolean) {
this.isFabOpen = !isFabOpen
if (binding!!.fabPlus.isShown) {
if (isFabOpen) {
binding!!.fabPlus.startAnimation(rotate_backward)
binding!!.fabCamera.startAnimation(fab_close)
binding!!.fabGallery.startAnimation(fab_close)
binding!!.fabCustomGallery.startAnimation(fab_close)
binding!!.fabCamera.hide()
binding!!.fabGallery.hide()
binding!!.fabCustomGallery.hide()
} else {
binding!!.fabPlus.startAnimation(rotate_forward)
binding!!.fabCamera.startAnimation(fab_open)
binding!!.fabGallery.startAnimation(fab_open)
binding!!.fabCustomGallery.startAnimation(fab_open)
binding!!.fabCamera.show()
binding!!.fabGallery.show()
binding!!.fabCustomGallery.show()
}
this.isFabOpen = !isFabOpen
}
}
/** /**
* Shows welcome message if user has no contributions yet i.e. new user. * Shows welcome message if user has no contributions yet i.e. new user.
*/ */
override fun showWelcomeTip(shouldShow: Boolean) { override fun showWelcomeTip(numberOfUploads: Boolean) {
binding!!.noContributionsYet.visibility = binding!!.noContributionsYet.visibility =
if (shouldShow) View.VISIBLE else View.GONE if (numberOfUploads) View.VISIBLE else View.GONE
} }
/** /**
@ -469,9 +336,9 @@ class ContributionsListFragment : CommonsDaggerSupportFragment(), ContributionsL
} }
} }
override fun openMediaDetail(position: Int, isWikipediaButtonDisplayed: Boolean) { override fun openMediaDetail(contribution: Int, isWikipediaPageExists: Boolean) {
if (null != callback) { //Just being safe, ideally they won't be called when detached if (null != callback) { //Just being safe, ideally they won't be called when detached
callback!!.showDetail(position, isWikipediaButtonDisplayed) callback!!.showDetail(contribution, isWikipediaPageExists)
} }
} }
@ -483,8 +350,8 @@ class ContributionsListFragment : CommonsDaggerSupportFragment(), ContributionsL
override fun addImageToWikipedia(contribution: Contribution?) { override fun addImageToWikipedia(contribution: Contribution?) {
showAlertDialog( showAlertDialog(
requireActivity(), requireActivity(),
getString(fr.free.nrw.commons.R.string.add_picture_to_wikipedia_article_title), getString(R.string.add_picture_to_wikipedia_article_title),
getString(fr.free.nrw.commons.R.string.add_picture_to_wikipedia_article_desc), getString(R.string.add_picture_to_wikipedia_article_desc),
{ {
if (contribution != null) { if (contribution != null) {
showAddImageToWikipediaInstructions(contribution) showAddImageToWikipediaInstructions(contribution)
@ -502,7 +369,7 @@ class ContributionsListFragment : CommonsDaggerSupportFragment(), ContributionsL
val fragment = newInstance(contribution) val fragment = newInstance(contribution)
fragment.callback = fragment.callback =
WikipediaInstructionsDialogFragment.Callback { contribution: Contribution?, copyWikicode: Boolean -> WikipediaInstructionsDialogFragment.Callback { contribution: Contribution?, copyWikicode: Boolean ->
this.onConfirmClicked( onConfirmClicked(
contribution, contribution,
copyWikicode copyWikicode
) )

View file

@ -0,0 +1,167 @@
package fr.free.nrw.commons.ui
import android.view.animation.Animation
import android.view.animation.AnimationUtils
import fr.free.nrw.commons.R
import android.content.Context
import android.content.Intent
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
import androidx.fragment.app.Fragment
import com.google.android.material.floatingactionbutton.FloatingActionButton
import fr.free.nrw.commons.contributions.ContributionController
import fr.free.nrw.commons.filepicker.FilePicker
import android.os.Build
import android.Manifest.permission
import android.app.Activity
import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions
import fr.free.nrw.commons.utils.ViewUtil.showShortToast
class CustomFabController(
private val fragment: Fragment,
context: Context,
private val fabPlus: FloatingActionButton,
private val fabCamera: FloatingActionButton,
private val fabGallery: FloatingActionButton,
private val fabCustomGallery: FloatingActionButton,
private val controller: ContributionController
) {
private var isFabOpen = false
private val fabOpen: Animation = AnimationUtils.loadAnimation(context, R.anim.fab_open)
private val fabClose: Animation = AnimationUtils.loadAnimation(context, R.anim.fab_close)
private val rotateForward: Animation = AnimationUtils.loadAnimation(context, R.anim.rotate_forward)
private val rotateBackward: Animation = AnimationUtils.loadAnimation(context, R.anim.rotate_backward)
private lateinit var inAppCameraLocationPermissionLauncher: ActivityResultLauncher<Array<String>>
private lateinit var galleryPickLauncherForResult: ActivityResultLauncher<Intent>
private lateinit var customSelectorLauncherForResult: ActivityResultLauncher<Intent>
private lateinit var cameraPickLauncherForResult: ActivityResultLauncher<Intent>
fun initializeLaunchers() {
inAppCameraLocationPermissionLauncher =
fragment.registerForActivityResult(RequestMultiplePermissions()) { result ->
val areAllGranted = result.values.all { it }
if (areAllGranted) {
controller.locationPermissionCallback?.onLocationPermissionGranted()
} else {
val activity = fragment.activity
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
activity?.shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION) == true
) {
controller.handleShowRationaleFlowCameraLocation(
activity,
inAppCameraLocationPermissionLauncher,
cameraPickLauncherForResult
)
} else {
activity?.getString(R.string.in_app_camera_location_permission_denied)?.let {
controller.locationPermissionCallback?.onLocationPermissionDenied(
it
)
}
}
}
}
galleryPickLauncherForResult = fragment.registerForActivityResult(StartActivityForResult()) { result: ActivityResult? ->
controller.handleActivityResultWithCallback(fragment.requireActivity()) { callbacks: FilePicker.Callbacks? ->
controller.onPictureReturnedFromGallery(result!!, fragment.requireActivity(), callbacks!!)
}
}
customSelectorLauncherForResult = fragment.registerForActivityResult(StartActivityForResult()) { result: ActivityResult? ->
controller.handleActivityResultWithCallback(fragment.requireActivity()) { callbacks: FilePicker.Callbacks? ->
controller.onPictureReturnedFromCustomSelector(result!!, fragment.requireActivity(), callbacks!!)
}
}
cameraPickLauncherForResult = fragment.registerForActivityResult(StartActivityForResult()) { result: ActivityResult? ->
controller.handleActivityResultWithCallback(fragment.requireActivity()) { callbacks: FilePicker.Callbacks? ->
controller.onPictureReturnedFromCamera(result!!, fragment.requireActivity(), callbacks!!)
}
}
}
private fun toggleFabMenu() {
isFabOpen = !isFabOpen
if (fabPlus.isShown) {
if (isFabOpen) {
fabPlus.startAnimation(rotateForward)
fabCamera.startAnimation(fabOpen)
fabGallery.startAnimation(fabOpen)
fabCustomGallery.startAnimation(fabOpen)
fabCamera.show()
fabGallery.show()
fabCustomGallery.show()
} else {
fabPlus.startAnimation(rotateBackward)
fabCamera.startAnimation(fabClose)
fabGallery.startAnimation(fabClose)
fabCustomGallery.startAnimation(fabClose)
fabCamera.hide()
fabGallery.hide()
fabCustomGallery.hide()
}
}
}
private fun closeFabMenu() {
if (isFabOpen) toggleFabMenu()
}
fun closeFabMenuIfOpen() {
if (isFabOpen) {
closeFabMenu()
}
}
fun setListeners(controller: ContributionController, activity: Activity) {
fabPlus.setOnClickListener {
toggleFabMenu()
}
fabCamera.setOnClickListener {
controller.initiateCameraPick(
activity,
inAppCameraLocationPermissionLauncher,
cameraPickLauncherForResult
)
closeFabMenu()
}
fabCamera.setOnLongClickListener {
showShortToast(activity, R.string.add_contribution_from_camera)
true
}
fabGallery.setOnClickListener {
controller.initiateGalleryPick(activity, galleryPickLauncherForResult, true)
closeFabMenu()
}
fabGallery.setOnLongClickListener {
showShortToast(activity, R.string.menu_from_gallery)
true
}
fabCustomGallery.setOnClickListener {
controller.initiateCustomGalleryPickWithPermission(
activity,
customSelectorLauncherForResult
)
closeFabMenu()
}
fabCustomGallery.setOnLongClickListener {
showShortToast(activity, R.string.custom_selector_title)
true
}
}
}

View file

@ -13,10 +13,12 @@ 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_IN_PROGRESS
import fr.free.nrw.commons.contributions.Contribution.Companion.STATE_PAUSED 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.Contribution.Companion.STATE_QUEUED
import fr.free.nrw.commons.contributions.ContributionController
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.ui.CustomFabController
import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog
import fr.free.nrw.commons.utils.ViewUtil import fr.free.nrw.commons.utils.ViewUtil.showShortToast
import java.util.Locale import java.util.Locale
import javax.inject.Inject import javax.inject.Inject
@ -30,17 +32,17 @@ class PendingUploadsFragment :
PendingUploadsAdapter.Callback { PendingUploadsAdapter.Callback {
@Inject @Inject
lateinit var pendingUploadsPresenter: PendingUploadsPresenter 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 private var contributionsSize = 0
private var contributionsList = mutableListOf<Contribution>() private var contributionsList = mutableListOf<Contribution>()
@JvmField
@Inject
var controller: ContributionController? = null
private lateinit var fabController: CustomFabController
override fun onAttach(context: Context) { override fun onAttach(context: Context) {
super.onAttach(context) super.onAttach(context)
if (context is UploadProgressActivity) { if (context is UploadProgressActivity) {
@ -60,15 +62,23 @@ class PendingUploadsFragment :
return binding.root return binding.root
} }
fun initAdapter() { private fun initAdapter() {
adapter = PendingUploadsAdapter(this) adapter = PendingUploadsAdapter(this)
} }
override fun onViewCreated( override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
view: View,
savedInstanceState: Bundle?,
) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
fabController = CustomFabController(
this,
requireContext(),
binding.fabPlus,
binding.fabCamera,
binding.fabGallery,
binding.fabCustomGallery,
controller!!
)
fabController.initializeLaunchers()
fabController.setListeners(controller!!, requireActivity())
initRecyclerView() initRecyclerView()
} }
@ -98,14 +108,14 @@ class PendingUploadsFragment :
} }
} }
if (contributionsSize == 0) { if (contributionsSize == 0) {
binding.nopendingTextView.visibility = View.VISIBLE binding.noPendingTextView.visibility = View.VISIBLE
binding.pendingUplaodsLl.visibility = View.GONE binding.pendingUploadsLl.visibility = View.GONE
uploadProgressActivity.hidePendingIcons() uploadProgressActivity.hidePendingIcons()
} else { } else {
binding.nopendingTextView.visibility = View.GONE binding.noPendingTextView.visibility = View.GONE
binding.pendingUplaodsLl.visibility = View.VISIBLE binding.pendingUploadsLl.visibility = View.VISIBLE
adapter.submitList(list) adapter.submitList(list)
binding.progressTextView.setText("$contributionsSize uploads left") binding.progressTextView.text = "$contributionsSize uploads left"
if ((pausedOrQueuedUploads == contributionsSize) || CommonsApplication.isPaused) { if ((pausedOrQueuedUploads == contributionsSize) || CommonsApplication.isPaused) {
uploadProgressActivity.setPausedIcon(true) uploadProgressActivity.setPausedIcon(true)
} else { } else {
@ -128,7 +138,7 @@ class PendingUploadsFragment :
String.format(locale, activity.getString(R.string.yes)), String.format(locale, activity.getString(R.string.yes)),
String.format(locale, activity.getString(R.string.no)), String.format(locale, activity.getString(R.string.no)),
{ {
ViewUtil.showShortToast(context, R.string.cancelling_upload) showShortToast(context, R.string.cancelling_upload)
pendingUploadsPresenter.deleteUpload( pendingUploadsPresenter.deleteUpload(
contribution, requireContext().applicationContext, contribution, requireContext().applicationContext,
) )
@ -162,7 +172,7 @@ class PendingUploadsFragment :
String.format(locale, activity.getString(R.string.yes)), String.format(locale, activity.getString(R.string.yes)),
String.format(locale, activity.getString(R.string.no)), String.format(locale, activity.getString(R.string.no)),
{ {
ViewUtil.showShortToast(context, R.string.cancelling_upload) showShortToast(context, R.string.cancelling_upload)
uploadProgressActivity.hidePendingIcons() uploadProgressActivity.hidePendingIcons()
pendingUploadsPresenter.deleteUploads( pendingUploadsPresenter.deleteUploads(
listOf( listOf(

View file

@ -1,67 +1,132 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context=".upload.PendingUploadsFragment"> tools:context=".upload.PendingUploadsFragment">
<TextView
android:id="@+id/nopendingTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="You do not have any pending Uploads!"
android:visibility="gone" />
<LinearLayout <LinearLayout
android:id="@+id/pendingUplaodsLl"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:gravity="center"
android:visibility="visible"> android:orientation="vertical">
<LinearLayout <TextView
android:id="@+id/noPendingTextView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="10dp" android:gravity="center"
android:gravity="bottom" android:text="@string/no_pending_uploads"
android:orientation="horizontal"> android:visibility="gone" />
<TextView <LinearLayout
android:layout_width="match_parent" android:id="@+id/pendingUploadsLl"
android:layout_height="match_parent" android:layout_width="match_parent"
android:layout_weight="1" android:layout_height="match_parent"
android:text="Progress:" android:orientation="vertical"
android:textSize="22sp" /> android:visibility="visible">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_margin="10dp"
android:gravity="center" android:gravity="bottom"
android:orientation="vertical"> android:orientation="horizontal">
<TextView <TextView
android:id="@+id/progress_text_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:gravity="right" android:layout_weight="1"
android:text="" android:text="@string/progress"
android:textSize="21sp" /> android:textSize="22sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/progress_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end"
android:text=""
android:textSize="21sp" />
</LinearLayout>
</LinearLayout> </LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/pending_uploads_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginHorizontal="10dp" />
</LinearLayout> </LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/pending_uploads_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginHorizontal="10dp" />
</LinearLayout> </LinearLayout>
<LinearLayout
android:id="@+id/fab_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:orientation="vertical"
android:focusableInTouchMode="true"
android:gravity="center_horizontal">
</LinearLayout> <com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_camera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/add_contribution_from_camera"
android:tint="@color/button_blue"
android:visibility="gone"
app:backgroundTint="@color/main_background_light"
app:elevation="@dimen/tiny_margin"
app:fabSize="mini"
app:srcCompat="@drawable/ic_photo_camera_white_24dp"
app:useCompatPadding="true" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_gallery"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/add_contribution_from_photos"
android:tint="@color/button_blue"
android:visibility="gone"
app:backgroundTint="@color/main_background_light"
app:elevation="@dimen/tiny_margin"
app:fabSize="mini"
app:srcCompat="@drawable/ic_photo_white_24dp"
app:useCompatPadding="true" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_custom_gallery"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/commons"
android:contentDescription="@string/add_contribution_from_contributions_gallery"
android:tint="@color/button_blue"
android:visibility="gone"
app:backgroundTint="@color/main_background_light"
app:elevation="@dimen/tiny_margin"
app:fabSize="mini"
app:srcCompat="@drawable/ic_custom_image_picker"
app:useCompatPadding="true" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_plus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/add_new_contribution"
android:visibility="visible"
app:elevation="@dimen/tiny_margin"
app:backgroundTint="@color/status_bar_blue"
app:srcCompat="@drawable/ic_add_white_24dp"
app:useCompatPadding="true" />
</LinearLayout>
</FrameLayout>

View file

@ -10,6 +10,7 @@
<string name="add_another_description">Add another description</string> <string name="add_another_description">Add another description</string>
<string name="add_new_contribution">Add new contribution</string> <string name="add_new_contribution">Add new contribution</string>
<string name="add_contribution_from_camera">Add contribution from camera</string> <string name="add_contribution_from_camera">Add contribution from camera</string>
<string name="add_upload">Add Upload</string>
<string name="add_contribution_from_photos">Add contribution from Photos</string> <string name="add_contribution_from_photos">Add contribution from Photos</string>
<string name="add_contribution_from_contributions_gallery">Add contribution from previous contributions gallery</string> <string name="add_contribution_from_contributions_gallery">Add contribution from previous contributions gallery</string>
<string name="show_captions">Captions</string> <string name="show_captions">Captions</string>
@ -22,6 +23,8 @@
<string name="nearby_filter_search">Search View</string> <string name="nearby_filter_search">Search View</string>
<string name="nearby_filter_state">Place State</string> <string name="nearby_filter_state">Place State</string>
<string name="appwidget_img">Pic of the Day</string> <string name="appwidget_img">Pic of the Day</string>
<string name="progress">Progress</string>
<string name="no_pending_uploads">You do not have any pending Uploads!</string>
<!--Other strings--> <!--Other strings-->
<plurals name="uploads_pending_notification_indicator"> <plurals name="uploads_pending_notification_indicator">