Merge branch 'main' into Custom-Picker-Overflow-Menu-Icon-Color

This commit is contained in:
Nicolas Raoul 2025-10-14 21:43:56 +09:00 committed by GitHub
commit cfeaa17f9f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 232 additions and 190 deletions

View file

@ -70,7 +70,7 @@ body:
required: false required: false
- type: textarea - type: textarea
attributes: attributes:
label: Screen-shots label: Screenshots
description: Add screenshots related to the issue (if available). Can be created by pressing the Volume Down and Power Button at the same time on Android 4.0 and higher. description: Add screenshots related to the issue (if available). Can be created by pressing the Volume Down and Power Button at the same time on Android 4.0 and higher.
validations: validations:
required: false required: false

View file

@ -57,8 +57,7 @@
tools:replace="android:appComponentFactory"> tools:replace="android:appComponentFactory">
<activity <activity
android:name=".activity.SingleWebViewActivity" android:name=".activity.SingleWebViewActivity"
android:exported="false" android:exported="false" />
android:label="@string/title_activity_single_web_view" />
<activity <activity
android:name=".nearby.WikidataFeedback" android:name=".nearby.WikidataFeedback"
android:exported="false" /> android:exported="false" />

View file

@ -180,8 +180,8 @@ class ContributionController @Inject constructor(@param:Named("default_preferenc
showAlertDialog( showAlertDialog(
activity, activity.getString(R.string.location_permission_title), activity, activity.getString(R.string.location_permission_title),
activity.getString(R.string.in_app_camera_location_permission_rationale), activity.getString(R.string.in_app_camera_location_permission_rationale),
activity.getString(android.R.string.ok), activity.getString(R.string.ok),
activity.getString(android.R.string.cancel), activity.getString(R.string.cancel),
{ {
createDialogsAndHandleLocationPermissions( createDialogsAndHandleLocationPermissions(
activity, activity,

View file

@ -47,6 +47,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber
import java.util.TreeMap import java.util.TreeMap
import javax.inject.Inject import javax.inject.Inject
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
@ -211,8 +212,12 @@ class ImageFragment :
savedInstanceState: Bundle?, savedInstanceState: Bundle?,
): View? { ): View? {
_binding = FragmentCustomSelectorBinding.inflate(inflater, container, false) _binding = FragmentCustomSelectorBinding.inflate(inflater, container, false)
imageAdapter =
ImageAdapter(requireActivity(), activity as ImageSelectListener, imageLoader!!) // ensures imageAdapter is initialized
if (!::imageAdapter.isInitialized) {
imageAdapter = ImageAdapter(requireActivity(), activity as ImageSelectListener, imageLoader!!)
Timber.d("Initialized imageAdapter in onCreateView")
}
// Set single selection mode if needed // Set single selection mode if needed
val singleSelection = (activity as? CustomSelectorActivity)?.intent?.getBooleanExtra(CustomSelectorActivity.EXTRA_SINGLE_SELECTION, false) == true val singleSelection = (activity as? CustomSelectorActivity)?.intent?.getBooleanExtra(CustomSelectorActivity.EXTRA_SINGLE_SELECTION, false) == true
imageAdapter.setSingleSelection(singleSelection) imageAdapter.setSingleSelection(singleSelection)
@ -370,7 +375,12 @@ class ImageFragment :
* notifyDataSetChanged, rebuild the holder views to account for deleted images. * notifyDataSetChanged, rebuild the holder views to account for deleted images.
*/ */
override fun onResume() { override fun onResume() {
imageAdapter.notifyDataSetChanged() if (::imageAdapter.isInitialized) {
imageAdapter.notifyDataSetChanged()
Timber.d("Notified imageAdapter in onResume")
} else {
Timber.w("imageAdapter not initialized in onResume")
}
super.onResume() super.onResume()
} }
@ -380,14 +390,19 @@ class ImageFragment :
* Save the Image Fragment state. * Save the Image Fragment state.
*/ */
override fun onDestroy() { override fun onDestroy() {
imageAdapter.cleanUp() if (::imageAdapter.isInitialized) {
imageAdapter.cleanUp()
Timber.d("Cleaned up imageAdapter in onDestroy")
} else {
Timber.w("imageAdapter not initialized in onDestroy, skipping cleanup")
}
val position = val position =
(selectorRV?.layoutManager as GridLayoutManager) (selectorRV?.layoutManager as? GridLayoutManager)
.findFirstVisibleItemPosition() ?.findFirstVisibleItemPosition() ?: -1
// Check for empty RecyclerView. // check for valid position and non-empty image list
if (position != -1 && filteredImages.size > 0) { if (position != -1 && filteredImages.isNotEmpty() && ::imageAdapter.isInitialized) {
context?.let { context -> context?.let { context ->
context context
.getSharedPreferences( .getSharedPreferences(
@ -396,34 +411,57 @@ class ImageFragment :
)?.let { prefs -> )?.let { prefs ->
prefs.edit()?.let { editor -> prefs.edit()?.let { editor ->
editor.putLong("ItemId", imageAdapter.getImageIdAt(position))?.apply() editor.putLong("ItemId", imageAdapter.getImageIdAt(position))?.apply()
Timber.d("Saved last visible item ID: %d", imageAdapter.getImageIdAt(position))
} }
} }
} }
} else {
Timber.d("Skipped saving item ID: position=%d, filteredImages.size=%d, imageAdapter initialized=%b",
position, filteredImages.size, ::imageAdapter.isInitialized)
} }
super.onDestroy() super.onDestroy()
} }
override fun onDestroyView() { override fun onDestroyView() {
_binding = null _binding = null
selectorRV = null
loader = null
switch = null
progressLayout = null
super.onDestroyView() super.onDestroyView()
} }
override fun refresh() { override fun refresh() {
imageAdapter.refresh(filteredImages, allImages, getUploadingContributions()) if (::imageAdapter.isInitialized) {
imageAdapter.refresh(filteredImages, allImages, getUploadingContributions())
Timber.d("Refreshed imageAdapter")
} else {
Timber.w("imageAdapter not initialized in refresh")
}
} }
/** /**
* Removes the image from the actionable image map * Removes the image from the actionable image map
*/ */
fun removeImage(image: Image) { fun removeImage(image: Image) {
imageAdapter.removeImageFromActionableImageMap(image) if (::imageAdapter.isInitialized) {
imageAdapter.removeImageFromActionableImageMap(image)
Timber.d("Removed image from actionable image map")
} else {
Timber.w("imageAdapter not initialized in removeImage")
}
} }
/** /**
* Clears the selected images * Clears the selected images
*/ */
fun clearSelectedImages() { fun clearSelectedImages() {
imageAdapter.clearSelectedImages() if (::imageAdapter.isInitialized) {
imageAdapter.clearSelectedImages()
Timber.d("Cleared selected images")
} else {
Timber.w("imageAdapter not initialized in clearSelectedImages")
}
} }
/** /**
@ -434,6 +472,15 @@ class ImageFragment :
selectedImages: ArrayList<Image>, selectedImages: ArrayList<Image>,
shouldRefresh: Boolean, shouldRefresh: Boolean,
) { ) {
if (::imageAdapter.isInitialized) {
imageAdapter.setSelectedImages(selectedImages)
if (shouldRefresh) {
imageAdapter.refresh(filteredImages, allImages, getUploadingContributions())
}
Timber.d("Passed %d selected images to imageAdapter, shouldRefresh=%b", selectedImages.size, shouldRefresh)
} else {
Timber.w("imageAdapter not initialized in passSelectedImages")
}
} }
/** /**
@ -443,6 +490,7 @@ class ImageFragment :
if (!progressDialog.isShowing) { if (!progressDialog.isShowing) {
progressDialogLayout.progressDialogText.text = text progressDialogLayout.progressDialogText.text = text
progressDialog.show() progressDialog.show()
Timber.d("Showing mark/unmark progress dialog: %s", text)
} }
} }
@ -452,6 +500,7 @@ class ImageFragment :
fun dismissMarkUnmarkProgressDialog() { fun dismissMarkUnmarkProgressDialog() {
if (progressDialog.isShowing) { if (progressDialog.isShowing) {
progressDialog.dismiss() progressDialog.dismiss()
Timber.d("Dismissed mark/unmark progress dialog")
} }
} }

View file

@ -150,7 +150,7 @@ class DescriptionEditActivity :
this, this,
getString(titleStringID), getString(titleStringID),
getString(messageStringId), getString(messageStringId),
getString(android.R.string.ok), getString(R.string.ok),
null null
) )
} }

View file

@ -140,8 +140,8 @@ class ExploreMapFragment : CommonsDaggerSupportFragment(), ExploreMapContract.Vi
requireActivity(), requireActivity(),
requireActivity().getString(R.string.location_permission_title), requireActivity().getString(R.string.location_permission_title),
requireActivity().getString(R.string.location_permission_rationale_explore), requireActivity().getString(R.string.location_permission_rationale_explore),
requireActivity().getString(android.R.string.ok), requireActivity().getString(R.string.ok),
requireActivity().getString(android.R.string.cancel), requireActivity().getString(R.string.cancel),
{ askForLocationPermission() }, { askForLocationPermission() },
null, null,
null null
@ -287,6 +287,8 @@ class ExploreMapFragment : CommonsDaggerSupportFragment(), ExploreMapContract.Vi
super.onPause() super.onPause()
// unregistering the broadcastReceiver, as it was causing an exception and a potential crash // unregistering the broadcastReceiver, as it was causing an exception and a potential crash
unregisterNetworkReceiver() unregisterNetworkReceiver()
locationManager.unregisterLocationManager()
locationManager.removeLocationListener(this)
} }
fun requestLocationIfNeeded() { fun requestLocationIfNeeded() {
@ -963,13 +965,17 @@ class ExploreMapFragment : CommonsDaggerSupportFragment(), ExploreMapContract.Vi
if (geoPoint != null) { if (geoPoint != null) {
binding!!.mapView.controller.setCenter(geoPoint) binding!!.mapView.controller.setCenter(geoPoint)
val overlays = binding!!.mapView.overlays val overlays = binding!!.mapView.overlays
// collects the indices of items to remove
val indicesToRemove = mutableListOf<Int>()
for (i in overlays.indices) { for (i in overlays.indices) {
if (overlays[i] is Marker) { if (overlays[i] is Marker || overlays[i] is ScaleDiskOverlay) {
binding!!.mapView.overlays.removeAt(i) indicesToRemove.add(i)
} else if (overlays[i] is ScaleDiskOverlay) {
binding!!.mapView.overlays.removeAt(i)
} }
} }
// removes the items in reverse order to avoid index shifting
indicesToRemove.sortedDescending().forEach { index ->
binding!!.mapView.overlays.removeAt(index)
}
val diskOverlay = ScaleDiskOverlay( val diskOverlay = ScaleDiskOverlay(
requireContext(), requireContext(),
geoPoint, 2000, GeoConstants.UnitOfMeasure.foot geoPoint, 2000, GeoConstants.UnitOfMeasure.foot
@ -979,7 +985,6 @@ class ExploreMapFragment : CommonsDaggerSupportFragment(), ExploreMapContract.Vi
this.style = Paint.Style.STROKE this.style = Paint.Style.STROKE
this.strokeWidth = 2f this.strokeWidth = 2f
}) })
setCirclePaint1(Paint().apply { setCirclePaint1(Paint().apply {
setColor(Color.argb(40, 128, 128, 128)) setColor(Color.argb(40, 128, 128, 128))
this.style = Paint.Style.FILL_AND_STROKE this.style = Paint.Style.FILL_AND_STROKE
@ -988,7 +993,6 @@ class ExploreMapFragment : CommonsDaggerSupportFragment(), ExploreMapContract.Vi
setDisplaySizeMax(1700) setDisplaySizeMax(1700)
} }
binding!!.mapView.overlays.add(diskOverlay) binding!!.mapView.overlays.add(diskOverlay)
val startMarker = Marker( val startMarker = Marker(
binding!!.mapView binding!!.mapView
).apply { ).apply {

View file

@ -67,10 +67,10 @@ class RecentSearchesFragment : CommonsDaggerSupportFragment() {
private fun showDeleteRecentAlertDialog(context: Context) { private fun showDeleteRecentAlertDialog(context: Context) {
AlertDialog.Builder(context) AlertDialog.Builder(context)
.setMessage(getString(R.string.delete_recent_searches_dialog)) .setMessage(getString(R.string.delete_recent_searches_dialog))
.setPositiveButton(android.R.string.yes) { dialog: DialogInterface, _: Int -> .setPositiveButton(R.string.yes) { dialog: DialogInterface, _: Int ->
setDeleteRecentPositiveButton(context, dialog) setDeleteRecentPositiveButton(context, dialog)
} }
.setNegativeButton(android.R.string.no, null) .setNegativeButton(R.string.no, null)
.setCancelable(false) .setCancelable(false)
.create() .create()
.show() .show()
@ -102,7 +102,7 @@ class RecentSearchesFragment : CommonsDaggerSupportFragment() {
setDeletePositiveButton(context, dialog, position) setDeletePositiveButton(context, dialog, position)
} }
) )
.setNegativeButton(android.R.string.cancel, null) .setNegativeButton(R.string.cancel, null)
.setCancelable(false) .setCancelable(false)
.create() .create()
.show() .show()

View file

@ -64,8 +64,8 @@ class LocationPermissionsHelper(
activity, activity,
activity.getString(dialogTitleResource), activity.getString(dialogTitleResource),
activity.getString(dialogTextResource), activity.getString(dialogTextResource),
activity.getString(android.R.string.ok), activity.getString(R.string.ok),
activity.getString(android.R.string.cancel), activity.getString(R.string.cancel),
{ {
ActivityCompat.requestPermissions( ActivityCompat.requestPermissions(
activity, activity,

View file

@ -1027,12 +1027,12 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C
val message: String = if (result) { val message: String = if (result) {
context.getString( context.getString(
R.string.send_thank_success_message, R.string.send_thank_success_message,
media!!.displayTitle media!!.user
) )
} else { } else {
context.getString( context.getString(
R.string.send_thank_failure_message, R.string.send_thank_failure_message,
media!!.displayTitle media!!.user
) )
} }

View file

@ -151,7 +151,7 @@ class QuizChecker @Inject constructor(
activity.getString(R.string.quiz), activity.getString(R.string.quiz),
activity.getString(R.string.quiz_alert_message, revertPercentageForMessage), activity.getString(R.string.quiz_alert_message, revertPercentageForMessage),
activity.getString(R.string.about_translate_proceed), activity.getString(R.string.about_translate_proceed),
activity.getString(android.R.string.cancel), activity.getString(R.string.cancel),
{ startQuizActivity(activity) }, { startQuizActivity(activity) },
null null
) )

View file

@ -193,7 +193,7 @@ class QuizResultActivity : AppCompatActivity() {
alertadd.setPositiveButton(R.string.about_translate_proceed) { dialog, _ -> alertadd.setPositiveButton(R.string.about_translate_proceed) { dialog, _ ->
shareScreen(screenshot) shareScreen(screenshot)
} }
alertadd.setNegativeButton(android.R.string.cancel) { dialog, _ -> alertadd.setNegativeButton(R.string.cancel) { dialog, _ ->
dialog.cancel() dialog.cancel()
} }
alertadd.show() alertadd.show()

View file

@ -238,7 +238,7 @@ class ReviewActivity : BaseActivity() {
this, this,
getString(R.string.skip_image).uppercase(Locale.ROOT), getString(R.string.skip_image).uppercase(Locale.ROOT),
getString(R.string.skip_image_explanation), getString(R.string.skip_image_explanation),
getString(android.R.string.ok), getString(R.string.ok),
null, null,
null, null,
null null
@ -250,7 +250,7 @@ class ReviewActivity : BaseActivity() {
this, this,
getString(R.string.title_activity_review), getString(R.string.title_activity_review),
getString(R.string.review_image_explanation), getString(R.string.review_image_explanation),
getString(android.R.string.ok), getString(R.string.ok),
null, null,
null, null,
null null

View file

@ -446,7 +446,7 @@ class UploadActivity : BaseActivity(), UploadContract.View, UploadBaseFragment.C
this, this,
getString(R.string.storage_permissions_denied), getString(R.string.storage_permissions_denied),
getString(R.string.unable_to_share_upload_item), getString(R.string.unable_to_share_upload_item),
getString(android.R.string.ok) getString(R.string.ok)
) { finish() } ) { finish() }
} else { } else {
showAlertDialog( showAlertDialog(
@ -455,7 +455,7 @@ class UploadActivity : BaseActivity(), UploadContract.View, UploadBaseFragment.C
getString( getString(
R.string.write_storage_permission_rationale_for_image_share R.string.write_storage_permission_rationale_for_image_share
), ),
getString(android.R.string.ok) getString(R.string.ok)
) { checkStoragePermissions() } ) { checkStoragePermissions() }
} }
} }
@ -508,24 +508,17 @@ class UploadActivity : BaseActivity(), UploadContract.View, UploadBaseFragment.C
fragments = mutableListOf() fragments = mutableListOf()
} }
for (uploadableFile in uploadableFiles) { for (uploadableFile in uploadableFiles) {
val uploadMediaDetailFragment = UploadMediaDetailFragment() val uploadMediaDetailFragment = UploadMediaDetailFragment()
if (!uploadIsOfAPlace) { // set fragment properties but defer initialization
uploadMediaDetailFragment.uploadableFile = uploadableFile
uploadMediaDetailFragment.place = place
uploadMediaDetailFragment.inAppPictureLocation = if (!uploadIsOfAPlace) {
handleLocation() handleLocation()
uploadMediaDetailFragment.setImageToBeUploaded( currLocation
uploadableFile,
place,
currLocation
)
locationManager!!.unregisterLocationManager()
} else { } else {
uploadMediaDetailFragment.setImageToBeUploaded( currLocation
uploadableFile,
place,
currLocation
)
} }
val uploadMediaDetailFragmentCallback: UploadMediaDetailFragmentCallback = val uploadMediaDetailFragmentCallback: UploadMediaDetailFragmentCallback =
@ -580,13 +573,19 @@ class UploadActivity : BaseActivity(), UploadContract.View, UploadBaseFragment.C
if (isFragmentsSaved) { if (isFragmentsSaved) {
val fragment = fragments!![0] as UploadMediaDetailFragment? val fragment = fragments!![0] as UploadMediaDetailFragment?
fragment!!.fragmentCallback = uploadMediaDetailFragmentCallback fragment!!.fragmentCallback = uploadMediaDetailFragmentCallback
fragment.initializeFragment()
} else { } else {
uploadMediaDetailFragment.fragmentCallback = uploadMediaDetailFragmentCallback uploadMediaDetailFragment.fragmentCallback = uploadMediaDetailFragmentCallback
fragments!!.add(uploadMediaDetailFragment) fragments!!.add(uploadMediaDetailFragment)
} }
} }
//If fragments are not created, create them and add them to the fragments ArrayList // unregister location manager after loop if needed
if (!uploadIsOfAPlace) {
locationManager!!.unregisterLocationManager()
}
// If fragments are not created, create them and add them to the fragments ArrayList
if (!isFragmentsSaved) { if (!isFragmentsSaved) {
uploadCategoriesFragment = UploadCategoriesFragment() uploadCategoriesFragment = UploadCategoriesFragment()
if (place != null) { if (place != null) {

View file

@ -117,7 +117,7 @@ class UploadCategoriesFragment : UploadBaseFragment(), CategoriesContract.View {
requireActivity(), requireActivity(),
getString(R.string.categories_activity_title), getString(R.string.categories_activity_title),
getString(R.string.categories_tooltip), getString(R.string.categories_tooltip),
getString(android.R.string.ok), getString(R.string.ok),
null null
) )
} }

View file

@ -116,7 +116,7 @@ class DepictsFragment : UploadBaseFragment(), DepictsContract.View {
requireActivity(), requireActivity(),
getString(R.string.depicts_step_title), getString(R.string.depicts_step_title),
getString(R.string.depicts_tooltip), getString(R.string.depicts_tooltip),
getString(android.R.string.ok), getString(R.string.ok),
null null
) )
} }

View file

@ -119,8 +119,8 @@ class UploadMediaDetailFragment : UploadBaseFragment(), UploadMediaDetailsContra
private var basicKvStore: BasicKvStore? = null private var basicKvStore: BasicKvStore? = null
private val keyForShowingAlertDialog = "isNoNetworkAlertDialogShowing" private val keyForShowingAlertDialog = "isNoNetworkAlertDialogShowing"
private var uploadableFile: UploadableFile? = null internal var uploadableFile: UploadableFile? = null
private var place: Place? = null internal var place: Place? = null
private lateinit var uploadMediaDetailAdapter: UploadMediaDetailAdapter private lateinit var uploadMediaDetailAdapter: UploadMediaDetailAdapter
var indexOfFragment = 0 var indexOfFragment = 0
var isExpanded = true var isExpanded = true
@ -142,19 +142,24 @@ class UploadMediaDetailFragment : UploadBaseFragment(), UploadMediaDetailsContra
} }
} }
fun setImageToBeUploaded(
uploadableFile: UploadableFile?, place: Place?, inAppPictureLocation: LatLng?
) {
this.uploadableFile = uploadableFile
this.place = place
this.inAppPictureLocation = inAppPictureLocation
}
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View { ): View {
_binding = FragmentUploadMediaDetailFragmentBinding.inflate(inflater, container, false) _binding = FragmentUploadMediaDetailFragmentBinding.inflate(inflater, container, false)
_binding!!.mediaDetailCardView.handleKeyboardInsets() _binding!!.mediaDetailCardView.handleKeyboardInsets()
// intialise the adapter early to prevent uninitialized access
uploadMediaDetailAdapter = UploadMediaDetailAdapter(
this,
defaultKvStore.getString(Prefs.DESCRIPTION_LANGUAGE, "")!!,
recentLanguagesDao, voiceInputResultLauncher
)
uploadMediaDetailAdapter.callback =
UploadMediaDetailAdapter.Callback { titleStringID: Int, messageStringId: Int ->
showInfoAlert(titleStringID, messageStringId)
}
uploadMediaDetailAdapter.eventListener = this
binding.rvDescriptions.layoutManager = LinearLayoutManager(context)
binding.rvDescriptions.adapter = uploadMediaDetailAdapter
return binding.root return binding.root
} }
@ -163,20 +168,48 @@ class UploadMediaDetailFragment : UploadBaseFragment(), UploadMediaDetailsContra
basicKvStore = BasicKvStore(requireActivity(), "CurrentUploadImageQualities") basicKvStore = BasicKvStore(requireActivity(), "CurrentUploadImageQualities")
if (fragmentCallback != null) { // restore adapter items from savedInstanceState if available
indexOfFragment = fragmentCallback!!.getIndexInViewFlipper(this)
initializeFragment()
}
if (savedInstanceState != null) { if (savedInstanceState != null) {
if (uploadMediaDetailAdapter.items.isEmpty() && fragmentCallback != null) { val savedItems = savedInstanceState.getParcelableArrayList<UploadMediaDetail>(UPLOAD_MEDIA_DETAILS)
uploadMediaDetailAdapter.items = savedInstanceState.getParcelableArrayList(UPLOAD_MEDIA_DETAILS)!! Timber.d("Restoring state: savedItems size = %s", savedItems?.size ?: "null")
presenter.setUploadMediaDetails(uploadMediaDetailAdapter.items, indexOfFragment) if (savedItems != null && savedItems.isNotEmpty()) {
uploadMediaDetailAdapter.items = savedItems
// only call setUploadMediaDetails if indexOfFragment is valid
if (fragmentCallback != null) {
indexOfFragment = fragmentCallback!!.getIndexInViewFlipper(this)
if (indexOfFragment >= 0) {
presenter.setUploadMediaDetails(uploadMediaDetailAdapter.items, indexOfFragment)
Timber.d("Restored and set upload media details for index %d", indexOfFragment)
} else {
Timber.w("Invalid indexOfFragment %d, skipping setUploadMediaDetails", indexOfFragment)
}
} else {
Timber.w("fragmentCallback is null, skipping setUploadMediaDetails")
}
} else {
// initialize with a default UploadMediaDetail if saved state is empty or null
uploadMediaDetailAdapter.items = mutableListOf(UploadMediaDetail())
Timber.d("Initialized default UploadMediaDetail due to empty or null savedItems")
}
} else {
// intitialise with a default UploadMediaDetail for fresh fragment
if (uploadMediaDetailAdapter.items.isEmpty()) {
uploadMediaDetailAdapter.items = mutableListOf(UploadMediaDetail())
Timber.d("Initialized default UploadMediaDetail for new fragment")
} }
} }
if (fragmentCallback != null) {
indexOfFragment = fragmentCallback!!.getIndexInViewFlipper(this)
Timber.d("Fragment callback present, indexOfFragment = %d", indexOfFragment)
initializeFragment()
} else {
Timber.w("Fragment callback is null, skipping initializeFragment")
}
try { try {
if (!presenter.getImageQuality(indexOfFragment, inAppPictureLocation, requireActivity())) { if (indexOfFragment >= 0 && !presenter.getImageQuality(indexOfFragment, inAppPictureLocation, requireActivity())) {
Timber.d("Image quality check failed, redirecting to MainActivity")
startActivityWithFlags( startActivityWithFlags(
requireActivity(), requireActivity(),
MainActivity::class.java, MainActivity::class.java,
@ -184,11 +217,12 @@ class UploadMediaDetailFragment : UploadBaseFragment(), UploadMediaDetailsContra
Intent.FLAG_ACTIVITY_SINGLE_TOP Intent.FLAG_ACTIVITY_SINGLE_TOP
) )
} }
} catch (_: Exception) { } catch (e: Exception) {
Timber.e(e, "Error during image quality check")
} }
} }
private fun initializeFragment() { internal fun initializeFragment() {
if (_binding == null) { if (_binding == null) {
return return
} }
@ -206,7 +240,6 @@ class UploadMediaDetailFragment : UploadBaseFragment(), UploadMediaDetailsContra
presenter.setupBasicKvStoreFactory { BasicKvStore(requireActivity(), it) } presenter.setupBasicKvStoreFactory { BasicKvStore(requireActivity(), it) }
presenter.receiveImage(uploadableFile, place, inAppPictureLocation) presenter.receiveImage(uploadableFile, place, inAppPictureLocation)
initRecyclerView()
with (binding){ with (binding){
if (indexOfFragment == 0) { if (indexOfFragment == 0) {
@ -265,30 +298,12 @@ class UploadMediaDetailFragment : UploadBaseFragment(), UploadMediaDetailsContra
} }
} }
/**
* init the description recycler veiw and caption recyclerview
*/
private fun initRecyclerView() {
uploadMediaDetailAdapter = UploadMediaDetailAdapter(
this,
defaultKvStore.getString(Prefs.DESCRIPTION_LANGUAGE, "")!!,
recentLanguagesDao, voiceInputResultLauncher
)
uploadMediaDetailAdapter.callback =
UploadMediaDetailAdapter.Callback { titleStringID: Int, messageStringId: Int ->
showInfoAlert(titleStringID, messageStringId)
}
uploadMediaDetailAdapter.eventListener = this
binding.rvDescriptions.layoutManager = LinearLayoutManager(context)
binding.rvDescriptions.adapter = uploadMediaDetailAdapter
}
private fun showInfoAlert(titleStringID: Int, messageStringId: Int) { private fun showInfoAlert(titleStringID: Int, messageStringId: Int) {
showAlertDialog( showAlertDialog(
requireActivity(), requireActivity(),
getString(titleStringID), getString(titleStringID),
getString(messageStringId), getString(messageStringId),
getString(android.R.string.ok), getString(R.string.ok),
null null
) )
} }
@ -590,16 +605,14 @@ class UploadMediaDetailFragment : UploadBaseFragment(), UploadMediaDetailsContra
var defaultLongitude = -122.431297 var defaultLongitude = -122.431297
var defaultZoom = 16.0 var defaultZoom = 16.0
val locationPickerIntent: Intent
/* Retrieve image location from EXIF if present or /* Retrieve image location from EXIF if present or
check if user has provided location while using the in-app camera. check if user has provided location while using the in-app camera.
Use location of last UploadItem if none of them is available */ Use location of last UploadItem if none of them is available */
val locationPickerIntent: Intent
if (uploadItem.gpsCoords != null && uploadItem.gpsCoords!! if (uploadItem.gpsCoords != null && uploadItem.gpsCoords!!
.decLatitude != 0.0 && uploadItem.gpsCoords!!.decLongitude != 0.0 .decLatitude != 0.0 && uploadItem.gpsCoords!!.decLongitude != 0.0
) { ) {
defaultLatitude = uploadItem.gpsCoords!! defaultLatitude = uploadItem.gpsCoords!!.decLatitude
.decLatitude
defaultLongitude = uploadItem.gpsCoords!!.decLongitude defaultLongitude = uploadItem.gpsCoords!!.decLongitude
defaultZoom = uploadItem.gpsCoords!!.zoomLevel defaultZoom = uploadItem.gpsCoords!!.zoomLevel
@ -615,8 +628,7 @@ class UploadMediaDetailFragment : UploadBaseFragment(), UploadMediaDetailsContra
defaultLongitude = locationLatLng[1].toDouble() defaultLongitude = locationLatLng[1].toDouble()
} }
if (defaultKvStore.getString(LAST_ZOOM) != null) { if (defaultKvStore.getString(LAST_ZOOM) != null) {
defaultZoom = defaultKvStore.getString(LAST_ZOOM)!! defaultZoom = defaultKvStore.getString(LAST_ZOOM)!!.toDouble()
.toDouble()
} }
locationPickerIntent = LocationPicker.IntentBuilder() locationPickerIntent = LocationPicker.IntentBuilder()

View file

@ -69,7 +69,18 @@ class UploadMediaPresenter @Inject constructor(
uploadMediaDetails: List<UploadMediaDetail>, uploadMediaDetails: List<UploadMediaDetail>,
uploadItemIndex: Int uploadItemIndex: Int
) { ) {
repository.getUploads()[uploadItemIndex].uploadMediaDetails = uploadMediaDetails.toMutableList() val uploadItems = repository.getUploads()
if (uploadItemIndex >= 0 && uploadItemIndex < uploadItems.size) {
if (uploadMediaDetails.isNotEmpty()) {
uploadItems[uploadItemIndex].uploadMediaDetails = uploadMediaDetails.toMutableList()
Timber.d("Set uploadMediaDetails for index %d, size %d", uploadItemIndex, uploadMediaDetails.size)
} else {
uploadItems[uploadItemIndex].uploadMediaDetails = mutableListOf(UploadMediaDetail())
Timber.w("Received empty uploadMediaDetails for index %d, initialized default", uploadItemIndex)
}
} else {
Timber.e("Invalid index %d for uploadItems size %d, skipping setUploadMediaDetails", uploadItemIndex, uploadItems.size)
}
} }
override fun setupBasicKvStoreFactory(factory: (String) -> BasicKvStore) { override fun setupBasicKvStoreFactory(factory: (String) -> BasicKvStore) {

View file

@ -209,8 +209,8 @@ object PermissionUtils {
activity, activity,
activity.getString(rationaleTitle), activity.getString(rationaleTitle),
activity.getString(rationaleMessage), activity.getString(rationaleMessage),
activity.getString(android.R.string.ok), activity.getString(R.string.ok),
activity.getString(android.R.string.cancel), activity.getString(R.string.cancel),
{ {
if (activity is UploadActivity) { if (activity is UploadActivity) {
activity.isShowPermissionsDialog = true activity.isShowPermissionsDialog = true

View file

@ -1,4 +0,0 @@
<vector android:height="16dp" android:viewportHeight="28"
android:viewportWidth="28" android:width="16dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#2D8BA4" android:pathData="M14,0L11.533,2.467L21.298,12.25H0V15.75H21.298L11.533,25.532L14,28L28,14L14,0Z"/>
</vector>

View file

@ -149,13 +149,6 @@
android:textColor="#2D8BA4" android:textColor="#2D8BA4"
android:textSize="@dimen/normal_text" android:textSize="@dimen/normal_text"
android:textStyle="bold" /> android:textStyle="bold" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/tiny_margin"
android:layout_weight="1"
android:src="@drawable/ic_arrow_16dp" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

View file

@ -3,6 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/category_layout" android:id="@+id/category_layout"
android:layoutDirection="locale"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
@ -10,26 +11,31 @@
android:id="@+id/upload_category_checkbox" android:id="@+id/upload_category_checkbox"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minWidth="48dp"
android:minHeight="48dp"
android:checkMark="?android:attr/textCheckMark" android:checkMark="?android:attr/textCheckMark"
android:checked="false" android:checked="false"
android:gravity="center_vertical" android:gravity="center_vertical"
android:padding="@dimen/tiny_gap" android:padding="@dimen/tiny_gap"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/category_image" app:layout_constraintEnd_toStartOf="@+id/category_image"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<com.facebook.drawee.view.SimpleDraweeView <com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/category_image" android:id="@+id/category_image"
android:layout_width="50dp" android:layout_width="50dp"
android:layout_height="50dp" android:layout_height="50dp"
android:paddingEnd="@dimen/tiny_gap" android:layout_marginStart="@dimen/tiny_gap"
android:layout_marginEnd="@dimen/tiny_gap"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@+id/upload_category_checkbox" app:layout_constraintStart_toEndOf="@+id/upload_category_checkbox"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toStartOf="@+id/text_container"
app:placeholderImage="@drawable/commons" /> app:placeholderImage="@drawable/commons" />
<LinearLayout <LinearLayout
android:id="@+id/text_container"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"

View file

@ -2,6 +2,7 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/depicts_layout" android:id="@+id/depicts_layout"
android:layoutDirection="locale"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
@ -9,26 +10,31 @@
android:id="@+id/depict_checkbox" android:id="@+id/depict_checkbox"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minWidth="48dp"
android:minHeight="48dp"
android:checkMark="?android:attr/textCheckMark" android:checkMark="?android:attr/textCheckMark"
android:checked="false" android:checked="false"
android:gravity="center_vertical" android:gravity="center_vertical"
android:padding="@dimen/tiny_gap" android:padding="@dimen/tiny_gap"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/depicted_image" app:layout_constraintEnd_toStartOf="@+id/depicted_image"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<com.facebook.drawee.view.SimpleDraweeView <com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/depicted_image" android:id="@+id/depicted_image"
android:layout_width="50dp" android:layout_width="50dp"
android:layout_height="50dp" android:layout_height="50dp"
android:paddingRight="@dimen/tiny_gap" android:layout_marginStart="@dimen/tiny_gap"
android:layout_marginEnd="@dimen/tiny_gap"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@+id/depict_checkbox" app:layout_constraintStart_toEndOf="@+id/depict_checkbox"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toStartOf="@+id/text_container"
app:placeholderImage="@drawable/ic_wikidata_logo_24dp" /> app:placeholderImage="@drawable/ic_wikidata_logo_24dp" />
<LinearLayout <LinearLayout
android:id="@+id/text_container"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
@ -41,14 +47,14 @@
android:id="@+id/depicts_label" android:id="@+id/depicts_label"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Label" android:text="@string/depicts_label"
android:textStyle="bold" /> android:textStyle="bold" />
<TextView <TextView
android:id="@+id/description" android:id="@+id/description"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Description" /> android:text="@string/depicts_description" />
</LinearLayout> </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -17,7 +17,6 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="@dimen/half_standard_height" android:layout_height="@dimen/half_standard_height"
android:layout_marginEnd="@dimen/standard_gap" android:layout_marginEnd="@dimen/standard_gap"
android:layout_marginRight="@dimen/standard_gap"
android:orientation="horizontal"> android:orientation="horizontal">
<TextView <TextView
@ -25,7 +24,6 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="@dimen/half_standard_height" android:layout_height="@dimen/half_standard_height"
android:layout_marginEnd="@dimen/standard_gap" android:layout_marginEnd="@dimen/standard_gap"
android:layout_marginRight="@dimen/standard_gap"
android:gravity="center_vertical" android:gravity="center_vertical"
android:textSize="@dimen/normal_text" android:textSize="@dimen/normal_text"
android:textStyle="bold" android:textStyle="bold"
@ -77,7 +75,6 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/tiny_gap" android:layout_marginEnd="@dimen/tiny_gap"
android:layout_marginRight="@dimen/tiny_gap"
android:layout_gravity="center_vertical|end" android:layout_gravity="center_vertical|end"
android:indeterminate="true" android:indeterminate="true"
android:indeterminateOnly="true" android:indeterminateOnly="true"

View file

@ -22,7 +22,6 @@
android:layout_marginEnd="@dimen/standard_gap" android:layout_marginEnd="@dimen/standard_gap"
android:layout_marginRight="@dimen/standard_gap" android:layout_marginRight="@dimen/standard_gap"
android:layout_alignParentStart="true" android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true" android:layout_alignParentTop="true"
android:orientation="horizontal"> android:orientation="horizontal">
<TextView <TextView
@ -30,7 +29,6 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="@dimen/half_standard_height" android:layout_height="@dimen/half_standard_height"
android:layout_marginEnd="@dimen/standard_gap" android:layout_marginEnd="@dimen/standard_gap"
android:layout_marginRight="@dimen/standard_gap"
android:gravity="center_vertical" android:gravity="center_vertical"
android:textSize="@dimen/normal_text" android:textSize="@dimen/normal_text"
android:textStyle="bold" android:textStyle="bold"
@ -99,7 +97,6 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/tiny_gap" android:layout_marginEnd="@dimen/tiny_gap"
android:layout_marginRight="@dimen/tiny_gap"
android:layout_gravity="center_vertical|end" android:layout_gravity="center_vertical|end"
android:indeterminate="true" android:indeterminate="true"
android:indeterminateOnly="true" android:indeterminateOnly="true"

View file

@ -5,7 +5,7 @@
* Nemoralis * Nemoralis
--> -->
<resources> <resources>
<string name="crash_dialog_title">Nasazlıq</string> <string name="crash_dialog_title">Commons çökdü</string>
<string name="crash_dialog_text">Uups. Nəsə düzgün çalışmır!</string> <string name="crash_dialog_text">Uups. Nəsə düzgün çalışmır!</string>
<string name="crash_dialog_comment_prompt">Nə etdiyinizi bizə deyin, sonra e-poçt vasitəsilə bizimlə paylaşın. Bu, bizə bunu düzəltməyə kömək edəcək!</string> <string name="crash_dialog_comment_prompt">Nə etdiyinizi bizə deyin, sonra e-poçt vasitəsilə bizimlə paylaşın. Bu, bizə bunu düzəltməyə kömək edəcək!</string>
<string name="crash_dialog_ok_toast">Təşəkkürlər!</string> <string name="crash_dialog_ok_toast">Təşəkkürlər!</string>

View file

@ -1,9 +1,11 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Authors: <!-- Authors:
* Amire80
* Shirayuki * Shirayuki
--> -->
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="all"> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="all">
<string name="crash_dialog_title">Title of dialog to show when the app crashes</string> <string name="crash_dialog_title">Title of dialog to show when the app crashes</string>
<string name="crash_dialog_text">Shown when the application crashed.</string>
<string name="crash_dialog_comment_prompt">Prompt asking people to enter info about what they were doing when the app crashed</string> <string name="crash_dialog_comment_prompt">Prompt asking people to enter info about what they were doing when the app crashed</string>
<string name="crash_dialog_ok_toast">Toast to be displayed once someone sends an error report thanking them.\n{{Identical|Thank you}}</string> <string name="crash_dialog_ok_toast">Toast to be displayed once someone sends an error report thanking them.\n{{Identical|Thank you}}</string>
</resources> </resources>

View file

@ -468,6 +468,8 @@
<string name="map_attribution">{{Optional}}\n&lt;code&gt;&amp;amp;#169;&lt;/code&gt; is the copyright symbol (©).</string> <string name="map_attribution">{{Optional}}\n&lt;code&gt;&amp;amp;#169;&lt;/code&gt; is the copyright symbol (©).</string>
<string name="categories_tooltip">{{Doc-commons-app-depicts}}</string> <string name="categories_tooltip">{{Doc-commons-app-depicts}}</string>
<string name="depicts_step_title">{{Doc-commons-app-depicts}}</string> <string name="depicts_step_title">{{Doc-commons-app-depicts}}</string>
<string name="depicts_label">Label</string>
<string name="depicts_description">Description</string>
<string name="pan_and_zoom_to_adjust">Panning means moving the map left/right/up/down, typically by touching the screen with one finger and moving it.\n\nZooming means making the map\'s scale bigger or smaller, typically by pinching with two fingers.\n\nExample in other app:\nhttps://igss.schneider-electric.com/features/pan-and-zoom-in-definition/</string> <string name="pan_and_zoom_to_adjust">Panning means moving the map left/right/up/down, typically by touching the screen with one finger and moving it.\n\nZooming means making the map\'s scale bigger or smaller, typically by pinching with two fingers.\n\nExample in other app:\nhttps://igss.schneider-electric.com/features/pan-and-zoom-in-definition/</string>
<string name="location_picker_image_view_shadow">A description of a visual element, location picker image shadow. Used for accesibility usually.</string> <string name="location_picker_image_view_shadow">A description of a visual element, location picker image shadow. Used for accesibility usually.</string>
<string name="label">{{Identical|Label}}</string> <string name="label">{{Identical|Label}}</string>

View file

@ -133,6 +133,7 @@
<string name="title_activity_settings">Settings</string> <string name="title_activity_settings">Settings</string>
<string name="title_activity_signup">Sign Up</string> <string name="title_activity_signup">Sign Up</string>
<string name="title_activity_featured_images">Featured Images</string> <string name="title_activity_featured_images">Featured Images</string>
<string name="images_featured_explanation">Featured images are contributions by highly skilled photographers and illustrators that the Wikimedia Commons community has chosen as some of the highest quality on the site.</string>
<string name="title_activity_custom_selector">Custom Selector</string> <string name="title_activity_custom_selector">Custom Selector</string>
<string name="title_activity_category_details">Category</string> <string name="title_activity_category_details">Category</string>
<string name="title_activity_review">Peer Review</string> <string name="title_activity_review">Peer Review</string>
@ -493,8 +494,8 @@ Upload your first media by tapping on the add button.</string>
<string name="check_category_toast">Requesting category check for %1$s</string> <string name="check_category_toast">Requesting category check for %1$s</string>
<string name="nominate_for_deletion_done">Done</string> <string name="nominate_for_deletion_done">Done</string>
<string name="send_thank_success_title">Sending Thanks: Success</string> <string name="send_thank_success_title">Sending Thanks: Success</string>
<string name="send_thank_success_message">Successfully sent thanks to %1$s</string> <string name="send_thank_success_message">Sent thanks to %1$s</string>
<string name="send_thank_failure_message">Failed to send thanks %1$s</string> <string name="send_thank_failure_message">Failed to send thanks to %1$s</string>
<string name="send_thank_failure_title">Sending Thanks: Failure</string> <string name="send_thank_failure_title">Sending Thanks: Failure</string>
<string name="send_thank_toast">Sending Thanks for %1$s</string> <string name="send_thank_toast">Sending Thanks for %1$s</string>
@ -529,10 +530,9 @@ Upload your first media by tapping on the add button.</string>
<string name="error_occurred_in_picking_images">Error occurred while picking images</string> <string name="error_occurred_in_picking_images">Error occurred while picking images</string>
<string name="please_wait">Please wait…</string> <string name="please_wait">Please wait…</string>
<string name="images_featured_explanation">Featured pictures are images from highly skilled photographers and illustrators that the Wikimedia Commons community has chosen as some of the highest quality on the site.</string>
<string name="images_via_nearby_explanation">Images Uploaded via Nearby places are the images which are uploaded by discovering places on the map.</string> <string name="images_via_nearby_explanation">Images Uploaded via Nearby places are the images which are uploaded by discovering places on the map.</string>
<string name="thanks_received_explanation">This feature allows editors to send a Thank you notification to users who make useful edits by using a small thank link on the history page or diff page.</string> <string name="thanks_received_explanation">This feature allows editors to send a Thank you notification to users who make useful edits by using a small thank link on the history page or diff page.</string>
<string name="copy_image_caption_description">Copy to subsequent media</string> <string name="copy_image_caption_description">Copy to the next items</string>
<string name="copied_successfully">Copied</string> <string name="copied_successfully">Copied</string>
<string name="welcome_do_upload_content_description">Examples of good images to upload to Commons</string> <string name="welcome_do_upload_content_description">Examples of good images to upload to Commons</string>
<string name="welcome_dont_upload_content_description">Examples of images not to upload</string> <string name="welcome_dont_upload_content_description">Examples of images not to upload</string>
@ -619,7 +619,7 @@ Upload your first media by tapping on the add button.</string>
<string name="place_state_exists">Exists</string> <string name="place_state_exists">Exists</string>
<string name="place_state_needs_photo">Needs Photo</string> <string name="place_state_needs_photo">Needs Photo</string>
<string name="place_type">Place type:</string> <string name="place_type">Place type:</string>
<string name="nearby_search_hint">Bridge, museum, hotel etc.</string> <string name="nearby_search_hint">Bridge, museum, hotel, etc.</string>
<string name="you_must_reset_your_passsword">Something went wrong with log-in. You must reset your password!</string> <string name="you_must_reset_your_passsword">Something went wrong with log-in. You must reset your password!</string>
<string name="title_for_media">MEDIA</string> <string name="title_for_media">MEDIA</string>
<string name="title_for_child_classes">CHILD CLASSES</string> <string name="title_for_child_classes">CHILD CLASSES</string>
@ -710,6 +710,8 @@ Upload your first media by tapping on the add button.</string>
<string name="categories_tooltip">Please select the appropriate categories. Unlike depictions, categories are only in English.</string> <string name="categories_tooltip">Please select the appropriate categories. Unlike depictions, categories are only in English.</string>
<string name="license_tooltip">Commons makes your pictures reusable and adapted by everyone. Do you want to waive all rights? Do you want to be attributed? Do you want adaptations to use the same license?</string> <string name="license_tooltip">Commons makes your pictures reusable and adapted by everyone. Do you want to waive all rights? Do you want to be attributed? Do you want adaptations to use the same license?</string>
<string name="depicts_step_title">Depicts</string> <string name="depicts_step_title">Depicts</string>
<string name="depicts_label">Label</string>
<string name="depicts_description">Description</string>
<string name="license_step_title">Media License</string> <string name="license_step_title">Media License</string>
<string name="media_detail_step_title">Media Details</string> <string name="media_detail_step_title">Media Details</string>
<string name="menu_view_category_page">View category page</string> <string name="menu_view_category_page">View category page</string>
@ -736,7 +738,7 @@ Upload your first media by tapping on the add button.</string>
<string name="back">Back</string> <string name="back">Back</string>
<string name="welcome_custom_picture_selector_text">Welcome to Custom Picture Selector</string> <string name="welcome_custom_picture_selector_text">Welcome to Custom Picture Selector</string>
<string name="custom_selector_info_text1">This picker shows you which pictures you have already uploaded to Commons.</string> <string name="custom_selector_info_text1">This picker shows you which pictures you have already uploaded to Commons.</string>
<string name="custom_selector_info_text2">Unlike the picture on the left, the picture on the right has the Commons logo indicating it is already uploaded. \n Touch and hold for image preview.</string> <string name="custom_selector_info_text2">Unlike the picture on the left, the picture on the right has the Commons logo indicating it is already uploaded.\n\nTouch and hold for image preview.</string>
<string name="welcome_custom_selector_ok">Awesome</string> <string name="welcome_custom_selector_ok">Awesome</string>
<string name="custom_selector_already_uploaded_image_text">This image has already been uploaded to Commons.</string> <string name="custom_selector_already_uploaded_image_text">This image has already been uploaded to Commons.</string>
<string name="custom_selector_over_limit_warning">For technical reasons, the app can\'t reliably upload more than %1$d pictures at once. The upload limit of %1$d has been exceeded by %2$d.</string> <string name="custom_selector_over_limit_warning">For technical reasons, the app can\'t reliably upload more than %1$d pictures at once. The upload limit of %1$d has been exceeded by %2$d.</string>
@ -767,7 +769,7 @@ Upload your first media by tapping on the add button.</string>
<string name="location_message">Location data helps Wiki editors find your picture, making it much more useful.\nYour recent uploads have no location.\nWe suggest you turn on location in your camera app\'s settings.\nThank you for uploading!</string> <string name="location_message">Location data helps Wiki editors find your picture, making it much more useful.\nYour recent uploads have no location.\nWe suggest you turn on location in your camera app\'s settings.\nThank you for uploading!</string>
<string name="no_location_found_title">No location found</string> <string name="no_location_found_title">No location found</string>
<string name="no_location_found_message">How about adding the place where this image was taken?\nLocation data helps Wiki editors find your picture, making it much more useful.\nThank you!</string> <string name="no_location_found_message">How about adding the place where this image was taken?\nLocation data helps Wiki editors find your picture, making it much more useful.\nThank you!</string>
<string name="add_location">Add location</string> <string name="add_location">Add Location</string>
<string name="feedback_sharing_data_alert">Please remove from this email any information that you are not comfortable sharing publicly. Also, please be aware that your email address with which you are posting, and the associated name and profile picture, will be visible publicly.</string> <string name="feedback_sharing_data_alert">Please remove from this email any information that you are not comfortable sharing publicly. Also, please be aware that your email address with which you are posting, and the associated name and profile picture, will be visible publicly.</string>
<string name="explore_map_details">Details</string> <string name="explore_map_details">Details</string>
<string name="achievements_unavailable_beta">Achievements are only available in the prod flavor. Please check the developer documentation.</string> <string name="achievements_unavailable_beta">Achievements are only available in the prod flavor. Please check the developer documentation.</string>
@ -788,8 +790,8 @@ Upload your first media by tapping on the add button.</string>
<string name="unmark_as_not_for_upload">Unmark as not for upload</string> <string name="unmark_as_not_for_upload">Unmark as not for upload</string>
<string name="marking_as_not_for_upload">Marking as not for upload</string> <string name="marking_as_not_for_upload">Marking as not for upload</string>
<string name="unmarking_as_not_for_upload">Unmarking as not for upload</string> <string name="unmarking_as_not_for_upload">Unmarking as not for upload</string>
<string name="show_already_actioned_pictures">Show already actioned pictures</string> <string name="show_already_actioned_pictures">Show already handled pictures</string>
<string name="hiding_already_actioned_pictures">Hiding already actioned pictures</string> <string name="hiding_already_actioned_pictures">Hiding already handled pictures</string>
<string name="no_more_images_found">No more images found</string> <string name="no_more_images_found">No more images found</string>
<string name="this_image_is_already_uploaded">This image is already uploaded</string> <string name="this_image_is_already_uploaded">This image is already uploaded</string>
<string name="can_not_select_this_image_for_upload">Can not select this image for upload</string> <string name="can_not_select_this_image_for_upload">Can not select this image for upload</string>
@ -825,12 +827,12 @@ Upload your first media by tapping on the add button.</string>
<string name="invalid_login_message">Your log-in has expired. Please log in again.</string> <string name="invalid_login_message">Your log-in has expired. Please log in again.</string>
<string name="no_application_available_to_open_gpx_files">No application available to open GPX files</string> <string name="no_application_available_to_open_gpx_files">No application available to open GPX files</string>
<string name="file_saved_successfully">File Saved Successfully</string> <string name="file_saved_successfully">File Saved Successfully</string>
<string name="do_you_want_to_open_gpx_file">Do you want to open GPX file?</string> <string name="do_you_want_to_open_gpx_file">Do you want to open the GPX file?</string>
<string name="do_you_want_to_open_kml_file">Do you want to open KML file?</string> <string name="do_you_want_to_open_kml_file">Do you want to open the KML file?</string>
<string name="failed_to_save_kml_file">Failed to save KML file.</string> <string name="failed_to_save_kml_file">Failed to save the KML file.</string>
<string name="failed_to_save_gpx_file">Failed to save GPX file.</string> <string name="failed_to_save_gpx_file">Failed to save the GPX file.</string>
<string name="saving_kml_file">Saving KML File</string> <string name="saving_kml_file">Saving as a KML file...</string>
<string name="saving_gpx_file">Saving GPX File</string> <string name="saving_gpx_file">Saving as a GPX file...</string>
<plurals name="custom_picker_images_selected_title_appendix"> <plurals name="custom_picker_images_selected_title_appendix">
<item quantity="one">%d image selected</item> <item quantity="one">%d image selected</item>
<item quantity="other">%d images selected</item> <item quantity="other">%d images selected</item>
@ -873,7 +875,6 @@ Upload your first media by tapping on the add button.</string>
<string name="usages_on_other_wikis_heading">Other wikis</string> <string name="usages_on_other_wikis_heading">Other wikis</string>
<string name="bullet_point"></string> <string name="bullet_point"></string>
<string name="file_usages_container_heading">File usages</string> <string name="file_usages_container_heading">File usages</string>
<string name="title_activity_single_web_view">SingleWebViewActivity</string>
<string name="account">Account</string> <string name="account">Account</string>
<string name="vanish_account">Vanish Account</string> <string name="vanish_account">Vanish Account</string>
<string name="account_vanish_request_confirm_title">Vanish account warning</string> <string name="account_vanish_request_confirm_title">Vanish account warning</string>

View file

@ -193,8 +193,8 @@ class DescriptionEditActivityUnitTest {
method.isAccessible = true method.isAccessible = true
method.invoke( method.invoke(
activity, activity,
android.R.string.ok, R.string.ok,
android.R.string.ok, R.string.ok,
) )
val dialog: AlertDialog = ShadowAlertDialog.getLatestDialog() as AlertDialog val dialog: AlertDialog = ShadowAlertDialog.getLatestDialog() as AlertDialog
assertEquals(dialog.isShowing, true) assertEquals(dialog.isShowing, true)

View file

@ -145,6 +145,8 @@ class UploadMediaDetailFragmentUnitTest {
ibExpandCollapse = view.findViewById(R.id.ib_expand_collapse) ibExpandCollapse = view.findViewById(R.id.ib_expand_collapse)
Whitebox.setInternalState(fragment, "uploadMediaDetailAdapter", uploadMediaDetailAdapter) Whitebox.setInternalState(fragment, "uploadMediaDetailAdapter", uploadMediaDetailAdapter)
Whitebox.setInternalState(fragment, "defaultKvStore", defaultKvStore)
`when`(defaultKvStore.getString("description_language", "")).thenReturn("en")
} }
@Test @Test
@ -160,16 +162,10 @@ class UploadMediaDetailFragmentUnitTest {
fragment.onCreate(Bundle()) fragment.onCreate(Bundle())
} }
@Test
@Throws(Exception::class)
fun testSetImageToBeUploaded() {
Shadows.shadowOf(Looper.getMainLooper()).idle()
fragment.setImageToBeUploaded(null, null, location)
}
@Test @Test
@Throws(Exception::class) @Throws(Exception::class)
fun testOnCreateView() { fun testOnCreateView() {
Shadows.shadowOf(Looper.getMainLooper()).idle()
fragment.onCreateView(layoutInflater, null, savedInstanceState) fragment.onCreateView(layoutInflater, null, savedInstanceState)
} }
@ -181,34 +177,6 @@ class UploadMediaDetailFragmentUnitTest {
fragment.onViewCreated(view, savedInstanceState) fragment.onViewCreated(view, savedInstanceState)
} }
@Test
@Throws(Exception::class)
fun testInit() {
Shadows.shadowOf(Looper.getMainLooper()).idle()
Whitebox.setInternalState(fragment, "presenter", presenter)
val method: Method =
UploadMediaDetailFragment::class.java.getDeclaredMethod(
"initializeFragment",
)
method.isAccessible = true
method.invoke(fragment)
}
@Test
@Throws(Exception::class)
fun testInitCaseGetIndexInViewFlipperNonZero() {
Shadows.shadowOf(Looper.getMainLooper()).idle()
Whitebox.setInternalState(fragment, "presenter", presenter)
`when`(callback.getIndexInViewFlipper(fragment)).thenReturn(1)
`when`(callback.totalNumberOfSteps).thenReturn(5)
val method: Method =
UploadMediaDetailFragment::class.java.getDeclaredMethod(
"initializeFragment",
)
method.isAccessible = true
method.invoke(fragment)
}
@Test @Test
@Throws(Exception::class) @Throws(Exception::class)
fun testShowInfoAlert() { fun testShowInfoAlert() {
@ -317,7 +285,7 @@ class UploadMediaDetailFragmentUnitTest {
@Test @Test
@Throws(Exception::class) @Throws(Exception::class)
fun testShowExternalMap() { fun testShowExternalMap() {
shadowOf(Looper.getMainLooper()).idle() Shadows.shadowOf(Looper.getMainLooper()).idle()
`when`(uploadItem.gpsCoords).thenReturn(imageCoordinates) `when`(uploadItem.gpsCoords).thenReturn(imageCoordinates)
`when`(imageCoordinates.decLatitude).thenReturn(0.0) `when`(imageCoordinates.decLatitude).thenReturn(0.0)
`when`(imageCoordinates.decLongitude).thenReturn(0.0) `when`(imageCoordinates.decLongitude).thenReturn(0.0)
@ -328,7 +296,7 @@ class UploadMediaDetailFragmentUnitTest {
@Test @Test
@Throws(Exception::class) @Throws(Exception::class)
fun testOnCameraPositionCallbackOnMapIconClicked() { fun testOnCameraPositionCallbackOnMapIconClicked() {
shadowOf(Looper.getMainLooper()).idle() Shadows.shadowOf(Looper.getMainLooper()).idle()
Mockito.mock(LocationPicker::class.java) Mockito.mock(LocationPicker::class.java)
val intent = Mockito.mock(Intent::class.java) val intent = Mockito.mock(Intent::class.java)
val cameraPosition = Mockito.mock(CameraPosition::class.java) val cameraPosition = Mockito.mock(CameraPosition::class.java)
@ -357,7 +325,7 @@ class UploadMediaDetailFragmentUnitTest {
@Test @Test
@Throws(Exception::class) @Throws(Exception::class)
fun testOnCameraPositionCallbackAddLocationDialog() { fun testOnCameraPositionCallbackAddLocationDialog() {
shadowOf(Looper.getMainLooper()).idle() Shadows.shadowOf(Looper.getMainLooper()).idle()
Mockito.mock(LocationPicker::class.java) Mockito.mock(LocationPicker::class.java)
val intent = Mockito.mock(Intent::class.java) val intent = Mockito.mock(Intent::class.java)
val cameraPosition = Mockito.mock(CameraPosition::class.java) val cameraPosition = Mockito.mock(CameraPosition::class.java)
@ -427,7 +395,7 @@ class UploadMediaDetailFragmentUnitTest {
@Test @Test
@Throws(Exception::class) @Throws(Exception::class)
fun testRememberedZoomLevelOnNull() { fun testRememberedZoomLevelOnNull() {
shadowOf(Looper.getMainLooper()).idle() Shadows.shadowOf(Looper.getMainLooper()).idle()
Whitebox.setInternalState(fragment, "defaultKvStore", defaultKvStore) Whitebox.setInternalState(fragment, "defaultKvStore", defaultKvStore)
`when`(uploadItem.gpsCoords).thenReturn(null) `when`(uploadItem.gpsCoords).thenReturn(null)
`when`(defaultKvStore.getString(LAST_ZOOM)).thenReturn("13.0") `when`(defaultKvStore.getString(LAST_ZOOM)).thenReturn("13.0")
@ -443,7 +411,7 @@ class UploadMediaDetailFragmentUnitTest {
@Test @Test
@Throws(Exception::class) @Throws(Exception::class)
fun testRememberedZoomLevelOnNotNull() { fun testRememberedZoomLevelOnNotNull() {
shadowOf(Looper.getMainLooper()).idle() Shadows.shadowOf(Looper.getMainLooper()).idle()
`when`(uploadItem.gpsCoords).thenReturn(imageCoordinates) `when`(uploadItem.gpsCoords).thenReturn(imageCoordinates)
`when`(imageCoordinates.decLatitude).thenReturn(8.0) `when`(imageCoordinates.decLatitude).thenReturn(8.0)
`when`(imageCoordinates.decLongitude).thenReturn(-8.0) `when`(imageCoordinates.decLongitude).thenReturn(-8.0)