mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-27 12:53:55 +01:00
Merge branch 'commons-app:main' into issue#6084
This commit is contained in:
commit
546437b186
14 changed files with 323 additions and 81 deletions
84
.github/workflows/android-ci-comment.yml
vendored
Normal file
84
.github/workflows/android-ci-comment.yml
vendored
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
name: Android CI Comment
|
||||
|
||||
on: [pull_request_target]
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
comment:
|
||||
name: Comment on PR with APK links
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout base branch
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.base_ref }}
|
||||
|
||||
- name: Download Run ID Artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: run-id
|
||||
|
||||
- name: Read Run ID
|
||||
id: read-run-id
|
||||
run: echo "RUN_ID=$(cat run_id.txt)" >> $GITHUB_ENV
|
||||
|
||||
- name: Comment on PR with APK download links
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
try {
|
||||
const token = process.env.GH_TOKEN;
|
||||
if (!token) {
|
||||
throw new Error('GITHUB_TOKEN is not set.');
|
||||
}
|
||||
|
||||
const runId = "${{ env.RUN_ID }}";
|
||||
if (!runId) {
|
||||
throw new Error('Run ID not found.');
|
||||
}
|
||||
|
||||
const { data: { artifacts } } = await github.rest.actions.listWorkflowRunArtifacts({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
run_id: runId
|
||||
});
|
||||
|
||||
if (!artifacts || artifacts.length === 0) {
|
||||
console.log('No artifacts found for this workflow run.');
|
||||
return;
|
||||
}
|
||||
|
||||
const betaArtifact = artifacts.find(artifact => artifact.name === "betaDebugAPK");
|
||||
const prodArtifact = artifacts.find(artifact => artifact.name === "prodDebugAPK");
|
||||
|
||||
if (!betaArtifact || !prodArtifact) {
|
||||
console.log('Could not find both Beta and Prod APK artifacts.');
|
||||
console.log('Available artifacts:', artifacts.map(a => a.name).join(', '));
|
||||
return;
|
||||
}
|
||||
|
||||
const betaDownloadUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/suites/${runId}/artifacts/${betaArtifact.id}`;
|
||||
const prodDownloadUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/suites/${runId}/artifacts/${prodArtifact.id}`;
|
||||
|
||||
const commentBody = `
|
||||
📱 **APK for pull request is ready to see the changes** 📱
|
||||
- [Download Beta APK](${betaDownloadUrl})
|
||||
- [Download Prod APK](${prodDownloadUrl})
|
||||
`;
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: commentBody
|
||||
});
|
||||
|
||||
console.log('Successfully posted comment with APK download links');
|
||||
} catch (error) {
|
||||
console.error('Error in PR comment creation:', error);
|
||||
core.setFailed(`Workflow failed: ${error.message}`);
|
||||
}
|
||||
67
.github/workflows/android.yml
vendored
67
.github/workflows/android.yml
vendored
|
|
@ -3,7 +3,6 @@ name: Android CI
|
|||
on: [push, pull_request, workflow_dispatch]
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
contents: read
|
||||
actions: read
|
||||
|
||||
|
|
@ -108,63 +107,13 @@ jobs:
|
|||
name: prodDebugAPK
|
||||
path: app/build/outputs/apk/prod/debug/app-*.apk
|
||||
|
||||
- name: Comment on PR with APK download links
|
||||
- name: Store Workflow Run ID
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: actions/github-script@v6
|
||||
run: echo "${{ github.run_id }}" > run_id.txt
|
||||
|
||||
- name: Upload Run ID as Artifact
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||
script: |
|
||||
try {
|
||||
const token = process.env.GITHUB_TOKEN;
|
||||
if (!token) {
|
||||
throw new Error('GITHUB_TOKEN is not set. Please check workflow permissions.');
|
||||
}
|
||||
|
||||
|
||||
const { data: { artifacts } } = await github.rest.actions.listWorkflowRunArtifacts({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
run_id: context.runId
|
||||
});
|
||||
|
||||
if (!artifacts || artifacts.length === 0) {
|
||||
console.log('No artifacts found for this workflow run.');
|
||||
return;
|
||||
}
|
||||
|
||||
const betaArtifact = artifacts.find(artifact => artifact.name === "betaDebugAPK");
|
||||
const prodArtifact = artifacts.find(artifact => artifact.name === "prodDebugAPK");
|
||||
|
||||
if (!betaArtifact || !prodArtifact) {
|
||||
console.log('Could not find both Beta and Prod APK artifacts.');
|
||||
console.log('Available artifacts:', artifacts.map(a => a.name).join(', '));
|
||||
return;
|
||||
}
|
||||
|
||||
const betaDownloadUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/suites/${context.runId}/artifacts/${betaArtifact.id}`;
|
||||
const prodDownloadUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/suites/${context.runId}/artifacts/${prodArtifact.id}`;
|
||||
|
||||
const commentBody = `
|
||||
📱 **APK for pull request is ready to see the changes** 📱
|
||||
- [Download Beta APK](${betaDownloadUrl})
|
||||
- [Download Prod APK](${prodDownloadUrl})
|
||||
`;
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: commentBody
|
||||
});
|
||||
|
||||
console.log('Successfully posted comment with APK download links');
|
||||
} catch (error) {
|
||||
console.error('Error in PR comment creation:', error);
|
||||
if (error.message.includes('GITHUB_TOKEN')) {
|
||||
core.setFailed('Missing or invalid GITHUB_TOKEN. Please check repository secrets configuration.');
|
||||
} else if (error.status === 403) {
|
||||
core.setFailed('Permission denied. Please check workflow permissions in repository settings.');
|
||||
} else {
|
||||
core.setFailed(`Workflow failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
name: run-id
|
||||
path: run_id.txt
|
||||
|
|
|
|||
|
|
@ -175,8 +175,8 @@ dependencies {
|
|||
testImplementation "androidx.work:work-testing:$work_version"
|
||||
|
||||
//Glide
|
||||
implementation 'com.github.bumptech.glide:glide:4.12.0'
|
||||
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
|
||||
implementation 'com.github.bumptech.glide:glide:4.16.0'
|
||||
annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0'
|
||||
kaptTest "androidx.databinding:databinding-compiler:8.0.2"
|
||||
kaptAndroidTest "androidx.databinding:databinding-compiler:8.0.2"
|
||||
|
||||
|
|
|
|||
|
|
@ -90,6 +90,41 @@ class Media constructor(
|
|||
captions = captions,
|
||||
)
|
||||
|
||||
constructor(
|
||||
captions: Map<String, String>,
|
||||
categories: List<String>?,
|
||||
filename: String?,
|
||||
fallbackDescription: String?,
|
||||
author: String?,
|
||||
user: String?,
|
||||
dateUploaded: Date? = Date(),
|
||||
license: String? = null,
|
||||
licenseUrl: String? = null,
|
||||
imageUrl: String? = null,
|
||||
thumbUrl: String? = null,
|
||||
coordinates: LatLng? = null,
|
||||
descriptions: Map<String, String> = emptyMap(),
|
||||
depictionIds: List<String> = emptyList(),
|
||||
categoriesHiddenStatus: Map<String, Boolean> = emptyMap()
|
||||
) : this(
|
||||
pageId = UUID.randomUUID().toString(),
|
||||
filename = filename,
|
||||
fallbackDescription = fallbackDescription,
|
||||
dateUploaded = dateUploaded,
|
||||
author = author,
|
||||
user = user,
|
||||
categories = categories,
|
||||
captions = captions,
|
||||
license = license,
|
||||
licenseUrl = licenseUrl,
|
||||
imageUrl = imageUrl,
|
||||
thumbUrl = thumbUrl,
|
||||
coordinates = coordinates,
|
||||
descriptions = descriptions,
|
||||
depictionIds = depictionIds,
|
||||
categoriesHiddenStatus = categoriesHiddenStatus
|
||||
)
|
||||
|
||||
/**
|
||||
* Gets media display title
|
||||
* @return Media title
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import android.view.KeyEvent
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewTreeObserver
|
||||
import android.view.ViewTreeObserver.OnGlobalLayoutListener
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.Button
|
||||
|
|
@ -405,9 +406,14 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C
|
|||
* Gets the height of the frame layout as soon as the view is ready and updates aspect ratio
|
||||
* of the picture.
|
||||
*/
|
||||
view.post {
|
||||
view.post{
|
||||
val width = binding.mediaDetailScrollView.width
|
||||
if (width > 0) {
|
||||
frameLayoutHeight = binding.mediaDetailFrameLayout.measuredHeight
|
||||
updateAspectRatio(binding.mediaDetailScrollView.width)
|
||||
updateAspectRatio(width)
|
||||
} else {
|
||||
view.postDelayed({ updateAspectRatio(binding.root.width) }, 1)
|
||||
}
|
||||
}
|
||||
|
||||
return view
|
||||
|
|
|
|||
|
|
@ -185,10 +185,12 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
|
|||
* or a fragment
|
||||
*/
|
||||
private void initProvider() {
|
||||
if (getParentFragment() != null) {
|
||||
if (getParentFragment() instanceof MediaDetailProvider) {
|
||||
provider = (MediaDetailProvider) getParentFragment();
|
||||
} else {
|
||||
} else if (getActivity() instanceof MediaDetailProvider) {
|
||||
provider = (MediaDetailProvider) getActivity();
|
||||
} else {
|
||||
throw new ClassCastException("Parent must implement MediaDetailProvider");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,11 +39,13 @@ import androidx.appcompat.app.AlertDialog
|
|||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.bumptech.glide.Glide
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
|
|
@ -51,6 +53,7 @@ import com.jakewharton.rxbinding2.view.RxView
|
|||
import com.jakewharton.rxbinding3.appcompat.queryTextChanges
|
||||
import fr.free.nrw.commons.CommonsApplication
|
||||
import fr.free.nrw.commons.MapController.NearbyPlacesInfo
|
||||
import fr.free.nrw.commons.Media
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.Utils
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao
|
||||
|
|
@ -67,6 +70,10 @@ import fr.free.nrw.commons.location.LocationPermissionsHelper.LocationPermission
|
|||
import fr.free.nrw.commons.location.LocationServiceManager
|
||||
import fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType
|
||||
import fr.free.nrw.commons.location.LocationUpdateListener
|
||||
import fr.free.nrw.commons.media.MediaClient
|
||||
import fr.free.nrw.commons.media.MediaDetailPagerFragment
|
||||
import fr.free.nrw.commons.media.MediaDetailPagerFragment.MediaDetailProvider
|
||||
import fr.free.nrw.commons.navtab.NavTab
|
||||
import fr.free.nrw.commons.nearby.BottomSheetAdapter
|
||||
import fr.free.nrw.commons.nearby.BottomSheetAdapter.ItemClickListener
|
||||
import fr.free.nrw.commons.nearby.CheckBoxTriStates
|
||||
|
|
@ -118,17 +125,25 @@ import timber.log.Timber
|
|||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.net.URLDecoder
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Named
|
||||
import kotlin.concurrent.Volatile
|
||||
|
||||
|
||||
class NearbyParentFragment : CommonsDaggerSupportFragment(), NearbyParentFragmentContract.View,
|
||||
WikidataP18EditListener, LocationUpdateListener, LocationPermissionCallback, ItemClickListener {
|
||||
class NearbyParentFragment : CommonsDaggerSupportFragment(),
|
||||
NearbyParentFragmentContract.View,
|
||||
WikidataP18EditListener,
|
||||
LocationUpdateListener,
|
||||
LocationPermissionCallback,
|
||||
ItemClickListener,
|
||||
MediaDetailPagerFragment.MediaDetailProvider {
|
||||
var binding: FragmentNearbyParentBinding? = null
|
||||
|
||||
val mapEventsOverlay: MapEventsOverlay = MapEventsOverlay(object : MapEventsReceiver {
|
||||
|
|
@ -163,6 +178,13 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(), NearbyParentFragmen
|
|||
@Named("default_preferences")
|
||||
lateinit var applicationKvStore: JsonKvStore
|
||||
|
||||
@Inject
|
||||
lateinit var mediaClient: MediaClient
|
||||
|
||||
lateinit var mediaDetails: MediaDetailPagerFragment
|
||||
|
||||
lateinit var media: Media
|
||||
|
||||
@Inject
|
||||
lateinit var bookmarkLocationDao: BookmarkLocationsDao
|
||||
|
||||
|
|
@ -716,6 +738,10 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(), NearbyParentFragmen
|
|||
presenter?.attachView(this)
|
||||
registerNetworkReceiver()
|
||||
|
||||
binding?.coordinatorLayout?.visibility = View.VISIBLE
|
||||
binding?.map?.setMultiTouchControls(true)
|
||||
binding?.map?.isClickable = true
|
||||
|
||||
if (isResumed && (activity as? MainActivity)?.activeFragment == ActiveFragment.NEARBY) {
|
||||
if (activity?.let { locationPermissionsHelper?.checkLocationPermission(it) } == true) {
|
||||
locationPermissionGranted()
|
||||
|
|
@ -1853,7 +1879,31 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(), NearbyParentFragmen
|
|||
}
|
||||
|
||||
fun backButtonClicked(): Boolean {
|
||||
return presenter!!.backButtonClicked()
|
||||
if (::mediaDetails.isInitialized && mediaDetails.isVisible) {
|
||||
removeFragment(mediaDetails)
|
||||
|
||||
binding?.coordinatorLayout?.visibility = View.VISIBLE
|
||||
binding?.map?.setMultiTouchControls(true)
|
||||
binding?.map?.isClickable = true
|
||||
|
||||
val transaction = childFragmentManager.beginTransaction()
|
||||
val fragmentContainer = childFragmentManager.findFragmentById(R.id.coordinator_layout)
|
||||
|
||||
if (fragmentContainer != null) {
|
||||
transaction.show(fragmentContainer)
|
||||
}
|
||||
|
||||
transaction.commit()
|
||||
childFragmentManager.executePendingTransactions()
|
||||
|
||||
(activity as? MainActivity)?.showTabs()
|
||||
(activity as? MainActivity)?.supportActionBar?.setDisplayHomeAsUpEnabled(false)
|
||||
return true
|
||||
} else {
|
||||
(activity as? MainActivity)?.setSelectedItemId(NavTab.NEARBY.code())
|
||||
}
|
||||
|
||||
return presenter?.backButtonClicked() ?: false
|
||||
}
|
||||
|
||||
override fun onLocationPermissionDenied(toastMessage: String) {
|
||||
|
|
@ -2299,7 +2349,23 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(), NearbyParentFragmen
|
|||
bottomSheetAdapter!!.setClickListener(this)
|
||||
binding!!.bottomSheetDetails.bottomSheetRecyclerView.adapter = bottomSheetAdapter
|
||||
updateBookmarkButtonImage(selectedPlace!!)
|
||||
|
||||
selectedPlace?.pic?.substringAfterLast("/")?.takeIf { it.isNotEmpty() }?.let { imageName ->
|
||||
Glide.with(binding!!.bottomSheetDetails.icon.context)
|
||||
.clear(binding!!.bottomSheetDetails.icon)
|
||||
Glide.with(binding!!.bottomSheetDetails.icon.context)
|
||||
.load("https://commons.wikimedia.org/wiki/Special:Redirect/file/$imageName?width=25")
|
||||
.placeholder(fr.free.nrw.commons.R.drawable.ic_refresh_24dp_nearby)
|
||||
.error(selectedPlace!!.label.icon)
|
||||
.into(binding!!.bottomSheetDetails.icon)
|
||||
|
||||
binding!!.bottomSheetDetails.icon.setOnClickListener {
|
||||
handleMediaClick(imageName)
|
||||
}
|
||||
} ?: run {
|
||||
binding!!.bottomSheetDetails.icon.setImageResource(selectedPlace!!.label.icon)
|
||||
}
|
||||
|
||||
binding!!.bottomSheetDetails.title.text = selectedPlace!!.name
|
||||
binding!!.bottomSheetDetails.category.text = selectedPlace!!.distance
|
||||
// Remove label since it is double information
|
||||
|
|
@ -2354,6 +2420,101 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(), NearbyParentFragmen
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleMediaClick(imageName: String) {
|
||||
val decodedImageName = URLDecoder.decode(imageName, StandardCharsets.UTF_8.toString())
|
||||
|
||||
mediaClient.getMedia("File:$decodedImageName")
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({ mediaResponse ->
|
||||
if (mediaResponse != null) {
|
||||
// Create a Media object from the response
|
||||
media = Media(
|
||||
pageId = mediaResponse.pageId ?: UUID.randomUUID().toString(),
|
||||
thumbUrl = mediaResponse.thumbUrl,
|
||||
imageUrl = mediaResponse.imageUrl,
|
||||
filename = mediaResponse.filename,
|
||||
fallbackDescription = mediaResponse.fallbackDescription,
|
||||
dateUploaded = mediaResponse.dateUploaded,
|
||||
license = mediaResponse.license,
|
||||
licenseUrl = mediaResponse.licenseUrl,
|
||||
author = mediaResponse.author,
|
||||
user = mediaResponse.user,
|
||||
categories = mediaResponse.categories,
|
||||
coordinates = mediaResponse.coordinates,
|
||||
captions = mediaResponse.captions ?: emptyMap(),
|
||||
descriptions = mediaResponse.descriptions ?: emptyMap(),
|
||||
depictionIds = mediaResponse.depictionIds ?: emptyList(),
|
||||
categoriesHiddenStatus = mediaResponse.categoriesHiddenStatus ?: emptyMap()
|
||||
)
|
||||
// Remove existing fragment before showing new details
|
||||
if (::mediaDetails.isInitialized && mediaDetails.isAdded) {
|
||||
removeFragment(mediaDetails)
|
||||
}
|
||||
showMediaDetails()
|
||||
} else {
|
||||
Timber.e("Fetched media is null for image: $decodedImageName")
|
||||
}
|
||||
}, { throwable ->
|
||||
Timber.e(throwable, "Error fetching media for image: $decodedImageName")
|
||||
})
|
||||
}
|
||||
|
||||
private fun showMediaDetails() {
|
||||
binding?.map?.setMultiTouchControls(false)
|
||||
binding?.map?.isClickable = false
|
||||
|
||||
mediaDetails = MediaDetailPagerFragment.newInstance(false, true)
|
||||
|
||||
|
||||
val transaction = childFragmentManager.beginTransaction()
|
||||
|
||||
val fragmentContainer = childFragmentManager.findFragmentById(R.id.coordinator_layout)
|
||||
if (fragmentContainer != null) {
|
||||
transaction.hide(fragmentContainer)
|
||||
}
|
||||
|
||||
// Replace instead of add to ensure new fragment is used
|
||||
transaction.replace(R.id.coordinator_layout, mediaDetails, "MediaDetailFragmentTag")
|
||||
transaction.addToBackStack("Nearby_Parent_Fragment_Tag").commit()
|
||||
childFragmentManager.executePendingTransactions()
|
||||
|
||||
(activity as? MainActivity)?.supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
|
||||
if (mediaDetails.isAdded) {
|
||||
mediaDetails.showImage(0)
|
||||
} else {
|
||||
Timber.e("Error: MediaDetailPagerFragment is NOT added")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMediaAtPosition(i: Int): Media? {
|
||||
return media
|
||||
}
|
||||
|
||||
override fun getTotalMediaCount(): Int {
|
||||
return 2
|
||||
}
|
||||
|
||||
override fun getContributionStateAt(position: Int): Int? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun refreshNominatedMedia(index: Int) {
|
||||
if (this::mediaDetails.isInitialized && !binding?.map?.isClickable!! == true) {
|
||||
removeFragment(mediaDetails)
|
||||
showMediaDetails()
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeFragment(fragment: Fragment) {
|
||||
childFragmentManager
|
||||
.beginTransaction()
|
||||
.remove(fragment)
|
||||
.commit()
|
||||
childFragmentManager.executePendingTransactions()
|
||||
}
|
||||
|
||||
private fun storeSharedPrefs(selectedPlace: Place) {
|
||||
applicationKvStore!!.putJson<Place>(WikidataConstants.PLACE_OBJECT, selectedPlace)
|
||||
val place =
|
||||
|
|
|
|||
|
|
@ -68,10 +68,10 @@
|
|||
<string name="username">Декъашхочун цӀе</string>
|
||||
<string name="password">Пароль</string>
|
||||
<string name="login_credential">Commons Beta тӀехь хьай цӀарца чугӀо</string>
|
||||
<string name="login">ЧугӀо</string>
|
||||
<string name="login">Чувала</string>
|
||||
<string name="forgot_password">Йицйелла пароль?</string>
|
||||
<string name="signup">ДӀайаздалар</string>
|
||||
<string name="logging_in_title">Системин чу дахар</string>
|
||||
<string name="logging_in_title">Системи чу валар</string>
|
||||
<string name="logging_in_message">Дехар до, собарде…</string>
|
||||
<string name="updating_caption_title">титраш а, йийцарш а карладохуш ду..</string>
|
||||
<string name="updating_caption_message">Дехар до, собарде…</string>
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
<string name="exit_location_picker">निकास स्थान चयनकर्ता</string>
|
||||
<string name="submit">जमा करें</string>
|
||||
<string name="add_another_description">एक और विवरण जोड़ें</string>
|
||||
<string name="add_new_contribution">नया योगदान</string>
|
||||
<string name="add_new_contribution">नया योगदान जोड़ें</string>
|
||||
<string name="add_contribution_from_camera">कैमरे से योगदान जोड़ें</string>
|
||||
<string name="add_contribution_from_photos">फ़ोटो से योगदान जोड़ें</string>
|
||||
<string name="add_contribution_from_contributions_gallery">पिछले योगदान गैलरी से योगदान जोड़ें</string>
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@
|
|||
<string name="provider_modifications">שינויים</string>
|
||||
<string name="menu_upload_single">העלאה</string>
|
||||
<string name="categories_search_text_hint">חיפוש קטגוריות</string>
|
||||
<string name="depicts_search_text_hint">חפשו פריטים שהמדיה שלכם מציגה (הר, טאג\' מהאל, וכו\')</string>
|
||||
<string name="depicts_search_text_hint">נא לחפש פריטים שהמדיה שלך מציגה (הר, טאג\' מהאל וכו\')</string>
|
||||
<string name="menu_save_categories">שמירה</string>
|
||||
<string name="menu_overflow_desc">תפריט גלישה</string>
|
||||
<string name="refresh_button">רענון</string>
|
||||
|
|
@ -851,7 +851,7 @@
|
|||
<string name="account">חשבון</string>
|
||||
<string name="vanish_account">העלמת חשבון</string>
|
||||
<string name="account_vanish_request_confirm_title">אזהרת העלמת חשבון</string>
|
||||
<string name="account_vanish_request_confirm">היעלמות היא <b>מוצא אחרון</b> וצריך <b>להשתמש בו רק כאשר אתם רוצים להפסיק לערוך לנצח</b> וגם כדי להסתיר כמה שיותר מהאסוציאציות שלכם בעבר.<br/><br/>מחיקת חשבון בויקישיתוף נעשית על ידי שינוי שם החשבון שלכם כך שאחרים לא יוכלו לזהות את התרומות שלכם בתהליך שנקרא חשבון היעלמות. <b>היעלמות אינה מבטיחה אנונימיות מוחלטת או הסרה של תרומות לפרויקטים</b>.</string>
|
||||
<string name="account_vanish_request_confirm">היעלמות היא <b>מוצא אחרון</b> וצריך להשתמש בה <b>רק כשברצונך להפסיק לערוך לתמיד</b> וגם להסתיר את הקשרים הקודמים שלך במידת האפשר.<br/><br/>מחיקת חשבון בוויקישיתוף נעשית על־ידי שינוי שם החשבון שלך כדי להסוות אותו מפני אחרים כדי שלא יוכלו לזהות את התרומות שלך בתהליך שנקרא העלמת חשבון. <b>העלמה לא מבטיחה אלמוניות מלאה או הסרת התרומות למיזמים</b>.</string>
|
||||
<string name="caption">כותרת</string>
|
||||
<string name="caption_copied_to_clipboard">הכותרת הועתקה ללוח</string>
|
||||
<string name="congratulations_all_pictures_in_this_album_have_been_either_uploaded_or_marked_as_not_for_upload">ברכותינו, כל התמונות באלבום הזה הועלו או שסומנו לא להעלאה.</string>
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@
|
|||
<string name="menu_settings">امستنې</string>
|
||||
<string name="intent_share_upload_label">خونديځ ته راپورته کول</string>
|
||||
<string name="upload_in_progress">راپورته کول جريان لري</string>
|
||||
<string name="username">کارننوم</string>
|
||||
<string name="username">کارننوم</string>
|
||||
<string name="password">پټنوم</string>
|
||||
<string name="login_credential">خپل خونديځ بېټا ګڼون ته ورننوځئ</string>
|
||||
<string name="login">ننوتل</string>
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@
|
|||
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="all">
|
||||
<string name="submit">{{Identical|Submit}}</string>
|
||||
<string name="nearby_all">{{identical|All}}</string>
|
||||
<string name="nearby_filter_toggle">יש קצת בלבול בתרגום עם להחליף למעלה, למרות שהתרגום באופן טכני נכון, המשמעות באנגלית היא החלפה בין מצבים (במקרה הזה, החלפת מצב פעיל) אז אפשר להשתמש בהפעלה כתרגום</string>
|
||||
<string name="uploads_pending_notification_indicator">Status text about number of uploads left.\n* %1$d represents number of uploads left, including current one</string>
|
||||
<string name="contributions_subtitle">See the current issue [https://phabricator.wikimedia.org/T267142 T267142] tracked in Phabricator about the <code><nowiki>|zero=</nowiki></code> option currently not supported on Translatewiki.net with the custom <code><nowiki>{{PLURAL}}</nowiki></code> rules used by this project for Android, using a non-MediaWiki syntax.</string>
|
||||
<string name="multiple_uploads_title">{{Identical|Upload}}</string>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* Alexandr Efremov
|
||||
* Av6
|
||||
* Butko
|
||||
* Cabadeck
|
||||
* DDPAT
|
||||
* Deltaspace
|
||||
* Dirruw'o
|
||||
|
|
@ -177,6 +178,7 @@
|
|||
<string name="categories_search_text_hint">Выбор категорий</string>
|
||||
<string name="depicts_search_text_hint">Искать элементы, которые изображены на вашем изображении (гора, Тадж-Махал и т. д.)</string>
|
||||
<string name="menu_save_categories">Сохранить</string>
|
||||
<string name="menu_overflow_desc">Дополнительное меню</string>
|
||||
<string name="refresh_button">Обновить</string>
|
||||
<string name="display_list_button">Список</string>
|
||||
<string name="contributions_subtitle_zero">(Загрузок пока нет)</string>
|
||||
|
|
@ -872,7 +874,11 @@
|
|||
<string name="file_usages_container_heading">Использование файла</string>
|
||||
<string name="title_activity_single_web_view">SingleWebViewActivity</string>
|
||||
<string name="account">Учётная запись</string>
|
||||
<string name="vanish_account">Удалить учётную запись</string>
|
||||
<string name="account_vanish_request_confirm_title">Предупреждение об удалении учётной записи</string>
|
||||
<string name="caption">Подпись</string>
|
||||
<string name="caption_copied_to_clipboard">Подпись скопирована в буфер обмена</string>
|
||||
<string name="congratulations_all_pictures_in_this_album_have_been_either_uploaded_or_marked_as_not_for_upload">Поздравляем, все фотографии в этом альбоме либо загружены, либо помечены как не предназначенные для загрузки.</string>
|
||||
<string name="show_in_explore">Показать в Explore</string>
|
||||
<string name="show_in_nearby">Показать в Nearby</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@
|
|||
<string name="depicts_search_text_hint">Oza merkošiid maid du media govahallá (várri, Taj Mahal, jná.)</string>
|
||||
<string name="menu_save_categories">Vurke</string>
|
||||
<string name="refresh_button">Ođasmahte</string>
|
||||
<string name="display_list_button">Liste</string>
|
||||
<string name="display_list_button">Listu</string>
|
||||
<string name="contributions_subtitle_zero">Eai vuos bajásluđemat)</string>
|
||||
<string name="categories_not_found">Ii oktage kategoriija heiven oktii %1$s:ain</string>
|
||||
<string name="depictions_not_found">Ii oktage Wikidata mearkkuš heiven oktii %1$s:ain</string>
|
||||
|
|
@ -211,7 +211,7 @@
|
|||
<string name="delete_search_dialog">Áiggutgo don duođaid dán ohcama sihkkut?</string>
|
||||
<string name="delete">Sihko</string>
|
||||
<string name="statistics">Statistihkka</string>
|
||||
<string name="level" fuzzy="true">Dássi</string>
|
||||
<string name="level">Dássi %d</string>
|
||||
<string name="notifications">Almmuhusat</string>
|
||||
<string name="list_sheet">Listu</string>
|
||||
<string name="next">Čuovvovaš</string>
|
||||
|
|
@ -250,7 +250,7 @@
|
|||
<string name="media_detail_in_all_languages">Buot gielaide</string>
|
||||
<string name="description">Govvádus</string>
|
||||
<string name="learn_more">LASSEDIEĐUT</string>
|
||||
<string name="menu_view_user_page" fuzzy="true">Čájet geavaheaddjisiiddu</string>
|
||||
<string name="menu_view_user_page">Čájet geavaheaddjidieđuid</string>
|
||||
<string name="edit_categories">Rievdat kategoriijaid</string>
|
||||
<string name="advanced_options">Lasseásahusat</string>
|
||||
<string name="apply">Geavat</string>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue