mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
Merge d505266985 into aae9d4a387
This commit is contained in:
commit
980b590022
6 changed files with 354 additions and 235 deletions
|
|
@ -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)
|
|
||||||
|
|
||||||
|
val place = defaultKvStore.getJson<Place>(PLACE_OBJECT, Place::class.java)
|
||||||
if (place != null) {
|
if (place != null) {
|
||||||
shareIntent.putExtra(PLACE_OBJECT, place)
|
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
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
shareIntent.putExtra(
|
putExtra(
|
||||||
UploadActivity.IN_APP_CAMERA_UPLOAD,
|
UploadActivity.IN_APP_CAMERA_UPLOAD,
|
||||||
isInAppCameraUpload
|
isInAppCameraUpload
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ✅ Prevent multiple UploadActivity instances on backstack
|
||||||
|
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||||
|
}
|
||||||
|
|
||||||
isInAppCameraUpload = false // reset the flag for next use
|
isInAppCameraUpload = false // reset the flag for next use
|
||||||
return shareIntent
|
return shareIntent
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
)
|
)
|
||||||
|
|
|
||||||
167
app/src/main/java/fr/free/nrw/commons/ui/CustomFabController.kt
Normal file
167
app/src/main/java/fr/free/nrw/commons/ui/CustomFabController.kt
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,27 @@
|
||||||
<?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">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/nopendingTextView"
|
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:gravity="center"
|
android:gravity="center"
|
||||||
android:text="You do not have any pending Uploads!"
|
android:text="@string/no_pending_uploads"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/pendingUplaodsLl"
|
android:id="@+id/pendingUploadsLl"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
|
|
@ -33,7 +38,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:text="Progress:"
|
android:text="@string/progress"
|
||||||
android:textSize="22sp" />
|
android:textSize="22sp" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
|
@ -47,12 +52,11 @@
|
||||||
android:id="@+id/progress_text_view"
|
android:id="@+id/progress_text_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="right"
|
android:gravity="end"
|
||||||
android:text=""
|
android:text=""
|
||||||
android:textSize="21sp" />
|
android:textSize="21sp" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
|
@ -62,6 +66,67 @@
|
||||||
android:layout_marginHorizontal="10dp" />
|
android:layout_marginHorizontal="10dp" />
|
||||||
|
|
||||||
</LinearLayout>
|
</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>
|
||||||
|
|
|
||||||
|
|
@ -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">
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue