From 3779cfb6a5adec86cd5dd9f95b32ed32a21eafa7 Mon Sep 17 00:00:00 2001 From: Kanahia <114223204+kanahia1@users.noreply.github.com> Date: Mon, 8 Jul 2024 11:43:57 +0530 Subject: [PATCH 1/3] Added Wikitalk Page (#5740) * Added wikitalk page and improved bottomsheet for landscape mode * Improved wikitalk page * Fixed italics * Fixed little bug * Improved the wiki talk page * . * changed commons url to wikidata url * changed commons url to wikidata url + 1 * fixed bookmark issue * Added kdoc and javadoc --------- Co-authored-by: Nicolas Raoul --- app/src/main/AndroidManifest.xml | 440 +++++++++--------- .../nrw/commons/actions/PageEditClient.kt | 37 +- .../nrw/commons/actions/PageEditInterface.kt | 27 ++ .../nrw/commons/di/ActivityBuilderModule.java | 4 + .../di/CommonsApplicationComponent.java | 5 + .../free/nrw/commons/di/NetworkingModule.java | 49 +- .../commons/mwapi/OkHttpJsonApiClient.java | 4 +- .../nrw/commons/nearby/BottomSheetAdapter.kt | 108 +++++ .../nrw/commons/nearby/PageEditHelper.java | 164 +++++++ .../nrw/commons/nearby/WikidataFeedback.kt | 96 ++++ .../fragments/NearbyParentFragment.java | 432 ++++++++++------- .../commons/nearby/model/BottomSheetItem.kt | 3 + .../res/layout/activity_wikidata_feedback.xml | 111 +++++ .../main/res/layout/bottom_sheet_details.xml | 172 +------ .../res/layout/bottom_sheet_item_layout.xml | 27 ++ app/src/main/res/values/strings.xml | 8 + 16 files changed, 1142 insertions(+), 545 deletions(-) create mode 100644 app/src/main/java/fr/free/nrw/commons/nearby/BottomSheetAdapter.kt create mode 100644 app/src/main/java/fr/free/nrw/commons/nearby/PageEditHelper.java create mode 100644 app/src/main/java/fr/free/nrw/commons/nearby/WikidataFeedback.kt create mode 100644 app/src/main/java/fr/free/nrw/commons/nearby/model/BottomSheetItem.kt create mode 100644 app/src/main/res/layout/activity_wikidata_feedback.xml create mode 100644 app/src/main/res/layout/bottom_sheet_item_layout.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5ba49201a..02f31185a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,262 +1,266 @@ - - - - - - - - - - - - - - - - - - + xmlns:tools="http://schemas.android.com/tools"> + + + + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - + - + - + - + - + - - - + - - + + + - + + - - + - - - + + - + + + - - - - - + - + + + + + - - - - - - - + - + + + + + + + - + - + - + - + - + - + - + - + - + - + - - - - - - + - + + + + + + - - - + - + + + - + - + - + - + - + - - - - + - - + + + + - + + - + - + + + \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/actions/PageEditClient.kt b/app/src/main/java/fr/free/nrw/commons/actions/PageEditClient.kt index cb153b7cb..93e833c15 100644 --- a/app/src/main/java/fr/free/nrw/commons/actions/PageEditClient.kt +++ b/app/src/main/java/fr/free/nrw/commons/actions/PageEditClient.kt @@ -4,6 +4,7 @@ import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException import io.reactivex.Observable import io.reactivex.Single import fr.free.nrw.commons.auth.csrf.CsrfTokenClient +import timber.log.Timber /** * This class acts as a Client to facilitate wiki page editing @@ -27,7 +28,41 @@ class PageEditClient( fun edit(pageTitle: String, text: String, summary: String): Observable { return try { pageEditInterface.postEdit(pageTitle, summary, text, csrfTokenClient.getTokenBlocking()) - .map { editResponse -> editResponse.edit()!!.editSucceeded() } + .map { editResponse -> + editResponse.edit()!!.editSucceeded() + } + } catch (throwable: Throwable) { + if (throwable is InvalidLoginTokenException) { + throw throwable + } else { + Observable.just(false) + } + } + } + + /** + * Creates a new page with the given title, text, and summary. + * + * @param pageTitle The title of the page to be created. + * @param text The content of the page in wikitext format. + * @param summary The edit summary for the page creation. + * @return An observable that emits true if the page creation succeeded, false otherwise. + * @throws InvalidLoginTokenException If an invalid login token is encountered during the process. + */ + fun postCreate(pageTitle: String, text: String, summary: String): Observable { + return try { + pageEditInterface.postCreate( + pageTitle, + summary, + text, + "text/x-wiki", + "wikitext", + true, + true, + csrfTokenClient.getTokenBlocking() + ).map { editResponse -> + editResponse.edit()!!.editSucceeded() + } } catch (throwable: Throwable) { if (throwable is InvalidLoginTokenException) { throw throwable diff --git a/app/src/main/java/fr/free/nrw/commons/actions/PageEditInterface.kt b/app/src/main/java/fr/free/nrw/commons/actions/PageEditInterface.kt index 070aaaa64..1aa0bbfce 100644 --- a/app/src/main/java/fr/free/nrw/commons/actions/PageEditInterface.kt +++ b/app/src/main/java/fr/free/nrw/commons/actions/PageEditInterface.kt @@ -36,6 +36,33 @@ interface PageEditInterface { @Field("token") token: String ): Observable + /** + * This method creates or edits a page for nearby items. + * + * @param title Title of the page to edit. Cannot be used together with pageid. + * @param summary Edit summary. Also used as the section title when section=new and sectiontitle is not set. + * @param text Text of the page. + * @param contentformat Format of the content (e.g., "text/x-wiki"). + * @param contentmodel Model of the content (e.g., "wikitext"). + * @param minor Whether the edit is a minor edit. + * @param recreate Whether to recreate the page if it does not exist. + * @param token A "csrf" token. This should always be sent as the last field of form data. + */ + @FormUrlEncoded + @Headers("Cache-Control: no-cache") + @POST(MW_API_PREFIX + "action=edit") + fun postCreate( + @Field("title") title: String, + @Field("summary") summary: String, + @Field("text") text: String, + @Field("contentformat") contentformat: String, + @Field("contentmodel") contentmodel: String, + @Field("minor") minor: Boolean, + @Field("recreate") recreate: Boolean, + // NOTE: This csrf shold always be sent as the last field of form data + @Field("token") token: String + ): Observable + /** * This method posts such that the Content which the page * has will be appended with the value being passed to the diff --git a/app/src/main/java/fr/free/nrw/commons/di/ActivityBuilderModule.java b/app/src/main/java/fr/free/nrw/commons/di/ActivityBuilderModule.java index 6a9277906..0df9685c1 100644 --- a/app/src/main/java/fr/free/nrw/commons/di/ActivityBuilderModule.java +++ b/app/src/main/java/fr/free/nrw/commons/di/ActivityBuilderModule.java @@ -14,6 +14,7 @@ import fr.free.nrw.commons.description.DescriptionEditActivity; import fr.free.nrw.commons.explore.depictions.WikidataItemDetailsActivity; import fr.free.nrw.commons.explore.SearchActivity; import fr.free.nrw.commons.media.ZoomableActivity; +import fr.free.nrw.commons.nearby.WikidataFeedback; import fr.free.nrw.commons.notification.NotificationActivity; import fr.free.nrw.commons.profile.ProfileActivity; import fr.free.nrw.commons.review.ReviewActivity; @@ -79,4 +80,7 @@ public abstract class ActivityBuilderModule { @ContributesAndroidInjector abstract ZoomableActivity bindZoomableActivity(); + + @ContributesAndroidInjector + abstract WikidataFeedback bindWikiFeedback(); } diff --git a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java index cbbf1f0c5..1390bd8ef 100644 --- a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java +++ b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java @@ -2,9 +2,11 @@ package fr.free.nrw.commons.di; import com.google.gson.Gson; +import fr.free.nrw.commons.actions.PageEditClient; import fr.free.nrw.commons.explore.categories.CategoriesModule; import fr.free.nrw.commons.navtab.MoreBottomSheetFragment; import fr.free.nrw.commons.navtab.MoreBottomSheetLoggedOutFragment; +import fr.free.nrw.commons.nearby.NearbyController; import fr.free.nrw.commons.upload.worker.UploadWorker; import javax.inject.Singleton; @@ -68,6 +70,9 @@ public interface CommonsApplicationComponent extends AndroidInjector" + "\n"; - List placeBindings = runQuery(leftLatLng,rightLatLng); + List placeBindings = runQuery(leftLatLng, rightLatLng); if (placeBindings != null) { for (PlaceBindings item : placeBindings) { if (item.getItem() != null && item.getLabel() != null && item.getClas() != null) { diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/BottomSheetAdapter.kt b/app/src/main/java/fr/free/nrw/commons/nearby/BottomSheetAdapter.kt new file mode 100644 index 000000000..ca21f25ad --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/nearby/BottomSheetAdapter.kt @@ -0,0 +1,108 @@ +package fr.free.nrw.commons.nearby + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.View.OnLongClickListener +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.annotation.NonNull +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.RecyclerView +import fr.free.nrw.commons.R +import fr.free.nrw.commons.nearby.model.BottomSheetItem + +/** + * RecyclerView Adapter for displaying items in a bottom sheet. + * + * @property context The context used for inflating layout resources. + * @property itemList The list of BottomSheetItem objects to display. + * @constructor Creates an instance of BottomSheetAdapter. + */ +class BottomSheetAdapter(context: Context?, private val itemList: List) : + RecyclerView.Adapter() { + private val layoutInflater: LayoutInflater = LayoutInflater.from(context) + private var itemClickListener: ItemClickListener? = null + + @NonNull + override fun onCreateViewHolder(@NonNull parent: ViewGroup, viewType: Int): ViewHolder { + val view: View = layoutInflater.inflate(R.layout.bottom_sheet_item_layout, parent, false) + return ViewHolder(view) + } + + override fun onBindViewHolder(@NonNull holder: ViewHolder, position: Int) { + val item = itemList[position] + holder.imageView.setImageDrawable( + ContextCompat.getDrawable( + getContext(), + item.imageResourceId + ) + ) + holder.title.setText(item.title) + } + + /** + * Returns the total number of items in the data set held by the adapter. + * + * @return The total number of items in this adapter. + */ + override fun getItemCount(): Int { + return itemList.size + } + + /** + * Updates the icon for bookmark item. + * + * @param icon The resource ID of the new icon to set. + */ + fun updateBookmarkIcon(icon: Int) { + itemList.forEachIndexed { index, item -> + if (item.imageResourceId == R.drawable.ic_round_star_filled_24px || item.imageResourceId == R.drawable.ic_round_star_border_24px) { + item.imageResourceId = icon + this.notifyItemChanged(index) + return + } + } + } + + inner class ViewHolder internal constructor(itemView: View) : RecyclerView.ViewHolder(itemView), + View.OnClickListener, OnLongClickListener { + var imageView: ImageView = itemView.findViewById(R.id.buttonImage) + var title: TextView = itemView.findViewById(R.id.buttonText) + + init { + itemView.setOnClickListener(this) + itemView.setOnLongClickListener(this) + } + + override fun onClick(view: View) { + if (itemClickListener != null) itemClickListener!!.onBottomSheetItemClick( + view, + adapterPosition + ) + } + + override fun onLongClick(view: View): Boolean { + if (itemClickListener != null) itemClickListener!!.onBottomSheetItemLongClick( + view, + adapterPosition + ) + return true + } + } + + fun setClickListener(itemClickListener: ItemClickListener?) { + this.itemClickListener = itemClickListener + } + + fun getContext(): Context { + return layoutInflater.context + } + + interface ItemClickListener { + fun onBottomSheetItemClick(view: View?, position: Int) + fun onBottomSheetItemLongClick(view: View?, position: Int) + } +} + diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/PageEditHelper.java b/app/src/main/java/fr/free/nrw/commons/nearby/PageEditHelper.java new file mode 100644 index 000000000..9d4b1069c --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/nearby/PageEditHelper.java @@ -0,0 +1,164 @@ +package fr.free.nrw.commons.nearby; + + +import static fr.free.nrw.commons.notification.NotificationHelper.NOTIFICATION_DELETE; + +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.Uri; +import androidx.appcompat.app.AlertDialog; +import fr.free.nrw.commons.BuildConfig; +import fr.free.nrw.commons.R; +import fr.free.nrw.commons.actions.PageEditClient; +import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException; +import fr.free.nrw.commons.notification.NotificationHelper; +import fr.free.nrw.commons.utils.ViewUtilWrapper; +import io.reactivex.Observable; +import io.reactivex.Single; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; +import timber.log.Timber; + +/** + * Singleton class for making edits to wiki pages asynchronously using RxJava. + * + * @property notificationHelper A helper class for displaying notifications. + * @property pageEditClient A client for making page edit requests. + * @property viewUtil A utility class for common view operations. + * @property username The username used for page edits. + * @constructor Initializes the PageEditHelper with required dependencies. + */ +@Singleton +public class PageEditHelper { + + private final NotificationHelper notificationHelper; + private final PageEditClient pageEditClient; + private final ViewUtilWrapper viewUtil; + private final String username; + private AlertDialog d; + private DialogInterface.OnMultiChoiceClickListener listener; + + @Inject + public PageEditHelper(NotificationHelper notificationHelper, + @Named("wikidata-page-edit") PageEditClient pageEditClient, + ViewUtilWrapper viewUtil, + @Named("username") String username) { + this.notificationHelper = notificationHelper; + this.pageEditClient = pageEditClient; + this.viewUtil = viewUtil; + this.username = username; + } + + /** + * Public interface to make a page edit request asynchronously. + * + * @param context The context for displaying messages. + * @param title The title of the page to edit. + * @param preText The existing content of the page. + * @param description The description of the issue to be fixed. + * @param details Additional details about the issue. + * @param lat The latitude of the location related to the page. + * @param lng The longitude of the location related to the page. + * @return A Single emitting true if the edit was successful, false otherwise. + */ + public Single makePageEdit(Context context, String title, String preText, + String description, + String details, Double lat, Double lng) { + viewUtil.showShortToast(context, "Trying to edit " + title); + + return editPage(title, preText, description, details, lat, lng) + .flatMapSingle(result -> Single.just(showNotification(context, title, result))) + .firstOrError() + .onErrorResumeNext(throwable -> { + if (throwable instanceof InvalidLoginTokenException) { + return Single.error(throwable); + } + return Single.error(throwable); + }); + } + + /** + * Creates the text content for the page edit based on provided parameters. + * + * @param title The title of the page to edit. + * @param preText The existing content of the page. + * @param description The description of the issue to be fixed. + * @param details Additional details about the issue. + * @param lat The latitude of the location related to the page. + * @param lng The longitude of the location related to the page. + * @return An Observable emitting true if the edit was successful, false otherwise. + */ + private Observable editPage(String title, String preText, String description, + String details, Double lat, Double lng) { + Timber.d("thread is edit %s", Thread.currentThread().getName()); + String summary = "Please fix this item"; + String text = ""; + String marker = "Please anyone fix the item accordingly, then reply to mark this section as fixed. Thanks a lot for your cooperation!"; + int markerIndex = preText.indexOf(marker); + if (preText == "" || markerIndex == -1) { + text = "==Please fix this item==\n" + + "Someone using the [[Commons:Mobile_app|Commons Android app]] went to this item's geographical location (" + + lat + "," + lng + + ") and noted the following problem(s):\n" + + "* " + description + "\n" + + "\n" + + "Details: " + details + "\n" + + "\n" + + "Please anyone fix the item accordingly, then reply to mark this section as fixed. Thanks a lot for your cooperation!\n" + + "\n" + + "~~~~"; + } else { + text = preText.substring(0, markerIndex); + text = text + "* " + description + "\n" + + "\n" + + "Details: " + details + "\n" + + "\n" + + "Please anyone fix the item accordingly, then reply to mark this section as fixed. Thanks a lot for your cooperation!\n" + + "\n" + + "~~~~"; + } + + return pageEditClient.postCreate(title, text, summary); + } + + /** + * Displays a notification based on the result of the page edit. + * + * @param context The context for displaying the notification. + * @param title The title of the page edited. + * @param result The result of the edit operation. + * @return true if the edit was successful, false otherwise. + */ + private boolean showNotification(Context context, String title, boolean result) { + String message; + + if (result) { + message = title + " Edited Successfully"; + } else { + message = context.getString(R.string.delete_helper_show_deletion_message_else); + } + + String url = BuildConfig.WIKIDATA_URL + "/wiki/" + title; + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + notificationHelper.showNotification(context, title, message, NOTIFICATION_DELETE, + browserIntent); + return result; + } + + /** + * returns the instance of shown AlertDialog, used for taking reference during unit test + */ + public AlertDialog getDialog() { + return d; + } + + /** + * returns the instance of shown DialogInterface.OnMultiChoiceClickListener, used for taking + * reference during unit test + */ + public DialogInterface.OnMultiChoiceClickListener getListener() { + return listener; + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/WikidataFeedback.kt b/app/src/main/java/fr/free/nrw/commons/nearby/WikidataFeedback.kt new file mode 100644 index 000000000..7c62b3646 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/nearby/WikidataFeedback.kt @@ -0,0 +1,96 @@ +package fr.free.nrw.commons.nearby + +import android.annotation.SuppressLint +import android.os.Bundle +import android.widget.RadioButton +import android.widget.Toast +import fr.free.nrw.commons.R +import fr.free.nrw.commons.databinding.ActivityWikidataFeedbackBinding +import fr.free.nrw.commons.theme.BaseActivity +import io.reactivex.Single +import io.reactivex.SingleSource +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.schedulers.Schedulers +import timber.log.Timber +import java.util.concurrent.Callable +import javax.inject.Inject + +/** + * Activity for providing feedback about Wikidata items. + */ +class WikidataFeedback : BaseActivity() { + private lateinit var binding: ActivityWikidataFeedbackBinding + var place: String = "" + var wikidataQId: String = "" + var pageTitle: String = "" + var preText: String = "" + var lat: Double = 0.0 + var lng: Double = 0.0 + + @Inject + lateinit var pageEditHelper: PageEditHelper + + @Inject + lateinit var nearbyController: NearbyController + + @SuppressLint("CheckResult") + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityWikidataFeedbackBinding.inflate(layoutInflater) + setContentView(binding.root) + lat = intent.getDoubleExtra("lat", 0.0) + lng = intent.getDoubleExtra("lng", 0.0) + place = intent.getStringExtra("place") ?: "" + wikidataQId = intent.getStringExtra("qid") ?: "" + pageTitle = getString(R.string.talk) + ":" + wikidataQId + binding.toolbarBinding.toolbar.title = pageTitle + binding.textHeader.text = + getString(R.string.write_something_about_the) + "'$place'" + getString(R.string.item_it_will_be_publicly_visible) + binding.radioButton1.setText( + getString( + R.string.does_not_exist_anymore_no_picture_can_ever_be_taken_of_it, + place + )) + binding.radioButton2.setText( + getString( + R.string.is_at_a_different_place_please_specify_the_correct_place_below_if_possible_tell_us_the_correct_latitude_longitude, + place + )) + binding.radioButton3.setText(getString(R.string.other_problem_or_information_please_explain_below)) + setSupportActionBar(binding.toolbarBinding.toolbar) + supportActionBar!!.setDisplayHomeAsUpEnabled(true) + + binding.appCompatButton.setOnClickListener { + var desc = findViewById(binding.radioGroup.checkedRadioButtonId).text + var det = binding.detailsEditText.text.toString() + if (binding.radioGroup.checkedRadioButtonId == R.id.radioButton3 && binding.detailsEditText.text.isNullOrEmpty()) { + Toast.makeText( + this, + getString(R.string.please_enter_some_comments), Toast.LENGTH_SHORT + ).show() + } else { + binding.radioGroup.clearCheck() + binding.detailsEditText.setText("") + Single.defer(Callable> { + pageEditHelper.makePageEdit( + this, pageTitle, preText, + desc.toString(), + det, lat, lng + ) + } as Callable>) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ aBoolean: Boolean? -> + }, { throwable: Throwable? -> + Timber.e(throwable!!) + }) + } + } + } + + override fun onSupportNavigateUp(): Boolean { + onBackPressed() + return true + } + +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java index 877f22f5a..d1e28eb7e 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java @@ -48,6 +48,7 @@ import androidx.appcompat.app.AlertDialog; import androidx.core.content.ContextCompat; import androidx.core.content.FileProvider; import androidx.recyclerview.widget.DividerItemDecoration; +import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager; import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.snackbar.Snackbar; @@ -70,6 +71,7 @@ import fr.free.nrw.commons.location.LocationPermissionsHelper; import fr.free.nrw.commons.location.LocationPermissionsHelper.LocationPermissionCallback; import fr.free.nrw.commons.location.LocationServiceManager; import fr.free.nrw.commons.location.LocationUpdateListener; +import fr.free.nrw.commons.nearby.BottomSheetAdapter; import fr.free.nrw.commons.nearby.CheckBoxTriStates; import fr.free.nrw.commons.nearby.Label; import fr.free.nrw.commons.nearby.MarkerPlaceGroup; @@ -77,8 +79,10 @@ import fr.free.nrw.commons.nearby.NearbyController; import fr.free.nrw.commons.nearby.NearbyFilterSearchRecyclerViewAdapter; import fr.free.nrw.commons.nearby.NearbyFilterState; import fr.free.nrw.commons.nearby.Place; +import fr.free.nrw.commons.nearby.WikidataFeedback; import fr.free.nrw.commons.nearby.contract.NearbyParentFragmentContract; import fr.free.nrw.commons.nearby.fragments.AdvanceQueryFragment.Callback; +import fr.free.nrw.commons.nearby.model.BottomSheetItem; import fr.free.nrw.commons.nearby.presenter.NearbyParentFragmentPresenter; import fr.free.nrw.commons.upload.FileUtils; import fr.free.nrw.commons.utils.DialogUtil; @@ -131,7 +135,7 @@ import timber.log.Timber; public class NearbyParentFragment extends CommonsDaggerSupportFragment implements NearbyParentFragmentContract.View, WikidataEditListener.WikidataP18EditListener, LocationUpdateListener, - LocationPermissionCallback { + LocationPermissionCallback, BottomSheetAdapter.ItemClickListener { FragmentNearbyParentBinding binding; @@ -189,6 +193,9 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment private NearbyParentFragmentInstanceReadyCallback nearbyParentFragmentInstanceReadyCallback; private boolean isAdvancedQueryFragmentVisible = false; private Place nearestPlace; + private GridLayoutManager gridLayoutManager; + private List dataList; + private BottomSheetAdapter bottomSheetAdapter; private ActivityResultLauncher inAppCameraLocationPermissionLauncher = registerForActivityResult( new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback>() { @@ -203,7 +210,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment controller.locationPermissionCallback.onLocationPermissionGranted(); } else { if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) { - controller.handleShowRationaleFlowCameraLocation(getActivity(), inAppCameraLocationPermissionLauncher); + controller.handleShowRationaleFlowCameraLocation(getActivity(), + inAppCameraLocationPermissionLauncher); } else { controller.locationPermissionCallback.onLocationPermissionDenied( getActivity().getString( @@ -434,10 +442,10 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment moveCameraToPosition(lastMapFocus); initRvNearbyList(); onResume(); - binding.tvAttribution.setText(Html.fromHtml(getString(R.string.map_attribution))); - binding.tvAttribution.setMovementMethod(LinkMovementMethod.getInstance()); + binding.tvAttribution.setText(Html.fromHtml(getString(R.string.map_attribution))); + binding.tvAttribution.setMovementMethod(LinkMovementMethod.getInstance()); binding.nearbyFilterList.btnAdvancedOptions.setOnClickListener(v -> { - binding.nearbyFilter.searchViewLayout.searchView.clearFocus(); + binding.nearbyFilter.searchViewLayout.searchView.clearFocus(); showHideAdvancedQueryFragment(true); final AdvanceQueryFragment fragment = new AdvanceQueryFragment(); final Bundle bundle = new Bundle(); @@ -473,7 +481,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment .commit(); }); - binding.tvLearnMore.setOnClickListener(v ->onLearnMoreClicked()); + binding.tvLearnMore.setOnClickListener(v -> onLearnMoreClicked()); binding.nearbyFilter.ivToggleChips.setOnClickListener(v -> onToggleChipsClicked()); if (!locationPermissionsHelper.checkLocationPermission(getActivity())) { @@ -510,7 +518,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment } private void initRvNearbyList() { - binding.bottomSheetNearby.rvNearbyList.setLayoutManager(new LinearLayoutManager(getContext())); + binding.bottomSheetNearby.rvNearbyList.setLayoutManager( + new LinearLayoutManager(getContext())); adapter = new PlaceAdapter(bookmarkLocationDao, place -> { moveCameraToPosition( @@ -566,7 +575,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment locationManager.requestLocationUpdatesFromProvider(LocationManager.GPS_PROVIDER); setProgressBarVisibility(true); } else { - locationPermissionsHelper.showLocationOffDialog(getActivity(), R.string.ask_to_turn_location_on_text); + locationPermissionsHelper.showLocationOffDialog(getActivity(), + R.string.ask_to_turn_location_on_text); } presenter.onMapReady(); registerUnregisterLocationListener(false); @@ -591,7 +601,6 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment * Starts the map without GPS and without permission By default it points to 51.50550,-0.07520 * coordinates, other than that it points to the last known location which can be get by the key * "LastLocation" from applicationKvStore - * */ private void startMapWithoutPermission() { if (applicationKvStore.getString("LastLocation") != null) { @@ -649,7 +658,6 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment initBottomSheets(); loadAnimations(); setBottomSheetCallbacks(); - decideButtonVisibilities(); addActionToTitle(); if (!Utils.isMonumentsEnabled(new Date())) { NearbyFilterState.setWlmSelected(false); @@ -673,26 +681,46 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment bottomSheetListBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); } + /** + * Determines the number of spans (columns) in the RecyclerView based on device orientation + * and adapter item count. + * + * @return The number of spans to be used in the RecyclerView. + */ + private int getSpanCount() { + int orientation = getResources().getConfiguration().orientation; + if (bottomSheetAdapter != null) { + return (orientation == Configuration.ORIENTATION_PORTRAIT) ? 3 + : bottomSheetAdapter.getItemCount(); + } else { + return (orientation == Configuration.ORIENTATION_PORTRAIT) ? 3 : 6; + } + } + public void initNearbyFilter() { binding.nearbyFilterList.getRoot().setVisibility(View.GONE); hideBottomSheet(); - binding.nearbyFilter.searchViewLayout.searchView.setOnQueryTextFocusChangeListener((v, hasFocus) -> { - LayoutUtils.setLayoutHeightAllignedToWidth(1.25, binding.nearbyFilterList.getRoot()); - if (hasFocus) { - binding.nearbyFilterList.getRoot().setVisibility(View.VISIBLE); - presenter.searchViewGainedFocus(); - } else { - binding.nearbyFilterList.getRoot().setVisibility(View.GONE); - } - }); - binding.nearbyFilterList.searchListView.setHasFixedSize(true); - binding.nearbyFilterList.searchListView.addItemDecoration(new DividerItemDecoration(getContext(), - DividerItemDecoration.VERTICAL)); + binding.nearbyFilter.searchViewLayout.searchView.setOnQueryTextFocusChangeListener( + (v, hasFocus) -> { + LayoutUtils.setLayoutHeightAllignedToWidth(1.25, + binding.nearbyFilterList.getRoot()); + if (hasFocus) { + binding.nearbyFilterList.getRoot().setVisibility(View.VISIBLE); + presenter.searchViewGainedFocus(); + } else { + binding.nearbyFilterList.getRoot().setVisibility(View.GONE); + } + }); + binding.nearbyFilterList.searchListView.setHasFixedSize(true); + binding.nearbyFilterList.searchListView.addItemDecoration( + new DividerItemDecoration(getContext(), + DividerItemDecoration.VERTICAL)); final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity()); linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); - binding.nearbyFilterList.searchListView.setLayoutManager(linearLayoutManager); + binding.nearbyFilterList.searchListView.setLayoutManager(linearLayoutManager); nearbyFilterSearchRecyclerViewAdapter = new NearbyFilterSearchRecyclerViewAdapter( - getContext(), new ArrayList<>(Label.valuesAsList()), binding.nearbyFilterList.searchListView); + getContext(), new ArrayList<>(Label.valuesAsList()), + binding.nearbyFilterList.searchListView); nearbyFilterSearchRecyclerViewAdapter.setCallback( new NearbyFilterSearchRecyclerViewAdapter.Callback() { @Override @@ -711,18 +739,20 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment return isDarkTheme; } }); - binding.nearbyFilterList.getRoot().getLayoutParams().width = (int) LayoutUtils.getScreenWidth(getActivity(), + binding.nearbyFilterList.getRoot() + .getLayoutParams().width = (int) LayoutUtils.getScreenWidth(getActivity(), 0.75); - binding.nearbyFilterList.searchListView.setAdapter(nearbyFilterSearchRecyclerViewAdapter); + binding.nearbyFilterList.searchListView.setAdapter(nearbyFilterSearchRecyclerViewAdapter); LayoutUtils.setLayoutHeightAllignedToWidth(1.25, binding.nearbyFilterList.getRoot()); - compositeDisposable.add(RxSearchView.queryTextChanges( binding.nearbyFilter.searchViewLayout.searchView) - .takeUntil(RxView.detaches(binding.nearbyFilter.searchViewLayout.searchView)) - .debounce(500, TimeUnit.MILLISECONDS) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(query -> { - ((NearbyFilterSearchRecyclerViewAdapter) binding.nearbyFilterList.searchListView.getAdapter()).getFilter() - .filter(query.toString()); - })); + compositeDisposable.add( + RxSearchView.queryTextChanges(binding.nearbyFilter.searchViewLayout.searchView) + .takeUntil(RxView.detaches(binding.nearbyFilter.searchViewLayout.searchView)) + .debounce(500, TimeUnit.MILLISECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(query -> { + ((NearbyFilterSearchRecyclerViewAdapter) binding.nearbyFilterList.searchListView.getAdapter()).getFilter() + .filter(query.toString()); + })); initFilterChips(); } @@ -739,9 +769,12 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment @Override public void setFilterState() { - binding.nearbyFilter.chipView.choiceChipNeedsPhoto.setChecked(NearbyFilterState.getInstance().isNeedPhotoSelected()); - binding.nearbyFilter.chipView.choiceChipExists.setChecked(NearbyFilterState.getInstance().isExistsSelected()); - binding.nearbyFilter.chipView.choiceChipWlm.setChecked(NearbyFilterState.getInstance().isWlmSelected()); + binding.nearbyFilter.chipView.choiceChipNeedsPhoto.setChecked( + NearbyFilterState.getInstance().isNeedPhotoSelected()); + binding.nearbyFilter.chipView.choiceChipExists.setChecked( + NearbyFilterState.getInstance().isExistsSelected()); + binding.nearbyFilter.chipView.choiceChipWlm.setChecked( + NearbyFilterState.getInstance().isWlmSelected()); if (NearbyController.currentLocation != null) { presenter.filterByMarkerType(nearbyFilterSearchRecyclerViewAdapter.selectedLabels, binding.nearbyFilterList.checkboxTriStates.getState(), true, false); @@ -749,44 +782,53 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment } private void initFilterChips() { - binding.nearbyFilter.chipView.choiceChipNeedsPhoto.setOnCheckedChangeListener((buttonView, isChecked) -> { - if (NearbyController.currentLocation != null) { - binding.nearbyFilterList.checkboxTriStates.setState(CheckBoxTriStates.CHECKED); - NearbyFilterState.setNeedPhotoSelected(isChecked); - presenter.filterByMarkerType(nearbyFilterSearchRecyclerViewAdapter.selectedLabels, - binding.nearbyFilterList.checkboxTriStates.getState(), true, true); - updatePlaceList( binding.nearbyFilter.chipView.choiceChipNeedsPhoto.isChecked(), - binding.nearbyFilter.chipView.choiceChipExists.isChecked(), binding.nearbyFilter.chipView.choiceChipWlm.isChecked()); - } else { - binding.nearbyFilter.chipView.choiceChipNeedsPhoto.setChecked(!isChecked); - } - }); + binding.nearbyFilter.chipView.choiceChipNeedsPhoto.setOnCheckedChangeListener( + (buttonView, isChecked) -> { + if (NearbyController.currentLocation != null) { + binding.nearbyFilterList.checkboxTriStates.setState(CheckBoxTriStates.CHECKED); + NearbyFilterState.setNeedPhotoSelected(isChecked); + presenter.filterByMarkerType( + nearbyFilterSearchRecyclerViewAdapter.selectedLabels, + binding.nearbyFilterList.checkboxTriStates.getState(), true, true); + updatePlaceList(binding.nearbyFilter.chipView.choiceChipNeedsPhoto.isChecked(), + binding.nearbyFilter.chipView.choiceChipExists.isChecked(), + binding.nearbyFilter.chipView.choiceChipWlm.isChecked()); + } else { + binding.nearbyFilter.chipView.choiceChipNeedsPhoto.setChecked(!isChecked); + } + }); - binding.nearbyFilter.chipView.choiceChipExists.setOnCheckedChangeListener((buttonView, isChecked) -> { - if (NearbyController.currentLocation != null) { - binding.nearbyFilterList.checkboxTriStates.setState(CheckBoxTriStates.CHECKED); - NearbyFilterState.setExistsSelected(isChecked); - presenter.filterByMarkerType(nearbyFilterSearchRecyclerViewAdapter.selectedLabels, - binding.nearbyFilterList.checkboxTriStates.getState(), true, true); - updatePlaceList( binding.nearbyFilter.chipView.choiceChipNeedsPhoto.isChecked(), - binding.nearbyFilter.chipView.choiceChipExists.isChecked(), binding.nearbyFilter.chipView.choiceChipWlm.isChecked()); - } else { - binding.nearbyFilter.chipView.choiceChipExists.setChecked(!isChecked); - } - }); + binding.nearbyFilter.chipView.choiceChipExists.setOnCheckedChangeListener( + (buttonView, isChecked) -> { + if (NearbyController.currentLocation != null) { + binding.nearbyFilterList.checkboxTriStates.setState(CheckBoxTriStates.CHECKED); + NearbyFilterState.setExistsSelected(isChecked); + presenter.filterByMarkerType( + nearbyFilterSearchRecyclerViewAdapter.selectedLabels, + binding.nearbyFilterList.checkboxTriStates.getState(), true, true); + updatePlaceList(binding.nearbyFilter.chipView.choiceChipNeedsPhoto.isChecked(), + binding.nearbyFilter.chipView.choiceChipExists.isChecked(), + binding.nearbyFilter.chipView.choiceChipWlm.isChecked()); + } else { + binding.nearbyFilter.chipView.choiceChipExists.setChecked(!isChecked); + } + }); - binding.nearbyFilter.chipView.choiceChipWlm.setOnCheckedChangeListener((buttonView, isChecked) -> { - if (NearbyController.currentLocation != null) { - binding.nearbyFilterList.checkboxTriStates.setState(CheckBoxTriStates.CHECKED); - NearbyFilterState.setWlmSelected(isChecked); - presenter.filterByMarkerType(nearbyFilterSearchRecyclerViewAdapter.selectedLabels, - binding.nearbyFilterList.checkboxTriStates.getState(), true, true); - updatePlaceList( binding.nearbyFilter.chipView.choiceChipNeedsPhoto.isChecked(), - binding.nearbyFilter.chipView.choiceChipExists.isChecked(), binding.nearbyFilter.chipView.choiceChipWlm.isChecked()); - } else { - binding.nearbyFilter.chipView.choiceChipWlm.setChecked(!isChecked); - } - }); + binding.nearbyFilter.chipView.choiceChipWlm.setOnCheckedChangeListener( + (buttonView, isChecked) -> { + if (NearbyController.currentLocation != null) { + binding.nearbyFilterList.checkboxTriStates.setState(CheckBoxTriStates.CHECKED); + NearbyFilterState.setWlmSelected(isChecked); + presenter.filterByMarkerType( + nearbyFilterSearchRecyclerViewAdapter.selectedLabels, + binding.nearbyFilterList.checkboxTriStates.getState(), true, true); + updatePlaceList(binding.nearbyFilter.chipView.choiceChipNeedsPhoto.isChecked(), + binding.nearbyFilter.chipView.choiceChipExists.isChecked(), + binding.nearbyFilter.chipView.choiceChipWlm.isChecked()); + } else { + binding.nearbyFilter.chipView.choiceChipWlm.setChecked(!isChecked); + } + }); } /** @@ -838,7 +880,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment } adapter.setItems(updatedPlaces); - binding.bottomSheetNearby.noResultsMessage.setVisibility(updatedPlaces.isEmpty() ? View.VISIBLE : View.GONE); + binding.bottomSheetNearby.noResultsMessage.setVisibility( + updatedPlaces.isEmpty() ? View.VISIBLE : View.GONE); } /** @@ -867,8 +910,9 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment } }); - binding.bottomSheetNearby.bottomSheet.getLayoutParams().height = getActivity().getWindowManager() - .getDefaultDisplay().getHeight() / 16 * 9; + binding.bottomSheetNearby.bottomSheet.getLayoutParams().height = + getActivity().getWindowManager() + .getDefaultDisplay().getHeight() / 16 * 9; bottomSheetListBehavior = BottomSheetBehavior.from(binding.bottomSheetNearby.bottomSheet); bottomSheetListBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); bottomSheetListBehavior.setBottomSheetCallback(new BottomSheetBehavior @@ -897,26 +941,13 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment rotate_backward = AnimationUtils.loadAnimation(getActivity(), R.anim.rotate_backward); } - /** - * Fits buttons according to our layout - */ - private void decideButtonVisibilities() { - // Remove button text if they exceed 1 line or if internal layout has not been built - // Only need to check for directions button because it is the longest - if ( binding.bottomSheetDetails.directionsButtonText.getLineCount() > 1 || binding.bottomSheetDetails.directionsButtonText.getLineCount() == 0) { - binding.bottomSheetDetails.wikipediaButtonText.setVisibility(View.GONE); - binding.bottomSheetDetails.wikidataButtonText.setVisibility(View.GONE); - binding.bottomSheetDetails.commonsButtonText.setVisibility(View.GONE); - binding.bottomSheetDetails.directionsButtonText.setVisibility(View.GONE); - } - } - /** * */ private void addActionToTitle() { binding.bottomSheetDetails.title.setOnLongClickListener(view -> { - Utils.copy("place", binding.bottomSheetDetails.title.getText().toString(), getContext()); + Utils.copy("place", binding.bottomSheetDetails.title.getText().toString(), + getContext()); Toast.makeText(getContext(), R.string.text_copy, Toast.LENGTH_SHORT).show(); return true; }); @@ -963,7 +994,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment public void updateListFragment(final List placeList) { places = placeList; adapter.setItems(placeList); - binding.bottomSheetNearby.noResultsMessage.setVisibility(placeList.isEmpty() ? View.VISIBLE : View.GONE); + binding.bottomSheetNearby.noResultsMessage.setVisibility( + placeList.isEmpty() ? View.VISIBLE : View.GONE); } @Override @@ -1006,7 +1038,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment @Override public fr.free.nrw.commons.location.LatLng getMapFocus() { fr.free.nrw.commons.location.LatLng mapFocusedLatLng = new fr.free.nrw.commons.location.LatLng( - binding.map.getMapCenter().getLatitude(), binding.map.getMapCenter().getLongitude(), 100); + binding.map.getMapCenter().getLatitude(), binding.map.getMapCenter().getLongitude(), + 100); return mapFocusedLatLng; } @@ -1077,8 +1110,10 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment @Override public void populatePlaces(final fr.free.nrw.commons.location.LatLng currentLatLng) { - IGeoPoint screenTopRight = binding.map.getProjection().fromPixels(binding.map.getWidth(), 0); - IGeoPoint screenBottomLeft = binding.map.getProjection().fromPixels(0, binding.map.getHeight()); + IGeoPoint screenTopRight = binding.map.getProjection() + .fromPixels(binding.map.getWidth(), 0); + IGeoPoint screenBottomLeft = binding.map.getProjection() + .fromPixels(0, binding.map.getHeight()); fr.free.nrw.commons.location.LatLng screenTopRightLatLng = new fr.free.nrw.commons.location.LatLng( screenBottomLeft.getLatitude(), screenBottomLeft.getLongitude(), 0); fr.free.nrw.commons.location.LatLng screenBottomLeftLatLng = new fr.free.nrw.commons.location.LatLng( @@ -1135,8 +1170,10 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment populatePlaces(currentLatLng); return; } - IGeoPoint screenTopRight = binding.map.getProjection().fromPixels(binding.map.getWidth(), 0); - IGeoPoint screenBottomLeft = binding.map.getProjection().fromPixels(0, binding.map.getHeight()); + IGeoPoint screenTopRight = binding.map.getProjection() + .fromPixels(binding.map.getWidth(), 0); + IGeoPoint screenBottomLeft = binding.map.getProjection() + .fromPixels(0, binding.map.getHeight()); fr.free.nrw.commons.location.LatLng screenTopRightLatLng = new fr.free.nrw.commons.location.LatLng( screenBottomLeft.getLatitude(), screenBottomLeft.getLongitude(), 0); fr.free.nrw.commons.location.LatLng screenBottomLeftLatLng = new fr.free.nrw.commons.location.LatLng( @@ -1250,7 +1287,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment (isGPX) ? getString(R.string.do_you_want_to_open_gpx_file) : getString(R.string.do_you_want_to_open_kml_file); Runnable runnable = () -> openFile(context, fileName, isGPX); - DialogUtil.showAlertDialog(getActivity(), title, message, runnable,() -> {}); + DialogUtil.showAlertDialog(getActivity(), title, message, runnable, () -> { + }); } private void openFile(Context context, String fileName, Boolean isGPX) { @@ -1418,9 +1456,9 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment @Override public void setProgressBarVisibility(final boolean isVisible) { if (isVisible) { - binding.mapProgressBar.setVisibility(View.VISIBLE); + binding.mapProgressBar.setVisibility(View.VISIBLE); } else { - binding.mapProgressBar.setVisibility(View.GONE); + binding.mapProgressBar.setVisibility(View.GONE); } } @@ -1444,7 +1482,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment } private void showFABs() { - NearbyFABUtils.addAnchorToBigFABs(binding.fabPlus, binding.bottomSheetDetails.getRoot().getId()); + NearbyFABUtils.addAnchorToBigFABs(binding.fabPlus, + binding.bottomSheetDetails.getRoot().getId()); binding.fabPlus.show(); NearbyFABUtils.addAnchorToSmallFABs(binding.fabGallery, getView().findViewById(R.id.empty_view).getId()); @@ -1576,17 +1615,17 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment @Override public void setFABRecenterAction(final View.OnClickListener onClickListener) { - binding.fabRecenter.setOnClickListener(onClickListener); + binding.fabRecenter.setOnClickListener(onClickListener); } @Override public void disableFABRecenter() { - binding.fabRecenter.setEnabled(false); + binding.fabRecenter.setEnabled(false); } @Override public void enableFABRecenter() { - binding.fabRecenter.setEnabled(true); + binding.fabRecenter.setEnabled(true); } /** @@ -1865,7 +1904,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment } /** - * Extracts text between the first occurrence of '(' and its corresponding ')' in the input string. + * Extracts text between the first occurrence of '(' and its corresponding ')' in the input + * string. * * @param input The input string from which to extract text between parentheses. * @return The text between parentheses if found, or {@code null} if no parentheses are found. @@ -1890,14 +1930,17 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment return input.contains("(") || input.contains(")"); } - private void removeMarker(Place place){ + private void removeMarker(Place place) { List overlays = binding.map.getOverlays(); - for (int i = 0; i < overlays.size();i++){ - if (overlays.get(i) instanceof ItemizedOverlayWithFocus){ - ItemizedOverlayWithFocus item = (ItemizedOverlayWithFocus)overlays.get(i); + for (int i = 0; i < overlays.size(); i++) { + if (overlays.get(i) instanceof ItemizedOverlayWithFocus) { + ItemizedOverlayWithFocus item = (ItemizedOverlayWithFocus) overlays.get(i); OverlayItem overlayItem = item.getItem(0); - fr.free.nrw.commons.location.LatLng diffLatLang = new fr.free.nrw.commons.location.LatLng(overlayItem.getPoint().getLatitude(),overlayItem.getPoint().getLongitude(),100); - if (place.location.getLatitude() == overlayItem.getPoint().getLatitude() && place.location.getLongitude() == overlayItem.getPoint().getLongitude()){ + fr.free.nrw.commons.location.LatLng diffLatLang = new fr.free.nrw.commons.location.LatLng( + overlayItem.getPoint().getLatitude(), overlayItem.getPoint().getLongitude(), + 100); + if (place.location.getLatitude() == overlayItem.getPoint().getLatitude() + && place.location.getLongitude() == overlayItem.getPoint().getLongitude()) { binding.map.getOverlays().remove(i); binding.map.invalidate(); break; @@ -2020,50 +2063,33 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment */ private void passInfoToSheet(final Place place) { selectedPlace = place; + dataList = new ArrayList<>(); + // TODO: Decide button text for fitting in the screen + dataList.add(new BottomSheetItem(R.drawable.ic_round_star_border_24px, "")); + dataList.add(new BottomSheetItem(R.drawable.ic_directions_black_24dp, + getResources().getString(R.string.nearby_directions))); + if (place.hasWikidataLink()) { + dataList.add(new BottomSheetItem(R.drawable.ic_wikidata_logo_24dp, + getResources().getString(R.string.nearby_wikidata))); + } + dataList.add(new BottomSheetItem(R.drawable.ic_feedback_black_24dp, + getResources().getString(R.string.nearby_wikitalk))); + if (place.hasWikipediaLink()) { + dataList.add(new BottomSheetItem(R.drawable.ic_wikipedia_logo_24dp, + getResources().getString(R.string.nearby_wikipedia))); + } + if (selectedPlace.hasCommonsLink()) { + dataList.add(new BottomSheetItem(R.drawable.ic_commons_icon_vector, + getResources().getString(R.string.nearby_commons))); + } + int spanCount = getSpanCount(); + gridLayoutManager = new GridLayoutManager(this.getContext(), spanCount); + binding.bottomSheetDetails.bottomSheetRecyclerView.setLayoutManager(gridLayoutManager); + bottomSheetAdapter = new BottomSheetAdapter(this.getContext(), dataList); + bottomSheetAdapter.setClickListener(this); + binding.bottomSheetDetails.bottomSheetRecyclerView.setAdapter(bottomSheetAdapter); updateBookmarkButtonImage(selectedPlace); - binding.bottomSheetDetails.bookmarkButton.setOnClickListener(view -> { - final boolean isBookmarked = bookmarkLocationDao.updateBookmarkLocation(selectedPlace); - updateBookmarkButtonImage(selectedPlace); - updateMarker(isBookmarked, selectedPlace, locationManager.getLastLocation()); - binding.map.invalidate(); - }); - binding.bottomSheetDetails.bookmarkButton.setOnLongClickListener(view -> { - Toast.makeText(getContext(), R.string.menu_bookmark, Toast.LENGTH_SHORT).show(); - return true; - }); - - binding.bottomSheetDetails.wikipediaButton.setVisibility(place.hasWikipediaLink() ? View.VISIBLE : View.GONE); - binding.bottomSheetDetails.wikipediaButton.setOnClickListener( - view -> Utils.handleWebUrl(getContext(), selectedPlace.siteLinks.getWikipediaLink())); - binding.bottomSheetDetails.wikipediaButton.setOnLongClickListener(view -> { - Toast.makeText(getContext(), R.string.nearby_wikipedia, Toast.LENGTH_SHORT).show(); - return true; - }); - - binding.bottomSheetDetails.wikidataButton.setVisibility(place.hasWikidataLink() ? View.VISIBLE : View.GONE); - binding.bottomSheetDetails.wikidataButton.setOnClickListener( - view -> Utils.handleWebUrl(getContext(), selectedPlace.siteLinks.getWikidataLink())); - binding.bottomSheetDetails.wikidataButton.setOnLongClickListener(view -> { - Toast.makeText(getContext(), R.string.nearby_wikidata, Toast.LENGTH_SHORT).show(); - return true; - }); - - binding.bottomSheetDetails.directionsButton.setOnClickListener(view -> Utils.handleGeoCoordinates(getActivity(), - selectedPlace.getLocation())); - binding.bottomSheetDetails.directionsButton.setOnLongClickListener(view -> { - Toast.makeText(getContext(), R.string.nearby_directions, Toast.LENGTH_SHORT).show(); - return true; - }); - - binding.bottomSheetDetails.commonsButton.setVisibility(selectedPlace.hasCommonsLink() ? View.VISIBLE : View.GONE); - binding.bottomSheetDetails.commonsButton.setOnClickListener( - view -> Utils.handleWebUrl(getContext(), selectedPlace.siteLinks.getCommonsLink())); - binding.bottomSheetDetails.commonsButton.setOnLongClickListener(view -> { - Toast.makeText(getContext(), R.string.nearby_commons, Toast.LENGTH_SHORT).show(); - return true; - }); - binding.bottomSheetDetails.icon.setImageResource(selectedPlace.getLabel().getIcon()); binding.bottomSheetDetails.title.setText(selectedPlace.name); @@ -2074,7 +2100,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment descriptionText = (descriptionText.equals(selectedPlace.getLongDescription()) ? descriptionText : descriptionText.replaceFirst(".$", "")); // Set the short description after we remove place name from long description - binding.bottomSheetDetails.description.setText(descriptionText); + binding.bottomSheetDetails.description.setText(descriptionText); binding.fabCamera.setOnClickListener(view -> { if (binding.fabCamera.isShown()) { @@ -2088,7 +2114,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment if (binding.fabGallery.isShown()) { Timber.d("Gallery button tapped. Place: %s", selectedPlace.toString()); storeSharedPrefs(selectedPlace); - controller.initiateGalleryPick(getActivity(), binding.nearbyFilter.chipView.choiceChipWlm.isChecked()); + controller.initiateGalleryPick(getActivity(), + binding.nearbyFilter.chipView.choiceChipWlm.isChecked()); } }); @@ -2115,9 +2142,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment } else { bookmarkIcon = R.drawable.ic_round_star_border_24px; } - if ( binding.bottomSheetDetails.bookmarkButtonImage != null) { - binding.bottomSheetDetails.bookmarkButtonImage.setImageResource(bookmarkIcon); - } + bottomSheetAdapter.updateBookmarkIcon(bookmarkIcon); } @Override @@ -2295,6 +2320,83 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment binding.map.getController().animateTo(geoPoint); } + @Override + public void onBottomSheetItemClick(@Nullable View view, int position) { + BottomSheetItem item = dataList.get(position); + boolean isBookmarked = bookmarkLocationDao.findBookmarkLocation(selectedPlace); + switch (item.getImageResourceId()) { + case R.drawable.ic_round_star_border_24px: + bookmarkLocationDao.updateBookmarkLocation(selectedPlace); + updateBookmarkButtonImage(selectedPlace); + isBookmarked = bookmarkLocationDao.findBookmarkLocation(selectedPlace); + updateMarker(isBookmarked, selectedPlace, locationManager.getLastLocation()); + binding.map.invalidate(); + break; + case R.drawable.ic_round_star_filled_24px: + bookmarkLocationDao.updateBookmarkLocation(selectedPlace); + updateBookmarkButtonImage(selectedPlace); + isBookmarked = bookmarkLocationDao.findBookmarkLocation(selectedPlace); + updateMarker(isBookmarked, selectedPlace, locationManager.getLastLocation()); + binding.map.invalidate(); + break; + case R.drawable.ic_directions_black_24dp: + Utils.handleGeoCoordinates(this.getContext(), selectedPlace.getLocation()); + break; + case R.drawable.ic_wikidata_logo_24dp: + Utils.handleWebUrl(this.getContext(), selectedPlace.siteLinks.getWikidataLink()); + break; + case R.drawable.ic_feedback_black_24dp: + Intent intent = new Intent(this.getContext(), WikidataFeedback.class); + intent.putExtra("lat", selectedPlace.location.getLatitude()); + intent.putExtra("lng", selectedPlace.location.getLongitude()); + intent.putExtra("place", selectedPlace.name); + intent.putExtra("qid", selectedPlace.getWikiDataEntityId()); + startActivity(intent); + break; + case R.drawable.ic_wikipedia_logo_24dp: + Utils.handleWebUrl(this.getContext(), selectedPlace.siteLinks.getWikipediaLink()); + break; + case R.drawable.ic_commons_icon_vector: + Utils.handleWebUrl(this.getContext(), selectedPlace.siteLinks.getCommonsLink()); + break; + default: + break; + } + } + + @Override + public void onBottomSheetItemLongClick(@Nullable View view, int position) { + BottomSheetItem item = dataList.get(position); + String message; + switch (item.getImageResourceId()) { + case R.drawable.ic_round_star_border_24px: + message = getString(R.string.menu_bookmark); + break; + case R.drawable.ic_round_star_filled_24px: + message = getString(R.string.menu_bookmark); + break; + case R.drawable.ic_directions_black_24dp: + message = getString(R.string.nearby_directions); + break; + case R.drawable.ic_wikidata_logo_24dp: + message = getString(R.string.nearby_wikidata); + break; + case R.drawable.ic_feedback_black_24dp: + message = getString(R.string.nearby_wikitalk); + break; + case R.drawable.ic_wikipedia_logo_24dp: + message = getString(R.string.nearby_wikipedia); + break; + case R.drawable.ic_commons_icon_vector: + message = getString(R.string.nearby_commons); + break; + default: + message = "Long click"; + break; + } + Toast.makeText(this.getContext(), message, Toast.LENGTH_SHORT).show(); + } + public interface NearbyParentFragmentInstanceReadyCallback { void onReady(); @@ -2312,9 +2414,12 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment rlBottomSheetLayoutParams.height = getActivity().getWindowManager().getDefaultDisplay().getHeight() / 16 * 9; binding.bottomSheetNearby.bottomSheet.setLayoutParams(rlBottomSheetLayoutParams); + int spanCount = getSpanCount(); + if (gridLayoutManager != null) { + gridLayoutManager.setSpanCount(spanCount); + } } - public void onLearnMoreClicked() { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse(WLM_URL)); @@ -2322,11 +2427,12 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment } public void onToggleChipsClicked() { - if ( binding.nearbyFilter.chipView.getRoot().getVisibility() == View.VISIBLE) { - binding.nearbyFilter.chipView.getRoot().setVisibility(View.GONE); + if (binding.nearbyFilter.chipView.getRoot().getVisibility() == View.VISIBLE) { + binding.nearbyFilter.chipView.getRoot().setVisibility(View.GONE); } else { - binding.nearbyFilter.chipView.getRoot().setVisibility(View.VISIBLE); + binding.nearbyFilter.chipView.getRoot().setVisibility(View.VISIBLE); } - binding.nearbyFilter.ivToggleChips.setRotation(binding.nearbyFilter.ivToggleChips.getRotation() + 180); + binding.nearbyFilter.ivToggleChips.setRotation( + binding.nearbyFilter.ivToggleChips.getRotation() + 180); } } diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/model/BottomSheetItem.kt b/app/src/main/java/fr/free/nrw/commons/nearby/model/BottomSheetItem.kt new file mode 100644 index 000000000..bf30be6ec --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/nearby/model/BottomSheetItem.kt @@ -0,0 +1,3 @@ +package fr.free.nrw.commons.nearby.model + +class BottomSheetItem(var imageResourceId: Int, val title: String) diff --git a/app/src/main/res/layout/activity_wikidata_feedback.xml b/app/src/main/res/layout/activity_wikidata_feedback.xml new file mode 100644 index 000000000..5f6647efe --- /dev/null +++ b/app/src/main/res/layout/activity_wikidata_feedback.xml @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/bottom_sheet_details.xml b/app/src/main/res/layout/bottom_sheet_details.xml index a8889aafa..8c354daae 100644 --- a/app/src/main/res/layout/bottom_sheet_details.xml +++ b/app/src/main/res/layout/bottom_sheet_details.xml @@ -53,169 +53,21 @@ android:layout_width="match_parent" android:layout_height="@dimen/tiny_height" android:layout_marginTop="@dimen/small_height" - android:layout_marginBottom="@dimen/activity_margin_horizontal" - android:background="@android:color/darker_gray"/> - + android:layout_marginBottom="@dimen/activity_margin_horizontal" + android:background="@android:color/darker_gray" /> - - - - + - - - - - - - - - - - - - - - - - - - + android:layout_width="match_parent" + android:layout_height="@dimen/tiny_height" + android:layout_marginTop="@dimen/small_height" + android:layout_marginBottom="@dimen/activity_margin_horizontal" + android:background="@android:color/darker_gray" /> + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fb73dd694..21741f6dc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -818,5 +818,13 @@ Upload your first media by tapping on the add button. Please remember that all images in a multi-upload get the same categories and depictions. If the images do not share depictions and categories, please perform several separate uploads. Note about multi-uploads + Report a problem about this item to Wikidata + Please enter some comments + Talk + "Write something about the " + " item. It will be publicly visible." + \'%1$s\' does not exist anymore, no picture can ever be taken of it. + \'%1$s\' is at a different place (please specify the correct place below, if possible tell us the correct latitude/longitude). + Other problem or information (please explain below). Your feedback gets posted to the following wiki page: Commons:Mobile app/Feedback ]]> From 018a924c533f2371e7b794dcdf14dd9981ae13dc Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Mon, 8 Jul 2024 14:02:00 +0200 Subject: [PATCH 2/3] Localisation updates from https://translatewiki.net. --- app/src/main/res/values-az/strings.xml | 1 + app/src/main/res/values-da/strings.xml | 48 +++++++++++++++----------- app/src/main/res/values-de/strings.xml | 2 ++ app/src/main/res/values-iw/strings.xml | 8 ++++- app/src/main/res/values-mk/strings.xml | 8 +++++ app/src/main/res/values-qq/strings.xml | 2 ++ app/src/main/res/values-sr/strings.xml | 2 ++ 7 files changed, 50 insertions(+), 21 deletions(-) diff --git a/app/src/main/res/values-az/strings.xml b/app/src/main/res/values-az/strings.xml index 866bf63d0..d5e83a2c7 100644 --- a/app/src/main/res/values-az/strings.xml +++ b/app/src/main/res/values-az/strings.xml @@ -88,6 +88,7 @@ Müzakirə Müəllif Lisenziya + Vikidata Vikipediya Təşəkkür uğurla göndərildi Təşəkkür göndərilə bilmədi %1$s diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index 3041fc8fa..a50318b2d 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -64,7 +64,7 @@ Udforsk Udseende Generelt - Tilbagemelding + Feedback Privatliv Commons @@ -90,11 +90,11 @@ Godkendelse mislykkedes. Log venligst ind igen. Upload påbegyndt! Upload i kø (begrænset forbindelsestilstand aktiveret) - %1$s overført! + %1$s uploadet! Tryk for at få vist dit upload Uploader fil: %s - %1$s overføres - Afslutter uploadning af %1$s + %1$s uploades + Afslutter upload af %1$s Upload af %1$s mislykkedes Upload af %1$s sat på pause Tryk for at se @@ -103,8 +103,8 @@ I kø Mislykkedes %1$d%% færdig - Overfører - Fra galleriet + Uploader + Fra galleri Tag billede I nærheden Mine uploads @@ -147,7 +147,7 @@ Privatlivspolitik Tak til Om - Send tilbagemelding (med e-mail) + Send feedback (via e-mail) Ingen e-mail-klient installeret Nyligt anvendte kategorier Venter på den første synkronisering… @@ -203,7 +203,7 @@ Anmoder om placeringstilladelse Registrer placering for billeder, der tages i appen Aktiver dette for at registrere placering for billeder i appen, i tilfælde af at enhedens kamera ikke gør det - O.k. + Ok Advarsel Dublet filnavn fundet Overfør @@ -214,7 +214,7 @@ Afbildning Beskrivelse Diskussion - Ophavsmand + Forfatter Upload-dato Licens Koordinater @@ -241,7 +241,7 @@ I nærheden Om Indstillinger - Tilbagemelding + Feedback Feedback via GitHub Log af Vejledning @@ -381,9 +381,9 @@ Antallet af billeder, du har uploadet til Commons, som blev brugt i Wikimedia-artikler Der opstod en fejl! Commons-notifikationer - Brug brugerdefineret navn for ophavsmand - Brug et brugerdefineret navn for ophavsmand i stedet for dit brugernavn, når du uploader billeder - Brugerdefineret ophavsmandsnavn + Brug brugerdefineret forfatternavn + Brug et brugerdefineret forfatternavn i stedet for dit brugernavn, når du uploader billeder + Brugerdefineret forfatternavn Bidrag I nærheden Notifikationer @@ -413,7 +413,7 @@ Beklager dette billede er ikke interessant for en encyklopædi Uploadet af mig selv på %1$s , brugt i %2$d artikel(er). Velkommen til Commons!\n\nUpload dit første medie ved at trykke på Tilføj-knappen. - Ingen valgte kategorier + Ingen kategorier valgt Billeder uden kategorier er sjældent brugbare. Er du sikker på, at du vil fortsætte uden at vælge kategorier? Ingen afbildninger valgt Billeder med afbildninger er lettere at finde og mere tilbøjelige til at blive brugt. Er du sikker på, at du vil fortsætte uden at vælge afbildninger? @@ -497,7 +497,7 @@ Download mislykkedes!!. Vi kan ikke downloade filen uden tilladelse til ekstern lagring. Administrer EXIF-tags Vælg hvilke EXIF-tags, der skal beholdes i uploads - Ophavsmand + Forfatter Ophavsret Placering Kameramodel @@ -609,7 +609,7 @@ 2. Hvis du klikker på Bekræft, åbnes Wikipedia-artiklen 3. Find en passende sektion i artiklen til dit billede 4. Klik på Rediger-ikonet (det som ligner en blyant) for den sektion. - 5. Indsæt wikiteksten på det rigtige sted. + 5. Indsæt wikiteksten på det rette sted. 6. Rediger wikiteksten for passende placering, hvis det er nødvendigt. For mere information, se <a href=\"https://en.wikipedia.org/wiki/Wikipedia:Manual_of_Style/Images#How_to_place_an_image\">her</a>. 7. Udgiv artiklen Kopier wikikode til udklipsholder @@ -660,7 +660,7 @@ Appens brugergrænsefladesprog Fjerner en billedtekst og beskrivelse Læs mere - For alle sprog + På alle sprog Vælg en placering Panorer og zoom for at justere Vælg placering @@ -718,7 +718,7 @@ Enhedsmodel Enhedsnavn Netværkstype - Tak for tilbagemeldingen + Tak for din feedback Fejl under afsendelse af feedback Hvad er din feedback? Din feedback @@ -758,8 +758,8 @@ Fjern placering-advarsel Placering gør billeder mere nyttige og nemmere at finde. Ønsker du virkelig at fjerne placering fra dette billede? Placering fjernet! - Tak ophavsmanden - Fejl ved afsendelse af tak til ophavsmand. + Tak forfatteren + Fejl ved afsendelse af tak til forfatter. Login udløb. Log venligst ind igen. Der er ingen tilgængelig applikation til at åbne GPX-filer Fil gemt @@ -775,5 +775,13 @@ Husk, at alle billeder i et multi-upload får de samme kategorier og afbildninger. Hvis billederne ikke deler afbildninger og kategorier, skal du udføre flere separate uploads. Bemærkning om at uploade flere billeder + Rapporter et problem med dette element til Wikidata + Skriv nogle kommentarer + Tal + \"Skriv noget om\" + \" elementet. Det vil være offentligt synligt.\" + \'%1$s\' eksisterer ikke længere, der kan aldrig tages et billede af det. + \'%1$s\' ligger et andet sted (angiv venligst det korrekte sted nedenfor, fortæl os om muligt den korrekte breddegrad/længdegrad). + Andet problem eller anden information (forklar venligst nedenfor). Din feedback bliver slået op på følgende wiki-side: <a href=\"https://commons.wikimedia.org/wiki/Commons:Mobile_app/Feedback\">Commons:Mobile app/Feedback</a> diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index da7c9c317..3c74f41a9 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -11,6 +11,7 @@ * FF11 * Ferdinand0101 * Icke +* Ignatgg * Inkowik * Justman10000 * Kghbln @@ -800,4 +801,5 @@ Bitte beachte, dass bei einem Multiupload alle Bilder die gleichen Kategorien und Bezeichnungen erhalten. Sollten die Bilder keine gemeinsamen Bezeichnungen und Kategorien haben, führe bitte mehrere separate Uploads durch. Hinweis zu Mehrfach-Uploads + Ihr Feedback wird auf der folgenden Wiki-Seite veröffentlicht: <a href=\"https://commons.wikimedia.org/wiki/Commons:Mobile_app/Feedback\">Commons:Mobile App/Feedback</a> diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index 70288b1cc..257188b11 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -707,7 +707,7 @@ חזרה ברוך בואך לבוחר התמונות המותאמות הבורר מציג לך אילו תמונות כבר העלית לוויקישיתוף. - בניגוד לתמונה מימין, על התמונה שמשמאל יש את הלוגו של ויקישיתוף שמעיד שהיא כבר הועלתה. יש לגעת ולהחזיר לקבלת תצוגה מקדימה של התמונה. + בניגוד לתמונה מימין, על התמונה שמשמאל מופיע הסמל של ויקישיתוף שמציין שהיא כבר הועלתה. יש לגעת ולהחזיק לקבלת תצוגה מקדימה של התמונה. מגניב התמונה הזאת כבר הועלתה לוויקישיתוף. מסיבות טכניות, היישום לא יכול להעלות יותר מ־%1$d תמונות בבת אחת בצורה מהימנה. חרגת ממגבלת ההעלאה על סך %1$d ב־%2$d. @@ -807,5 +807,11 @@ נא לזכור שכשמועלות כמה תמונות, כולן מקבלות את אותן הקטגוריות והמוצגים. אם התמונות אינן חולקות מוצגים וקטגוריות, נא לעשות כמה העלאות נפרדות. הערה על העלאות מרובות + דווח על בעיה בפריט הזה לוויקינתונים + נא להזין הערות כלשהן + שיחה + \"נא לכתוב משהו על הפריט \" + \" . זה יהיה גלוי לציבור.\" + \"%1$s\" כבר לא קיים, אי־אפשר לצלם אותו. המשוב שלך מתפרסם בדף הוויקי הבא: <a href=\"https://commons.wikimedia.org/wiki/Commons:Mobile_app/Feedback\">Commons:Mobile app/Feedback</a> diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml index 28034afee..1440c6a90 100644 --- a/app/src/main/res/values-mk/strings.xml +++ b/app/src/main/res/values-mk/strings.xml @@ -771,5 +771,13 @@ Запомнете дека сите слики што ги подигате наеднаш се очекуваат да ја прикажуваат истата работа и ги добиваат истите категории и описи. Ако сликите прикажуваат различни нешта и треба да имаат различни категории, извршете неколку одделни подигања. Напомена за подигање повеќе слики наеднаш + Пријавете проблем со овој предмет на Википодатоци + Внесете коментар + Разговор + „Напишете нешто за предметот “ + “. Ова ќе биде јавно видливо.“ + „%1$s“ повеќе не постои, нема да може да се фотографира. + „%1$s“ се наоѓа на друго место (подолу укажете го сегашното место, ако е можно со географска ширина и должина). + Друг проблем или информација (објаснете подолу). Вашите мислења се објавуваат на следнава викистраница: <a href=\"https://commons.wikimedia.org/wiki/Commons:Mobile_app/Feedback\">Commons:Mobile app/Feedback</a> diff --git a/app/src/main/res/values-qq/strings.xml b/app/src/main/res/values-qq/strings.xml index e06969dc2..2753ee09b 100644 --- a/app/src/main/res/values-qq/strings.xml +++ b/app/src/main/res/values-qq/strings.xml @@ -204,4 +204,6 @@ {{Identical|Detail}} \"Set as avatar\" should be translated the same as {{msg-wm|Commons-android-strings-menu set avatar}}. {{Doc-commons-app-depicts}} + Shown before {{msg-wm|Commons-android-strings-item it will be publicly visible}}. Between them, the item name is shown. + Shown after {{msg-wm|Commons-android-strings-write something about the}}. Between them, the item name is shown. diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 4313d05fd..f05487488 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -731,4 +731,6 @@ %d слика је одабрана %d слика је одабрано + Разговор + „%1$s” не постоји више, и није га могуће више сликати. From 5bcbaa1bebf7cb3f6ad355e5ca0560ef96b2c647 Mon Sep 17 00:00:00 2001 From: "Amir E. Aharoni" Date: Mon, 8 Jul 2024 10:16:26 -0400 Subject: [PATCH 3/3] Improve the messages about being in a different place (#5764) Remove parentheses and comma splice, and replace them with more straightforward grammar. --- app/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 21741f6dc..82be02da2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -824,7 +824,7 @@ Upload your first media by tapping on the add button. "Write something about the " " item. It will be publicly visible." \'%1$s\' does not exist anymore, no picture can ever be taken of it. - \'%1$s\' is at a different place (please specify the correct place below, if possible tell us the correct latitude/longitude). + \'%1$s\' is at a different place. Please specify the correct place below, and if possible, write the correct latitude and longitude. Other problem or information (please explain below). Your feedback gets posted to the following wiki page: Commons:Mobile app/Feedback ]]>