mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 12:23:58 +01:00
Merge branch 'master' into macgills/3847-convert-media-and-contribution
This commit is contained in:
commit
f6267577f4
33 changed files with 575 additions and 302 deletions
|
|
@ -76,7 +76,7 @@ dependencies {
|
||||||
testImplementation "org.powermock:powermock-api-mockito2:2.0.0-beta.5"
|
testImplementation "org.powermock:powermock-api-mockito2:2.0.0-beta.5"
|
||||||
|
|
||||||
// Unit testing
|
// Unit testing
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.13'
|
||||||
testImplementation 'org.robolectric:robolectric:4.3'
|
testImplementation 'org.robolectric:robolectric:4.3'
|
||||||
testImplementation 'androidx.test:core:1.2.0'
|
testImplementation 'androidx.test:core:1.2.0'
|
||||||
testImplementation 'com.squareup.okhttp3:mockwebserver:3.12.1'
|
testImplementation 'com.squareup.okhttp3:mockwebserver:3.12.1'
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import androidx.test.espresso.matcher.ViewMatchers
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withText
|
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||||
import androidx.test.rule.ActivityTestRule
|
import androidx.test.rule.ActivityTestRule
|
||||||
import androidx.test.runner.AndroidJUnit4
|
import androidx.test.runner.AndroidJUnit4
|
||||||
import fr.free.nrw.commons.utils.ConfigUtils
|
import fr.free.nrw.commons.utils.ConfigUtils.getVersionNameWithSha
|
||||||
import org.hamcrest.CoreMatchers
|
import org.hamcrest.CoreMatchers
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
|
|
@ -36,7 +36,9 @@ class AboutActivityTest {
|
||||||
@Test
|
@Test
|
||||||
fun testBuildNumber() {
|
fun testBuildNumber() {
|
||||||
Espresso.onView(ViewMatchers.withId(R.id.about_version))
|
Espresso.onView(ViewMatchers.withId(R.id.about_version))
|
||||||
.check(ViewAssertions.matches(withText(ConfigUtils.getVersionNameWithSha(getApplicationContext()))))
|
.check(ViewAssertions.matches(
|
||||||
|
withText(getApplicationContext<CommonsApplication>().getVersionNameWithSha())
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import androidx.test.rule.ActivityTestRule
|
||||||
import androidx.test.rule.GrantPermissionRule
|
import androidx.test.rule.GrantPermissionRule
|
||||||
import androidx.test.runner.AndroidJUnit4
|
import androidx.test.runner.AndroidJUnit4
|
||||||
import fr.free.nrw.commons.auth.LoginActivity
|
import fr.free.nrw.commons.auth.LoginActivity
|
||||||
import fr.free.nrw.commons.upload.DescriptionsAdapter
|
import fr.free.nrw.commons.upload.UploadMediaDetailAdapter
|
||||||
import fr.free.nrw.commons.util.MyViewAction
|
import fr.free.nrw.commons.util.MyViewAction
|
||||||
import fr.free.nrw.commons.utils.ConfigUtils
|
import fr.free.nrw.commons.utils.ConfigUtils
|
||||||
import org.hamcrest.core.AllOf.allOf
|
import org.hamcrest.core.AllOf.allOf
|
||||||
|
|
@ -78,7 +78,7 @@ class UploadTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testUploadWithDescription() {
|
fun testUploadWithDescription() {
|
||||||
if (!ConfigUtils.isBetaFlavour()) {
|
if (!ConfigUtils.isBetaFlavour) {
|
||||||
throw Error("This test should only be run in Beta!")
|
throw Error("This test should only be run in Beta!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,7 +96,7 @@ class UploadTest {
|
||||||
// Try to dismiss the error, if there is one (probably about duplicate files on Commons)
|
// Try to dismiss the error, if there is one (probably about duplicate files on Commons)
|
||||||
dismissWarning("Yes")
|
dismissWarning("Yes")
|
||||||
|
|
||||||
onView(allOf<View>(isDisplayed(), withId(R.id.et_title)))
|
onView(allOf<View>(isDisplayed(), withId(R.id.tv_title)))
|
||||||
.perform(replaceText(commonsFileName))
|
.perform(replaceText(commonsFileName))
|
||||||
|
|
||||||
onView(allOf<View>(isDisplayed(), withId(R.id.description_item_edit_text)))
|
onView(allOf<View>(isDisplayed(), withId(R.id.description_item_edit_text)))
|
||||||
|
|
@ -150,7 +150,7 @@ class UploadTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testUploadWithoutDescription() {
|
fun testUploadWithoutDescription() {
|
||||||
if (!ConfigUtils.isBetaFlavour()) {
|
if (!ConfigUtils.isBetaFlavour) {
|
||||||
throw Error("This test should only be run in Beta!")
|
throw Error("This test should only be run in Beta!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -168,7 +168,7 @@ class UploadTest {
|
||||||
// Try to dismiss the error, if there is one (probably about duplicate files on Commons)
|
// Try to dismiss the error, if there is one (probably about duplicate files on Commons)
|
||||||
dismissWarning("Yes")
|
dismissWarning("Yes")
|
||||||
|
|
||||||
onView(allOf<View>(isDisplayed(), withId(R.id.et_title)))
|
onView(allOf<View>(isDisplayed(), withId(R.id.tv_title)))
|
||||||
.perform(replaceText(commonsFileName))
|
.perform(replaceText(commonsFileName))
|
||||||
|
|
||||||
onView(allOf(isDisplayed(), withId(R.id.btn_next)))
|
onView(allOf(isDisplayed(), withId(R.id.btn_next)))
|
||||||
|
|
@ -209,7 +209,7 @@ class UploadTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testUploadWithMultilingualDescription() {
|
fun testUploadWithMultilingualDescription() {
|
||||||
if (!ConfigUtils.isBetaFlavour()) {
|
if (!ConfigUtils.isBetaFlavour) {
|
||||||
throw Error("This test should only be run in Beta!")
|
throw Error("This test should only be run in Beta!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -227,12 +227,12 @@ class UploadTest {
|
||||||
// Try to dismiss the error, if there is one (probably about duplicate files on Commons)
|
// Try to dismiss the error, if there is one (probably about duplicate files on Commons)
|
||||||
dismissWarningDialog()
|
dismissWarningDialog()
|
||||||
|
|
||||||
onView(allOf<View>(isDisplayed(), withId(R.id.et_title)))
|
onView(allOf<View>(isDisplayed(), withId(R.id.tv_title)))
|
||||||
.perform(replaceText(commonsFileName))
|
.perform(replaceText(commonsFileName))
|
||||||
|
|
||||||
onView(withId(R.id.rv_descriptions)).perform(
|
onView(withId(R.id.rv_descriptions)).perform(
|
||||||
RecyclerViewActions
|
RecyclerViewActions
|
||||||
.actionOnItemAtPosition<DescriptionsAdapter.ViewHolder>(0,
|
.actionOnItemAtPosition<UploadMediaDetailAdapter.ViewHolder>(0,
|
||||||
MyViewAction.typeTextInChildViewWithId(R.id.description_item_edit_text, "Test description")))
|
MyViewAction.typeTextInChildViewWithId(R.id.description_item_edit_text, "Test description")))
|
||||||
|
|
||||||
onView(withId(R.id.btn_add_description))
|
onView(withId(R.id.btn_add_description))
|
||||||
|
|
@ -240,12 +240,12 @@ class UploadTest {
|
||||||
|
|
||||||
onView(withId(R.id.rv_descriptions)).perform(
|
onView(withId(R.id.rv_descriptions)).perform(
|
||||||
RecyclerViewActions
|
RecyclerViewActions
|
||||||
.actionOnItemAtPosition<DescriptionsAdapter.ViewHolder>(1,
|
.actionOnItemAtPosition<UploadMediaDetailAdapter.ViewHolder>(1,
|
||||||
MyViewAction.selectSpinnerItemInChildViewWithId(R.id.spinner_description_languages, 2)))
|
MyViewAction.selectSpinnerItemInChildViewWithId(R.id.spinner_description_languages, 2)))
|
||||||
|
|
||||||
onView(withId(R.id.rv_descriptions)).perform(
|
onView(withId(R.id.rv_descriptions)).perform(
|
||||||
RecyclerViewActions
|
RecyclerViewActions
|
||||||
.actionOnItemAtPosition<DescriptionsAdapter.ViewHolder>(1,
|
.actionOnItemAtPosition<UploadMediaDetailAdapter.ViewHolder>(1,
|
||||||
MyViewAction.typeTextInChildViewWithId(R.id.description_item_edit_text, "Description")))
|
MyViewAction.typeTextInChildViewWithId(R.id.description_item_edit_text, "Description")))
|
||||||
|
|
||||||
onView(allOf(isDisplayed(), withId(R.id.btn_next)))
|
onView(allOf(isDisplayed(), withId(R.id.btn_next)))
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ class WelcomeActivityTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun ifBetaShowsSkipButton() {
|
fun ifBetaShowsSkipButton() {
|
||||||
if (ConfigUtils.isBetaFlavour()) {
|
if (ConfigUtils.isBetaFlavour) {
|
||||||
onView(withId(R.id.finishTutorialButton))
|
onView(withId(R.id.finishTutorialButton))
|
||||||
.check(matches(isDisplayed()))
|
.check(matches(isDisplayed()))
|
||||||
}
|
}
|
||||||
|
|
@ -31,7 +31,7 @@ class WelcomeActivityTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun ifProdHidesSkipButton() {
|
fun ifProdHidesSkipButton() {
|
||||||
if (!ConfigUtils.isBetaFlavour()) {
|
if (!ConfigUtils.isBetaFlavour) {
|
||||||
onView(withId(R.id.finishTutorialButton))
|
onView(withId(R.id.finishTutorialButton))
|
||||||
.check(matches(not(isDisplayed())))
|
.check(matches(not(isDisplayed())))
|
||||||
}
|
}
|
||||||
|
|
@ -39,7 +39,7 @@ class WelcomeActivityTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testBetaSkipButton() {
|
fun testBetaSkipButton() {
|
||||||
if (ConfigUtils.isBetaFlavour()) {
|
if (ConfigUtils.isBetaFlavour) {
|
||||||
onView(withId(R.id.finishTutorialButton))
|
onView(withId(R.id.finishTutorialButton))
|
||||||
.perform(ViewActions.click())
|
.perform(ViewActions.click())
|
||||||
assert(activityRule.activity.isDestroyed)
|
assert(activityRule.activity.isDestroyed)
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import fr.free.nrw.commons.Utils;
|
||||||
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
|
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
|
||||||
import fr.free.nrw.commons.media.MediaClient;
|
import fr.free.nrw.commons.media.MediaClient;
|
||||||
import fr.free.nrw.commons.utils.DialogUtil;
|
import fr.free.nrw.commons.utils.DialogUtil;
|
||||||
|
import fr.free.nrw.commons.wikidata.WikidataEditService;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
|
|
@ -41,7 +42,8 @@ import org.wikipedia.dataclient.WikiSite;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class ContributionsListFragment extends CommonsDaggerSupportFragment implements
|
public class ContributionsListFragment extends CommonsDaggerSupportFragment implements
|
||||||
ContributionsListContract.View, ContributionsListAdapter.Callback, WikipediaInstructionsDialogFragment.Callback {
|
ContributionsListContract.View, ContributionsListAdapter.Callback,
|
||||||
|
WikipediaInstructionsDialogFragment.Callback {
|
||||||
|
|
||||||
private static final String RV_STATE = "rv_scroll_state";
|
private static final String RV_STATE = "rv_scroll_state";
|
||||||
|
|
||||||
|
|
@ -275,7 +277,6 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public Media getMediaAtPosition(final int i) {
|
public Media getMediaAtPosition(final int i) {
|
||||||
return adapter.getContributionForPosition(i).getMedia();
|
return adapter.getContributionForPosition(i).getMedia();
|
||||||
}
|
}
|
||||||
|
|
@ -291,12 +292,13 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onConfirmClicked(@Nullable Contribution contribution, boolean copyWikicode) {
|
public void onConfirmClicked(@Nullable Contribution contribution, boolean copyWikicode) {
|
||||||
if(copyWikicode) {
|
if (copyWikicode) {
|
||||||
String wikicode = contribution.getMedia().getWikiCode();
|
String wikicode = contribution.getWikiCode();
|
||||||
Utils.copy("wikicode", wikicode, getContext());
|
Utils.copy("wikicode", wikicode, getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
final String url = languageWikipediaSite.mobileUrl() + "/wiki/" + contribution.getWikidataPlace()
|
final String url =
|
||||||
|
languageWikipediaSite.mobileUrl() + "/wiki/" + contribution.getWikidataPlace()
|
||||||
.getWikipediaPageTitle();
|
.getWikipediaPageTitle();
|
||||||
Utils.handleWebUrl(getContext(), Uri.parse(url));
|
Utils.handleWebUrl(getContext(), Uri.parse(url));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,8 @@ public class MainActivity extends NavigationBaseActivity implements FragmentMana
|
||||||
tabLayout.getTabAt(1).setCustomView(nearbyTabLinearLayout);
|
tabLayout.getTabAt(1).setCustomView(nearbyTabLinearLayout);
|
||||||
|
|
||||||
nearbyInfo.setOnClickListener(view ->
|
nearbyInfo.setOnClickListener(view ->
|
||||||
new AlertDialog.Builder(MainActivity.this).setTitle(R.string.title_activity_nearby).setMessage(R.string.showcase_view_whole_nearby_activity)
|
new AlertDialog.Builder(MainActivity.this).setTitle(R.string.title_activity_nearby)
|
||||||
|
.setView(getLayoutInflater().inflate(R.layout.dialog_nearby, null))
|
||||||
.setCancelable(true)
|
.setCancelable(true)
|
||||||
.setPositiveButton(android.R.string.ok, (dialog, id) -> dialog.cancel())
|
.setPositiveButton(android.R.string.ok, (dialog, id) -> dialog.cancel())
|
||||||
.create()
|
.create()
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,12 @@ import java.io.IOException
|
||||||
*
|
*
|
||||||
* @author Ashish Kumar
|
* @author Ashish Kumar
|
||||||
*/
|
*/
|
||||||
class CountingRequestBody(protected var delegate: RequestBody, protected var listener: Listener) : RequestBody() {
|
class CountingRequestBody(
|
||||||
|
protected var delegate: RequestBody,
|
||||||
|
protected var listener: Listener,
|
||||||
|
var offset: Long,
|
||||||
|
var totalContentLength: Long
|
||||||
|
) : RequestBody() {
|
||||||
protected var countingSink: CountingSink? = null
|
protected var countingSink: CountingSink? = null
|
||||||
override fun contentType(): MediaType? {
|
override fun contentType(): MediaType? {
|
||||||
return delegate.contentType()
|
return delegate.contentType()
|
||||||
|
|
@ -37,11 +42,12 @@ class CountingRequestBody(protected var delegate: RequestBody, protected var lis
|
||||||
|
|
||||||
protected inner class CountingSink(delegate: Sink?) : ForwardingSink(delegate!!) {
|
protected inner class CountingSink(delegate: Sink?) : ForwardingSink(delegate!!) {
|
||||||
private var bytesWritten: Long = 0
|
private var bytesWritten: Long = 0
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
override fun write(source: Buffer, byteCount: Long) {
|
override fun write(source: Buffer, byteCount: Long) {
|
||||||
super.write(source, byteCount)
|
super.write(source, byteCount)
|
||||||
bytesWritten += byteCount
|
bytesWritten += byteCount
|
||||||
listener.onRequestProgress(bytesWritten, contentLength())
|
listener.onRequestProgress(offset + bytesWritten, totalContentLength)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,21 @@
|
||||||
package fr.free.nrw.commons.upload;
|
package fr.free.nrw.commons.upload;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import io.reactivex.Observable;
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class FileUtilsWrapper {
|
public class FileUtilsWrapper {
|
||||||
|
|
@ -30,4 +40,45 @@ public class FileUtilsWrapper {
|
||||||
public String getGeolocationOfFile(String filePath) {
|
public String getGeolocationOfFile(String filePath) {
|
||||||
return FileUtils.getGeolocationOfFile(filePath);
|
return FileUtils.getGeolocationOfFile(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a file as input and returns an Observable of files with the specified chunk size
|
||||||
|
*/
|
||||||
|
public Observable<File> getFileChunks(Context context, File file, final int chunkSize)
|
||||||
|
throws IOException {
|
||||||
|
final byte[] buffer = new byte[chunkSize];
|
||||||
|
|
||||||
|
//try-with-resources to ensure closing stream
|
||||||
|
try (final FileInputStream fis = new FileInputStream(file);
|
||||||
|
final BufferedInputStream bis = new BufferedInputStream(fis)) {
|
||||||
|
final List<File> buffers = new ArrayList<>();
|
||||||
|
int size;
|
||||||
|
while ((size = bis.read(buffer)) > 0) {
|
||||||
|
buffers.add(writeToFile(context, Arrays.copyOf(buffer, size), file.getName(),
|
||||||
|
getFileExt(file.getName())));
|
||||||
|
}
|
||||||
|
return Observable.fromIterable(buffers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a temp file containing the passed byte data.
|
||||||
|
*/
|
||||||
|
private File writeToFile(Context context, final byte[] data, final String fileName,
|
||||||
|
String fileExtension)
|
||||||
|
throws IOException {
|
||||||
|
final File file = File.createTempFile(fileName, fileExtension, context.getCacheDir());
|
||||||
|
try {
|
||||||
|
if (!file.exists()) {
|
||||||
|
file.createNewFile();
|
||||||
|
}
|
||||||
|
final FileOutputStream fos = new FileOutputStream(file);
|
||||||
|
fos.write(data);
|
||||||
|
fos.close();
|
||||||
|
} catch (final Exception throwable) {
|
||||||
|
Timber.e(throwable, "Failed to create file");
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,15 @@ import static fr.free.nrw.commons.di.NetworkingModule.NAMED_COMMONS_CSRF;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import fr.free.nrw.commons.CommonsApplication;
|
import fr.free.nrw.commons.CommonsApplication;
|
||||||
import fr.free.nrw.commons.contributions.Contribution;
|
import fr.free.nrw.commons.contributions.Contribution;
|
||||||
import fr.free.nrw.commons.upload.UploadService.NotificationUpdateProgressListener;
|
import fr.free.nrw.commons.upload.UploadService.NotificationUpdateProgressListener;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
@ -16,57 +20,110 @@ import okhttp3.MediaType;
|
||||||
import okhttp3.MultipartBody;
|
import okhttp3.MultipartBody;
|
||||||
import okhttp3.RequestBody;
|
import okhttp3.RequestBody;
|
||||||
import org.wikipedia.csrf.CsrfTokenClient;
|
import org.wikipedia.csrf.CsrfTokenClient;
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class UploadClient {
|
public class UploadClient {
|
||||||
|
|
||||||
|
private final int CHUNK_SIZE = 256 * 1024; // 256 KB
|
||||||
|
|
||||||
private final UploadInterface uploadInterface;
|
private final UploadInterface uploadInterface;
|
||||||
private final CsrfTokenClient csrfTokenClient;
|
private final CsrfTokenClient csrfTokenClient;
|
||||||
private final PageContentsCreator pageContentsCreator;
|
private final PageContentsCreator pageContentsCreator;
|
||||||
|
private final FileUtilsWrapper fileUtilsWrapper;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public UploadClient(UploadInterface uploadInterface,
|
public UploadClient(final UploadInterface uploadInterface,
|
||||||
@Named(NAMED_COMMONS_CSRF) CsrfTokenClient csrfTokenClient,
|
@Named(NAMED_COMMONS_CSRF) final CsrfTokenClient csrfTokenClient,
|
||||||
PageContentsCreator pageContentsCreator) {
|
final PageContentsCreator pageContentsCreator,
|
||||||
|
final FileUtilsWrapper fileUtilsWrapper) {
|
||||||
this.uploadInterface = uploadInterface;
|
this.uploadInterface = uploadInterface;
|
||||||
this.csrfTokenClient = csrfTokenClient;
|
this.csrfTokenClient = csrfTokenClient;
|
||||||
this.pageContentsCreator = pageContentsCreator;
|
this.pageContentsCreator = pageContentsCreator;
|
||||||
|
this.fileUtilsWrapper = fileUtilsWrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
Observable<UploadResult> uploadFileToStash(Context context, String filename, File file,
|
/**
|
||||||
NotificationUpdateProgressListener notificationUpdater) {
|
* Upload file to stash in chunks of specified size. Uploading files in chunks will make handling
|
||||||
RequestBody requestBody = RequestBody
|
* of large files easier. Also, it will be useful in supporting pause/resume of uploads
|
||||||
.create(MediaType.parse(FileUtils.getMimeType(context, Uri.parse(file.getPath()))), file);
|
*/
|
||||||
|
Observable<UploadResult> uploadFileToStash(
|
||||||
|
final Context context, final String filename, final File file,
|
||||||
|
final NotificationUpdateProgressListener notificationUpdater) throws IOException {
|
||||||
|
final Observable<File> fileChunks = fileUtilsWrapper.getFileChunks(context, file, CHUNK_SIZE);
|
||||||
|
final MediaType mediaType = MediaType
|
||||||
|
.parse(FileUtils.getMimeType(context, Uri.parse(file.getPath())));
|
||||||
|
|
||||||
CountingRequestBody countingRequestBody = new CountingRequestBody(requestBody,
|
final long[] offset = {0};
|
||||||
(bytesWritten, contentLength) -> notificationUpdater
|
final String[] fileKey = {null};
|
||||||
.onProgress(bytesWritten, contentLength));
|
final AtomicReference<UploadResult> result = new AtomicReference<>();
|
||||||
|
fileChunks.blockingForEach(chunkFile -> {
|
||||||
|
final RequestBody requestBody = RequestBody
|
||||||
|
.create(mediaType, chunkFile);
|
||||||
|
final CountingRequestBody countingRequestBody = new CountingRequestBody(requestBody,
|
||||||
|
notificationUpdater::onProgress, offset[0], file.length());
|
||||||
|
uploadChunkToStash(filename,
|
||||||
|
file.length(),
|
||||||
|
offset[0],
|
||||||
|
fileKey[0],
|
||||||
|
countingRequestBody).blockingSubscribe(uploadResult -> {
|
||||||
|
result.set(uploadResult);
|
||||||
|
offset[0] = uploadResult.getOffset();
|
||||||
|
fileKey[0] = uploadResult.getFilekey();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return Observable.just(result.get());
|
||||||
|
}
|
||||||
|
|
||||||
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", filename, countingRequestBody);
|
/**
|
||||||
RequestBody fileNameRequestBody = RequestBody.create(okhttp3.MultipartBody.FORM, filename);
|
* Uploads a file chunk to stash
|
||||||
RequestBody tokenRequestBody;
|
*
|
||||||
|
* @param filename The name of the file being uploaded
|
||||||
|
* @param fileSize The total size of the file
|
||||||
|
* @param offset The offset returned by the previous chunk upload
|
||||||
|
* @param fileKey The filekey returned by the previous chunk upload
|
||||||
|
* @param countingRequestBody Request body with chunk file
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Observable<UploadResult> uploadChunkToStash(final String filename,
|
||||||
|
final long fileSize,
|
||||||
|
final long offset,
|
||||||
|
final String fileKey,
|
||||||
|
final CountingRequestBody countingRequestBody) {
|
||||||
|
final MultipartBody.Part filePart = MultipartBody.Part
|
||||||
|
.createFormData("chunk", filename, countingRequestBody);
|
||||||
try {
|
try {
|
||||||
tokenRequestBody = RequestBody.create(MultipartBody.FORM, csrfTokenClient.getTokenBlocking());
|
return uploadInterface.uploadFileToStash(toRequestBody(filename),
|
||||||
return uploadInterface.uploadFileToStash(fileNameRequestBody, tokenRequestBody, filePart)
|
toRequestBody(String.valueOf(fileSize)),
|
||||||
.map(stashUploadResponse -> stashUploadResponse.getUpload());
|
toRequestBody(String.valueOf(offset)),
|
||||||
} catch (Throwable throwable) {
|
toRequestBody(fileKey),
|
||||||
throwable.printStackTrace();
|
toRequestBody(csrfTokenClient.getTokenBlocking()),
|
||||||
|
filePart)
|
||||||
|
.map(UploadResponse::getUpload);
|
||||||
|
} catch (final Throwable throwable) {
|
||||||
|
Timber.e(throwable, "Failed to upload chunk to stash");
|
||||||
return Observable.error(throwable);
|
return Observable.error(throwable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Observable<UploadResult> uploadFileFromStash(Context context,
|
@Nullable
|
||||||
Contribution contribution,
|
private RequestBody toRequestBody(@Nullable final String value) {
|
||||||
String uniqueFileName,
|
return value == null ? null : RequestBody.create(okhttp3.MultipartBody.FORM, value);
|
||||||
String fileKey) {
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Observable<UploadResult> uploadFileFromStash(final Context context,
|
||||||
|
final Contribution contribution,
|
||||||
|
final String uniqueFileName,
|
||||||
|
final String fileKey) {
|
||||||
try {
|
try {
|
||||||
return uploadInterface
|
return uploadInterface
|
||||||
.uploadFileFromStash(csrfTokenClient.getTokenBlocking(),
|
.uploadFileFromStash(csrfTokenClient.getTokenBlocking(),
|
||||||
pageContentsCreator.createFrom(contribution),
|
pageContentsCreator.createFrom(contribution),
|
||||||
CommonsApplication.DEFAULT_EDIT_SUMMARY,
|
CommonsApplication.DEFAULT_EDIT_SUMMARY,
|
||||||
uniqueFileName,
|
uniqueFileName,
|
||||||
fileKey).map(uploadResponse -> uploadResponse.getUpload());
|
fileKey).map(UploadResponse::getUpload);
|
||||||
} catch (Throwable throwable) {
|
} catch (final Throwable throwable) {
|
||||||
throwable.printStackTrace();
|
throwable.printStackTrace();
|
||||||
return Observable.error(throwable);
|
return Observable.error(throwable);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,9 @@ public interface UploadInterface {
|
||||||
@Multipart
|
@Multipart
|
||||||
@POST(MW_API_PREFIX + "action=upload&stash=1&ignorewarnings=1")
|
@POST(MW_API_PREFIX + "action=upload&stash=1&ignorewarnings=1")
|
||||||
Observable<UploadResponse> uploadFileToStash(@Part("filename") RequestBody filename,
|
Observable<UploadResponse> uploadFileToStash(@Part("filename") RequestBody filename,
|
||||||
|
@Part("filesize") RequestBody totalFileSize,
|
||||||
|
@Part("offset") RequestBody offset,
|
||||||
|
@Part("filekey") RequestBody fileKey,
|
||||||
@Part("token") RequestBody token,
|
@Part("token") RequestBody token,
|
||||||
@Part MultipartBody.Part filePart);
|
@Part MultipartBody.Part filePart);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ private const val RESULT_SUCCESS = "Success"
|
||||||
data class UploadResult(
|
data class UploadResult(
|
||||||
val result: String,
|
val result: String,
|
||||||
val filekey: String,
|
val filekey: String,
|
||||||
|
val offset: Int,
|
||||||
val filename: String,
|
val filename: String,
|
||||||
val sessionkey: String,
|
val sessionkey: String,
|
||||||
val imageinfo: ImageInfo
|
val imageinfo: ImageInfo
|
||||||
|
|
|
||||||
|
|
@ -22,24 +22,16 @@ import fr.free.nrw.commons.contributions.MainActivity;
|
||||||
import fr.free.nrw.commons.di.CommonsApplicationModule;
|
import fr.free.nrw.commons.di.CommonsApplicationModule;
|
||||||
import fr.free.nrw.commons.di.CommonsDaggerService;
|
import fr.free.nrw.commons.di.CommonsDaggerService;
|
||||||
import fr.free.nrw.commons.media.MediaClient;
|
import fr.free.nrw.commons.media.MediaClient;
|
||||||
import fr.free.nrw.commons.utils.CommonsDateUtil;
|
|
||||||
import fr.free.nrw.commons.wikidata.WikidataEditService;
|
import fr.free.nrw.commons.wikidata.WikidataEditService;
|
||||||
import io.reactivex.Completable;
|
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.Scheduler;
|
import io.reactivex.Scheduler;
|
||||||
import io.reactivex.Single;
|
|
||||||
import io.reactivex.disposables.CompositeDisposable;
|
import io.reactivex.disposables.CompositeDisposable;
|
||||||
import io.reactivex.disposables.Disposable;
|
|
||||||
import io.reactivex.functions.Action;
|
|
||||||
import io.reactivex.functions.Consumer;
|
|
||||||
import io.reactivex.processors.PublishProcessor;
|
import io.reactivex.processors.PublishProcessor;
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.text.ParseException;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
@ -316,7 +308,7 @@ public class UploadService extends CommonsDaggerService {
|
||||||
.add(wikidataEditService.addDepictionsAndCaptions(uploadResult, contribution));
|
.add(wikidataEditService.addDepictionsAndCaptions(uploadResult, contribution));
|
||||||
WikidataPlace wikidataPlace = contribution.getWikidataPlace();
|
WikidataPlace wikidataPlace = contribution.getWikidataPlace();
|
||||||
if (wikidataPlace != null && wikidataPlace.getImageValue() == null) {
|
if (wikidataPlace != null && wikidataPlace.getImageValue() == null) {
|
||||||
wikidataEditService.createImageClaim(wikidataPlace, uploadResult);
|
wikidataEditService.createClaim(wikidataPlace, uploadResult.getFilename(), contribution.getCaptions());
|
||||||
}
|
}
|
||||||
saveCompletedContribution(contribution, uploadResult);
|
saveCompletedContribution(contribution, uploadResult);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package fr.free.nrw.commons.wikidata;
|
package fr.free.nrw.commons.wikidata;
|
||||||
|
|
||||||
import fr.free.nrw.commons.upload.WikidataItem;
|
import com.google.gson.Gson;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
@ -9,64 +9,38 @@ import javax.inject.Singleton;
|
||||||
import fr.free.nrw.commons.wikidata.model.AddEditTagResponse;
|
import fr.free.nrw.commons.wikidata.model.AddEditTagResponse;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.ObservableSource;
|
import io.reactivex.ObservableSource;
|
||||||
import okhttp3.MediaType;
|
import org.wikipedia.wikidata.Statement_partial;
|
||||||
import okhttp3.RequestBody;
|
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class WikidataClient {
|
public class WikidataClient {
|
||||||
|
|
||||||
|
|
||||||
private final WikidataInterface wikidataInterface;
|
private final WikidataInterface wikidataInterface;
|
||||||
|
private final Gson gson;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public WikidataClient(WikidataInterface wikidataInterface) {
|
public WikidataClient(WikidataInterface wikidataInterface, final Gson gson) {
|
||||||
this.wikidataInterface = wikidataInterface;
|
this.wikidataInterface = wikidataInterface;
|
||||||
|
this.gson = gson;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create wikidata claim to add P18 value
|
* Create wikidata claim to add P18 value
|
||||||
* @param entity wikidata entity ID
|
*
|
||||||
* @param value value of the P18 edit
|
|
||||||
* @return revisionID of the edit
|
* @return revisionID of the edit
|
||||||
*/
|
*/
|
||||||
Observable<Long> createImageClaim(WikidataItem entity, String value) {
|
Observable<Long> setClaim(Statement_partial claim, String tags) {
|
||||||
return getCsrfToken()
|
return getCsrfToken()
|
||||||
.flatMap(csrfToken -> wikidataInterface.postCreateClaim(
|
.flatMap(csrfToken -> wikidataInterface.postSetClaim(gson.toJson(claim), tags, csrfToken))
|
||||||
toRequestBody(entity.getId()),
|
|
||||||
toRequestBody("value"),
|
|
||||||
toRequestBody(WikidataProperties.IMAGE.getPropertyName()),
|
|
||||||
toRequestBody(value),
|
|
||||||
toRequestBody("en"),
|
|
||||||
toRequestBody(csrfToken)))
|
|
||||||
.map(mwPostResponse -> mwPostResponse.getPageinfo().getLastrevid());
|
.map(mwPostResponse -> mwPostResponse.getPageinfo().getLastrevid());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts string value to RequestBody for multipart request
|
|
||||||
*/
|
|
||||||
private RequestBody toRequestBody(String value) {
|
|
||||||
return RequestBody.create(MediaType.parse("text/plain"), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get csrf token for wikidata edit
|
* Get csrf token for wikidata edit
|
||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
private Observable<String> getCsrfToken() {
|
private Observable<String> getCsrfToken() {
|
||||||
return wikidataInterface.getCsrfToken().map(mwQueryResponse -> mwQueryResponse.query().csrfToken());
|
return wikidataInterface.getCsrfToken()
|
||||||
}
|
.map(mwQueryResponse -> mwQueryResponse.query().csrfToken());
|
||||||
|
|
||||||
/**
|
|
||||||
* Add edit tag for a given revision ID. The app currently uses this to tag P18 edits
|
|
||||||
* @param revisionId revision ID of the page edited
|
|
||||||
* @param tag to be added
|
|
||||||
* @param reason to be mentioned
|
|
||||||
*/
|
|
||||||
ObservableSource<AddEditTagResponse> addEditTag(Long revisionId, String tag, String reason) {
|
|
||||||
return getCsrfToken()
|
|
||||||
.flatMap(csrfToken -> wikidataInterface.addEditTag(String.valueOf(revisionId),
|
|
||||||
tag,
|
|
||||||
reason,
|
|
||||||
csrfToken));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,24 +20,33 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.disposables.Disposable;
|
import io.reactivex.disposables.Disposable;
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
import org.wikipedia.dataclient.mwapi.MwPostResponse;
|
import org.wikipedia.dataclient.mwapi.MwPostResponse;
|
||||||
|
import org.wikipedia.wikidata.DataValue;
|
||||||
|
import org.wikipedia.wikidata.DataValue.ValueString;
|
||||||
import org.wikipedia.wikidata.EditClaim;
|
import org.wikipedia.wikidata.EditClaim;
|
||||||
|
import org.wikipedia.wikidata.Snak_partial;
|
||||||
|
import org.wikipedia.wikidata.Statement_partial;
|
||||||
|
import org.wikipedia.wikidata.WikiBaseMonolingualTextValue;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is meant to handle the Wikidata edits made through the app
|
* This class is meant to handle the Wikidata edits made through the app It will talk with MediaWiki
|
||||||
* It will talk with MediaWiki Apis to make the necessary calls, log the edits and fire listeners
|
* Apis to make the necessary calls, log the edits and fire listeners on successful edits
|
||||||
* on successful edits
|
|
||||||
*/
|
*/
|
||||||
@Singleton
|
@Singleton
|
||||||
public class WikidataEditService {
|
public class WikidataEditService {
|
||||||
|
|
||||||
private static final String COMMONS_APP_TAG = "wikimedia-commons-app";
|
public static final String COMMONS_APP_TAG = "wikimedia-commons-app";
|
||||||
private static final String COMMONS_APP_EDIT_REASON = "Add tag for edits made using Android Commons app";
|
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final WikidataEditListener wikidataEditListener;
|
private final WikidataEditListener wikidataEditListener;
|
||||||
|
|
@ -61,8 +70,8 @@ public class WikidataEditService {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edits the wikibase entity by adding DEPICTS property.
|
* Edits the wikibase entity by adding DEPICTS property. Adding DEPICTS property requires call to
|
||||||
* Adding DEPICTS property requires call to the wikibase API to set tag against the entity.
|
* the wikibase API to set tag against the entity.
|
||||||
*/
|
*/
|
||||||
@SuppressLint("CheckResult")
|
@SuppressLint("CheckResult")
|
||||||
private Observable<Boolean> addDepictsProperty(final String fileEntityId,
|
private Observable<Boolean> addDepictsProperty(final String fileEntityId,
|
||||||
|
|
@ -81,7 +90,7 @@ public class WikidataEditService {
|
||||||
Timber.d("Unable to set DEPICTS property for %s", fileEntityId);
|
Timber.d("Unable to set DEPICTS property for %s", fileEntityId);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.doOnError( throwable -> {
|
.doOnError(throwable -> {
|
||||||
Timber.e(throwable, "Error occurred while setting DEPICTS property");
|
Timber.e(throwable, "Error occurred while setting DEPICTS property");
|
||||||
ViewUtil.showLongToast(context, throwable.toString());
|
ViewUtil.showLongToast(context, throwable.toString());
|
||||||
})
|
})
|
||||||
|
|
@ -97,12 +106,14 @@ public class WikidataEditService {
|
||||||
*/
|
*/
|
||||||
private void showSuccessToast(final String wikiItemName) {
|
private void showSuccessToast(final String wikiItemName) {
|
||||||
final String successStringTemplate = context.getString(R.string.successful_wikidata_edit);
|
final String successStringTemplate = context.getString(R.string.successful_wikidata_edit);
|
||||||
final String successMessage = String.format(Locale.getDefault(), successStringTemplate, wikiItemName);
|
final String successMessage = String
|
||||||
|
.format(Locale.getDefault(), successStringTemplate, wikiItemName);
|
||||||
ViewUtil.showLongToast(context, successMessage);
|
ViewUtil.showLongToast(context, successMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds label to Wikidata using the fileEntityId and the edit token, obtained from csrfTokenClient
|
* Adds label to Wikidata using the fileEntityId and the edit token, obtained from
|
||||||
|
* csrfTokenClient
|
||||||
*
|
*
|
||||||
* @param fileEntityId
|
* @param fileEntityId
|
||||||
* @return
|
* @return
|
||||||
|
|
@ -112,7 +123,7 @@ public class WikidataEditService {
|
||||||
private Observable<Boolean> addCaption(final long fileEntityId, final String languageCode,
|
private Observable<Boolean> addCaption(final long fileEntityId, final String languageCode,
|
||||||
final String captionValue) {
|
final String captionValue) {
|
||||||
return wikiBaseClient.addLabelstoWikidata(fileEntityId, languageCode, captionValue)
|
return wikiBaseClient.addLabelstoWikidata(fileEntityId, languageCode, captionValue)
|
||||||
.doOnNext(mwPostResponse -> onAddCaptionResponse(fileEntityId, mwPostResponse) )
|
.doOnNext(mwPostResponse -> onAddCaptionResponse(fileEntityId, mwPostResponse))
|
||||||
.doOnError(throwable -> {
|
.doOnError(throwable -> {
|
||||||
Timber.e(throwable, "Error occurred while setting Captions");
|
Timber.e(throwable, "Error occurred while setting Captions");
|
||||||
ViewUtil.showLongToast(context, context.getString(R.string.wikidata_edit_failure));
|
ViewUtil.showLongToast(context, context.getString(R.string.wikidata_edit_failure));
|
||||||
|
|
@ -128,29 +139,41 @@ public class WikidataEditService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createImageClaim(@Nullable final WikidataPlace wikidataPlace, final UploadResult imageUpload) {
|
public void createClaim(@Nullable final WikidataPlace wikidataPlace, final String fileName, final
|
||||||
|
Map<String, String> captions) {
|
||||||
if (!(directKvStore.getBoolean("Picture_Has_Correct_Location", true))) {
|
if (!(directKvStore.getBoolean("Picture_Has_Correct_Location", true))) {
|
||||||
Timber.d("Image location and nearby place location mismatched, so Wikidata item won't be edited");
|
Timber
|
||||||
|
.d("Image location and nearby place location mismatched, so Wikidata item won't be edited");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
editWikidataImageProperty(wikidataPlace, imageUpload);
|
addImageAndMediaLegends(wikidataPlace, fileName, captions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("CheckResult")
|
public void addImageAndMediaLegends(final WikidataItem wikidataItem, final String fileName,
|
||||||
private void editWikidataImageProperty(final WikidataItem wikidataItem, final UploadResult imageUpload) {
|
final Map<String, String> captions) {
|
||||||
wikidataClient.createImageClaim(wikidataItem, String.format("\"%s\"", imageUpload.getFilename()))
|
final Snak_partial p18 = new Snak_partial("value", WikidataProperties.IMAGE.getPropertyName(),
|
||||||
.flatMap(revisionId -> {
|
new ValueString(fileName.replace("File:", "")));
|
||||||
if (revisionId != -1) {
|
|
||||||
return wikidataClient.addEditTag(revisionId, COMMONS_APP_TAG, COMMONS_APP_EDIT_REASON);
|
final List<Snak_partial> snaks = new ArrayList<>();
|
||||||
|
for (final Map.Entry<String, String> entry : captions.entrySet()) {
|
||||||
|
snaks.add(new Snak_partial("value",
|
||||||
|
WikidataProperties.MEDIA_LEGENDS.getPropertyName(), new DataValue.MonoLingualText(
|
||||||
|
new WikiBaseMonolingualTextValue(entry.getValue(), entry.getKey()))));
|
||||||
}
|
}
|
||||||
throw new RuntimeException("Unable to edit wikidata item");
|
|
||||||
})
|
final String id = wikidataItem.getId() + "$" + UUID.randomUUID().toString();
|
||||||
.subscribeOn(Schedulers.io())
|
final Statement_partial claim = new Statement_partial(p18, "statement", "normal", id,
|
||||||
|
Collections.singletonMap(WikidataProperties.MEDIA_LEGENDS.getPropertyName(), snaks),
|
||||||
|
Arrays.asList(WikidataProperties.MEDIA_LEGENDS.getPropertyName()));
|
||||||
|
|
||||||
|
wikidataClient.setClaim(claim, COMMONS_APP_TAG).subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(revisionId -> handleImageClaimResult(wikidataItem, String.valueOf(revisionId)), throwable -> {
|
.subscribe(revisionId -> handleImageClaimResult(wikidataItem, String.valueOf(revisionId)),
|
||||||
|
throwable -> {
|
||||||
Timber.e(throwable, "Error occurred while making claim");
|
Timber.e(throwable, "Error occurred while making claim");
|
||||||
ViewUtil.showLongToast(context, context.getString(R.string.wikidata_edit_failure));
|
ViewUtil.showLongToast(context, context.getString(R.string.wikidata_edit_failure));
|
||||||
});
|
});
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleImageClaimResult(final WikidataItem wikidataItem, final String revisionId) {
|
private void handleImageClaimResult(final WikidataItem wikidataItem, final String revisionId) {
|
||||||
|
|
@ -202,6 +225,6 @@ public class WikidataEditService {
|
||||||
depictedItems.add(wikidataPlace);
|
depictedItems.add(wikidataPlace);
|
||||||
}
|
}
|
||||||
return Observable.fromIterable(depictedItems)
|
return Observable.fromIterable(depictedItems)
|
||||||
.concatMap( wikidataItem -> addDepictsProperty(fileEntityId.toString(), wikidataItem));
|
.concatMap(wikidataItem -> addDepictsProperty(fileEntityId.toString(), wikidataItem));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package fr.free.nrw.commons.wikidata;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
import org.wikipedia.dataclient.mwapi.MwQueryResponse;
|
import org.wikipedia.dataclient.mwapi.MwQueryResponse;
|
||||||
|
|
||||||
import fr.free.nrw.commons.wikidata.model.AddEditTagResponse;
|
import fr.free.nrw.commons.wikidata.model.AddEditTagResponse;
|
||||||
|
|
@ -20,30 +21,6 @@ import static org.wikipedia.dataclient.Service.MW_API_PREFIX;
|
||||||
|
|
||||||
public interface WikidataInterface {
|
public interface WikidataInterface {
|
||||||
|
|
||||||
/**
|
|
||||||
* Wikidata create claim API. Posts a new claim for the given entity ID
|
|
||||||
*/
|
|
||||||
@Headers("Cache-Control: no-cache")
|
|
||||||
@POST("w/api.php?format=json&errorformat=plaintext&action=wbcreateclaim&errorlang=uselang")
|
|
||||||
@Multipart
|
|
||||||
Observable<WbCreateClaimResponse> postCreateClaim(@NonNull @Part("entity") RequestBody entity,
|
|
||||||
@NonNull @Part("snaktype") RequestBody snakType,
|
|
||||||
@NonNull @Part("property") RequestBody property,
|
|
||||||
@NonNull @Part("value") RequestBody value,
|
|
||||||
@NonNull @Part("uselang") RequestBody useLang,
|
|
||||||
@NonNull @Part("token") RequestBody token);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add edit tag and reason for any revision
|
|
||||||
*/
|
|
||||||
@Headers("Cache-Control: no-cache")
|
|
||||||
@POST(MW_API_PREFIX + "action=tag")
|
|
||||||
@FormUrlEncoded
|
|
||||||
Observable<AddEditTagResponse> addEditTag(@NonNull @Field("revid") String revId,
|
|
||||||
@NonNull @Field("add") String tagName,
|
|
||||||
@NonNull @Field("reason") String reason,
|
|
||||||
@NonNull @Field("token") String token);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get edit token for wikidata wiki site
|
* Get edit token for wikidata wiki site
|
||||||
*/
|
*/
|
||||||
|
|
@ -51,4 +28,14 @@ public interface WikidataInterface {
|
||||||
@GET(MW_API_PREFIX + "action=query&meta=tokens&type=csrf")
|
@GET(MW_API_PREFIX + "action=query&meta=tokens&type=csrf")
|
||||||
@NonNull
|
@NonNull
|
||||||
Observable<MwQueryResponse> getCsrfToken();
|
Observable<MwQueryResponse> getCsrfToken();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wikidata create claim API. Posts a new claim for the given entity ID
|
||||||
|
*/
|
||||||
|
@Headers("Cache-Control: no-cache")
|
||||||
|
@POST("w/api.php?format=json&action=wbsetclaim")
|
||||||
|
@FormUrlEncoded
|
||||||
|
Observable<WbCreateClaimResponse> postSetClaim(@NonNull @Field("claim") String request,
|
||||||
|
@NonNull @Field("tags") String tags,
|
||||||
|
@NonNull @Field("token") String token);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,5 +6,6 @@ enum class WikidataProperties(val propertyName: String) {
|
||||||
IMAGE("P18"),
|
IMAGE("P18"),
|
||||||
DEPICTS(BuildConfig.DEPICTS_PROPERTY),
|
DEPICTS(BuildConfig.DEPICTS_PROPERTY),
|
||||||
COMMONS_CATEGORY("P373"),
|
COMMONS_CATEGORY("P373"),
|
||||||
INSTANCE_OF("P31");
|
INSTANCE_OF("P31"),
|
||||||
|
MEDIA_LEGENDS("P2096");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
76
app/src/main/res/layout/dialog_nearby.xml
Normal file
76
app/src/main/res/layout/dialog_nearby.xml
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingLeft="20dp"
|
||||||
|
android:paddingRight="20dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:text="@string/showcase_view_whole_nearby_activity"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
app:srcCompat="@drawable/ic_custom_map_marker" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0"
|
||||||
|
android:text="@string/showcase_view_needs_photo"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
app:srcCompat="@drawable/ic_custom_map_marker_green" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0"
|
||||||
|
android:text="@string/showcase_view_has_photo"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
app:srcCompat="@drawable/ic_custom_map_marker_grey" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0"
|
||||||
|
android:text="@string/showcase_view_no_longer_exists"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
* Abijeet Patro
|
* Abijeet Patro
|
||||||
* Amirsara
|
* Amirsara
|
||||||
* Arash.pt
|
* Arash.pt
|
||||||
|
* BaRaN6161 TURK
|
||||||
* Ebraminio
|
* Ebraminio
|
||||||
* Eshagh79
|
* Eshagh79
|
||||||
* FarsiNevis
|
* FarsiNevis
|
||||||
|
|
@ -28,7 +29,11 @@
|
||||||
<item quantity="one">%1$d پرونده در حال بارگذاری</item>
|
<item quantity="one">%1$d پرونده در حال بارگذاری</item>
|
||||||
<item quantity="other">%1$d پرونده در حال بارگذاری</item>
|
<item quantity="other">%1$d پرونده در حال بارگذاری</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="contributions_subtitle">{{%1$d|zero=@string/contributions_subtitle_zero|one=(%1$d)|(%1$d)}}</string>
|
<plurals name="contributions_subtitle">
|
||||||
|
<item quantity="zero">\@string/contributions_subtitle_zero</item>
|
||||||
|
<item quantity="one">(%1$d)</item>
|
||||||
|
<item quantity="other">(%1$d)</item>
|
||||||
|
</plurals>
|
||||||
<plurals name="starting_multiple_uploads">
|
<plurals name="starting_multiple_uploads">
|
||||||
<item quantity="one">شروع %1$d بارگذاری پرونده</item>
|
<item quantity="one">شروع %1$d بارگذاری پرونده</item>
|
||||||
<item quantity="other">شروع بارگذاری %1$d پرونده</item>
|
<item quantity="other">شروع بارگذاری %1$d پرونده</item>
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="multiple_uploads_title">
|
<plurals name="multiple_uploads_title">
|
||||||
<item quantity="one">%1$d개 올리적재</item>
|
<item quantity="one">%1$d개 올리적재</item>
|
||||||
|
<item quantity="other">%1$d개 올리적재</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="share_license_summary">이 그림은 %1$s에 따라 사용이 허가됩니다</string>
|
<string name="share_license_summary">이 그림은 %1$s에 따라 사용이 허가됩니다</string>
|
||||||
<string name="title_activity_explore">찾아보기</string>
|
<string name="title_activity_explore">찾아보기</string>
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="multiple_uploads_title">
|
<plurals name="multiple_uploads_title">
|
||||||
<item quantity="one">%1$d개 업로드</item>
|
<item quantity="one">%1$d개 업로드</item>
|
||||||
|
<item quantity="other">%1$d개 업로드</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="share_license_summary">
|
<plurals name="share_license_summary">
|
||||||
<item quantity="one">이 그림은 %1$s에 따라 사용이 허가됩니다</item>
|
<item quantity="one">이 그림은 %1$s에 따라 사용이 허가됩니다</item>
|
||||||
|
|
|
||||||
10
app/src/main/res/values-nqo/error.xml
Normal file
10
app/src/main/res/values-nqo/error.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Authors:
|
||||||
|
* Lancine.kounfantoh.fofana
|
||||||
|
-->
|
||||||
|
<resources>
|
||||||
|
<string name="crash_dialog_title">ߞߐߡߐ߲ ߓߘߊ߫ ߗߌߙߏ߲߫</string>
|
||||||
|
<string name="crash_dialog_text">ߋߜߋ߫. ߞߏ ߘߏ߫ ߓߍ߲߬ߣߍ߲߫ ߕߎ߲߬ ߕߍ߫߹</string>
|
||||||
|
<string name="crash_dialog_comment_prompt">ߊ߲ ߠߎ߬ ߘߍ߬ߡߍ߲߬ ߊ߬ ߘߐߓߍ߲߬ߠߌ߲ ߡߊ߬߹</string>
|
||||||
|
<string name="crash_dialog_ok_toast">ߌ ߣߌ߫ ߗߋ߫߹</string>
|
||||||
|
</resources>
|
||||||
|
|
@ -50,10 +50,14 @@
|
||||||
<string name="provider_contributions">ߒ ߠߊ߫ ߟߊ߬ߦߟߍ߬ߣߍ߲ ߠߎ߬</string>
|
<string name="provider_contributions">ߒ ߠߊ߫ ߟߊ߬ߦߟߍ߬ߣߍ߲ ߠߎ߬</string>
|
||||||
<string name="menu_share">ߊ߬ ߟߊߖߍ߲ߛߍ߲߫</string>
|
<string name="menu_share">ߊ߬ ߟߊߖߍ߲ߛߍ߲߫</string>
|
||||||
<string name="menu_open_in_browser">ߊ߬ ߘߐߜߍ߫ ߛߏ߲߯ߓߊߟߊ߲ ߠߊ߫</string>
|
<string name="menu_open_in_browser">ߊ߬ ߘߐߜߍ߫ ߛߏ߲߯ߓߊߟߊ߲ ߠߊ߫</string>
|
||||||
<string name="share_title_hint" fuzzy="true">ߞߎ߲߬ߕߐ߰ ߞߊ߬ߣߌ߲߬ߣߍ߲</string>
|
<string name="share_title_hint">ߝߍ߬ߛߓߍߟߌ (ߡߊߢߌ߬ߣߌ߲߬ߞߊ߬ߣߍ߲)</string>
|
||||||
|
<string name="add_caption_toast">ߝߍ߬ߛߓߍߟߌ ߘߏ߫ ߡߊߛߐ߫ ߞߐߕߐ߮ ߣߌ߲߬ ߠߊ߫ ߖߊ߰ߣߌ߲߫</string>
|
||||||
<string name="share_description_hint">ߞߊ߲߬ߛߓߍߟߌ</string>
|
<string name="share_description_hint">ߞߊ߲߬ߛߓߍߟߌ</string>
|
||||||
|
<string name="share_caption_hint">ߝߍ߬ߛߓߍߟߌ (ߞߐߘߊ߲ ߦߋ߫ ߛߓߍߘߋ߲߫ ߂߅߅ ߟߋ߬ ߘߌ߫)</string>
|
||||||
<string name="login_failed_network">ߜߊ߲߬ߞߎ߲߬ߠߌ߲ ߛߐ߲߬ߣߍ߲߫ ߕߍ߫ ߞߍ߫ ߟߊ߫ - ߞߙߏߝߏ ߟߊ߫ ߗߌߙߏ߲ߠߌ߲</string>
|
<string name="login_failed_network">ߜߊ߲߬ߞߎ߲߬ߠߌ߲ ߛߐ߲߬ߣߍ߲߫ ߕߍ߫ ߞߍ߫ ߟߊ߫ - ߞߙߏߝߏ ߟߊ߫ ߗߌߙߏ߲ߠߌ߲</string>
|
||||||
<string name="login_failed_wrong_credentials">ߜߊ߲߬ߞߎ߲߬ߠߌ߲ ߛߐ߲߬ߣߍ߲߫ ߕߍ߫ ߞߍ߫ ߟߊ߫ - ߌ ߟߊ߫ ߕߐ߯ ߟߊߓߊ߯ߕߊ ߣߌ߫ ߕߊ߬ߡߌ߲߬ߞߊ߲ ߠߎ߬ ߡߊߝߟߍ߫ ߖߊ߰ߣߌ߲߬</string>
|
<string name="login_failed_wrong_credentials">ߜߊ߲߬ߞߎ߲߬ߠߌ߲ ߛߐ߲߬ߣߍ߲߫ ߕߍ߫ ߞߍ߫ ߟߊ߫ - ߌ ߟߊ߫ ߕߐ߯ ߟߊߓߊ߯ߕߊ ߣߌ߫ ߕߊ߬ߡߌ߲߬ߞߊ߲ ߠߎ߬ ߡߊߝߟߍ߫ ߖߊ߰ߣߌ߲߬</string>
|
||||||
|
<string name="login_failed_throttled">ߛߊ߯ߛߊ߯ߟߌ߫ ߛߎߘߊ߲ߓߊߟߌ߫ ߛߘߍߡߊ߲߫ ߓߘߊ߫ ߞߍ߫ ߢߐ߲߮ ߞߐ߫ ߞߏߖߎ߯ߦߊ߫.ߊ߬ ߡߊߝߍߣߍ߲߫ ߡߌ߬ߛߍ߲߬ ߘߊ߲ߘߐ߫ ߞߐ߫ ߖߊ߰ߣߌ߲߫.</string>
|
||||||
|
<string name="login_failed_blocked">ߤߊߞߍ߬ߕߏ߫߸ ߟߊ߬ߓߊ߰ߙߊ߬ߟߊ ߣߌ߲߬ ߓߘߊ߫ ߓߊ߬ߟߌ߬ ߞߐ߬ߡߐ߲ ߞߊ߲߬</string>
|
||||||
<string name="login_failed_generic">ߜߊ߲߬ߞߎ߲߬ߠߌ߲ ߓߘߊ߫ ߗߌߙߏ߲߫</string>
|
<string name="login_failed_generic">ߜߊ߲߬ߞߎ߲߬ߠߌ߲ ߓߘߊ߫ ߗߌߙߏ߲߫</string>
|
||||||
<string name="share_upload_button">ߊ߬ ߟߊߦߟߍ߬</string>
|
<string name="share_upload_button">ߊ߬ ߟߊߦߟߍ߬</string>
|
||||||
<string name="multiple_share_base_title">ߟߊ߬ߘߏ߲߬ߠߌ߲ ߣߌ߲߬ ߕߐ߯ߟߊ߫</string>
|
<string name="multiple_share_base_title">ߟߊ߬ߘߏ߲߬ߠߌ߲ ߣߌ߲߬ ߕߐ߯ߟߊ߫</string>
|
||||||
|
|
@ -74,7 +78,7 @@
|
||||||
<string name="title_activity_featured_images">ߟߊߓߊ߯ߙߊߟߌ ߖߌ߬ߦߊ߬ߓߍ ߟߎ߬</string>
|
<string name="title_activity_featured_images">ߟߊߓߊ߯ߙߊߟߌ ߖߌ߬ߦߊ߬ߓߍ ߟߎ߬</string>
|
||||||
<string name="title_activity_category_details">ߦߌߟߡߊ</string>
|
<string name="title_activity_category_details">ߦߌߟߡߊ</string>
|
||||||
<string name="menu_about">ߞߊ߬ ߓߍ߲߬</string>
|
<string name="menu_about">ߞߊ߬ ߓߍ߲߬</string>
|
||||||
<string name="about_privacy_policy" fuzzy="true"><u>ߜߎ߲߬ߘߎ߬ߢߐ߲߰ߦߊ ߞߎߙߎ߲߬ߘߎ</u></string>
|
<string name="about_privacy_policy">ߜߎ߲߬ߘߎ߬ߢߐ߲߰ߦߊ ߞߎߙߎ߲߬ߘߎ</string>
|
||||||
<string name="title_activity_about">ߞߊ߬ ߓߍ߲߬</string>
|
<string name="title_activity_about">ߞߊ߬ ߓߍ߲߬</string>
|
||||||
<string name="menu_feedback">ߞߙߐ߬ߛߌ߬ߕߊ ߗߋ߫ (ߢ:ߞߏ߲ߘߏ ߟߊ߫)</string>
|
<string name="menu_feedback">ߞߙߐ߬ߛߌ߬ߕߊ ߗߋ߫ (ߢ:ߞߏ߲ߘߏ ߟߊ߫)</string>
|
||||||
<string name="no_email_client">ߢߎߡߍߙߋ߲ߞߏ߲ߘߏ ߛߊ߲߬ߠߌ߲߬ߢߐ߲߰ ߡߊߞߍߣߍ߲߫ ߕߴߦߋ߲߬</string>
|
<string name="no_email_client">ߢߎߡߍߙߋ߲ߞߏ߲ߘߏ ߛߊ߲߬ߠߌ߲߬ߢߐ߲߰ ߡߊߞߍߣߍ߲߫ ߕߴߦߋ߲߬</string>
|
||||||
|
|
@ -107,15 +111,21 @@
|
||||||
<string name="detail_panel_cats_label">ߦߌߟߡߊ ߟߎ߬</string>
|
<string name="detail_panel_cats_label">ߦߌߟߡߊ ߟߎ߬</string>
|
||||||
<string name="detail_panel_cats_loading">ߟߊ߬ߢߎ߲߬ߠߌ߲ ߦߵߌ ߘߐ߫...</string>
|
<string name="detail_panel_cats_loading">ߟߊ߬ߢߎ߲߬ߠߌ߲ ߦߵߌ ߘߐ߫...</string>
|
||||||
<string name="detail_panel_cats_none">ߊ߬ ߡߊ߫ ߓߊߕߐ߬ߡߐ߲߬</string>
|
<string name="detail_panel_cats_none">ߊ߬ ߡߊ߫ ߓߊߕߐ߬ߡߐ߲߬</string>
|
||||||
|
<string name="detail_caption_empty">ߝߍ߬ߛߓߍߟߌ߫ ߕߍ߫ ߦߋ߲߬</string>
|
||||||
<string name="detail_description_empty">ߞߊ߲߬ߛߓߍߟߌ߫ ߕߴߦߋ߲߬</string>
|
<string name="detail_description_empty">ߞߊ߲߬ߛߓߍߟߌ߫ ߕߴߦߋ߲߬</string>
|
||||||
<string name="detail_discussion_empty">ߘߊߘߐߖߊߥߏ߫ ߕߴߦߋ߲߬</string>
|
<string name="detail_discussion_empty">ߘߊߘߐߖߊߥߏ߫ ߕߴߦߋ߲߬</string>
|
||||||
<string name="ok">ߏ߬ߞߍ߫</string>
|
<string name="ok">ߏ߬ߞߍ߫</string>
|
||||||
<string name="title_activity_nearby">ߛߌ߰ߢߐ߲߰ ߦߙߐ ߟߎ߬</string>
|
<string name="title_activity_nearby">ߛߌ߰ߢߐ߲߰ ߦߙߐ ߟߎ߬</string>
|
||||||
<string name="no_nearby">ߛߌ߰ߢߐ߲߰ ߦߙߐ߫ ߡߊ߫ ߛߐ߬ߘߐ߲߫</string>
|
<string name="no_nearby">ߛߌ߰ߢߐ߲߰ ߦߙߐ߫ ߡߊ߫ ߛߐ߬ߘߐ߲߫</string>
|
||||||
<string name="warning">ߖߊ߲߬ߓߌ߬ߟߊ߬ߟߌ</string>
|
<string name="warning">ߖߊ߲߬ߓߌ߬ߟߊ߬ߟߌ</string>
|
||||||
|
<string name="duplicate_image_found">ߖߌ߬ߦߊ߬ߓߍ߫ ߓߊߟߌߣߍ߲ ߠߎ߬ ߦߋ߫ ߦߋ߲߬</string>
|
||||||
|
<string name="upload_image_duplicate">ߞߐߕߐ߮ ߣߌ߲߬ ߓߘߊ߫ ߘߐߕߌߢߍ߫ ߞߐߡߐ߲ ߞߊ߲߬. ߌ ߟߊߣߴߊ߬ ߟߊ߫ ߞߴߌ ߦߴߊ߬ ߝߍ߬ ߞߵߊ߬ ߘߊߓߊ߲߫؟</string>
|
||||||
|
<string name="upload">ߊ߬ ߟߊߦߟߍ߬</string>
|
||||||
<string name="yes">ߐ߲߬ߐ߲߬ߐ߲߫</string>
|
<string name="yes">ߐ߲߬ߐ߲߬ߐ߲߫</string>
|
||||||
<string name="no">ߍ߲߬ߍ߲߫</string>
|
<string name="no">ߍ߲߬ߍ߲߫</string>
|
||||||
|
<string name="media_detail_caption">ߝߍ߬ߛߓߍߟߌ</string>
|
||||||
<string name="media_detail_title">ߞߎ߲߬ߕߐ߮</string>
|
<string name="media_detail_title">ߞߎ߲߬ߕߐ߮</string>
|
||||||
|
<string name="media_detail_depiction">ߞߐߦߌߘߊߟߌ</string>
|
||||||
<string name="media_detail_description">ߞߊ߲߬ߛߓߍߟߌ</string>
|
<string name="media_detail_description">ߞߊ߲߬ߛߓߍߟߌ</string>
|
||||||
<string name="media_detail_discussion">ߘߊߘߐߖߊߥߏ</string>
|
<string name="media_detail_discussion">ߘߊߘߐߖߊߥߏ</string>
|
||||||
<string name="media_detail_author">ߛߓߍߦߟߊ</string>
|
<string name="media_detail_author">ߛߓߍߦߟߊ</string>
|
||||||
|
|
@ -166,11 +176,15 @@
|
||||||
<string name="upload_problem_different_geolocation">ߖߌ߬ߦߊ߬ߓߍ ߣߌ߲߬ ߕߊ߬ߣߍ߲߬ ߦߋ߫ ߦߙߐ߫ ߜߘߍ߫ ߟߋ߬</string>
|
<string name="upload_problem_different_geolocation">ߖߌ߬ߦߊ߬ߓߍ ߣߌ߲߬ ߕߊ߬ߣߍ߲߬ ߦߋ߫ ߦߙߐ߫ ߜߘߍ߫ ߟߋ߬</string>
|
||||||
<string name="upload_problem_fbmd">ߌ ߦߋ߫ ߖߌ߬ߦߊ߬ߓߍ ߟߋ߬ ߟߊߦߍ߬ߟߍ߫ ߖߊ߰ߣߌ߲߫ ߌ ߖߍ߬ߘߍ ߞߊ߬ ߡߍ߲ ߠߎ߬ ߕߊ߬. ߒ߬ߞߊ߬ ߌ ߞߊ߫ ߖߌ߬ߦߊ߬ߓߍ߫ ߟߊߦߍ߬ߟߍ߫ ߡߎ߰ߡߍ߫ ߌ ߞߊ߬ ߡߍ߲ ߠߎ߬ ߕߊ߬ ߡߐ߱ ߟߎ߬ ߟߊ߫ ߝߋߛߑߓߎߞ ߞߊ߲߬.</string>
|
<string name="upload_problem_fbmd">ߌ ߦߋ߫ ߖߌ߬ߦߊ߬ߓߍ ߟߋ߬ ߟߊߦߍ߬ߟߍ߫ ߖߊ߰ߣߌ߲߫ ߌ ߖߍ߬ߘߍ ߞߊ߬ ߡߍ߲ ߠߎ߬ ߕߊ߬. ߒ߬ߞߊ߬ ߌ ߞߊ߫ ߖߌ߬ߦߊ߬ߓߍ߫ ߟߊߦߍ߬ߟߍ߫ ߡߎ߰ߡߍ߫ ߌ ߞߊ߬ ߡߍ߲ ߠߎ߬ ߕߊ߬ ߡߐ߱ ߟߎ߬ ߟߊ߫ ߝߋߛߑߓߎߞ ߞߊ߲߬.</string>
|
||||||
<string name="upload_problem_do_you_continue">ߌ ߦߴߊ߬ ߝߍ߬ ߞߊ߬ ߖߌ߬ߦߊ߬ߓߍ ߣߌ߲߬ ߠߊߦߟߍ߬ ߡߎߣߎ߲߬؟</string>
|
<string name="upload_problem_do_you_continue">ߌ ߦߴߊ߬ ߝߍ߬ ߞߊ߬ ߖߌ߬ߦߊ߬ߓߍ ߣߌ߲߬ ߠߊߦߟߍ߬ ߡߎߣߎ߲߬؟</string>
|
||||||
|
<string name="upload_problem_image">ߝߙߋߞߋ ߓߘߊ߫ ߦߋ߫ ߖߌ߬ߦߊ߬ߓߍ ߟߊ߫</string>
|
||||||
<string name="internet_downloaded">ߖߊ߰ߣߌ߲߬ ߌ ߦߋ߫ ߖߌ߬ߦߊ߬ߓߍ߬ ߟߎ߫ ߟߋ߬ ߟߊߦߟߍ߬ ߌ ߖߍ߬ߘߍ ߞߊ߬ ߡߍ߲ ߠߎ߬ ߕߊ߬. ߞߏ߬ߣߌ߲߬ ߌ ߞߊߣߊ߬ ߖߌ߬ߦߊ߬ߓߍ߬ ߟߊߦߟߍ߬ ߌ ߣߊ߬ ߡߍ߲ ߠߊߖߌ߰ ߟߴߌ ߞߎ߲߬ ߓߟߐߟߐ ߟߊ߫.</string>
|
<string name="internet_downloaded">ߖߊ߰ߣߌ߲߬ ߌ ߦߋ߫ ߖߌ߬ߦߊ߬ߓߍ߬ ߟߎ߫ ߟߋ߬ ߟߊߦߟߍ߬ ߌ ߖߍ߬ߘߍ ߞߊ߬ ߡߍ߲ ߠߎ߬ ߕߊ߬. ߞߏ߬ߣߌ߲߬ ߌ ߞߊߣߊ߬ ߖߌ߬ߦߊ߬ߓߍ߬ ߟߊߦߟߍ߬ ߌ ߣߊ߬ ߡߍ߲ ߠߊߖߌ߰ ߟߴߌ ߞߎ߲߬ ߓߟߐߟߐ ߟߊ߫.</string>
|
||||||
<string name="give_permission">ߟߊ߬ߘߌ߬ߢߍ߬ߟߌ ߦߌ߬ߘߊ߬</string>
|
<string name="give_permission">ߟߊ߬ߘߌ߬ߢߍ߬ߟߌ ߦߌ߬ߘߊ߬</string>
|
||||||
<string name="login_to_your_account">ߌ ߜߊ߲߬ߞߎ߲߫ ߌ ߟߊ߫ ߖߊ߬ߕߋ߬ߘߊ ߟߊ߫.</string>
|
<string name="login_to_your_account">ߌ ߜߊ߲߬ߞߎ߲߫ ߌ ߟߊ߫ ߖߊ߬ߕߋ߬ߘߊ ߟߊ߫.</string>
|
||||||
<string name="no_web_browser">ߓߟߐߟߐ ߛߏ߲߯ߓߊߟߊ߲߫ ߡߊ߫ ߛߐ߬ߘߐ߲߬ ߞߊ߬ URL ߟߊߞߊ߬</string>
|
<string name="no_web_browser">ߓߟߐߟߐ ߛߏ߲߯ߓߊߟߊ߲߫ ߡߊ߫ ߛߐ߬ߘߐ߲߬ ߞߊ߬ URL ߟߊߞߊ߬</string>
|
||||||
<string name="null_url">ߝߎ߬ߕߎ߲߬ߕߌ߹ URL ߡߊ߫ ߛߐ߬ߘߐ߲߬</string>
|
<string name="null_url">ߝߎ߬ߕߎ߲߬ߕߌ߹ URL ߡߊ߫ ߛߐ߬ߘߐ߲߬</string>
|
||||||
|
<string name="nominated_see_more">ߞߍߦߙߐ߫ ߞߐߜߍ ߘߐߜߍ߫ ߝߊߙߊ߲ߝߊ߯ߛߌ߫ ߞߏ ߘߐ߫</string>
|
||||||
|
<string name="nominating_file_for_deletion">ߕߐ߯ߦߊߟߌ ߖߏ߰ߛߌ߬ߟߌ ߞߊ߲ߡߊ߬</string>
|
||||||
|
<string name="nominating_for_deletion_status">ߞߐߕߐ߮ ߕߐ߯ߦߊߟߌ ߖߏ߬ߛߟߌ߬ ߞߊ߲ߡߊ߬: %1$s</string>
|
||||||
<string name="view_browser">ߊ߬ ߘߐߜߍ߫ ߛߏ߲߯ߓߊߟߊ߲ ߠߊ߫</string>
|
<string name="view_browser">ߊ߬ ߘߐߜߍ߫ ߛߏ߲߯ߓߊߟߊ߲ ߠߊ߫</string>
|
||||||
<string name="skip_login">ߊ߬ ߟߊߜߊ߲߫</string>
|
<string name="skip_login">ߊ߬ ߟߊߜߊ߲߫</string>
|
||||||
<string name="navigation_item_login">ߌ ߜߊ߲߬ߞߎ߲߬</string>
|
<string name="navigation_item_login">ߌ ߜߊ߲߬ߞߎ߲߬</string>
|
||||||
|
|
@ -187,11 +201,11 @@
|
||||||
<string name="nearby_wikidata">ߥߞߌߘߕߊ</string>
|
<string name="nearby_wikidata">ߥߞߌߘߕߊ</string>
|
||||||
<string name="nearby_wikipedia">ߥߞߌߔߋߘߌߦߊ߫</string>
|
<string name="nearby_wikipedia">ߥߞߌߔߋߘߌߦߊ߫</string>
|
||||||
<string name="nearby_commons">ߞߐߡߐ߲</string>
|
<string name="nearby_commons">ߞߐߡߐ߲</string>
|
||||||
<string name="about_rate_us" fuzzy="true"><u>ߊ߲ ߡߐ߬ߟߐ߲ ߦߌ߬ߘߊ߬</u></string>
|
<string name="about_rate_us">ߡߐ߬ߟߐ߲ ߘߴߊ߲ ߡߊ߬</string>
|
||||||
<string name="about_faq" fuzzy="true"><u>ߢ.ߡ</u></string>
|
<string name="about_faq">ߢ.ߡ</string>
|
||||||
<string name="no_internet">ߓߟߐߟߐ߫ ߕߴߦߋ߲߬</string>
|
<string name="no_internet">ߓߟߐߟߐ߫ ߕߴߦߋ߲߬</string>
|
||||||
<string name="internet_established">ߓߟߐߟߐ ߦߋ߫ ߦߋ߲߬</string>
|
<string name="internet_established">ߓߟߐߟߐ ߦߋ߫ ߦߋ߲߬</string>
|
||||||
<string name="about_translate" fuzzy="true"><u>ߘߟߊߡߌߘߊߟߌ</u></string>
|
<string name="about_translate">ߘߟߊߡߌߘߊߟߌ</string>
|
||||||
<string name="about_translate_title">ߞߊ߲ ߠߎ߬</string>
|
<string name="about_translate_title">ߞߊ߲ ߠߎ߬</string>
|
||||||
<string name="about_translate_message">ߞߊ߲ ߘߏ߫ ߓߊߕߐ߬ߡߐ߲߬ ߌ ߦߴߊ߬ ߝߍ߬ ߞߵߊ߬ ߘߟߊߡߌ߬ߘߊ߬ ߡߍ߲ ߘߐ߫.</string>
|
<string name="about_translate_message">ߞߊ߲ ߘߏ߫ ߓߊߕߐ߬ߡߐ߲߬ ߌ ߦߴߊ߬ ߝߍ߬ ߞߵߊ߬ ߘߟߊߡߌ߬ߘߊ߬ ߡߍ߲ ߘߐ߫.</string>
|
||||||
<string name="about_translate_cancel">ߊ߬ ߘߐߛߊ߬</string>
|
<string name="about_translate_cancel">ߊ߬ ߘߐߛߊ߬</string>
|
||||||
|
|
@ -274,6 +288,11 @@
|
||||||
<string name="review_thanks">ߊ߬ ߟߐ߯ ߦߴߌ ߟߊ߫ ߞߊ߬ ߓߟߏߓߌߟߊߢߐ߲߯ߞߊ߲ߠߊ ߟߎ߬ ߞߎߟߎ߲ߖߋ߫ ߓߊ߬؟</string>
|
<string name="review_thanks">ߊ߬ ߟߐ߯ ߦߴߌ ߟߊ߫ ߞߊ߬ ߓߟߏߓߌߟߊߢߐ߲߯ߞߊ߲ߠߊ ߟߎ߬ ߞߎߟߎ߲ߖߋ߫ ߓߊ߬؟</string>
|
||||||
<string name="review_no_category">ߐ߲߬ߤߐ߲߯߹ ߣߌ߲߬ ߝߊ߲߭ ߡߊ߫ ߦߌߟߡߊߦߊ߫ ߟߋ߬߹</string>
|
<string name="review_no_category">ߐ߲߬ߤߐ߲߯߹ ߣߌ߲߬ ߝߊ߲߭ ߡߊ߫ ߦߌߟߡߊߦߊ߫ ߟߋ߬߹</string>
|
||||||
<string name="review_category_explanation">ߖߌ߬ߦߊ߬ߓߍ ߣߌ߲߬ ߦߋ߫ %1$s ߦߌߟߡߊ ߟߎ߬ ߞߘߐ߫.</string>
|
<string name="review_category_explanation">ߖߌ߬ߦߊ߬ߓߍ ߣߌ߲߬ ߦߋ߫ %1$s ߦߌߟߡߊ ߟߎ߬ ߞߘߐ߫.</string>
|
||||||
|
<string name="review_c_violation_report_question">ߊ߬ ߦߋ߫ ߓߊߦߟߍߡߊ߲ߠߌ߲ ߤߊߞߍ ߞߎ߬ߙߎ߲߬ߘߎ ߕߌߢߍ ߟߋ߬ ߘߌ߫ ߓߊߏ߬ ߊ߬ ߦߋ߫</string>
|
||||||
|
<string name="review_category_yes_button_text">ߒ߬ߒ߫߸ ߦߌߟߡߦߊߟߌ ߞߐߢߌ߬ߣߊ߬ߣߍ߲߹</string>
|
||||||
|
<string name="review_category_no_button_text">ߊ߬ ߞߍߣߍ߲߫ ߦߴߊ߬ ߢߊ߬ߣߍ߲߫</string>
|
||||||
|
<string name="review_spam_yes_button_text">ߒ߬ߒ߫߸ ߊ߬ ߞߍߣߍ߲߫ ߦߏ߫ ߞߣߍ ߕߴߦߋ߲߬</string>
|
||||||
|
<string name="review_spam_no_button_text">ߊ߬ ߞߍߣߍ߲߫ ߦߴߊ߬ ߢߊ߬ߣߍ߲߫</string>
|
||||||
<string name="review_copyright_yes_button_text">ߒ߬ߒ߫߸ ߓߊߦߟߍߡߊ߲ ߤߊߞߍ ߡߊ߫ ߕߌߢߍ߫</string>
|
<string name="review_copyright_yes_button_text">ߒ߬ߒ߫߸ ߓߊߦߟߍߡߊ߲ ߤߊߞߍ ߡߊ߫ ߕߌߢߍ߫</string>
|
||||||
<string name="review_copyright_no_button_text">ߊ߬ ߞߍߣߍ߲߫ ߦߴߊ߬ ߓߍ߲߬ߣߍ߲߫</string>
|
<string name="review_copyright_no_button_text">ߊ߬ ߞߍߣߍ߲߫ ߦߴߊ߬ ߓߍ߲߬ߣߍ߲߫</string>
|
||||||
<string name="review_thanks_yes_button_text">ߐ߲߬ߐ߲ߐ߲߫߸ ߡߎ߲߬ߠߊ߫ ߍ߲߬ߍ߲߫</string>
|
<string name="review_thanks_yes_button_text">ߐ߲߬ߐ߲ߐ߲߫߸ ߡߎ߲߬ߠߊ߫ ߍ߲߬ߍ߲߫</string>
|
||||||
|
|
@ -287,10 +306,16 @@
|
||||||
<string name="exif_tag_name_copyright">ߓߊߦߟߍߡߊ߲ ߤߊߞߍ</string>
|
<string name="exif_tag_name_copyright">ߓߊߦߟߍߡߊ߲ ߤߊߞߍ</string>
|
||||||
<string name="exif_tag_name_location">ߘߌ߲߬ߞߌߙߊ</string>
|
<string name="exif_tag_name_location">ߘߌ߲߬ߞߌߙߊ</string>
|
||||||
<string name="exif_tag_name_cameraModel">ߖߌ߬ߦߊ߬ߕߊ߬ߟߊ߲ ߛߎ߮ߦߊ</string>
|
<string name="exif_tag_name_cameraModel">ߖߌ߬ߦߊ߬ߕߊ߬ߟߊ߲ ߛߎ߮ߦߊ</string>
|
||||||
|
<string name="image_info">ߖߌ߬ߦߊ߬ߓߍ ߞߌ߬ߓߊ߬ߙߏ߬ߦߊ</string>
|
||||||
|
<string name="no_categories_found">ߦߌߟߡߊߙߋ߲߫ ߕߴߦߋ߲߬</string>
|
||||||
|
<string name="no_depiction_found">ߘߊ߲߬ߠߊ߬ߕߍ߰ߟߌ ߡߊ߫ ߛߐ߬ߘߐ߲߬</string>
|
||||||
|
<string name="upload_cancelled">ߟߊ߬ߦߟߍ߬ߟߌ ߘߊߓߌ߬ߟߊ߬</string>
|
||||||
<string name="dialog_box_text_nomination">ߡߎ߲߬ߠߊ߫ %1$s ߖߏ߬ߛߌ߬ߕߐ߫؟</string>
|
<string name="dialog_box_text_nomination">ߡߎ߲߬ߠߊ߫ %1$s ߖߏ߬ߛߌ߬ߕߐ߫؟</string>
|
||||||
<string name="review_is_uploaded_by">%1$s ߟߊߦߟߍ߬ߣߍ߲߬ ߦߋ߫: %2$s ߟߋ߬ ߓߟߏ߫</string>
|
<string name="review_is_uploaded_by">%1$s ߟߊߦߟߍ߬ߣߍ߲߬ ߦߋ߫: %2$s ߟߋ߬ ߓߟߏ߫</string>
|
||||||
<string name="default_description_language">ߞߊ߲߬ߛߓߍߟߌ ߞߍ߫ ߞߊ߲ ߓߊߖߎߡߊ</string>
|
<string name="default_description_language">ߞߊ߲߬ߛߓߍߟߌ ߞߍ߫ ߞߊ߲ ߓߊߖߎߡߊ</string>
|
||||||
|
<string name="delete_helper_make_deletion_toast">ߌ ߦߴߌ ߞߊߘߊ߲ ߞߊ߲߬ ߞߊ߬ %1$s ߕߐ߯ߦߊ߫ ߖߏ߬ߛߟߌ߬ ߞߊ߲ߡߊ߬</string>
|
||||||
<string name="delete_helper_show_deletion_title">ߕߐ߯ߦߊߟߌ ߖߏ߰ߛߌ߬ߟߌ ߞߊ߲ߡߊ߬</string>
|
<string name="delete_helper_show_deletion_title">ߕߐ߯ߦߊߟߌ ߖߏ߰ߛߌ߬ߟߌ ߞߊ߲ߡߊ߬</string>
|
||||||
|
<string name="delete_helper_show_deletion_title_success">ߊ߬ ߓߘߊ߫ ߛߎߘߊ߲߫</string>
|
||||||
<string name="delete_helper_show_deletion_message_if">%1$s ߕߐ߯ߦߊߟߌ ߦߴߌ ߘߐ߫ ߖߏ߬ߛߌ߬ߟߌ ߞߊ߲ߡߊ߬</string>
|
<string name="delete_helper_show_deletion_message_if">%1$s ߕߐ߯ߦߊߟߌ ߦߴߌ ߘߐ߫ ߖߏ߬ߛߌ߬ߟߌ ߞߊ߲ߡߊ߬</string>
|
||||||
<string name="delete_helper_show_deletion_title_failed">ߊ߬ ߓߘߊ߫ ߗߌߙߏ߲߫</string>
|
<string name="delete_helper_show_deletion_title_failed">ߊ߬ ߓߘߊ߫ ߗߌߙߏ߲߫</string>
|
||||||
<string name="delete_helper_show_deletion_message_else">ߌ ߕߍ߫ ߛߋ߫ ߖߏ߰ߛߌ߬ߟߌ ߡߊߢߌߣߌ߲߫ ߠߊ߫</string>
|
<string name="delete_helper_show_deletion_message_else">ߌ ߕߍ߫ ߛߋ߫ ߖߏ߰ߛߌ߬ߟߌ ߡߊߢߌߣߌ߲߫ ߠߊ߫</string>
|
||||||
|
|
@ -302,5 +327,14 @@
|
||||||
<string name="delete_helper_ask_alert_set_positive_button_reason">ߓߊߏ߬ ߊ߬ ߦߋ߫</string>
|
<string name="delete_helper_ask_alert_set_positive_button_reason">ߓߊߏ߬ ߊ߬ ߦߋ߫</string>
|
||||||
<string name="share_image_via">ߖߌ߬ߦߊ߬ߓߍ ߟߊߖߍ߲ߛߍ߲߫ ߞߊߕߙߍ߬</string>
|
<string name="share_image_via">ߖߌ߬ߦߊ߬ߓߍ ߟߊߖߍ߲ߛߍ߲߫ ߞߊߕߙߍ߬</string>
|
||||||
<string name="no_achievements_yet">ߌ ߡߊ߫ ߓߟߏߓߌߟߊߢߐ߲߯ߞߊ߲ ߛߌ߫ ߞߍ߫ ߡߎߣߎ߲߬</string>
|
<string name="no_achievements_yet">ߌ ߡߊ߫ ߓߟߏߓߌߟߊߢߐ߲߯ߞߊ߲ ߛߌ߫ ߞߍ߫ ߡߎߣߎ߲߬</string>
|
||||||
|
<string name="account_created">ߖߊ߬ߕߋ߬ߘߊ ߓߘߊ߫ ߛߌ߲ߘߌ߫߹</string>
|
||||||
<string name="some_error">ߝߎ߬ߕߎ߲߬ߕߌ ߘߏ߫ ߕߘߍ߬ ߦߋ߫ ߦߋ߲߬߹</string>
|
<string name="some_error">ߝߎ߬ߕߎ߲߬ߕߌ ߘߏ߫ ߕߘߍ߬ ߦߋ߫ ߦߋ߲߬߹</string>
|
||||||
|
<string name="theme_dark_name">ߘߌ߬ߓߌ</string>
|
||||||
|
<string name="load_more">ߘߏߜߘߍ߫ ߟߎ߫ ߟߊߢߎ߲߫</string>
|
||||||
|
<string name="add_picture_to_wikipedia_article_title">ߖߌ߬ߦߊ߬ߓߍ ߝߙߊ߬ ߥߞߌߔߋߘߌߦߊ ߞߊ߲߬</string>
|
||||||
|
<string name="add_picture_to_wikipedia_article_desc">ߌ ߦߴߊ߬ ߝߍ߬ ߞߊ߬ ߖߌ߬ߦߊ߬ߓߍ ߣߌ߲߬ ߓߌ߬ߟߊ߬ %1$ ߞߊ߲ ߥߞߌߔߋߘߌߦߊ ߞߎߡߘߊ ߟߊ߫ ߓߊ߬؟</string>
|
||||||
|
<string name="confirm">ߊ߬ ߟߊߛߙߋߦߊ߫</string>
|
||||||
|
<string name="wikipedia_instructions_step_1">߁߭. ߥߞߌߛߓߍߟߌ ߢߌ߲߬ ߠߎ߬ ߟߊߓߊ߯ߙߊ߫:</string>
|
||||||
|
<string name="wikipedia_instructions_step_2">߂.ߟߊ߬ߛߙߋ߬ߦߊ߬ߟߌ ߛߐ߲߬ߞߌ߲ ߓߍߣߊ߬ ߥߞߌߔߋߘߌߦߊ ߞߎߡߘߊ ߘߊߦߟߍ߬</string>
|
||||||
|
<string name="wikipedia_instructions_step_7">߇߲. ߞߎߡߘߊ ߟߊߥߊ߲߬ߞߊ߫</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -600,4 +600,18 @@
|
||||||
<string name="use_location_from_similar_image">Tog du dessa två bilder på samma plats? Vill du använda den högra bildens latitud/longitud?</string>
|
<string name="use_location_from_similar_image">Tog du dessa två bilder på samma plats? Vill du använda den högra bildens latitud/longitud?</string>
|
||||||
<string name="load_more">Läs in fler</string>
|
<string name="load_more">Läs in fler</string>
|
||||||
<string name="nearby_no_results">Inga platser hittades, försök ändra dina sökkriterier.</string>
|
<string name="nearby_no_results">Inga platser hittades, försök ändra dina sökkriterier.</string>
|
||||||
|
<string name="add_picture_to_wikipedia_article_title">Lägg till bild på Wikipedia</string>
|
||||||
|
<string name="add_picture_to_wikipedia_article_desc">Vill du lägga till denna bild i Wikipedia-artikeln på %1$s?</string>
|
||||||
|
<string name="add_picture_to_wikipedia_instructions_title">Instruktioner</string>
|
||||||
|
<string name="add_picture_to_wikipedia_instructions_desc">Se till att följa riktlinjerna för hur man redigerar!</string>
|
||||||
|
<string name="confirm">Bekräfta</string>
|
||||||
|
<string name="instructions_title">Instruktioner</string>
|
||||||
|
<string name="wikipedia_instructions_step_1">1. Använd följande wikitext:</string>
|
||||||
|
<string name="wikipedia_instructions_step_2">2. Klicka på \"Bekräfta\" för att öppna Wikipedia-artikeln</string>
|
||||||
|
<string name="wikipedia_instructions_step_3">3. Hitta ett lämplig avsnitt i artikeln för din bild</string>
|
||||||
|
<string name="wikipedia_instructions_step_4">4. Klicka på redigeringsikonen (ser ut som en penna) för detta avsnitt.</string>
|
||||||
|
<string name="wikipedia_instructions_step_5">5. Klistra in wikitexten på det lämpliga stället.</string>
|
||||||
|
<string name="wikipedia_instructions_step_6">6. Redigera wikitexten för att placera den mer lämpligt vid behov. För mer information, se <a href=\"https://en.wikipedia.org/wiki/Wikipedia:Manual_of_Style/Images#How_to_place_an_image\">här</a>.</string>
|
||||||
|
<string name="wikipedia_instructions_step_7">7. Publicera artikeln</string>
|
||||||
|
<string name="copy_wikicode_to_clipboard">Kopiera wikikod till urklipp</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -419,7 +419,7 @@
|
||||||
<string name="preference_author_name_toggle_summary">Fotoğraf yüklerken kullanıcı adınız yerine özel bir yazar adı kullanın</string>
|
<string name="preference_author_name_toggle_summary">Fotoğraf yüklerken kullanıcı adınız yerine özel bir yazar adı kullanın</string>
|
||||||
<string name="preference_author_name">Özel yazar adı</string>
|
<string name="preference_author_name">Özel yazar adı</string>
|
||||||
<string name="contributions_fragment">Katkılar</string>
|
<string name="contributions_fragment">Katkılar</string>
|
||||||
<string name="nearby_fragment">Yakınımdakiler</string>
|
<string name="nearby_fragment">Yakınındakiler</string>
|
||||||
<string name="notifications">Bildirimler</string>
|
<string name="notifications">Bildirimler</string>
|
||||||
<string name="read_notifications">Bildirimler (okunmuş)</string>
|
<string name="read_notifications">Bildirimler (okunmuş)</string>
|
||||||
<string name="display_nearby_notification">Yakınımdakiler bildirimi görüntüle</string>
|
<string name="display_nearby_notification">Yakınımdakiler bildirimi görüntüle</string>
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,12 @@
|
||||||
<plurals name="starting_multiple_uploads">
|
<plurals name="starting_multiple_uploads">
|
||||||
<item quantity="one">იჭყაფუ %1$d ეხარგუა</item>
|
<item quantity="one">იჭყაფუ %1$d ეხარგუა</item>
|
||||||
<item quantity="few">იჭყაფუ %1$d ეხარგუა</item>
|
<item quantity="few">იჭყაფუ %1$d ეხარგუა</item>
|
||||||
|
<item quantity="other">იჭყაფუ %1$d ეხარგუა</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="multiple_uploads_title">
|
<plurals name="multiple_uploads_title">
|
||||||
<item quantity="one">%1$d ეხარგუა</item>
|
<item quantity="one">%1$d ეხარგუა</item>
|
||||||
<item quantity="few">%1$d ეხარგუა</item>
|
<item quantity="few">%1$d ეხარგუა</item>
|
||||||
|
<item quantity="other">%1$d ეხარგუა</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="share_license_summary">
|
<plurals name="share_license_summary">
|
||||||
<item quantity="one">თე სურათი გიბჟინუ %1$s ლიცენზიათ</item>
|
<item quantity="one">თე სურათი გიბჟინუ %1$s ლიცენზიათ</item>
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,11 @@
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="starting_multiple_uploads">
|
<plurals name="starting_multiple_uploads">
|
||||||
<item quantity="one">開始 %1$d 次上傳</item>
|
<item quantity="one">開始 %1$d 次上傳</item>
|
||||||
|
<item quantity="other">開始 %1$d 次上傳</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="multiple_uploads_title">
|
<plurals name="multiple_uploads_title">
|
||||||
<item quantity="one">%1$d 次上傳</item>
|
<item quantity="one">%1$d 次上傳</item>
|
||||||
|
<item quantity="other">%1$d 次上傳</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="share_license_summary">
|
<plurals name="share_license_summary">
|
||||||
<item quantity="one">此圖片會按 %1$s 協議授權上載</item>
|
<item quantity="one">此圖片會按 %1$s 協議授權上載</item>
|
||||||
|
|
|
||||||
|
|
@ -99,9 +99,10 @@
|
||||||
<string name="provider_contributions">我的上传</string>
|
<string name="provider_contributions">我的上传</string>
|
||||||
<string name="menu_share">分享</string>
|
<string name="menu_share">分享</string>
|
||||||
<string name="menu_open_in_browser">在浏览器中查看</string>
|
<string name="menu_open_in_browser">在浏览器中查看</string>
|
||||||
<string name="share_title_hint" fuzzy="true">标题 (要求)</string>
|
<string name="share_title_hint">说明 (要求)</string>
|
||||||
<string name="add_caption_toast">请提供此文件的描述</string>
|
<string name="add_caption_toast">请提供此文件的描述</string>
|
||||||
<string name="share_description_hint">描述</string>
|
<string name="share_description_hint">描述</string>
|
||||||
|
<string name="share_caption_hint">说明(255个字符以内)</string>
|
||||||
<string name="login_failed_network">无法登录 - 网络故障</string>
|
<string name="login_failed_network">无法登录 - 网络故障</string>
|
||||||
<string name="login_failed_wrong_credentials">无法登录——请检查您的用户名和密码</string>
|
<string name="login_failed_wrong_credentials">无法登录——请检查您的用户名和密码</string>
|
||||||
<string name="login_failed_throttled">失败次数过多。请在几分钟后重试。</string>
|
<string name="login_failed_throttled">失败次数过多。请在几分钟后重试。</string>
|
||||||
|
|
@ -206,8 +207,10 @@
|
||||||
<string name="no_nearby">找不到附近地点</string>
|
<string name="no_nearby">找不到附近地点</string>
|
||||||
<string name="warning">警告</string>
|
<string name="warning">警告</string>
|
||||||
<string name="upload_image_duplicate">此文件已在共享资源下存在。您确定要继续吗?</string>
|
<string name="upload_image_duplicate">此文件已在共享资源下存在。您确定要继续吗?</string>
|
||||||
|
<string name="upload">上传</string>
|
||||||
<string name="yes">是</string>
|
<string name="yes">是</string>
|
||||||
<string name="no">否</string>
|
<string name="no">否</string>
|
||||||
|
<string name="media_detail_caption">说明</string>
|
||||||
<string name="media_detail_title">标题</string>
|
<string name="media_detail_title">标题</string>
|
||||||
<string name="media_detail_description">描述</string>
|
<string name="media_detail_description">描述</string>
|
||||||
<string name="media_detail_discussion">讨论</string>
|
<string name="media_detail_discussion">讨论</string>
|
||||||
|
|
@ -315,8 +318,8 @@
|
||||||
<string name="nearby_wikidata">维基数据</string>
|
<string name="nearby_wikidata">维基数据</string>
|
||||||
<string name="nearby_wikipedia">维基百科</string>
|
<string name="nearby_wikipedia">维基百科</string>
|
||||||
<string name="nearby_commons">共享资源</string>
|
<string name="nearby_commons">共享资源</string>
|
||||||
<string name="about_rate_us" fuzzy="true"><u>评价我们</u></string>
|
<string name="about_rate_us">评价我们</string>
|
||||||
<string name="about_faq" fuzzy="true"><u>常见问题</u></string>
|
<string name="about_faq">常见问题</string>
|
||||||
<string name="welcome_skip_button">跳过指导</string>
|
<string name="welcome_skip_button">跳过指导</string>
|
||||||
<string name="no_internet">互联网不可用</string>
|
<string name="no_internet">互联网不可用</string>
|
||||||
<string name="internet_established">互联网可用</string>
|
<string name="internet_established">互联网可用</string>
|
||||||
|
|
@ -324,7 +327,7 @@
|
||||||
<string name="error_review">获取审查图片错误。按刷新键重试。</string>
|
<string name="error_review">获取审查图片错误。按刷新键重试。</string>
|
||||||
<string name="error_review_categories">获取审查图片类别错误。按刷新按键重试。</string>
|
<string name="error_review_categories">获取审查图片类别错误。按刷新按键重试。</string>
|
||||||
<string name="no_notifications">找不到通知</string>
|
<string name="no_notifications">找不到通知</string>
|
||||||
<string name="about_translate" fuzzy="true"><u>翻译</u></string>
|
<string name="about_translate">翻译</string>
|
||||||
<string name="about_translate_title">语言</string>
|
<string name="about_translate_title">语言</string>
|
||||||
<string name="about_translate_message">选择您希望提交翻译的语言</string>
|
<string name="about_translate_message">选择您希望提交翻译的语言</string>
|
||||||
<string name="about_translate_proceed">已处理</string>
|
<string name="about_translate_proceed">已处理</string>
|
||||||
|
|
@ -351,6 +354,7 @@
|
||||||
<string name="error_loading_subcategories">加载子分类时发生错误。</string>
|
<string name="error_loading_subcategories">加载子分类时发生错误。</string>
|
||||||
<string name="search_tab_title_media">媒体</string>
|
<string name="search_tab_title_media">媒体</string>
|
||||||
<string name="search_tab_title_categories">分类</string>
|
<string name="search_tab_title_categories">分类</string>
|
||||||
|
<string name="search_tab_title_depictions">项目</string>
|
||||||
<string name="explore_tab_title_featured">特色</string>
|
<string name="explore_tab_title_featured">特色</string>
|
||||||
<string name="explore_tab_title_mobile">通过移动端上传</string>
|
<string name="explore_tab_title_mobile">通过移动端上传</string>
|
||||||
<string name="successful_wikidata_edit">图片已添加到维基数据上的%1$s!</string>
|
<string name="successful_wikidata_edit">图片已添加到维基数据上的%1$s!</string>
|
||||||
|
|
@ -575,6 +579,9 @@
|
||||||
<string name="place_type">地点类型:</string>
|
<string name="place_type">地点类型:</string>
|
||||||
<string name="nearby_search_hint">桥梁、博物馆、旅馆等</string>
|
<string name="nearby_search_hint">桥梁、博物馆、旅馆等</string>
|
||||||
<string name="you_must_reset_your_passsword">登录时出现一些问题,您必须重新设置您的密码!</string>
|
<string name="you_must_reset_your_passsword">登录时出现一些问题,您必须重新设置您的密码!</string>
|
||||||
|
<string name="title_app_shortcut_explore">探索</string>
|
||||||
|
<string name="title_app_shortcut_bookmark">书签</string>
|
||||||
|
<string name="title_app_shortcut_setting">设置</string>
|
||||||
<string name="wallpaper_set_unsuccessfully">出错了。无法设置壁纸</string>
|
<string name="wallpaper_set_unsuccessfully">出错了。无法设置壁纸</string>
|
||||||
<string name="setting_wallpaper_dialog_title">设为壁纸</string>
|
<string name="setting_wallpaper_dialog_title">设为壁纸</string>
|
||||||
<string name="setting_wallpaper_dialog_message">正在设置壁纸。请稍等…</string>
|
<string name="setting_wallpaper_dialog_message">正在设置壁纸。请稍等…</string>
|
||||||
|
|
@ -582,4 +589,5 @@
|
||||||
<string name="add_picture_to_wikipedia_instructions_title">说明</string>
|
<string name="add_picture_to_wikipedia_instructions_title">说明</string>
|
||||||
<string name="confirm">确认</string>
|
<string name="confirm">确认</string>
|
||||||
<string name="instructions_title">说明</string>
|
<string name="instructions_title">说明</string>
|
||||||
|
<string name="copy_wikicode_to_clipboard">复制维基代码到剪贴板</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -331,6 +331,9 @@
|
||||||
<string name="retry">Retry</string>
|
<string name="retry">Retry</string>
|
||||||
<string name="showcase_view_got_it_button">Got it!</string>
|
<string name="showcase_view_got_it_button">Got it!</string>
|
||||||
<string name="showcase_view_whole_nearby_activity">These are the places near you that need pictures to illustrate their Wikipedia articles.\n\nClicking on \'SEARCH THIS AREA\' locks the map and launches a nearby search around that location.</string>
|
<string name="showcase_view_whole_nearby_activity">These are the places near you that need pictures to illustrate their Wikipedia articles.\n\nClicking on \'SEARCH THIS AREA\' locks the map and launches a nearby search around that location.</string>
|
||||||
|
<string name="showcase_view_needs_photo">This place needs a photo.</string>
|
||||||
|
<string name="showcase_view_has_photo">This place already has a photo.</string>
|
||||||
|
<string name="showcase_view_no_longer_exists">This place no longer exists.</string>
|
||||||
|
|
||||||
<string name="showcase_view_list_icon">Tapping this button brings up a list of these places</string>
|
<string name="showcase_view_list_icon">Tapping this button brings up a list of these places</string>
|
||||||
<string name="showcase_view_plus_fab">You can upload a picture for any place from your gallery or camera</string>
|
<string name="showcase_view_plus_fab">You can upload a picture for any place from your gallery or camera</string>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
package fr.free.nrw.commons.wikidata
|
package fr.free.nrw.commons.wikidata
|
||||||
|
|
||||||
import com.nhaarman.mockitokotlin2.mock
|
import com.google.gson.Gson
|
||||||
import fr.free.nrw.commons.wikidata.model.AddEditTagResponse
|
import com.nhaarman.mockitokotlin2.whenever
|
||||||
|
import fr.free.nrw.commons.wikidata.model.PageInfo
|
||||||
|
import fr.free.nrw.commons.wikidata.model.WbCreateClaimResponse
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
@ -14,12 +16,16 @@ import org.mockito.Mockito.mock
|
||||||
import org.mockito.MockitoAnnotations
|
import org.mockito.MockitoAnnotations
|
||||||
import org.wikipedia.dataclient.mwapi.MwQueryResponse
|
import org.wikipedia.dataclient.mwapi.MwQueryResponse
|
||||||
import org.wikipedia.dataclient.mwapi.MwQueryResult
|
import org.wikipedia.dataclient.mwapi.MwQueryResult
|
||||||
|
import org.wikipedia.wikidata.Statement_partial
|
||||||
|
|
||||||
class WikidataClientTest {
|
class WikidataClientTest {
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
internal var wikidataInterface: WikidataInterface? = null
|
internal var wikidataInterface: WikidataInterface? = null
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
internal var gson: Gson? = null
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
var wikidataClient: WikidataClient? = null
|
var wikidataClient: WikidataClient? = null
|
||||||
|
|
||||||
|
|
@ -35,26 +41,18 @@ class WikidataClientTest {
|
||||||
.thenReturn(Observable.just(mwQueryResponse))
|
.thenReturn(Observable.just(mwQueryResponse))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun createClaim() {
|
|
||||||
`when`(
|
|
||||||
wikidataInterface!!.postCreateClaim(
|
|
||||||
any(),
|
|
||||||
any(),
|
|
||||||
any(),
|
|
||||||
any(),
|
|
||||||
any(),
|
|
||||||
any()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.thenReturn(Observable.just(mock()))
|
|
||||||
wikidataClient!!.createImageClaim(mock(), "test.jpg")
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun addEditTag() {
|
fun addEditTag() {
|
||||||
`when`(wikidataInterface!!.addEditTag(anyString(), anyString(), anyString(), anyString()))
|
val response = mock(WbCreateClaimResponse::class.java)
|
||||||
.thenReturn(Observable.just(mock(AddEditTagResponse::class.java)))
|
val pageInfo = mock(PageInfo::class.java)
|
||||||
wikidataClient!!.addEditTag(1L, "test", "test")
|
whenever(pageInfo.lastrevid).thenReturn(1)
|
||||||
|
whenever(response.pageinfo).thenReturn(pageInfo)
|
||||||
|
`when`(wikidataInterface!!.postSetClaim(anyString(), anyString(), anyString()))
|
||||||
|
.thenReturn(Observable.just(response))
|
||||||
|
whenever(gson!!.toJson(any(Statement_partial::class.java))).thenReturn("claim")
|
||||||
|
val request = mock(Statement_partial::class.java)
|
||||||
|
|
||||||
|
val claim = wikidataClient!!.setClaim(request, "test").test()
|
||||||
|
.assertValue(1L)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
package fr.free.nrw.commons.wikidata
|
package fr.free.nrw.commons.wikidata
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import com.google.gson.Gson
|
||||||
import com.nhaarman.mockitokotlin2.mock
|
import com.nhaarman.mockitokotlin2.mock
|
||||||
import com.nhaarman.mockitokotlin2.verifyZeroInteractions
|
import com.nhaarman.mockitokotlin2.verifyZeroInteractions
|
||||||
import com.nhaarman.mockitokotlin2.whenever
|
import com.nhaarman.mockitokotlin2.whenever
|
||||||
import fr.free.nrw.commons.kvstore.JsonKvStore
|
import fr.free.nrw.commons.kvstore.JsonKvStore
|
||||||
import fr.free.nrw.commons.upload.UploadResult
|
import fr.free.nrw.commons.upload.UploadResult
|
||||||
import fr.free.nrw.commons.upload.WikidataPlace
|
import fr.free.nrw.commons.upload.WikidataPlace
|
||||||
import fr.free.nrw.commons.wikidata.model.AddEditTagResponse
|
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
@ -15,7 +15,6 @@ import org.mockito.ArgumentMatchers.any
|
||||||
import org.mockito.ArgumentMatchers.anyString
|
import org.mockito.ArgumentMatchers.anyString
|
||||||
import org.mockito.InjectMocks
|
import org.mockito.InjectMocks
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
import org.mockito.Mockito.*
|
|
||||||
import org.mockito.MockitoAnnotations
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
class WikidataEditServiceTest {
|
class WikidataEditServiceTest {
|
||||||
|
|
@ -31,6 +30,9 @@ class WikidataEditServiceTest {
|
||||||
@Mock
|
@Mock
|
||||||
internal lateinit var wikibaseClient: WikiBaseClient
|
internal lateinit var wikibaseClient: WikiBaseClient
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
internal lateinit var gson: Gson
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
lateinit var wikidataEditService: WikidataEditService
|
lateinit var wikidataEditService: WikidataEditService
|
||||||
|
|
||||||
|
|
@ -44,7 +46,7 @@ class WikidataEditServiceTest {
|
||||||
fun noClaimsWhenLocationIsNotCorrect() {
|
fun noClaimsWhenLocationIsNotCorrect() {
|
||||||
whenever(directKvStore.getBoolean("Picture_Has_Correct_Location", true))
|
whenever(directKvStore.getBoolean("Picture_Has_Correct_Location", true))
|
||||||
.thenReturn(false)
|
.thenReturn(false)
|
||||||
wikidataEditService.createImageClaim(mock(), mock())
|
wikidataEditService.createClaim(mock(), "Test.jpg", hashMapOf())
|
||||||
verifyZeroInteractions(wikidataClient)
|
verifyZeroInteractions(wikidataClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -52,15 +54,16 @@ class WikidataEditServiceTest {
|
||||||
fun createImageClaim() {
|
fun createImageClaim() {
|
||||||
whenever(directKvStore.getBoolean("Picture_Has_Correct_Location", true))
|
whenever(directKvStore.getBoolean("Picture_Has_Correct_Location", true))
|
||||||
.thenReturn(true)
|
.thenReturn(true)
|
||||||
whenever(wikidataClient.createImageClaim(any(), any()))
|
|
||||||
.thenReturn(Observable.just(1L))
|
|
||||||
whenever(wikidataClient.addEditTag(anyLong(), anyString(), anyString()))
|
|
||||||
.thenReturn(Observable.just(mock(AddEditTagResponse::class.java)))
|
|
||||||
whenever(wikibaseClient.getFileEntityId(any())).thenReturn(Observable.just(1L))
|
whenever(wikibaseClient.getFileEntityId(any())).thenReturn(Observable.just(1L))
|
||||||
val wikidataPlace:WikidataPlace = mock()
|
whenever(wikidataClient.setClaim(any(), anyString()))
|
||||||
|
.thenReturn(Observable.just(1L))
|
||||||
|
val wikidataPlace: WikidataPlace = mock()
|
||||||
val uploadResult = mock<UploadResult>()
|
val uploadResult = mock<UploadResult>()
|
||||||
whenever(uploadResult.filename).thenReturn("file")
|
whenever(uploadResult.filename).thenReturn("file")
|
||||||
wikidataEditService.createImageClaim(wikidataPlace, uploadResult)
|
wikidataEditService.createClaim(
|
||||||
verify(wikidataClient, times(1)).createImageClaim(wikidataPlace, """"file"""")
|
wikidataPlace,
|
||||||
|
uploadResult.filename,
|
||||||
|
hashMapOf<String, String>()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ sealed class DataValue(val type: String) {
|
||||||
.registerSubtype(GlobeCoordinate_partial::class.java, GlobeCoordinate_partial.TYPE)
|
.registerSubtype(GlobeCoordinate_partial::class.java, GlobeCoordinate_partial.TYPE)
|
||||||
.registerSubtype(Time_partial::class.java, Time_partial.TYPE)
|
.registerSubtype(Time_partial::class.java, Time_partial.TYPE)
|
||||||
.registerSubtype(Quantity_partial::class.java, Quantity_partial.TYPE)
|
.registerSubtype(Quantity_partial::class.java, Quantity_partial.TYPE)
|
||||||
.registerSubtype(MonoLingualText_partial::class.java, MonoLingualText_partial.TYPE)
|
.registerSubtype(MonoLingualText::class.java, MonoLingualText.TYPE)
|
||||||
}
|
}
|
||||||
|
|
||||||
// "value": {
|
// "value": {
|
||||||
|
|
@ -87,7 +87,7 @@ sealed class DataValue(val type: String) {
|
||||||
// "language": "ko"
|
// "language": "ko"
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
class MonoLingualText_partial() : DataValue(TYPE) {
|
class MonoLingualText(val value: WikiBaseMonolingualTextValue) : DataValue(TYPE) {
|
||||||
companion object {
|
companion object {
|
||||||
const val TYPE = "monolingualtext"
|
const val TYPE = "monolingualtext"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,5 +21,8 @@ import com.google.gson.annotations.SerializedName
|
||||||
data class Statement_partial(
|
data class Statement_partial(
|
||||||
@SerializedName("mainsnak") val mainSnak: Snak_partial,
|
@SerializedName("mainsnak") val mainSnak: Snak_partial,
|
||||||
val type: String,
|
val type: String,
|
||||||
val rank: String
|
val rank: String,
|
||||||
|
val id: String? = null,
|
||||||
|
val qualifiers: Map<String, List<Snak_partial>> = mapOf(),
|
||||||
|
@SerializedName("qualifiers-order") val qualifiersOrder: List<String> = listOf()
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package org.wikipedia.wikidata
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
/*"value": {
|
||||||
|
"type": "monolingualtext",
|
||||||
|
"value": {
|
||||||
|
"text": "some value",
|
||||||
|
"language": "en"
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
data class WikiBaseMonolingualTextValue(val text: String, val language: String)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue