diff --git a/.travis.yml b/.travis.yml index 20c5bfaee..5e76e09d9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,12 +19,13 @@ android: components: - tools - platform-tools - - build-tools-26.0.2 + - build-tools-27.0.0 - extra-google-m2repository - extra-android-m2repository - ${ANDROID_TARGET} - android-25 - android-26 + - android-27 - sys-img-${ANDROID_ABI}-${ANDROID_TARGET} licenses: - 'android-sdk-license-.+' diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md index 9d7150008..37e104d14 100644 --- a/PULL_REQUEST_TEMPLATE.md +++ b/PULL_REQUEST_TEMPLATE.md @@ -1,3 +1,7 @@ +## Title (required) + +Fixes #{GitHub issue number and title (Please do not forget adding title) } + ## Description (required) Fixes #{GitHub issue number and title} @@ -12,4 +16,4 @@ Tested on {API level & name of device/emulator}, with {build variant, e.g. ProdD {Only for user interface changes, otherwise remove this section. See [how to take a screenshot](https://android.stackexchange.com/questions/1759/how-to-take-a-screenshot-with-an-android-device)} -_Note: Please ensure that you have read CONTRIBUTING.md if this is your first pull request._ +_Note: Please ensure that you have read CONTRIBUTING.md if this is your first pull request._ \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 72dbd7546..fedd7d703 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,7 +11,6 @@ dependencies { implementation 'fr.avianey.com.viewpagerindicator:library:2.4.1.1@aar' implementation 'in.yuvi:http.fluent:1.3' implementation 'com.github.chrisbanes:PhotoView:2.0.0' - implementation 'com.android.volley:volley:1.0.0' implementation 'ch.acra:acra:4.9.2' implementation 'org.mediawiki:api:1.3' implementation 'commons-codec:commons-codec:1.10' @@ -20,7 +19,7 @@ dependencies { implementation 'com.jakewharton.timber:timber:4.5.1' implementation 'info.debatty:java-string-similarity:0.24' implementation 'com.borjabravo:readmoretextview:2.1.0' - implementation 'com.android.support.constraint:constraint-layout:1.0.2' + implementation 'com.android.support.constraint:constraint-layout:1.1.0' implementation ('com.mapbox.mapboxsdk:mapbox-android-sdk:5.4.1@aar'){ transitive=true } @@ -69,10 +68,14 @@ dependencies { testImplementation 'com.nhaarman:mockito-kotlin:1.5.0' testImplementation 'com.squareup.okhttp3:mockwebserver:3.8.1' + implementation 'com.caverock:androidsvg:1.2.1' + implementation 'com.github.bumptech.glide:glide:4.7.1' + kapt 'com.github.bumptech.glide:compiler:4.7.1' + androidTestImplementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" androidTestImplementation 'com.squareup.okhttp3:mockwebserver:3.8.1' androidTestImplementation "com.android.support:support-annotations:$SUPPORT_LIB_VERSION" - androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2-alpha1' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' debugImplementation "com.squareup.leakcanary:leakcanary-android:$LEAK_CANARY" releaseImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$LEAK_CANARY" @@ -117,7 +120,7 @@ android { buildTypes { release { minifyEnabled false // See https://stackoverflow.com/questions/40232404/google-play-apk-and-android-studio-apk-usb-debug-behaving-differently - proguard.cfg modification alone insufficient. - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt', 'proguard-glide.txt' } debug { applicationIdSuffix ".debug" diff --git a/app/proguard-glide.txt b/app/proguard-glide.txt new file mode 100644 index 000000000..ef3437660 --- /dev/null +++ b/app/proguard-glide.txt @@ -0,0 +1,9 @@ +-keep public class * implements com.bumptech.glide.module.GlideModule +-keep public class * extends com.bumptech.glide.module.AppGlideModule +-keep public enum com.bumptech.glide.load.ImageHeaderParser$** { + **[] $VALUES; + public *; +} + +# for DexGuard only +-keepresourcexmlelements manifest/application/meta-data@value=GlideModule \ No newline at end of file diff --git a/app/proguard-rules.txt b/app/proguard-rules.txt index bbf3a3f0d..39b618718 100644 --- a/app/proguard-rules.txt +++ b/app/proguard-rules.txt @@ -1,5 +1,4 @@ -dontobfuscate -keep class org.apache.http.** { *; } -dontwarn org.apache.http.** --keep class fr.free.nrw.commons.upload.MwVolleyApi$Page {*;} -keep class android.support.v7.widget.ShareActionProvider { *; } \ No newline at end of file diff --git a/app/quality.gradle b/app/quality.gradle index 7ea20916a..1afdf0d68 100644 --- a/app/quality.gradle +++ b/app/quality.gradle @@ -18,7 +18,7 @@ task checkstyle(type: Checkstyle) { reports { html { enabled true - destination "${project.buildDir}/reports/checkstyle/checkstyle.html" + destination file("${project.buildDir}/reports/checkstyle/checkstyle.html") } } } @@ -36,10 +36,10 @@ task pmd(type: Pmd) { xml.enabled = false html.enabled = true xml { - destination "${project.buildDir}/reports/pmd/pmd.xml" + destination file("${project.buildDir}/reports/pmd/pmd.xml") } html { - destination "${project.buildDir}/reports/pmd/pmd.html" + destination file("${project.buildDir}/reports/pmd/pmd.html") } } } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 17f6770d2..45a647227 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -15,6 +15,7 @@ + diff --git a/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java b/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java index d0fb628e3..b19d70a4e 100644 --- a/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java @@ -271,11 +271,11 @@ public class LoginActivity extends AccountAuthenticatorActivity { showMessageAndCancelDialog(R.string.login_failed_network); } else if (result.toLowerCase(Locale.getDefault()).contains("nosuchuser".toLowerCase()) || result.toLowerCase().contains("noname".toLowerCase())) { // Matches nosuchuser, nosuchusershort, noname - showMessageAndCancelDialog(R.string.login_failed_username); + showMessageAndCancelDialog(R.string.login_failed_wrong_credentials); emptySensitiveEditFields(); } else if (result.toLowerCase(Locale.getDefault()).contains("wrongpassword".toLowerCase())) { // Matches wrongpassword, wrongpasswordempty - showMessageAndCancelDialog(R.string.login_failed_password); + showMessageAndCancelDialog(R.string.login_failed_wrong_credentials); emptySensitiveEditFields(); } else if (result.toLowerCase(Locale.getDefault()).contains("throttle".toLowerCase())) { // Matches unknown throttle error codes diff --git a/app/src/main/java/fr/free/nrw/commons/caching/CacheController.java b/app/src/main/java/fr/free/nrw/commons/caching/CacheController.java index ff6ceece4..72de0db70 100644 --- a/app/src/main/java/fr/free/nrw/commons/caching/CacheController.java +++ b/app/src/main/java/fr/free/nrw/commons/caching/CacheController.java @@ -7,18 +7,25 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import fr.free.nrw.commons.upload.MwVolleyApi; +import javax.inject.Inject; +import javax.inject.Singleton; + +import fr.free.nrw.commons.upload.GpsCategoryModel; import timber.log.Timber; +@Singleton public class CacheController { + private final GpsCategoryModel gpsCategoryModel; + private final QuadTree> quadTree; private double x, y; - private QuadTree> quadTree; private double xMinus, xPlus, yMinus, yPlus; private static final int EARTH_RADIUS = 6378137; - public CacheController() { + @Inject + CacheController(GpsCategoryModel gpsCategoryModel) { + this.gpsCategoryModel = gpsCategoryModel; quadTree = new QuadTree<>(-180, -90, +180, +90); } @@ -31,8 +38,8 @@ public class CacheController { public void cacheCategory() { List pointCatList = new ArrayList<>(); - if (MwVolleyApi.GpsCatExists.getGpsCatExists()) { - pointCatList.addAll(MwVolleyApi.getGpsCat()); + if (gpsCategoryModel.getGpsCatExists()) { + pointCatList.addAll(gpsCategoryModel.getCategoryList()); Timber.d("Categories being cached: %s", pointCatList); } else { Timber.d("No categories found, so no categories cached"); @@ -65,7 +72,7 @@ public class CacheController { } //Based on algorithm at http://gis.stackexchange.com/questions/2951/algorithm-for-offsetting-a-latitude-longitude-by-some-amount-of-meters - public void convertCoordRange() { + private void convertCoordRange() { //Position, decimal degrees double lat = y; double lon = x; diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategorizationFragment.java b/app/src/main/java/fr/free/nrw/commons/category/CategorizationFragment.java index e804189ab..93ddb60d5 100644 --- a/app/src/main/java/fr/free/nrw/commons/category/CategorizationFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/category/CategorizationFragment.java @@ -39,7 +39,7 @@ import butterknife.ButterKnife; import fr.free.nrw.commons.R; import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; import fr.free.nrw.commons.mwapi.MediaWikiApi; -import fr.free.nrw.commons.upload.MwVolleyApi; +import fr.free.nrw.commons.upload.GpsCategoryModel; import fr.free.nrw.commons.utils.StringSortingUtils; import fr.free.nrw.commons.utils.ViewUtil; import io.reactivex.Observable; @@ -73,6 +73,7 @@ public class CategorizationFragment extends CommonsDaggerSupportFragment { @Inject @Named("prefs") SharedPreferences prefsPrefs; @Inject @Named("direct_nearby_upload_prefs") SharedPreferences directPrefs; @Inject CategoryDao categoryDao; + @Inject GpsCategoryModel gpsCategoryModel; private RVRendererAdapter categoriesAdapter; private OnCategoriesSaveHandler onCategoriesSaveHandler; @@ -253,7 +254,6 @@ public class CategorizationFragment extends CommonsDaggerSupportFragment { } private Observable defaultCategories() { - Observable directCat = directCategories(); if (hasDirectCategories) { Timber.d("Image has direct Cat"); @@ -287,9 +287,7 @@ public class CategorizationFragment extends CommonsDaggerSupportFragment { } private Observable gpsCategories() { - return Observable.fromIterable( - MwVolleyApi.GpsCatExists.getGpsCatExists() - ? MwVolleyApi.getGpsCat() : new ArrayList<>()) + return Observable.fromIterable(gpsCategoryModel.getCategoryList()) .map(name -> new CategoryItem(name, false)); } diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategoryImagesListFragment.java b/app/src/main/java/fr/free/nrw/commons/category/CategoryImagesListFragment.java index 3b6734edd..a44e19a29 100644 --- a/app/src/main/java/fr/free/nrw/commons/category/CategoryImagesListFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/category/CategoryImagesListFragment.java @@ -224,4 +224,14 @@ public class CategoryImagesListFragment extends DaggerFragment { public ListAdapter getAdapter() { return gridView.getAdapter(); } + + /** + * This method will be called on back pressed of CategoryImagesActivity. + * It initializes the grid view by setting adapter. + */ + @Override + public void onResume() { + gridView.setAdapter(gridAdapter); + super.onResume(); + } } diff --git a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java index 91f6d4ccb..5662bb885 100644 --- a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java +++ b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java @@ -9,17 +9,16 @@ import dagger.android.support.AndroidSupportInjectionModule; import fr.free.nrw.commons.CommonsApplication; import fr.free.nrw.commons.MediaWikiImageView; import fr.free.nrw.commons.auth.LoginActivity; -import fr.free.nrw.commons.contributions.Contribution; -import fr.free.nrw.commons.contributions.ContributionsActivity; import fr.free.nrw.commons.contributions.ContributionsSyncAdapter; import fr.free.nrw.commons.delete.DeleteTask; import fr.free.nrw.commons.modifications.ModificationsSyncAdapter; -import fr.free.nrw.commons.settings.SettingsFragment; import fr.free.nrw.commons.nearby.PlaceRenderer; +import fr.free.nrw.commons.settings.SettingsFragment; @Singleton @Component(modules = { CommonsApplicationModule.class, + NetworkingModule.class, AndroidInjectionModule.class, AndroidSupportInjectionModule.class, ActivityBuilderModule.class, diff --git a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java index 1c54366af..c5b9f0169 100644 --- a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java +++ b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java @@ -13,14 +13,10 @@ import javax.inject.Singleton; import dagger.Module; import dagger.Provides; -import fr.free.nrw.commons.BuildConfig; -import fr.free.nrw.commons.CommonsApplication; import fr.free.nrw.commons.auth.AccountUtil; import fr.free.nrw.commons.auth.SessionManager; -import fr.free.nrw.commons.caching.CacheController; import fr.free.nrw.commons.data.DBOpenHelper; import fr.free.nrw.commons.location.LocationServiceManager; -import fr.free.nrw.commons.mwapi.ApacheHttpClientMediaWikiApi; import fr.free.nrw.commons.mwapi.MediaWikiApi; import fr.free.nrw.commons.nearby.NearbyPlaces; import fr.free.nrw.commons.upload.UploadController; @@ -35,7 +31,6 @@ import static fr.free.nrw.commons.modifications.ModificationsContentProvider.MOD @SuppressWarnings({"WeakerAccess", "unused"}) public class CommonsApplicationModule { public static final String CATEGORY_AUTHORITY = "fr.free.nrw.commons.categories.contentprovider"; - public static final long OK_HTTP_CACHE_SIZE = 10 * 1024 * 1024; private Context applicationContext; @@ -144,12 +139,6 @@ public class CommonsApplicationModule { return new Gson(); } - @Provides - @Singleton - public CacheController provideCacheController() { - return new CacheController(); - } - @Provides @Singleton public DBOpenHelper provideDBOpenHelper(Context context) { diff --git a/app/src/main/java/fr/free/nrw/commons/di/NetworkingModule.java b/app/src/main/java/fr/free/nrw/commons/di/NetworkingModule.java new file mode 100644 index 000000000..8c0b52316 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/di/NetworkingModule.java @@ -0,0 +1,59 @@ +package fr.free.nrw.commons.di; + +import android.content.Context; +import android.content.SharedPreferences; +import android.support.annotation.NonNull; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import javax.inject.Named; +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; +import fr.free.nrw.commons.BuildConfig; +import fr.free.nrw.commons.mwapi.ApacheHttpClientMediaWikiApi; +import fr.free.nrw.commons.mwapi.MediaWikiApi; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; + +@Module +@SuppressWarnings({"WeakerAccess", "unused"}) +public class NetworkingModule { + public static final long OK_HTTP_CACHE_SIZE = 10 * 1024 * 1024; + + @Provides + @Singleton + public OkHttpClient provideOkHttpClient() { + return new OkHttpClient.Builder().build(); + } + + @Provides + @Singleton + public MediaWikiApi provideMediaWikiApi(Context context, + @Named("default_preferences") SharedPreferences defaultPreferences, + @Named("category_prefs") SharedPreferences categoryPrefs, + Gson gson) { + return new ApacheHttpClientMediaWikiApi(context, BuildConfig.WIKIMEDIA_API_HOST, defaultPreferences, categoryPrefs, gson); + } + + @Provides + @Named("commons_mediawiki_url") + @NonNull + @SuppressWarnings("ConstantConditions") + public HttpUrl provideMwUrl() { + return HttpUrl.parse(BuildConfig.COMMONS_URL); + } + + /** + * Gson objects are very heavy. The app should ideally be using just one instance of it instead of creating new instances everywhere. + * @return returns a singleton Gson instance + */ + @Provides + @Singleton + public Gson provideGson() { + return new GsonBuilder().create(); + } + +} diff --git a/app/src/main/java/fr/free/nrw/commons/glide/SvgDecoder.java b/app/src/main/java/fr/free/nrw/commons/glide/SvgDecoder.java new file mode 100644 index 000000000..9087f9501 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/glide/SvgDecoder.java @@ -0,0 +1,36 @@ +package fr.free.nrw.commons.glide; + +import android.support.annotation.NonNull; + +import com.bumptech.glide.load.Options; +import com.bumptech.glide.load.ResourceDecoder; +import com.bumptech.glide.load.engine.Resource; +import com.bumptech.glide.load.resource.SimpleResource; +import com.caverock.androidsvg.SVG; +import com.caverock.androidsvg.SVGParseException; + +import java.io.IOException; +import java.io.InputStream; + +/** + * Decodes an SVG internal representation from an {@link InputStream}. + */ +public class SvgDecoder implements ResourceDecoder { + + @Override + public boolean handles(@NonNull InputStream source, @NonNull Options options) { + // TODO: Can we tell? + return true; + } + + public Resource decode(@NonNull InputStream source, int width, int height, + @NonNull Options options) + throws IOException { + try { + SVG svg = SVG.getFromInputStream(source); + return new SimpleResource<>(svg); + } catch (SVGParseException ex) { + throw new IOException("Cannot load SVG from stream", ex); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/glide/SvgDrawableTranscoder.java b/app/src/main/java/fr/free/nrw/commons/glide/SvgDrawableTranscoder.java new file mode 100644 index 000000000..89910c8fb --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/glide/SvgDrawableTranscoder.java @@ -0,0 +1,28 @@ +package fr.free.nrw.commons.glide; + +import android.graphics.Picture; +import android.graphics.drawable.PictureDrawable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import com.bumptech.glide.load.Options; +import com.bumptech.glide.load.engine.Resource; +import com.bumptech.glide.load.resource.SimpleResource; +import com.bumptech.glide.load.resource.transcode.ResourceTranscoder; +import com.caverock.androidsvg.SVG; + +/** + * Convert the {@link SVG}'s internal representation to an Android-compatible one + * ({@link Picture}). + */ +public class SvgDrawableTranscoder implements ResourceTranscoder { + @Nullable + @Override + public Resource transcode(@NonNull Resource toTranscode, + @NonNull Options options) { + SVG svg = toTranscode.get(); + Picture picture = svg.renderToPicture(); + PictureDrawable drawable = new PictureDrawable(picture); + return new SimpleResource<>(drawable); + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/glide/SvgSoftwareLayerSetter.java b/app/src/main/java/fr/free/nrw/commons/glide/SvgSoftwareLayerSetter.java new file mode 100644 index 000000000..66a3bd6bf --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/glide/SvgSoftwareLayerSetter.java @@ -0,0 +1,51 @@ +package fr.free.nrw.commons.glide; + +import android.graphics.drawable.PictureDrawable; +import android.widget.ImageView; + +import com.bumptech.glide.load.DataSource; +import com.bumptech.glide.load.engine.GlideException; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.target.ImageViewTarget; +import com.bumptech.glide.request.target.Target; + +/** + * Listener which updates the {@link ImageView} to be software rendered, because + * {@link com.caverock.androidsvg.SVG SVG}/{@link android.graphics.Picture Picture} can't render on + * a hardware backed {@link android.graphics.Canvas Canvas}. + */ +public class SvgSoftwareLayerSetter implements RequestListener { + + /** + * Sets the layer type to none if the load fails + * @param e + * @param model + * @param target + * @param isFirstResource + * @return + */ + @Override + public boolean onLoadFailed(GlideException e, Object model, Target target, + boolean isFirstResource) { + ImageView view = ((ImageViewTarget) target).getView(); + view.setLayerType(ImageView.LAYER_TYPE_NONE, null); + return false; + } + + /** + * Sets the layer type to software when the resource is ready + * @param resource + * @param model + * @param target + * @param dataSource + * @param isFirstResource + * @return + */ + @Override + public boolean onResourceReady(PictureDrawable resource, Object model, + Target target, DataSource dataSource, boolean isFirstResource) { + ImageView view = ((ImageViewTarget) target).getView(); + view.setLayerType(ImageView.LAYER_TYPE_SOFTWARE, null); + return false; + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java index 9614c4f00..54bb5981c 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java @@ -35,6 +35,9 @@ import java.util.Locale; import javax.inject.Inject; import javax.inject.Provider; +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; import fr.free.nrw.commons.License; import fr.free.nrw.commons.LicenseList; import fr.free.nrw.commons.Media; @@ -56,16 +59,16 @@ import static android.widget.Toast.LENGTH_SHORT; public class MediaDetailFragment extends CommonsDaggerSupportFragment { private boolean editable; - private boolean isFeaturedMedia; + private boolean isCategoryImage; private MediaDetailPagerFragment.MediaDetailProvider detailProvider; private int index; - public static MediaDetailFragment forMedia(int index, boolean editable, boolean isFeaturedMedia) { + public static MediaDetailFragment forMedia(int index, boolean editable, boolean isCategoryImage) { MediaDetailFragment mf = new MediaDetailFragment(); Bundle state = new Bundle(); state.putBoolean("editable", editable); - state.putBoolean("isFeaturedMedia", isFeaturedMedia); + state.putBoolean("isCategoryImage", isCategoryImage); state.putInt("index", index); state.putInt("listIndex", 0); state.putInt("listTop", 0); @@ -128,7 +131,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { super.onSaveInstanceState(outState); outState.putInt("index", index); outState.putBoolean("editable", editable); - outState.putBoolean("isFeaturedMedia", isFeaturedMedia); + outState.putBoolean("isCategoryImage", isCategoryImage); getScrollPosition(); outState.putInt("listTop", initialListTop); @@ -144,12 +147,12 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { if (savedInstanceState != null) { editable = savedInstanceState.getBoolean("editable"); - isFeaturedMedia = savedInstanceState.getBoolean("isFeaturedMedia"); + isCategoryImage = savedInstanceState.getBoolean("isCategoryImage"); index = savedInstanceState.getInt("index"); initialListTop = savedInstanceState.getInt("listTop"); } else { editable = getArguments().getBoolean("editable"); - isFeaturedMedia = getArguments().getBoolean("isFeaturedMedia"); + isCategoryImage = getArguments().getBoolean("isCategoryImage"); index = getArguments().getInt("index"); initialListTop = 0; } @@ -161,7 +164,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { ButterKnife.bind(this,view); - if (isFeaturedMedia){ + if (isCategoryImage){ authorLayout.setVisibility(VISIBLE); } else { authorLayout.setVisibility(GONE); @@ -328,7 +331,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { if (!TextUtils.isEmpty(licenseLink(media))) { openWebBrowser(licenseLink(media)); } else { - if(isFeaturedMedia) { + if(isCategoryImage) { Timber.d("Unable to fetch license URL for %s", media.getLicense()); } else { Toast toast = Toast.makeText(getContext(), getString(R.string.null_url), Toast.LENGTH_SHORT); @@ -503,8 +506,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { if (media.getRequestedDeletion()){ delete.setVisibility(GONE); nominatedForDeletion.setVisibility(VISIBLE); - } - else{ + } else if (!isCategoryImage) { delete.setVisibility(VISIBLE); nominatedForDeletion.setVisibility(GONE); } diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java index 62d1261cf..2c58e8dbb 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java @@ -2,9 +2,11 @@ package fr.free.nrw.commons.media; import android.annotation.SuppressLint; import android.app.DownloadManager; +import android.app.WallpaperManager; import android.content.Intent; import android.content.SharedPreferences; import android.database.DataSetObserver; +import android.graphics.Bitmap; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -26,6 +28,8 @@ import android.view.View; import android.view.ViewGroup; import android.widget.Toast; +import java.io.IOException; + import butterknife.BindView; import butterknife.ButterKnife; import javax.inject.Inject; @@ -38,12 +42,15 @@ import fr.free.nrw.commons.contributions.Contribution; import fr.free.nrw.commons.contributions.ContributionsActivity; import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; import fr.free.nrw.commons.mwapi.MediaWikiApi; +import fr.free.nrw.commons.utils.ImageUtils; +import timber.log.Timber; import static android.Manifest.permission.READ_EXTERNAL_STORAGE; import static android.content.Context.DOWNLOAD_SERVICE; import static android.content.Intent.ACTION_VIEW; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.widget.Toast.LENGTH_SHORT; +import static com.mapbox.mapboxsdk.Mapbox.getApplicationContext; public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment implements ViewPager.OnPageChangeListener { @@ -140,6 +147,10 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple // Download downloadMedia(m); return true; + case R.id.menu_set_as_wallpaper: + // Set wallpaper + setWallpaper(m); + return true; case R.id.menu_retry_current_image: // Retry ((ContributionsActivity) getActivity()).retryUpload(pager.getCurrentItem()); @@ -155,6 +166,19 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple } } + /** + * Set the media as the device's wallpaper if the imageUrl is not null + * Fails silently if setting the wallpaper fails + * @param media + */ + private void setWallpaper(Media media) { + if(media.getImageUrl() == null || media.getImageUrl().isEmpty()) { + Timber.d("Media URL not present"); + return; + } + ImageUtils.setWallpaperFromImageUrl(getActivity(), Uri.parse(media.getImageUrl())); + } + /** * Start the media file downloading to the local SD card/storage. * The file can then be opened in Gallery or other apps. diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java b/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java index 47b9b5925..3eeeec4e2 100644 --- a/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java @@ -517,8 +517,8 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi { .param("notprop", "list") .param("format", "xml") .param("meta", "notifications") -// .param("meta", "notifications") .param("notformat", "model") + .param("notwikis", "wikidatawiki|commonswiki|enwiki") .get() .getNode("/api/query/notifications/list"); } catch (IOException e) { diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/CategoryApi.java b/app/src/main/java/fr/free/nrw/commons/mwapi/CategoryApi.java new file mode 100644 index 000000000..031796745 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/CategoryApi.java @@ -0,0 +1,101 @@ +package fr.free.nrw.commons.mwapi; + +import com.google.gson.Gson; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import javax.inject.Inject; +import javax.inject.Named; + +import fr.free.nrw.commons.mwapi.model.ApiResponse; +import fr.free.nrw.commons.mwapi.model.Page; +import fr.free.nrw.commons.mwapi.model.PageCategory; +import io.reactivex.Single; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; +import timber.log.Timber; + +/** + * Uses the OkHttp library to implement calls to the Commons MediaWiki API to match GPS coordinates + * with nearby Commons categories. Parses the results using GSON to obtain a list of relevant + * categories. Note: that caller is responsible for executing the request() method on a background + * thread. + */ +public class CategoryApi { + + private final OkHttpClient okHttpClient; + private final HttpUrl mwUrl; + private final Gson gson; + + @Inject + public CategoryApi(OkHttpClient okHttpClient, Gson gson, + @Named("commons_mediawiki_url") HttpUrl mwUrl) { + this.okHttpClient = okHttpClient; + this.mwUrl = mwUrl; + this.gson = gson; + } + + public Single> request(String coords) { + return Single.fromCallable(() -> { + HttpUrl apiUrl = buildUrl(coords); + Timber.d("URL: %s", apiUrl.toString()); + + Request request = new Request.Builder().get().url(apiUrl).build(); + Response response = okHttpClient.newCall(request).execute(); + ResponseBody body = response.body(); + if (body == null) { + return Collections.emptyList(); + } + + ApiResponse apiResponse = gson.fromJson(body.charStream(), ApiResponse.class); + Set categories = new LinkedHashSet<>(); + if (apiResponse != null && apiResponse.hasPages()) { + for (Page page : apiResponse.query.pages) { + for (PageCategory category : page.getCategories()) { + categories.add(category.withoutPrefix()); + } + } + } + return new ArrayList<>(categories); + }); + } + + /** + * Builds URL with image coords for MediaWiki API calls + * Example URL: https://commons.wikimedia.org/w/api.php?action=query&prop=categories|coordinates|pageprops&format=json&clshow=!hidden&coprop=type|name|dim|country|region|globe&codistancefrompoint=38.11386944444445|13.356263888888888&generator=geosearch&redirects=&ggscoord=38.11386944444445|1.356263888888888&ggsradius=100&ggslimit=10&ggsnamespace=6&ggsprop=type|name|dim|country|region|globe&ggsprimary=all&formatversion=2 + * + * @param coords Coordinates to build query with + * @return URL for API query + */ + private HttpUrl buildUrl(String coords) { + return mwUrl.newBuilder() + .addPathSegment("w") + .addPathSegment("api.php") + .addQueryParameter("action", "query") + .addQueryParameter("prop", "categories|coordinates|pageprops") + .addQueryParameter("format", "json") + .addQueryParameter("clshow", "!hidden") + .addQueryParameter("coprop", "type|name|dim|country|region|globe") + .addQueryParameter("codistancefrompoint", coords) + .addQueryParameter("generator", "geosearch") + .addQueryParameter("ggscoord", coords) + .addQueryParameter("ggsradius", "10000") + .addQueryParameter("ggslimit", "10") + .addQueryParameter("ggsnamespace", "6") + .addQueryParameter("ggsprop", "type|name|dim|country|region|globe") + .addQueryParameter("ggsprimary", "all") + .addQueryParameter("formatversion", "2") + .build(); + } + +} + + + diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/model/ApiResponse.java b/app/src/main/java/fr/free/nrw/commons/mwapi/model/ApiResponse.java new file mode 100644 index 000000000..7feb90251 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/model/ApiResponse.java @@ -0,0 +1,12 @@ +package fr.free.nrw.commons.mwapi.model; + +public class ApiResponse { + public Query query; + + public ApiResponse() { + } + + public boolean hasPages() { + return query != null && query.pages != null; + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/model/Page.java b/app/src/main/java/fr/free/nrw/commons/mwapi/model/Page.java new file mode 100644 index 000000000..d01ba658f --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/model/Page.java @@ -0,0 +1,17 @@ +package fr.free.nrw.commons.mwapi.model; + +import android.support.annotation.NonNull; + +public class Page { + public String title; + public PageCategory[] categories; + public PageCategory category; + + public Page() { + } + + @NonNull + public PageCategory[] getCategories() { + return categories != null ? categories : new PageCategory[0]; + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/model/PageCategory.java b/app/src/main/java/fr/free/nrw/commons/mwapi/model/PageCategory.java new file mode 100644 index 000000000..be4b9fd79 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/model/PageCategory.java @@ -0,0 +1,12 @@ +package fr.free.nrw.commons.mwapi.model; + +public class PageCategory { + public String title; + + public PageCategory() { + } + + public String withoutPrefix() { + return title != null ? title.replace("Category:", "") : ""; + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/model/Query.java b/app/src/main/java/fr/free/nrw/commons/mwapi/model/Query.java new file mode 100644 index 000000000..b87f97cc3 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/model/Query.java @@ -0,0 +1,10 @@ +package fr.free.nrw.commons.mwapi.model; + +public class Query { + public Page[] pages; + + public Query() { + pages = new Page[0]; + } + +} diff --git a/app/src/main/java/fr/free/nrw/commons/notification/NotificationRenderer.java b/app/src/main/java/fr/free/nrw/commons/notification/NotificationRenderer.java index 17a318e74..6dcfca35d 100644 --- a/app/src/main/java/fr/free/nrw/commons/notification/NotificationRenderer.java +++ b/app/src/main/java/fr/free/nrw/commons/notification/NotificationRenderer.java @@ -1,6 +1,7 @@ package fr.free.nrw.commons.notification; -import android.util.Log; +import android.graphics.drawable.PictureDrawable; +import android.text.Html; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -8,17 +9,23 @@ import android.widget.ImageView; import android.widget.TextView; import com.borjabravo.readmoretextview.ReadMoreTextView; +import com.bumptech.glide.RequestBuilder; import com.pedrogomez.renderers.Renderer; import butterknife.BindView; import butterknife.ButterKnife; import fr.free.nrw.commons.R; +import fr.free.nrw.commons.glide.SvgSoftwareLayerSetter; + +import static com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withCrossFade; /** * Created by root on 19.12.2017. */ public class NotificationRenderer extends Renderer { + private RequestBuilder requestBuilder; + @BindView(R.id.title) ReadMoreTextView title; @BindView(R.id.time) TextView time; @BindView(R.id.icon) ImageView icon; @@ -41,23 +48,32 @@ public class NotificationRenderer extends Renderer { protected View inflate(LayoutInflater layoutInflater, ViewGroup viewGroup) { View inflatedView = layoutInflater.inflate(R.layout.item_notification, viewGroup, false); ButterKnife.bind(this, inflatedView); + requestBuilder = GlideApp.with(inflatedView.getContext()) + .as(PictureDrawable.class) + .error(R.drawable.round_icon_unknown) + .transition(withCrossFade()) + .listener(new SvgSoftwareLayerSetter()); return inflatedView; } @Override public void render() { Notification notification = getContent(); - String str = notification.notificationText.trim(); - str = str.concat(" "); - title.setText(str); + setTitle(notification.notificationText); time.setText(notification.date); - switch (notification.notificationType) { - case THANK_YOU_EDIT: - icon.setImageResource(R.drawable.ic_edit_black_24dp); - break; - default: - icon.setImageResource(R.drawable.round_icon_unknown); - } + requestBuilder.load(notification.iconUrl).into(icon); + } + + /** + * Cleans up the notification text and sets it as the title + * Clean up is required to fix escaped HTML string and extra white spaces at the beginning of the notification + * @param notificationText + */ + private void setTitle(String notificationText) { + notificationText = notificationText.trim().replaceAll("(^\\h*)|(\\h*$)", ""); + notificationText = Html.fromHtml(notificationText).toString(); + notificationText = notificationText.concat(" "); + title.setText(notificationText); } public interface NotificationClicked{ diff --git a/app/src/main/java/fr/free/nrw/commons/notification/NotificationUtils.java b/app/src/main/java/fr/free/nrw/commons/notification/NotificationUtils.java index 68c3add1c..e7c87d3f4 100644 --- a/app/src/main/java/fr/free/nrw/commons/notification/NotificationUtils.java +++ b/app/src/main/java/fr/free/nrw/commons/notification/NotificationUtils.java @@ -16,12 +16,13 @@ import javax.annotation.Nullable; import fr.free.nrw.commons.BuildConfig; import fr.free.nrw.commons.R; -import static fr.free.nrw.commons.notification.NotificationType.THANK_YOU_EDIT; import static fr.free.nrw.commons.notification.NotificationType.UNKNOWN; public class NotificationUtils { private static final String COMMONS_WIKI = "commonswiki"; + private static final String WIKIDATA_WIKI = "wikidatawiki"; + private static final String WIKIPEDIA_WIKI = "enwiki"; public static boolean isCommonsNotification(Node document) { if (document == null || !document.hasAttributes()) { @@ -31,6 +32,32 @@ public class NotificationUtils { return COMMONS_WIKI.equals(element.getAttribute("wiki")); } + /** + * Returns true if the wiki attribute corresponds to wikidatawiki + * @param document + * @return + */ + public static boolean isWikidataNotification(Node document) { + if (document == null || !document.hasAttributes()) { + return false; + } + Element element = (Element) document; + return WIKIDATA_WIKI.equals(element.getAttribute("wiki")); + } + + /** + * Returns true if the wiki attribute corresponds to enwiki + * @param document + * @return + */ + public static boolean isWikipediaNotification(Node document) { + if (document == null || !document.hasAttributes()) { + return false; + } + Element element = (Element) document; + return WIKIPEDIA_WIKI.equals(element.getAttribute("wiki")); + } + public static NotificationType getNotificationType(Node document) { Element element = (Element) document; String type = element.getAttribute("type"); @@ -68,10 +95,17 @@ public class NotificationUtils { return notifications; } + /** + * Currently the app is interested in showing notifications just from the following three wikis: commons, wikidata, wikipedia + * This function returns true only if the notification belongs to any of the above wikis and is of a known notification type + * @param node + * @return + */ private static boolean isUsefulNotification(Node node) { - return isCommonsNotification(node) - && !getNotificationType(node).equals(UNKNOWN) - && !getNotificationType(node).equals(THANK_YOU_EDIT); + return (isCommonsNotification(node) + || isWikidataNotification(node) + || isWikipediaNotification(node)) + && !getNotificationType(node).equals(UNKNOWN); } public static boolean isBundledNotification(Node document) { @@ -97,7 +131,7 @@ public class NotificationUtils { switch (type) { case THANK_YOU_EDIT: - notificationText = context.getString(R.string.notifications_thank_you_edit); + notificationText = getThankYouEditDescription(document); break; case EDIT_USER_TALK: notificationText = getNotificationText(document); @@ -146,6 +180,16 @@ public class NotificationUtils { return body != null ? body.getTextContent() : ""; } + /** + * Gets the header node returned in the XML document to form the description for thank you edits + * @param document + * @return + */ + private static String getThankYouEditDescription(Node document) { + Node body = getNode(getModel(document), "header"); + return body != null ? body.getTextContent() : ""; + } + private static String getNotificationIconUrl(Node document) { String format = "%s%s"; Node iconUrl = getNode(getModel(document), "iconUrl"); diff --git a/app/src/main/java/fr/free/nrw/commons/notification/SvgModule.java b/app/src/main/java/fr/free/nrw/commons/notification/SvgModule.java new file mode 100644 index 000000000..5a1e8ae63 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/notification/SvgModule.java @@ -0,0 +1,35 @@ +package fr.free.nrw.commons.notification; + +import android.content.Context; +import android.graphics.drawable.PictureDrawable; +import android.support.annotation.NonNull; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.Registry; +import com.bumptech.glide.annotation.GlideModule; +import com.bumptech.glide.module.AppGlideModule; +import com.caverock.androidsvg.SVG; + +import java.io.InputStream; + +import fr.free.nrw.commons.glide.SvgDecoder; +import fr.free.nrw.commons.glide.SvgDrawableTranscoder; + +/** + * Module for the SVG sample app. + */ +@GlideModule +public class SvgModule extends AppGlideModule { + @Override + public void registerComponents(@NonNull Context context, @NonNull Glide glide, + @NonNull Registry registry) { + registry.register(SVG.class, PictureDrawable.class, new SvgDrawableTranscoder()) + .append(InputStream.class, SVG.class, new SvgDecoder()); + } + + // Disable manifest parsing to avoid adding similar modules twice. + @Override + public boolean isManifestParsingEnabled() { + return false; + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/upload/GpsCategoryModel.java b/app/src/main/java/fr/free/nrw/commons/upload/GpsCategoryModel.java new file mode 100644 index 000000000..841210453 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/upload/GpsCategoryModel.java @@ -0,0 +1,40 @@ +package fr.free.nrw.commons.upload; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.inject.Inject; +import javax.inject.Singleton; + +@Singleton +public class GpsCategoryModel { + private Set categorySet; + + @Inject + public GpsCategoryModel() { + clear(); + } + + public void clear() { + categorySet = new HashSet<>(); + } + + public boolean getGpsCatExists() { + return !categorySet.isEmpty(); + } + + public List getCategoryList() { + return new ArrayList<>(categorySet); + } + + public void setCategoryList(List categoryList) { + clear(); + categorySet.addAll(categoryList != null ? categoryList : new ArrayList<>()); + } + + public void add(String categoryString) { + categorySet.add(categoryString); + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/upload/MultipleUploadListFragment.java b/app/src/main/java/fr/free/nrw/commons/upload/MultipleUploadListFragment.java index 4390bcef4..089f1ac46 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/MultipleUploadListFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/MultipleUploadListFragment.java @@ -26,6 +26,8 @@ import android.widget.GridView; import android.widget.RelativeLayout; import android.widget.TextView; +import butterknife.BindView; +import butterknife.ButterKnife; import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; import com.facebook.drawee.view.SimpleDraweeView; @@ -41,9 +43,13 @@ public class MultipleUploadListFragment extends Fragment { void OnMultipleUploadInitiated(); } - private GridView photosGrid; + @BindView(R.id.multipleShareBackground) + GridView photosGrid; + + @BindView(R.id.multipleBaseTitle) + EditText baseTitle; + private PhotoDisplayAdapter photosAdapter; - private EditText baseTitle; private TitleTextWatcher textWatcher = new TitleTextWatcher(); private Point photoSize; @@ -166,9 +172,7 @@ public class MultipleUploadListFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_multiple_uploads_list, container, false); - photosGrid = view.findViewById(R.id.multipleShareBackground); - baseTitle = view.findViewById(R.id.multipleBaseTitle); - + ButterKnife.bind(this,view); photosAdapter = new PhotoDisplayAdapter(); photosGrid.setAdapter(photosAdapter); photosGrid.setOnItemClickListener((AdapterView.OnItemClickListener) getActivity()); diff --git a/app/src/main/java/fr/free/nrw/commons/upload/MwVolleyApi.java b/app/src/main/java/fr/free/nrw/commons/upload/MwVolleyApi.java deleted file mode 100644 index a530e79e6..000000000 --- a/app/src/main/java/fr/free/nrw/commons/upload/MwVolleyApi.java +++ /dev/null @@ -1,249 +0,0 @@ -package fr.free.nrw.commons.upload; - -import android.content.Context; -import android.net.Uri; - -import com.android.volley.Cache; -import com.android.volley.NetworkResponse; -import com.android.volley.Request; -import com.android.volley.RequestQueue; -import com.android.volley.Response; -import com.android.volley.VolleyError; -import com.android.volley.toolbox.HttpHeaderParser; -import com.android.volley.toolbox.JsonRequest; -import com.android.volley.toolbox.Volley; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; - -import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import timber.log.Timber; - -/** - * Uses the Volley library to implement asynchronous calls to the Commons MediaWiki API to match - * GPS coordinates with nearby Commons categories. Parses the results using GSON to obtain a list - * of relevant categories. - */ -public class MwVolleyApi { - - private static RequestQueue REQUEST_QUEUE; - private static final Gson GSON = new GsonBuilder().create(); - - private static Set categorySet; - private static List categoryList; - - private static final String MWURL = "https://commons.wikimedia.org/"; - private final Context context; - - public MwVolleyApi(Context context) { - this.context = context; - categorySet = new HashSet<>(); - } - - public static List getGpsCat() { - return categoryList; - } - - public static void setGpsCat(List cachedList) { - categoryList = new ArrayList<>(); - categoryList.addAll(cachedList); - Timber.d("Setting GPS cats from cache: %s", categoryList); - } - - public void request(String coords) { - String apiUrl = buildUrl(coords); - Timber.d("URL: %s", apiUrl); - - JsonRequest request = new QueryRequest(apiUrl, - new LogResponseListener<>(), new LogResponseErrorListener()); - getQueue().add(request); - } - - /** - * Builds URL with image coords for MediaWiki API calls - * Example URL: https://commons.wikimedia.org/w/api.php?action=query&prop=categories|coordinates|pageprops&format=json&clshow=!hidden&coprop=type|name|dim|country|region|globe&codistancefrompoint=38.11386944444445|13.356263888888888&generator=geosearch&redirects=&ggscoord=38.11386944444445|1.356263888888888&ggsradius=100&ggslimit=10&ggsnamespace=6&ggsprop=type|name|dim|country|region|globe&ggsprimary=all&formatversion=2 - * @param coords Coordinates to build query with - * @return URL for API query - */ - private String buildUrl(String coords) { - - Uri.Builder builder = Uri.parse(MWURL).buildUpon(); - - builder.appendPath("w") - .appendPath("api.php") - .appendQueryParameter("action", "query") - .appendQueryParameter("prop", "categories|coordinates|pageprops") - .appendQueryParameter("format", "json") - .appendQueryParameter("clshow", "!hidden") - .appendQueryParameter("coprop", "type|name|dim|country|region|globe") - .appendQueryParameter("codistancefrompoint", coords) - .appendQueryParameter("generator", "geosearch") - .appendQueryParameter("ggscoord", coords) - .appendQueryParameter("ggsradius", "10000") - .appendQueryParameter("ggslimit", "10") - .appendQueryParameter("ggsnamespace", "6") - .appendQueryParameter("ggsprop", "type|name|dim|country|region|globe") - .appendQueryParameter("ggsprimary", "all") - .appendQueryParameter("formatversion", "2"); - - return builder.toString(); - } - - private synchronized RequestQueue getQueue() { - if (REQUEST_QUEUE == null) { - REQUEST_QUEUE = Volley.newRequestQueue(context); - } - return REQUEST_QUEUE; - } - - private static class LogResponseListener implements Response.Listener { - - @Override - public void onResponse(T response) { - Timber.d(response.toString()); - } - } - - private static class LogResponseErrorListener implements Response.ErrorListener { - - @Override - public void onErrorResponse(VolleyError error) { - Timber.e(error.toString()); - } - } - - private static class QueryRequest extends JsonRequest { - - public QueryRequest(String url, - Response.Listener listener, - Response.ErrorListener errorListener) { - super(Request.Method.GET, url, null, listener, errorListener); - } - - @Override - protected Response parseNetworkResponse(NetworkResponse response) { - String json = parseString(response); - QueryResponse queryResponse = GSON.fromJson(json, QueryResponse.class); - return Response.success(queryResponse, cacheEntry(response)); - } - - private Cache.Entry cacheEntry(NetworkResponse response) { - return HttpHeaderParser.parseCacheHeaders(response); - } - - private String parseString(NetworkResponse response) { - try { - return new String(response.data, HttpHeaderParser.parseCharset(response.headers)); - } catch (UnsupportedEncodingException e) { - return new String(response.data); - } - } - } - - public static class GpsCatExists { - private static boolean gpsCatExists; - - public static void setGpsCatExists(boolean gpsCat) { - gpsCatExists = gpsCat; - } - - public static boolean getGpsCatExists() { - return gpsCatExists; - } - } - - private static class QueryResponse { - private Query query = new Query(); - - private String printSet() { - if (categorySet == null || categorySet.isEmpty()) { - GpsCatExists.setGpsCatExists(false); - Timber.d("gpsCatExists=%b", GpsCatExists.getGpsCatExists()); - return "No collection of categories"; - } else { - GpsCatExists.setGpsCatExists(true); - Timber.d("gpsCatExists=%b", GpsCatExists.getGpsCatExists()); - return "CATEGORIES FOUND" + categorySet.toString(); - } - - } - - @Override - public String toString() { - if (query != null) { - return "query=" + query.toString() + "\n" + printSet(); - } else { - return "No pages found"; - } - } - } - - private static class Query { - private Page [] pages; - - @Override - public String toString() { - StringBuilder builder = new StringBuilder("pages=" + "\n"); - if (pages != null) { - for (Page page : pages) { - builder.append(page.toString()); - builder.append("\n"); - } - builder.replace(builder.length() - 1, builder.length(), ""); - return builder.toString(); - } else { - return "No pages found"; - } - } - } - - public static class Page { - private int pageid; - private int ns; - private String title; - private Category[] categories; - private Category category; - - public Page() { - } - - @Override - public String toString() { - - StringBuilder builder = new StringBuilder("PAGEID=" + pageid + " ns=" + ns + " title=" + title + "\n" + " CATEGORIES= "); - - if (categories == null || categories.length == 0) { - builder.append("no categories exist\n"); - } else { - for (Category category : categories) { - builder.append(category.toString()); - builder.append("\n"); - if (category != null) { - String categoryString = category.toString().replace("Category:", ""); - categorySet.add(categoryString); - } - } - } - - categoryList = new ArrayList<>(categorySet); - builder.replace(builder.length() - 1, builder.length(), ""); - return builder.toString(); - } - } - - private static class Category { - private String title; - - @Override - public String toString() { - return title; - } - } -} - - - diff --git a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java index 40e36e0e0..b7a5e0f42 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java @@ -1,6 +1,7 @@ package fr.free.nrw.commons.upload; import android.Manifest; +import android.annotation.SuppressLint; import android.app.Activity; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -31,16 +32,16 @@ import android.support.v4.app.ActivityCompat; import android.support.v4.app.FragmentManager; import android.support.v4.content.ContextCompat; import android.support.v4.graphics.BitmapCompat; -import android.support.v7.app.AlertDialog; import android.util.Log; import android.view.MenuItem; import android.view.View; -import android.view.WindowManager; import android.view.animation.DecelerateInterpolator; -import android.view.inputmethod.InputMethodManager; +import android.widget.FrameLayout; import android.widget.TextView; import android.widget.Toast; +import butterknife.BindView; +import butterknife.OnClick; import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; import com.facebook.drawee.view.SimpleDraweeView; import com.github.chrisbanes.photoview.PhotoView; @@ -73,14 +74,16 @@ import fr.free.nrw.commons.modifications.ModificationsContentProvider; import fr.free.nrw.commons.modifications.ModifierSequence; import fr.free.nrw.commons.modifications.ModifierSequenceDao; import fr.free.nrw.commons.modifications.TemplateRemoveModifier; +import fr.free.nrw.commons.mwapi.CategoryApi; + import fr.free.nrw.commons.mwapi.MediaWikiApi; +import io.reactivex.schedulers.Schedulers; import fr.free.nrw.commons.utils.ViewUtil; import timber.log.Timber; import android.support.design.widget.FloatingActionButton; import static fr.free.nrw.commons.upload.ExistingFileAsync.Result.DUPLICATE_PROCEED; import static fr.free.nrw.commons.upload.ExistingFileAsync.Result.NO_DUPLICATE; -import static java.lang.Long.min; /** * Activity for the title/desc screen after image is selected. Also starts processing image @@ -91,6 +94,22 @@ public class ShareActivity implements SingleUploadFragment.OnUploadActionInitiated, OnCategoriesSaveHandler,SimilarImageDialogFragment.onResponse { + @BindView(R.id.container) + FrameLayout flContainer; + @BindView(R.id.backgroundImage) + SimpleDraweeView backgroundImageView; + @BindView(R.id.media_map) + FloatingActionButton mapsFragment; //Lets stick to camelCase + @BindView(R.id.media_upload_zoom_in) + FloatingActionButton zoomInButton; + @BindView(R.id.media_upload_zoom_out) + FloatingActionButton zoomOutButton; + @BindView(R.id.main_fab) + FloatingActionButton mainFab; + @BindView(R.id.expanded_image) + PhotoView expandedImageView; + + private static final int REQUEST_PERM_ON_CREATE_STORAGE = 1; private static final int REQUEST_PERM_ON_CREATE_LOCATION = 2; private static final int REQUEST_PERM_ON_CREATE_STORAGE_AND_LOCATION = 3; @@ -108,8 +127,12 @@ public class ShareActivity @Inject ModifierSequenceDao modifierSequenceDao; @Inject + CategoryApi apiCall; + @Inject @Named("default_preferences") SharedPreferences prefs; + @Inject + GpsCategoryModel gpsCategoryModel; private String source; private String mimeType; @@ -145,6 +168,12 @@ public class ShareActivity private FloatingActionButton mainFab; private boolean isFABOpen = false; + //Had to make them class variables, to extract out the click listeners, also I see no harm in this + final Rect startBounds = new Rect(); + final Rect finalBounds = new Rect(); + final Point globalOffset = new Point(); + private float startScaleFinal; + /** * Called when user taps the submit button. @@ -254,7 +283,6 @@ public class ShareActivity setContentView(R.layout.activity_share); ButterKnife.bind(this); initBack(); - backgroundImageView = (SimpleDraweeView) findViewById(R.id.backgroundImage); backgroundImageView.setHierarchy(GenericDraweeHierarchyBuilder .newInstance(getResources()) .setPlaceholderImage(VectorDrawableCompat.create(getResources(), @@ -286,37 +314,6 @@ public class ShareActivity if (mediaUri != null) { backgroundImageView.setImageURI(mediaUri); } - - mainFab = (FloatingActionButton) findViewById(R.id.main_fab); - /* - * called when upper arrow floating button - */ - mainFab.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if(!isFABOpen){ - showFABMenu(); - }else{ - closeFABMenu(); - } - } - }); - - - - zoomInButton = (FloatingActionButton) findViewById(R.id.media_upload_zoom_in); - try { - zoomInButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - zoomImageFromThumb(backgroundImageView, mediaUri); - } - }); - } catch (Exception e){ - Log.i("exception", e.toString()); - } - zoomOutButton = (FloatingActionButton) findViewById(R.id.media_upload_zoom_out); - if (savedInstanceState != null) { contribution = savedInstanceState.getParcelable("contribution"); } @@ -378,25 +375,13 @@ public class ShareActivity .commitAllowingStateLoss(); } uploadController.prepareService(); - maps_fragment = (FloatingActionButton) findViewById(R.id.media_map); - maps_fragment.setVisibility(View.VISIBLE); + mapsFragment.setVisibility(View.VISIBLE); if( imageObj == null || imageObj.imageCoordsExists != true){ - maps_fragment.setVisibility(View.INVISIBLE); + mapsFragment.setVisibility(View.INVISIBLE); } - - maps_fragment.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if( imageObj != null && imageObj.imageCoordsExists == true) { - Uri gmmIntentUri = Uri.parse("google.streetview:cbll=" + imageObj.getDecLatitude() + "," + imageObj.getDecLongitude()); - Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri); - mapIntent.setPackage("com.google.android.apps.maps"); - startActivity(mapIntent); - } - } - }); } + /* * Function to display the zoom and map FAB */ @@ -404,11 +389,11 @@ public class ShareActivity isFABOpen=true; if( imageObj != null && imageObj.imageCoordsExists == true) - maps_fragment.setVisibility(View.VISIBLE); + mapsFragment.setVisibility(View.VISIBLE); zoomInButton.setVisibility(View.VISIBLE); mainFab.animate().rotationBy(180); - maps_fragment.animate().translationY(-getResources().getDimension(R.dimen.second_fab)); + mapsFragment.animate().translationY(-getResources().getDimension(R.dimen.second_fab)); zoomInButton.animate().translationY(-getResources().getDimension(R.dimen.first_fab)); } @@ -418,7 +403,7 @@ public class ShareActivity private void closeFABMenu(){ isFABOpen=false; mainFab.animate().rotationBy(-180); - maps_fragment.animate().translationY(0); + mapsFragment.animate().translationY(0); zoomInButton.animate().translationY(0).setListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) { @@ -428,7 +413,7 @@ public class ShareActivity @Override public void onAnimationEnd(Animator animator) { if(!isFABOpen){ - maps_fragment.setVisibility(View.GONE); + mapsFragment.setVisibility(View.GONE); zoomInButton.setVisibility(View.GONE); } @@ -446,6 +431,7 @@ public class ShareActivity }); } + @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { @@ -699,8 +685,9 @@ public class ShareActivity return; } + //I might not be supposed to change it, but still, I saw it @Override - public void onPostiveResponse() { + public void onPositiveResponse() { imageObj = tempImageObj; decimalCoords = imageObj.getCoords(false);// Not necessary to use gps as image already ha EXIF data Timber.d("EXIF from tempImageObj"); @@ -716,8 +703,9 @@ public class ShareActivity /** * Initiates retrieval of image coordinates or user coordinates, and caching of coordinates. - * Then initiates the calls to MediaWiki API through an instance of MwVolleyApi. + * Then initiates the calls to MediaWiki API through an instance of CategpryApi. */ + @SuppressLint("CheckResult") public void useImageCoords() { if (decimalCoords != null) { Timber.d("Decimal coords of image: %s", decimalCoords); @@ -730,20 +718,27 @@ public class ShareActivity cacheController.setQtPoint(decLongitude, decLatitude); } - MwVolleyApi apiCall = new MwVolleyApi(this); - List displayCatList = cacheController.findCategory(); boolean catListEmpty = displayCatList.isEmpty(); // If no categories found in cache, call MediaWiki API to match image coords with nearby Commons categories if (catListEmpty) { cacheFound = false; - apiCall.request(decimalCoords); + apiCall.request(decimalCoords) + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.io()) + .subscribe( + gpsCategoryModel::setCategoryList, + throwable -> { + Timber.e(throwable); + gpsCategoryModel.clear(); + } + ); Timber.d("displayCatList size 0, calling MWAPI %s", displayCatList); } else { cacheFound = true; - Timber.d("Cache found, setting categoryList in MwVolleyApi to %s", displayCatList); - MwVolleyApi.setGpsCat(displayCatList); + Timber.d("Cache found, setting categoryList in model to %s", displayCatList); + gpsCategoryModel.setCategoryList(displayCatList); } }else{ Timber.d("EXIF: no coords"); @@ -864,26 +859,19 @@ public class ShareActivity scaled = bitmap; } // Load the high-resolution "zoomed-in" image. - PhotoView expandedImageView = (PhotoView) findViewById( - R.id.expanded_image); expandedImageView.setImageBitmap(scaled); - + // Calculate the starting and ending bounds for the zoomed-in image. // This step involves lots of math. Yay, math. - final Rect startBounds = new Rect(); - final Rect finalBounds = new Rect(); - final Point globalOffset = new Point(); - // The start bounds are the global visible rectangle of the thumbnail, // and the final bounds are the global visible rectangle of the container // view. Also set the container view's offset as the origin for the // bounds, since that's the origin for the positioning animation // properties (X, Y). thumbView.getGlobalVisibleRect(startBounds); - findViewById(R.id.container) - .getGlobalVisibleRect(finalBounds, globalOffset); + flContainer.getGlobalVisibleRect(finalBounds, globalOffset); startBounds.offset(-globalOffset.x, -globalOffset.y); finalBounds.offset(-globalOffset.x, -globalOffset.y); @@ -954,53 +942,86 @@ public class ShareActivity // Upon clicking the zoomed-in image, it should zoom back down // to the original bounds and show the thumbnail instead of // the expanded image. - final float startScaleFinal = startScale; - zoomOutButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (CurrentAnimator != null) { - CurrentAnimator.cancel(); - } - zoomOutButton.setVisibility(View.GONE); - mainFab.setVisibility(View.VISIBLE); + startScaleFinal = startScale; - // Animate the four positioning/sizing properties in parallel, - // back to their original values. - AnimatorSet set = new AnimatorSet(); - set.play(ObjectAnimator - .ofFloat(expandedImageView, View.X, startBounds.left)) - .with(ObjectAnimator - .ofFloat(expandedImageView, - View.Y,startBounds.top)) - .with(ObjectAnimator - .ofFloat(expandedImageView, - View.SCALE_X, startScaleFinal)) - .with(ObjectAnimator - .ofFloat(expandedImageView, - View.SCALE_Y, startScaleFinal)); - set.setDuration(ShortAnimationDuration); - set.setInterpolator(new DecelerateInterpolator()); - set.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - thumbView.setAlpha(1f); - expandedImageView.setVisibility(View.GONE); - CurrentAnimator = null; - } - - @Override - public void onAnimationCancel(Animator animation) { - thumbView.setAlpha(1f); - expandedImageView.setVisibility(View.GONE); - CurrentAnimator = null; - } - }); - set.start(); - CurrentAnimator = set; - - } - - }); } + /* + * called when upper arrow floating button + */ + @OnClick(R.id.main_fab) + public void onMainFabClicked() { + if (!isFABOpen) { + showFABMenu(); + } else { + closeFABMenu(); + } + } + + @OnClick(R.id.media_upload_zoom_in) + public void onZoomInFabClicked() { + //This try catch block was originally holding the entire click listener on the fab button, I did not wanted to risk exceptions + try { + zoomImageFromThumb(backgroundImageView, mediaUri); + } catch (Exception e) { + Log.i("exception", e.toString()); + } + } + + @OnClick(R.id.media_upload_zoom_out) + public void onZoomOutFabClicked() { + if (CurrentAnimator != null) { + CurrentAnimator.cancel(); + } + zoomOutButton.setVisibility(View.GONE); + mainFab.setVisibility(View.VISIBLE); + + // Animate the four positioning/sizing properties in parallel, + // back to their original values. + AnimatorSet set = new AnimatorSet(); + set.play(ObjectAnimator + .ofFloat(expandedImageView, View.X, startBounds.left)) + .with(ObjectAnimator + .ofFloat(expandedImageView, + View.Y, startBounds.top)) + .with(ObjectAnimator + .ofFloat(expandedImageView, + View.SCALE_X, startScaleFinal)) + .with(ObjectAnimator + .ofFloat(expandedImageView, + View.SCALE_Y, startScaleFinal)); + set.setDuration(ShortAnimationDuration); + set.setInterpolator(new DecelerateInterpolator()); + set.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + //background image view is thumbView + backgroundImageView.setAlpha(1f); + expandedImageView.setVisibility(View.GONE); + CurrentAnimator = null; + } + + @Override + public void onAnimationCancel(Animator animation) { + //background image view is thumbView + backgroundImageView.setAlpha(1f); + expandedImageView.setVisibility(View.GONE); + CurrentAnimator = null; + } + }); + set.start(); + CurrentAnimator = set; + } + + @OnClick(R.id.media_map) + public void onFabShowMapsClicked() { + if (imageObj != null && imageObj.imageCoordsExists == true) { + Uri gmmIntentUri = Uri + .parse("google.streetview:cbll=" + imageObj.getDecLatitude() + "," + imageObj + .getDecLongitude()); + Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri); + mapIntent.setPackage("com.google.android.apps.maps"); + startActivity(mapIntent); + } + } } diff --git a/app/src/main/java/fr/free/nrw/commons/upload/SimilarImageDialogFragment.java b/app/src/main/java/fr/free/nrw/commons/upload/SimilarImageDialogFragment.java index a8f336927..59b8a1223 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/SimilarImageDialogFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/SimilarImageDialogFragment.java @@ -13,6 +13,9 @@ import android.view.ViewGroup; import android.view.Window; import android.widget.Button; +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; import com.facebook.drawee.view.SimpleDraweeView; import com.facebook.imagepipeline.listener.RequestListener; @@ -29,29 +32,33 @@ import fr.free.nrw.commons.R; */ public class SimilarImageDialogFragment extends DialogFragment { + + @BindView(R.id.orginalImage) SimpleDraweeView originalImage; + @BindView(R.id.possibleImage) SimpleDraweeView possibleImage; + @BindView(R.id.postive_button) Button positiveButton; + @BindView(R.id.negative_button) Button negativeButton; onResponse mOnResponse;//Implemented interface from shareActivity Boolean gotResponse = false; + public SimilarImageDialogFragment() { } public interface onResponse{ - public void onPostiveResponse(); + public void onPositiveResponse(); + public void onNegativeResponse(); } + @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_similar_image_dialog, container, false); + ButterKnife.bind(this,view); Set requestListeners = new HashSet<>(); requestListeners.add(new RequestLoggingListener()); - originalImage =(SimpleDraweeView) view.findViewById(R.id.orginalImage); - possibleImage =(SimpleDraweeView) view.findViewById(R.id.possibleImage); - positiveButton = (Button) view.findViewById(R.id.postive_button); - negativeButton = (Button) view.findViewById(R.id.negative_button); - originalImage.setHierarchy(GenericDraweeHierarchyBuilder .newInstance(getResources()) .setPlaceholderImage(VectorDrawableCompat.create(getResources(), @@ -70,22 +77,6 @@ public class SimilarImageDialogFragment extends DialogFragment { originalImage.setImageURI(Uri.fromFile(new File(getArguments().getString("originalImagePath")))); possibleImage.setImageURI(Uri.fromFile(new File(getArguments().getString("possibleImagePath")))); - negativeButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - mOnResponse.onNegativeResponse(); - gotResponse = true; - dismiss(); - } - }); - positiveButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - mOnResponse.onPostiveResponse(); - gotResponse = true; - dismiss(); - } - }); return view; } @@ -105,8 +96,23 @@ public class SimilarImageDialogFragment extends DialogFragment { @Override public void onDismiss(DialogInterface dialog) { // I user dismisses dialog by pressing outside the dialog. - if(!gotResponse) + if (!gotResponse) { mOnResponse.onNegativeResponse(); + } super.onDismiss(dialog); } + + @OnClick(R.id.negative_button) + public void onNegativeButtonClicked() { + mOnResponse.onNegativeResponse(); + gotResponse = true; + dismiss(); + } + + @OnClick(R.id.postive_button) + public void onPositiveButtonClicked() { + mOnResponse.onPositiveResponse(); + gotResponse = true; + dismiss(); + } } diff --git a/app/src/main/java/fr/free/nrw/commons/utils/ImageUtils.java b/app/src/main/java/fr/free/nrw/commons/utils/ImageUtils.java index 4f6a6d456..a091d7758 100644 --- a/app/src/main/java/fr/free/nrw/commons/utils/ImageUtils.java +++ b/app/src/main/java/fr/free/nrw/commons/utils/ImageUtils.java @@ -1,12 +1,34 @@ package fr.free.nrw.commons.utils; +import android.app.WallpaperManager; +import android.content.Context; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.BitmapRegionDecoder; import android.graphics.Color; import android.graphics.Rect; +import android.net.Uri; +import android.os.Build; +import android.support.annotation.Nullable; +import android.support.annotation.RequiresApi; +import com.facebook.common.executors.CallerThreadExecutor; +import com.facebook.common.references.CloseableReference; +import com.facebook.datasource.DataSource; +import com.facebook.drawee.backends.pipeline.Fresco; +import com.facebook.imagepipeline.core.ImagePipeline; +import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber; +import com.facebook.imagepipeline.image.CloseableImage; +import com.facebook.imagepipeline.request.ImageRequest; +import com.facebook.imagepipeline.request.ImageRequestBuilder; + +import java.io.IOException; + +import fr.free.nrw.commons.R; import timber.log.Timber; +import static com.mapbox.mapboxsdk.Mapbox.getApplicationContext; + /** * Created by bluesir9 on 3/10/17. */ @@ -132,4 +154,52 @@ public class ImageUtils { return isImageDark; } + + /** + * Downloads the image from the URL and sets it as the phone's wallpaper + * Fails silently if download or setting wallpaper fails. + * @param context + * @param imageUrl + */ + public static void setWallpaperFromImageUrl(Context context, Uri imageUrl) { + Timber.d("Trying to set wallpaper from url %s", imageUrl.toString()); + ImageRequest imageRequest = ImageRequestBuilder + .newBuilderWithSource(imageUrl) + .setAutoRotateEnabled(true) + .build(); + + ImagePipeline imagePipeline = Fresco.getImagePipeline(); + final DataSource> + dataSource = imagePipeline.fetchDecodedImage(imageRequest, context); + + dataSource.subscribe(new BaseBitmapDataSubscriber() { + + @Override + public void onNewResultImpl(@Nullable Bitmap bitmap) { + if (dataSource.isFinished() && bitmap != null){ + Timber.d("Bitmap loaded from url %s", imageUrl.toString()); + setWallpaper(context, Bitmap.createBitmap(bitmap)); + dataSource.close(); + } + } + + @Override + public void onFailureImpl(DataSource dataSource) { + Timber.d("Error getting bitmap from image url %s", imageUrl.toString()); + if (dataSource != null) { + dataSource.close(); + } + } + }, CallerThreadExecutor.getInstance()); + } + + private static void setWallpaper(Context context, Bitmap bitmap) { + WallpaperManager wallpaperManager = WallpaperManager.getInstance(context); + try { + wallpaperManager.setBitmap(bitmap); + ViewUtil.showLongToast(context, context.getString(R.string.wallpaper_set_successfully)); + } catch (IOException e) { + Timber.e(e,"Error setting wallpaper"); + } + } } diff --git a/app/src/main/res/menu/fragment_image_detail.xml b/app/src/main/res/menu/fragment_image_detail.xml index e864dddb2..70a35951a 100644 --- a/app/src/main/res/menu/fragment_image_detail.xml +++ b/app/src/main/res/menu/fragment_image_detail.xml @@ -15,6 +15,10 @@ android:id="@+id/menu_download_current_image" android:title="@string/menu_download" app:showAsAction="never" /> + العنوان الوصف لا يمكن تسجيل الدخول - فشل في شبكة الاتصال - لا يمكن تسجيل الدخول - فضلا تحقق من اسم المستخدم - لا يمكن تسجيل الدخول - فضلا تحقق من كلمة السر الكثير من المحاولات غير الناجحة. الرجاء المحاولة مرة أخرى في بضع دقائق. عذراً، لقد تم منع هذا المستخدم على كومنز يجب توفير رمز التحقق المزدوج. diff --git a/app/src/main/res/values-ast/strings.xml b/app/src/main/res/values-ast/strings.xml index 947bc441a..e92f5dc0a 100644 --- a/app/src/main/res/values-ast/strings.xml +++ b/app/src/main/res/values-ast/strings.xml @@ -49,8 +49,6 @@ Apurre un títulu pa esti ficheru Descripción Nun se pudo aniciar sesión – error de rede - Nun se pudo aniciar sesión – por favor compruebe\'l so nome d\'usuariu - Nun se pudo aniciar sesión – por favor compruebe la so contraseña Demasiaos intentos incorreutos. Téntalo otra vuelta n\'unos minutos. Sentímoslo, esti usuariu ta bloquiáu en Commons Tienes de dar el códigu d\'identificación de dos factores. diff --git a/app/src/main/res/values-b+sr+Latn/strings.xml b/app/src/main/res/values-b+sr+Latn/strings.xml index 0cd72a167..81b826d36 100644 --- a/app/src/main/res/values-b+sr+Latn/strings.xml +++ b/app/src/main/res/values-b+sr+Latn/strings.xml @@ -43,8 +43,6 @@ Naslov Opis Ne mogu da vas prijavim – mreža ne radi - Ne mogu da vas prijavim – proverite svoje korisničko ime - Ne mogu da vas prijavim – proverite svoju lozinku Previše neuspešnih pokušaja. Probajte ponovo za nekoliko minuta. Nažalost, korisnik je blokiran na Ostavi Morate uneti svoj dvofaktorski kod za autentifikaciju. diff --git a/app/src/main/res/values-ba/strings.xml b/app/src/main/res/values-ba/strings.xml index 293dd3f73..f54a93831 100644 --- a/app/src/main/res/values-ba/strings.xml +++ b/app/src/main/res/values-ba/strings.xml @@ -50,8 +50,6 @@ Был файлдың атамаһын күрһәт Тасуирлама Инеп булмай - интернет хатаһы - Инмәнең - ҡулланыусы исемеңде тикшер - Инмәнең - серһуҙеңде тикшер Күп тапҡыр яңылыштың. Зинһар, бер-нисә минуттан тағы ла инеп ҡара Ғәфү итегеҙ, әммә был исемдәге ҡатнашыусыға Викискладҡа инеү тыйылған Ике тапҡыр раҫлай торған шәхси кодты яҙырға кәрәк diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml index cfaf021f9..28b092add 100644 --- a/app/src/main/res/values-bg/strings.xml +++ b/app/src/main/res/values-bg/strings.xml @@ -32,8 +32,6 @@ Заглавие Описание Неуспешно влизане – проблем в мрежата - Неуспешно влизане – моля проверете потребителското си име - Неуспешно влизане – моля проверете паролата си Качване Изменения Качване diff --git a/app/src/main/res/values-bn/strings.xml b/app/src/main/res/values-bn/strings.xml index 7c76ebaea..69bb5fc33 100644 --- a/app/src/main/res/values-bn/strings.xml +++ b/app/src/main/res/values-bn/strings.xml @@ -57,8 +57,6 @@ এই ফাইলটির জন্য একটি শিরোনাম প্রদান করুন বিবরণ প্রবেশ করা যাচ্ছে না - নেটওয়ার্ক ব্যর্থতা - প্রবেশ করা যাচ্ছে না - অনুগ্রহ করে আপনার ব্যবহারকারী নাম পরীক্ষা করুন। - প্রবেশ করা যাচ্ছে না - অনুগ্রহ করে আপনার পাসওয়ার্ড পরীক্ষা করুন খুব বেশি অসফল প্রচেষ্টা। অনুগ্রহ করে কয়েক মিনিট পরে আবারও চেষ্টা করুন। দুঃখিত, এই ব্যবহারকারীকে কমন্সে বাধা দেয়া হয়েছে অাপনাকে অবশ্যই অাপনার দু\'স্তরের সত্যায়নকরণ কোড দিতে হবে। diff --git a/app/src/main/res/values-br/strings.xml b/app/src/main/res/values-br/strings.xml index 8383f7cbe..2a7cd2284 100644 --- a/app/src/main/res/values-br/strings.xml +++ b/app/src/main/res/values-br/strings.xml @@ -52,8 +52,6 @@ Roit un titl d\'ar restr-mañ, mar plij Deskrivadur Ne c\'haller ket kevreañ - rouedad sac\'het - Ne c\'haller ket kevreañ - Gwiriit hoc\'h anv implijer, mar plij - Ne c\'haller ket kevreañ - Gwiriit ho ker tremen, mar plij Re a daolioù-esae. Klaskit en-dro a-benn ur pennadig amzer. Hon digarezit, prennet eo bet an implijer-mañ e Commons Rankout a rit reiñ ho kod dilesa gant daou faktor. diff --git a/app/src/main/res/values-bs/strings.xml b/app/src/main/res/values-bs/strings.xml index 6c0097089..e6667a083 100644 --- a/app/src/main/res/values-bs/strings.xml +++ b/app/src/main/res/values-bs/strings.xml @@ -43,8 +43,6 @@ Naslov Opis Ne mogu Vas prijaviti – mreža ne radi - Ne mogu Vas prijaviti – provjerite svoje korisničko ime - Ne mogu Vas prijaviti – provjerite svoje lozinku Napravili ste previše grešaka u prijavi. Pokušajte ponovo za nekoliko minuta. Žao nam je, korisnik je blokiran na Commonsu Morate upisati kôd za potvrdu u 2 koraka. diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index f7f40f427..aaf5ca737 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -50,8 +50,6 @@ Títol Descripció No s\'ha pogut iniciar la sessió – error de xarxa - No s\'ha pogut iniciar la sessió – si et plau comprova el teu nom d\'usuari - No s’ha pogut iniciar la sessió. Comproveu la vostra contrasenya Massa intents erronis – Proveu-ho de nou d\'aquí uns minuts. Ho sentim, aquest usuari ha estat blocat a Commons Heu de proporcionar el vostre codi d\'autenticació de dos factors. @@ -192,4 +190,5 @@ Gràcies per fer una modificació %1$s us ha mencionat a %2$s. Preguntes freqüents + No s’ha trobat cap imatge. diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 6e2453d6d..eb87ab83e 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -61,8 +61,6 @@ Vložte prosím název tohoto souboru Popis Nelze se přihlásit - selhání sítě - Nelze se přihlásit - prosím zkontrolujte své uživatelské jméno - Nelze se přihlásit - zkontrolujte prosím své heslo Příliš mnoho neúspěšných pokusů. Zkuste to prosím znovu za několik minut. Omlouváme se, tento uživatel byl na Commons zablokován Prosím vložte kód pro své dvoufázové ověření. diff --git a/app/src/main/res/values-csb/strings.xml b/app/src/main/res/values-csb/strings.xml index 2d7b99904..f04df2055 100644 --- a/app/src/main/res/values-csb/strings.xml +++ b/app/src/main/res/values-csb/strings.xml @@ -41,8 +41,6 @@ Titel Òpisënk Ni mòże sã wlogòwac - fela sécë - Ni mòże sã wlogòwac - sprôwdzë miono brëkòwnika - Ni mòże sã wlogòwac - sprôwdzë parolã Za wiele nieùdałich prób wlogòwaniô. Spróbùjë znowa za czile minut. Nen brëkòwnik òstôł zablokòwóny na Commons Mùszisz wpisac swój kòd dlô dwafaktorowi aùtorizacëji. diff --git a/app/src/main/res/values-cy/strings.xml b/app/src/main/res/values-cy/strings.xml index ef56bc3b0..ca00d1c4d 100644 --- a/app/src/main/res/values-cy/strings.xml +++ b/app/src/main/res/values-cy/strings.xml @@ -43,8 +43,6 @@ Teitl Disgrifiad Yn methu mewngofnodi - methodd y rhwydwaith - Yn methu mewngofnodi - gwirwch eich enw defnyddiwr - Yn methu mewngofnodi - gwirwch eich cyfrinair Cafwyd gormod o ymgeision aflwyddiannus. Oedwch ennyd cyn ceisio eto. Ymddiheurwn. Mae\'r defnyddiwr hwn wedi ei flocio ar Gomin Wikimedia Mae\'n rhaid i chi roi eich cod adnabod 2 ffactor. diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index e10a93850..fe194ce94 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -54,8 +54,6 @@ Angiv venligt en titel for denne fil Beskrivelse Kan ikke logge på - netværksfejl - Ude af stand til at logge på - tjek venligst dit brugernavn - Ude af stand til at logge på - tjek venligst din adgangskode Alt for mange mislykkede forsøg. Prøv igen om et par minutter. Beklager, denne bruger er blevet blokeret på Commons Du skal angive din tofaktorgodkendelseskode. diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 9f47ce42e..6fbd7d517 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -53,8 +53,7 @@ Bitte gib einen Titel für diese Datei an Beschreibung Anmeldung fehlgeschlagen – Netzwerkfehler - Anmeldung fehlgeschlagen – Bitte Benutzernamen überprüfen - Anmeldung fehlgeschlagen – Bitte Passwort überprüfen + Anmeldung fehlgeschlagen. Bitte Benutzernamen und Passwort überprüfen. Zu viele erfolglose Versuche. Bitte in einigen Minuten erneut versuchen. Dieser Benutzer wurde leider auf Commons gesperrt Du musst deinen Code zur Zwei-Faktor-Authentifizierung angeben. diff --git a/app/src/main/res/values-diq/strings.xml b/app/src/main/res/values-diq/strings.xml index 53bd88bac..79da245fe 100644 --- a/app/src/main/res/values-diq/strings.xml +++ b/app/src/main/res/values-diq/strings.xml @@ -52,8 +52,6 @@ Sername Şınasnayış Xırabiya kewten-network xeta - Ronıştışo abeno - Namey karberi ye xo kontrol kerë - Ronıştışo nêabeno - Parolay xo kontrol kerë Şıma xeylê rayi kerd ke cı kewê, a ser nêvıst. Şıma rê zehmet 2-3 deqey ra tepeya reyna bıcerrebnên. Qısur mewni rê, Karber commons dı bloqe biyo. Nidekeweya de diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index e372df836..3002482a5 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -57,8 +57,7 @@ Παρακαλώ παρέχετε ένα τίτλο για αυτό το αρχείο Περιγραφή Δεν είναι δυνατή η σύνδεση - αποτυχία του δικτύου - Δεν είναι δυνατή η σύνδεση - ελέγξτε το όνομα χρήστη σας - Δεν είναι δυνατή η σύνδεση - παρακαλούμε ελέγξτε τον κωδικό σας + Αποτυχία σύνδεσης - παρακαλώ ελέγξτε το όνομα χρήστη και τον κωδικό σας Πάρα πολλές ανεπιτυχείς προσπάθειες. Παρακαλώ δοκιμάστε ξανά σε λίγα λεπτά. Συγνώμη, αυτός ο χρήστης έχει αποκλειστεί από τα Commons Πρέπει να δώσετε τον κωδικό πιστοποίησης με δύο παράγοντες diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 9e5dae650..1be0ebd1a 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -1,6 +1,7 @@ - Commons app on kaatunut + Commons on kaatunut Pahoittelemme, virhe tapahtui. Kerro meille mitä teit äsken, sähköpostitse. Se auttaa meitä korjaamaan ongelman! Kiitos! diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index e833932a8..b0ea9ce0f 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -58,8 +58,6 @@ Anna tälle tiedostolle otsikko Kuvaus Kirjautuminen epäonnistui - verkkovirhe - Kirjautuminen epäonnistui - tarkista käyttäjätunnus - Kirjautuminen epäonnistui - tarkista salasanasi Liikaa epäonnistuneita yrityksiä. Yritä uudelleen parin minuutin kuluttua. Pahoittelut, tämä käyttäjä on estetty Commonsissa Anna kaksivaiheisen tunnistuksen koodi. @@ -162,8 +160,8 @@ Ei kuvausta Tuntematon lisenssi Päivitä - Vaadittu oikeus: Ulkoisen tallennustilan luku. Appi ei voi päästä galleriaasi ilman tätä oikeutta. - Vaadittava lupa: Kirjoita ulkoiseen tallennustilaan. Appi ei voi päästä kameraasi ilman tätä oikeutta. + Vaadittu oikeus: Ulkoisen tallennustilan luku. Sovellus ei voi päästä galleriaasi ilman tätä oikeutta. + Vaadittu oikeus: Kirjoita ulkoiseen tallennustilaan. Sovellus ei voi päästä kameraasi ilman tätä oikeutta. Valinnainen lupa: Saada tämänhetkinen sijainti loukkasuosituksia varten. OK Lähellä olevat paikat @@ -262,4 +260,8 @@ Jatka Peruuta Yritä uudelleen + Selvä! + Kuvia ei löytynyt! + Tallentanut: %1$s + Jaa sovellus diff --git a/app/src/main/res/values-fo/strings.xml b/app/src/main/res/values-fo/strings.xml index c4649407a..58e26797b 100644 --- a/app/src/main/res/values-fo/strings.xml +++ b/app/src/main/res/values-fo/strings.xml @@ -34,8 +34,6 @@ Heiti Frágreiðing Ómøguligt at rita inn - feilur í netsambandinum - Ómøguligt at rita inn - vinarliga eftirkanna títt brúkaranavn - Ómøguligt at rita inn - vinarliga kanna eftir, um títt loyniorð er rætt Ov nógv miseydnaðar royndir. Vinarliga royn aftur um fáir minuttir Haldið okkum tilgóðar, hesin brúkari er blivin sperraður á Commons Login miseydnaðist diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index bfb14baf1..a93f3011d 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -65,8 +65,7 @@ Veuillez donner un titre à ce fichier Description Impossible de se connecter — panne de réseau - Impossible de se connecter — veuillez vérifier votre nom d’utilisateur - Impossible de se connecter — veuillez vérifier votre mot de passe + Impossible de se connecter — veuillez vérifier votre nom d’utilisateur et votre mot de passe Trop de tentatives infructueuses. Veuillez réessayer dans quelques minutes. Désolé, cet utilisateur a été bloqué dans Commons Vous devez fournir votre code d’authentification à deux facteurs. diff --git a/app/src/main/res/values-frr/strings.xml b/app/src/main/res/values-frr/strings.xml index f4866e705..1355096c5 100644 --- a/app/src/main/res/values-frr/strings.xml +++ b/app/src/main/res/values-frr/strings.xml @@ -42,8 +42,6 @@ Tiitel Beskriiwang Bi\'t uunmeldin as wat skiaf gingen - näätwerk-feeler - Bi\'t uunmeldin as wat skiaf gingen - luke ans efter di brükernööm - Bi\'t uunmeldin as wat skiaf gingen - luke ans efter det paaswurd Tu fölsis fersoocht saner lok. Ferschük det uun hög minüüten noch ans nei. Didiar brüker as üüb Commons speret wurden. Dü skel dan code för\'t tau-straal-gudkäänen (2FA) uundu. diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 630311db4..1dcd7ecca 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -55,8 +55,6 @@ Por favor, proporcione un título para este ficheiro Descrición Erro ao acceder ao sistema: Fallou a rede - Erro ao acceder ao sistema: Comprobe o seu nome de usuario - Erro ao acceder ao sistema: Comprobe o seu contrasinal Demasiados intentos incorrectos. Inténteo de novo nuns minutos. Sentímolo, este usuario está bloqueado en Commons Debe proporcionar o seu código de autenticación de dous factores. diff --git a/app/src/main/res/values-haw/strings.xml b/app/src/main/res/values-haw/strings.xml index a81ab120d..674dc6dbe 100644 --- a/app/src/main/res/values-haw/strings.xml +++ b/app/src/main/res/values-haw/strings.xml @@ -34,8 +34,6 @@ Poʻo Inoa Hōʻike ʻAno Hiki ʻole ke ʻeʻe - hāʻule pūnaewele - Hiki ʻole ke ʻeʻe - hōʻoiaʻiʻo i kāu inoa mea hoʻohana ke ʻoluʻolu - Hiki ʻole ke ʻeʻe - hōʻoiaʻiʻo i kāu ʻōlelo hūnā ke ʻoluʻolu Hoʻāʻo ʻeʻe ʻole he nui kā. E ʻoluʻolu, e hana hou i ka wā hou aku E kala mai, ua pale ʻia kēia mea hoʻohana ma ke Kahilehulehu Hāʻule ka ʻeʻena diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index 69bb67655..0404cacd2 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -53,8 +53,6 @@ शीर्षक विवरण प्रवेश नहीं हो रहा - नेटवर्क विफल - प्रवेश नहीं हो रहा - कृपया अपना सदस्य नाम जाँचें - प्रवेश नहीं हो रहा - कृपया अपना पासवर्ड जाँचें ढेर सारे असफल प्रयास होने के कारण कुछ मिनटों के बाद प्रयास करें। क्षमा करें, यह सदस्य कॉमन्स में अवरोधित है आपको अपना दो कारक प्रमाणन कोड प्रदान करना होगा। diff --git a/app/src/main/res/values-hr/error.xml b/app/src/main/res/values-hr/error.xml new file mode 100644 index 000000000..4bc77982c --- /dev/null +++ b/app/src/main/res/values-hr/error.xml @@ -0,0 +1,10 @@ + + + + Aplikacija Zajednički poslužitelj je prestala s radom + Nešto je krenulo po krivu! + Napišite nam što radite i podijelite s nama putem elektroničke pošte. Pomoći će nam da to popravimo! + Hvala Vam! + diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml new file mode 100644 index 000000000..f675e2f77 --- /dev/null +++ b/app/src/main/res/values-hr/strings.xml @@ -0,0 +1,275 @@ + + + + Izgled + Opće + Povratna informacija + Lokacija + Zajednički poslužitelj + + Postavke + Suradničko ime + Zaporka + Prijavite se na Commons beta račun + Prijavi se + Zaboravljena zaporka? + Otvori račun + Prijava + Molimo pričekajte ... + Prijava uspješna! + Prijava neuspješna! + Datoteka nije pronađena. Molimo probajte drugu. + Autentifikacija neuspješna! + Postavljanje započeto! + %1$s postavljeno! + Dodirnite da biste vidjeli datoteku + Počinje postavljanje %1$s + Postavljanje %1$s + Završeno postavljanje %1$s + Postavljanje %1$s neuspješno + Dodirnite da biste vidjeli + + Postavlja se %1$d datoteka + Postavljaju se %1$d datoteke + + Moja nedavja postavljanja + U redu čekanja + Neuspješno + %1$d%% postavljeno + Postavljanje + Iz galerije + Napravi sliku + U blizini + Moja postavljanja + Podijeli + Pogledaj u pregledniku + Naziv + Molimo imenujte ovu datoteku + Opis + Prijava nije moguća - mrežna pogrješka + Prijava nije moguća - molimo provjerite suradničko ime i zaportku + Previše neuspješnih pokušaja, molimo probajte opet za par minuta. + Ispričavamo se, ovaj je suradnik blokiran na Zajendičkom poslužitelju + Morate upisati autetifikacijski kôd od dva faktora + Prijava neuspješna + Postavljanje + Imenujte ovaj set + Promjene + Postavljanje + Pretraži kategorije + Spremi + Osvježi + Popis + GPS je onemogućen na Vašem uređaju. Želite li ga omogućiti? + Omogući GPS + Nemate još postavljenih datoteka + + \@string/contributions_subtitle_zero + %1$d postavljena datoteka + %1$d postavljene datoteke + + + Započeto %1$d postavljanje + Započeta %1$d postavljanja + + + %1$d postavljanje + %1$d postavljanja + + Nema kategorija koje odgovoraju upitu %1$s + Dodajte slikama kategorije kako bi se lakše pronašle. Da biste ih dodali, započnite s upisivanjem. + Kategorije + Postavke + Otvori račun + Izabrane slike + O + Aplikacija The Wikimedia Commons je aplikacija otvorenog kôda koju razvijaju i održavaju volonteri Wikimedijine zajednice. Zaklada Wikimedija nije uključena u stvaranje, razvoj ili održavanje ove aplikacije. + Da biste prijavili poteškoću ili dali prijedlog, stvorite <a href=\"https://github.com/commons-app/apps-android-commons/issues\">novi zahtjev na GitHubu</a>. + <u>Politika privatnosti</u> + <u>Zasluge</u> + O + Pošaljite povratnu informaciju (putem elektroničke pošte) + Klijent za elektroničku poštu nije instaliran + Nedavno rabljene kategorije + Pričekajte za prvu sinkronizaciju... + Nemate još postavljenih slika. + Pokušaj ponovo + Odustani + Ova će slika biti licencirana pod %1$s + Slanjem ove slike izjavljujem da je ona moje djelo i ne sadrži materijale zaštićene autorskim pravom ili selfije, te da je u skladu sa <a href=\"https://commons.wikimedia.org/wiki/Commons:Policies_and_guidelines\">smjernicama Zajedničkog poslužitelja</a>. + Preuzmi + Podrazumijevana licencija + Rabite prethodni naziv/opis + Automatski pribavi trenutačnu lokaciju + Ako slika nema oznaku lokacije, pribavi trenutačnu lokaciju kako bi se mogle ponuditi kategorije + Noćni način + Rabi tamnu temu + Imenovanje-Dijeli pod istim uvjetima 4.0 + Imenovanje 4.0 + Imenovanje-Dijeli pod istim uvjetima 3.0 + Imenovanje 3.0 + CC0 + CC BY-SA 3.0 + CC BY-SA 3.0 (Austrija) + CC BY-SA 3.0 (Njemačka) + CC BY-SA 3.0 (Estonija) + CC BY-SA 3.0 (Španjolska) + CC BY-SA 3.0 (Hrvatska) + CC BY-SA 3.0 (Luksemburg) + CC BY-SA 3.0 (Nizozemska) + CC BY-SA 3.0 (Norveška) + CC BY-SA 3.0 (Poljska) + CC BY-SA 3.0 (Rumunjska) + CC BY 3.0 + CC BY-SA 4.0 + CC BY 4.0 + CC Zero + Na Zajedničkom poslužitelju se nalazi većina slika rabljena na Wikipediji. + Vaše slike pomažu u edukaciji ljudi diljem svijeta! + Molimo postavite slike koje su u cijelosti Vaše djelo: + Objekti iz prirode (cvijeće, životinje, planine)\n• Korisni objekti (bicikla, željezničke postaje)\n• Poznate osobe (Vaš gradonačelnik, olimpijski sportaš kojeg ste sreli) + Objekti iz prirode (cvijeće, životinje, planine) + Korisni objekti (bicikla, željezničke postaje) + Poznate osobe (Vaš gradonačelnik, olimpijski sportaš kojeg ste sreli) + Molimo NE postavljajte: + - selfije ili slike Vaših prijatelja\n- slike koje ste preuzeli s interneta\n- snimke ekrana zaštićenih aplikacija + Selfije ili slike Vaših prijatelja + Slike koje ste preuzeli s interneta + Snimke ekrana zaštićenih aplikacija + Primjer postavljanja: + - Naziv: Sydneyska opera\n- Opis: Sydneyska opera viđena iz zaljeva\n- Kategorije: Sydney Opera House from the west, Sydney Opera House remote views + Naziv: Sydneyska opera + Opis: Sydneyska opera viđena iz zaljeva + Kategorije: Sydney Opera House from the west, Sydney Opera House remote views + Dijelite Vaše slike. Pomozite da članci na Wikipediji zažive! + Slike na wikipediji su sa Zajedničkog poslužitelja. + Vaše slike pomažu u edukaciji ljudi diljem svijeta. + Izbjegavajte materijale s autorskim pravima koje ste pronašli na internetu (slike plakata, naslovnice knjiga, i slično). + Jeste li razumjeli? + Da! + Kategorije + Učitavanje... + Ništa nije odabrano + Nema opisa + Nepoznata licencija + Osvježi + Potrebno dopuštenje čitanja vanjske pohrane. Bez toga aplikacija ne može pristupiti Vašoj galeriji. + Potrebno dopuštenje spremanja na vanjsku pohranu. Bez toga aplikacija ne može pristupiti Vašoj kameri. + Potrebno dopuštenje za određivanje trenutačne lokacije za prijedloge kategorija (nije obvezno) + U redu + Mjesta u blizini + Nisu pronađena mjesta u blizini + Upozorenje + Ova datoteka već postoji na Zajedničkom poslužitelju. Jeste li sigurni da želite nastaviti? + Da + Ne + Naslov + Naslov medija + Opis + Ovdje ide opis datoteke. Mogao bi biti poprilično dug i trebat će se prelomiti u nekoliko redova. Nadamo se da će lijepo izgledati. + Autor + Ovdje ide suradničko ime autora izabrane slike. + Datum postavljanja + Licencija + Koordinate + Ništa nije navedeno + Postani beta tester + Prijavite se na naš beta-kanal na Google Playu i dobijte raniji pristup novim mogućnostima i ispravkama pogrješaka + Kôd za provjeru u 2 koraka + Moje ograničenje nedavnih postavljanja + Najviše moguće + Nije moguće prikazati više od 500 + Postavi ograničenje nedavnih postavljanja + Kôd za provjeru u 2 koraka nije podržan. + Zaista se želite odjaviti? + Logotip Zajedničkog poslužitelja + Mrežno mjesto Zajedničkog poslužitelja + Stranica Zajedničkog poslužitelja na Facebooku + Izvorni kôd Zajedničkog poslužitelja na Githubu + Pozadinska slika + Slika nije uspjela + Slika nije pronađena + Postavi sliku + Planina Zao + Ljame + Dugin most + Tulipan + Bez selfija + Vlasnička slika + Welcome (Wikipedija) + Dobro došli (autorska prava) + Sidnejska opera + Odustani + Otvori + Zatvori + Početna stranica + Postavljanje + U blizini + O + Postavke + Povratna informacija + Odjava + Upute + Obavijesti + Izabrano + Mjesta u blizini ne mogu biti prikazana bez dopuštenja određivanja lokacije + nema opisa + Stranica datoteke na Zajedničkom poslužitelju + Stavka na Wikidati + Članak na Wikipediji + Pogrješka predmemoriranja slika + Jedinstveni naziv datoteke koji će služiti kao njeno ime. Možete koristiti uobičajeni jezik s razmacima. Ne uključuje datotečni nastavak. + Opišite medij što je više moguće: gdje je napravljen, što prikazuje,... Opišite objekte ili osobe. Napišite informacije koje ne mogu biti lako okrivene, npr. doba dana ako je u pitanju pejzaž. Ako medij prikazuje nešto neobično, molimo objasnite što je neobično. + Slika je pretamna, želite ili je ipak ostaviti? Zajednički poslužitelj je namijenjen slikama od enciklopedijske vrijednosti. + Slika je mutna, želite ili je ipak ostaviti? Zajednički poslužitelj je namijenjen slikama od enciklopedijske vrijednosti. + Daj dopuštenje + Rabi vanjsku pohranu + Spremite slike načinjene kamerom Vašeg uređaja + Prijavite se na Vaš račun + Pošalji zapisnik + Pošalji zapisnik elektroničkom poštom razvijateljima + Preglednik nije pronađen + Pogrješka! URL nije pronađen + Predloži za brisanje + Slika je predložena za brisanje + Pogledaj u pregledniku + Lokacija nepromijenjena. + Lokacija nedostupna. + Potrebno je dopuštenje za popis mjesta u blizini + PRIBAVI UPUTE + PROČITAJ ČLANAK + %1$s, dobro došli na Zajednički poslužitelj! Drago nam je da ste tu. + %1$s Vam je ostavio poruku na Vašoj razgovornoj stranici + Hvala Vam na uređivanju + %1$s Vas je spomenuo na %2$s. + Prebaci prikaz + UPUTE + WIKIDATA + WIKIPEDIJA + ZAJEDNIČKI POSLUŽITELJ + <u>Ocijenite nas</u> + <u>ČPP</u> + Preskoči upute + Internet nije dostupan + Internet je dostupan + Pogrješka dohvaćanja obavijesti + Nema obavijesti + <u>Prevedi</u> + Jezici + Odaberite jezik na koji bi željeli prevoditi + Nastavi + Odustani + Pokušaj ponovo + U redu! + Ovo su mjesta u blizini koja trebaju slike za ilustriranje članaka o njima na Wikipediji + Dodirnite da biste dobili popis ovih mjesta + Možete postaviti sliku s bilo kojeg mjesta u Vašoj galeriji ili kameri + Slike nisu pronađene! + Pogrješka prilikom učitavanja slika. + Postavio: %1$s + Aplikacija za dijeljenje + Prilikom označavanja slike koordinate nisu navedene + Pogrješka prilikom dohvaćanja mjesta u blizini. + diff --git a/app/src/main/res/values-hrx/strings.xml b/app/src/main/res/values-hrx/strings.xml index 7905a92d7..b6dbf026d 100644 --- a/app/src/main/res/values-hrx/strings.xml +++ b/app/src/main/res/values-hrx/strings.xml @@ -35,8 +35,6 @@ Titel Beschreibung Oonmeldung fehlgeschlooht – Netzwerrekfehler - Oonmeldung fehlgeschlooht – Bittschön Benutzernoome üwerprüfe - Oonmeldung fehlgeschlooht – Bittschön Passwort üwerprüfe Zu viele erfollichlose Versuche. Bittschön in en poor Minute wieder erneit versuche. Der Benutzer woard leider uff Commons gesperrt Oonmeldung fehlgeschlooht diff --git a/app/src/main/res/values-hsb/strings.xml b/app/src/main/res/values-hsb/strings.xml index 97b0d1af5..a8647fb56 100644 --- a/app/src/main/res/values-hsb/strings.xml +++ b/app/src/main/res/values-hsb/strings.xml @@ -34,8 +34,6 @@ Titul Wopisanje Přizjewjenje je so njeporadźiło - syćowy zmylk - Přizjewjenje je njemóžno - prošu přepruwuj swoje wužiwarske mjeno - Přizjewjenje njeje móžno - prošu přepruwuj swoje hesło Přewjele njewuspěšnych pospytow. Prošu spytaj za něšto mjeńšin hišće raz. Tutoho wužiwarja su bohužel na Commons zablokowali Přizjewjenje je so njeporadźiło diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index d9580dca1..fe91781d9 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -59,8 +59,6 @@ Kérlek, adj címet a fájlnak Leírás Nem lehet bejelentkezni - hálózati hiba - Nem lehet bejelentkezni - ellenőrizd a felhasználóneved - Nem lehet bejelentkezni - ellenőrizd a jelszavad Túl sok sikertelen próbálkozás. Próbálkozz újra pár perc múlva. Sajnáljuk, ezt a felhasználót blokkolták a Commonson Meg kell adnia a kétlépcsős hitelesítő kódját. diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 16185f35d..6a533ef67 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -46,8 +46,6 @@ Judul Deskripsi Tidak dapat login - kesalahan pada jaringan - Tidak dapat masuk log - harap periksa nama pengguna Anda - Tidak dapat masuk log - harap periksa kata sandi Anda Terlalu banyak usaha yang gagal. Harap coba lagi dalam beberapa menit Maaf, pengguna ini telah diblokir di Commons Gagal masuk log diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml index f1b020965..985e858bf 100644 --- a/app/src/main/res/values-is/strings.xml +++ b/app/src/main/res/values-is/strings.xml @@ -49,8 +49,6 @@ Gefðu þessari skrá einhvern titil Lýsing Innskráning mistókst - bilun í neti - Innskráning mistókst. Athugaðu notandanafnið þitt - Innskráning mistókst. Athugaðu lykilorðið þitt Of margar misteknar tilraunir. Reyndu aftur eftir nokkrar mínútur. Því miður, þessi notandi hefur verið bannaður á Commons Þú verður að setja inn tveggja-þrepa auðkenningarkóðann þinn. diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 06bfa701f..30a02428e 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -53,8 +53,6 @@ Titolo Descrizione Impossibile effettuare l\'accesso - errore di rete - Impossibile effettuare l\'accesso - controlla il nome utente - Impossibile effettuare l\'accesso - controlla la password Troppi tentativi falliti. Riprova tra alcuni minuti. Spiacente, questo utente è stato bloccato su Commons Devi fornire il tuo codice di autenticazione a due fattori. diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index 9ba67e4ee..03a76a3fc 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -58,8 +58,7 @@ נא לתת כותרת לקובץ הזה תיאור לא ניתן להיכנס – כשל בתקשורת - לא ניתן להיכנס – נא לבדוק את שם המשתמש שלך - לא ניתן להיכנס – נא לבדוק את הססמה שלך + לא ניתן להיכנס לחשבון – נא לבדוק את שם המשתמש ואת הסיסמה יותר מדי ניסיונות כושלים להיכנס. נא לנסות שוב בעוד מספר דקות. סליחה, החשבון הזה חסום בוויקישיתוף יש לספק את קוד האימות הדו־שלבי שלך. diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index ef45a5d3a..78127106f 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -40,7 +40,8 @@ %1$s のアップロードに失敗しました 閲覧するにはタップしてください - %1$d 件のファイルをアップロード中 + %1$d file uploading + %1$d件のファイルをアップロード中 自分の最近のアップロードファイル 順番待ち中 @@ -57,11 +58,9 @@ ファイル名をつけてください 説明 ログインできません - ネットワークのエラーです - ログインできません - 利用者名を確認してください - ログインできません - パスワードを確認してください - 失敗した回数が多すぎます。数分でもう一度お試しください。 + 失敗した回数が多すぎます。数分待ってからもう一度お試しください。 申し訳ありませんが、この利用者はコモンズでブロックされています。 - 2 要素認証コードを提供する必要があります。 + 2要素認証コードを提供する必要があります。 ログイン失敗 アップロード このセットに名前をつけてください @@ -76,22 +75,24 @@ まだ何もアップロードされていません。 \@string/contributions_subtitle_zero - %1$d 件のアップロード + pne=%1$d upload - %1$d 件のアップロードを開始中 + Starting %1$d upload + %1$d件のアップロードを開始中 + %1$d upload %1$d 件のアップロード %1$s に一致するカテゴリが見つかりません - あなたの画像をウィキメディア・コモンズで見つけやすくするためにカテゴリを追加してください。\n\nカテゴリ名の入力を開始してください。\nこの手順をスキップするにはこのメッセージをタップしてください(または戻るボタン)。 + あなたの画像をウィキメディア・コモンズで見つけやすくするためにカテゴリを追加してください。\nカテゴリ名の入力を開始してください。 カテゴリ 設定 利用者登録 秀逸な画像 このアプリについて - ウィキメディア・コモンズ・アプリはウィキメディア・コミュニティの助成金受給者とボランティアによって製作・メンテナンスされているオープンソースソフトウェアです。ウィキメディア財団はこのアプリの製作・開発・メンテナンスに関与していません。 + ウィキメディア・コモンズ・アプリはウィキメディア・コミュニティの助成金受給者とボランティアが製作・管理しているオープンソースソフトウェアです。ウィキメディア財団はこのアプリの製作・開発・メンテナンスに関与していません。 バグとアイディアは <a href=\"https://github.com/commons-app/apps-android-commons/issues\">Github</a> へ。 <u>プライバシー・ポリシー</u> <u>クレジット</u> @@ -103,7 +104,7 @@ まだ写真をアップロードしていません。 再試行 キャンセル - この画像が %1$s ライセンスでアップロードされます。 + この画像は%1$sライセンスのもとにアップロードされます。 この画像の投稿に当たり、私はこれが自分自身の作品であり、著作権のあるコンテンツや自撮りは含まれていないと宣言します。 ダウンロード 既定のライセンス @@ -148,6 +149,7 @@ - 題名: シドニー・オペラハウス\n- 説明: 湾の向こうから見たシドニー・オペラハウス\n- カテゴリ: 西側から見たシドニー・オペラハウス、遠くから見たシドニー・オペラハウス 題名: シドニーのオペラハウス 説明: シドニーのオペラハウス。湾を挟んで撮影。 + カテゴリ: シドニーオペラハウスの西面、シドニーオペラ遠景 画像を投稿してください。ウィキペディアの記事に彩りを! ウィキペディアの画像はウィキメディア・コモンズに保管されています。 あなたの画像は世界中の人々が学習する助けになります @@ -167,7 +169,7 @@ 近くの場所 付近の場所が見つかりません 警告 - このファイルが既にコモンズにあります。本当にアップロードしますか? + このファイルは既にコモンズにあります。本当にアップロードしますか? はい いいえ タイトル @@ -185,7 +187,7 @@ 2FA コード 最近のアップロードファイルに表示する最大件数 最大限 - 500 以上の項目を表示できません + 表示できるのは500件以下です 最近のアップロードファイルに表示する最大件数 2段階認証は現在サポートされていません。 ログアウトしてもよろしいですか? @@ -226,7 +228,7 @@ ウィキペディアの記事 画像をキャッシュする際のエラー ファイル固有の説明的な表題。ファイル名として使われます。平易な言葉を使い、空白を入れることができます。拡張子は含めないでください。 - 可能な限りメディアを説明してください:どこで撮られましたか?それは何を示していますか?文脈とは何ですか?物や人を説明してください。容易に推測できない情報、例えば風景の場合の時刻を明らかにする。メディアに珍しいことがある場合は、何が珍しいのかを説明してください。 + 可能な限りメディアを説明してください: 撮影地はどこですか? それは何を示していますか? どんな文脈がありますか? 被写体の物や人を説明してください。容易に推測できない情報、例えば風景であれば時刻を明示します。特筆すべき物事が映っている場合は、何が珍しいのかを説明してください。 この画像は暗すぎますがアップロードしますか? ウィキメディア・コモンズは百科事典に適した画像のみ受け付けます。 ピントが合っていませんが、アップロードしますか? ウィキメディア・コモンズは百科事典に適した画像のみ受け付けます。 権限を付与 @@ -255,7 +257,7 @@ ウィキペディア コモンズ <u>評価する</u> - <u>FAQ</u> + <u>よくある質問</u> チュートリアルをスキップする インターネットに接続していません インターネットに接続しました @@ -276,4 +278,5 @@ アップロードした人: %1$ アプリをシェアする 画像の選択中に位置情報を特定できませんでした + 付近の場所を取得しようとしてエラーが発生しました。 diff --git a/app/src/main/res/values-jv/strings.xml b/app/src/main/res/values-jv/strings.xml index e051b6f97..a4a85c80f 100644 --- a/app/src/main/res/values-jv/strings.xml +++ b/app/src/main/res/values-jv/strings.xml @@ -40,8 +40,6 @@ Sesirah Wedharan Ora bisa mlebu log - jaringané gagal - Ora bisa mlebu log - tiliki jeneng panganggoné panjenengan - Ora bisa mlebu log - tiliki tembung wadiné panjenengan Kakèhan upaya sing gagal. Jajalana manèh mengko. Ngapunten, panganggo iki wis diblokir ing Commons Panjenengan kudu ngisi kodhe otèntifikasi rong faktoré panjenengan diff --git a/app/src/main/res/values-ka/strings.xml b/app/src/main/res/values-ka/strings.xml index 2bb1c5191..60320dd9e 100644 --- a/app/src/main/res/values-ka/strings.xml +++ b/app/src/main/res/values-ka/strings.xml @@ -42,8 +42,6 @@ სათაური აღწერა შესვლა ვერ ხერხდება - ქსელის შეცდომა - შესვლა ვერ ხერხდება - გთხოვთ შეამოწმოთ სახელი - შესვლა ვერ ხერხდება - გთხოვთ შეამოწმოთ პაროლი ძალიან ბევრი წარუმატებელი მცდელობა. გთხოვთ, რამდენიმე წუთში სცადეთ კვლავ. უკაცრავად, ეს მომხმარებელი დაბლოკილია ვიკისაწყობში თქვენ უნდა შეიყვანოთ ორფაქტორიანი ავტორიზაციის კოდი. diff --git a/app/src/main/res/values-kab/strings.xml b/app/src/main/res/values-kab/strings.xml index 342c615b9..c88a34978 100644 --- a/app/src/main/res/values-kab/strings.xml +++ b/app/src/main/res/values-kab/strings.xml @@ -42,8 +42,6 @@ Azwel Aglam Ur izmir ara ad yeqqen - tuccḍa n uẓeṭṭa - Ur izmir ara ad yeqqen - wali isem-ik n useqdac - Ur izmir ara ad yeqqen - wali awal-ik uffir Ddeq n uɛraḍ ur yeddin ara. Ɛreḍ akka di kra n tisdatin Suref-aɣ, aseqdac-agi yewḥel di Commons Yessefk ad d-muddeḍ tangalt n n usesbteb s snat n tarrayin. diff --git a/app/src/main/res/values-km/strings.xml b/app/src/main/res/values-km/strings.xml index c057e04c7..ff4a6ce79 100644 --- a/app/src/main/res/values-km/strings.xml +++ b/app/src/main/res/values-km/strings.xml @@ -35,8 +35,6 @@ ចំណងជើង បរិយាយ មិនអាចកត់ឈ្មោះចូល - បណ្តាញ network បរាជ័យ - មិនអាចកត់ឈ្មោះចូល - សូមពិនិត្យឈ្មោះអ្នកប្រើប្រាស់របស់អ្នក - មិនអាចកត់ឈ្មោះចូល - សូមពិនិត្យលេខសម្ងាត់របស់អ្នក ការព្យាយាមមិនបានសម្រេចមានចំនួនច្រើនដងពេក។ សូមព្យាយាមម្តងទៀតនៅប៉ុន្មាននាទីក្រោយ។ សូមអភ័យទោស អ្នកប្រើប្រាស់រូបនេះត្រូវបានហាមឃាត់នៅ Commons កត់ឈ្មោះចូលបរាជ័យ diff --git a/app/src/main/res/values-ko-rKP/strings.xml b/app/src/main/res/values-ko-rKP/strings.xml index 670479f75..ccbe86100 100644 --- a/app/src/main/res/values-ko-rKP/strings.xml +++ b/app/src/main/res/values-ko-rKP/strings.xml @@ -42,8 +42,6 @@ 제목 설명 가입할수 없습니다 - 망 오유입니다 - 가입할수 없습니다 - 사용자이름을 확인하세요 - 가입할수 없습니다 - 통행암호를 확인하세요 실패한 시도가 너무 많습니다. 몇분후에 다시 시도하세요. 죄송합니다, 이 사용자는 공용에서 차단되였습니다 두인자검증부호를 제공해야 합니다. diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 883665c85..8005ce63c 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -58,8 +58,7 @@ 이 파일의 제목을 지정해 주십시오 설명 로그인할 수 없습니다 - 네트워크 오류입니다 - 로그인할 수 없습니다 - 사용자 이름을 확인하세요 - 로그인할 수 없습니다 - 비밀번호를 확인하세요 + 로그인할 수 없습니다 - 사용자 이름과 비밀번호를 확인해 주십시오 실패한 시도가 너무 많습니다. 몇 분 후에 다시 시도하세요. 죄송합니다, 이 사용자는 공용에서 차단되었습니다 2요소 인증 코드를 제공해야 합니다. diff --git a/app/src/main/res/values-kum/strings.xml b/app/src/main/res/values-kum/strings.xml new file mode 100644 index 000000000..34db9a395 --- /dev/null +++ b/app/src/main/res/values-kum/strings.xml @@ -0,0 +1,97 @@ + + + + Гёрюнюш + Ортакъ + + Кюйлевлер + Къоллавчу аты + Чечил + Гирмек + Чечилни унутдунгму? + Къайытланмакъ + %1$s юкленген! + %1$s юкленип тура + Къарамакъ учун бас + Гезикде + Юклев + Сурат алмакъ + Ювукъда + Юклевлерим + Пайлашмакъ + Ат + Тасвир + Юклев + Юклев + Сакъламакъ + Янгыртмакъ + Тизме + GPS ишлетмек + Юклевлер ёкъ гьали де + Категориялар + Кюйлевлер + Къайытланмакъ + Тасвири + <u>Баракаллалар</u> + Тасвири + Такрарламакъ + Гери алмакъ + Эндирмек + CC0 + CC BY-SA 3.0 + CC BY-SA 3.0 (Алмания) + CC BY-SA 3.0 (Эстония) + CC BY 3.0 + CC BY-SA 4.0 + CC BY 4.0 + CC Zero + Интернетден эндирген суратларынг + Юклев уьлгю: + Дюр! + Категориялар + Юклев... + Бир зат сайланмагъан + Тасвири ёкъ + Янгыртмакъ + OK + Буварыв + Дюр + Ёкъ + Ат + Тасвир + Ясавчу + Юклев тархы + 2FA код + Лале + Оьзсуратсыз + Хош гел Википедиягъа + Гери алмакъ + Ачмакъ + Япмакъ + Баш + Юклемек + Ювукъда + Тасвир + Кюйлевлер + Чыкъмакъ + Билдиривлер + Сайламлы + тасвири табылмады + Википедия макъала + Янгылыш! Байланыв табылмады + ЯКЪЛАР + ВИКИПЕДИЯ + <u>Къыйматла бизин</u> + Интернет гиришсиз + Интернет гиришли + Билдиривлер ёкъ + <u>Таржума этмек</u> + Тиллер + Гери алыв + Такрарламакъ + Тюшюндюм! + Гьеч сурат табылмады! + Уьстевню пайлашмакъ + diff --git a/app/src/main/res/values-ky/strings.xml b/app/src/main/res/values-ky/strings.xml index 6d78e91fe..33e79bd3c 100644 --- a/app/src/main/res/values-ky/strings.xml +++ b/app/src/main/res/values-ky/strings.xml @@ -39,8 +39,6 @@ Аталышы Баяндамасы Кирүүгө болбой жатат - тармакта үзгүлтүк бар - Кирүүгө мүмкүн эмес - сураныч, колдонуучу ысымыңызды текшериңиз - Кирүүгө мүмкүн эмес - сураныч, сыр сөзүңүздү текшериңиз Өтө көп натыйжасыз иш аракет. Суранабыз, бир нече мүнөттөн кийин кайталаңыз Кечириңиз, бул кодонуучу Уикиказынада блокко алынган. Системага кирүүдө катачылык бар! diff --git a/app/src/main/res/values-lb/strings.xml b/app/src/main/res/values-lb/strings.xml index d346b90bd..fa333fa23 100644 --- a/app/src/main/res/values-lb/strings.xml +++ b/app/src/main/res/values-lb/strings.xml @@ -50,8 +50,6 @@ Titel Beschreiwung Aloggen huet net funktionéiert - Feeler mam Reseau - Login net méiglech - kuckt w.e.g. Äre Benotzernumm no - Login net méiglech - kuckt w.e.g. Äert Passwuert no Ze dacks ouni Succès probéiert. Probéiert w.e.g. an e puer Minutten nach eng Kéier. Pardon, dëse Benotzer ass op Commons gespaart Aloggen huet net funktionéiert diff --git a/app/src/main/res/values-li/strings.xml b/app/src/main/res/values-li/strings.xml index a14add497..f92167522 100644 --- a/app/src/main/res/values-li/strings.xml +++ b/app/src/main/res/values-li/strings.xml @@ -50,8 +50,6 @@ Gaef estebleef \'ne naam veur dit bestandj Besjrieving Kan zich neet aanmelde - netwirkfout - Kan zich neet aanmelde - controleer de gebroekersnaam - Kan zich neet aanmelde - controleer die wachwaord Te väöl mislökde kieëre geperbeerd. Perbeer estebleef oppernuuj euver e paar menuut. Deze gebroeker is geblokkeerd op Commons Doe mós diene twieëfaktorische bevestigingscode opgaeve. diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml index c5c0813ab..7fc63d8b9 100644 --- a/app/src/main/res/values-lt/strings.xml +++ b/app/src/main/res/values-lt/strings.xml @@ -45,8 +45,6 @@ Pavadinimas Aprašymas Negalima prisijungti - tinklo klaida - Negalima prisijungti - prašome patikrinti savo vartotojo vardą - Negalima prisijungti - prašome patikrinti savo slaptažodį Per daug nesėkmingų bandymų. Pabandykite dar kartą po keleto minučių. Atsiprašome, šis vartotojas buvo užblokuotas Commons Prisijungti nepavyko diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml index a344fcad2..ee3d94a83 100644 --- a/app/src/main/res/values-mk/strings.xml +++ b/app/src/main/res/values-mk/strings.xml @@ -49,8 +49,7 @@ Ставете ѝ наслов на податотеката Опис Не можам да Ве најавам — мрежата не работи - Не можам да Ве најавам — проверете си го корисничкото име - Не можам да Ве најавам — проверете си ја лозинката + Не можев да ве најавам. Проверете ги корисничкото име и лозинката. Направени се премногу неуспешни обиди. Обидете се пак за некоја минута. Нажалост, корисникот е блокиран на Ризницата Мора да го укажете вашиот код за двочинителска заверка. diff --git a/app/src/main/res/values-ml/strings.xml b/app/src/main/res/values-ml/strings.xml index 632cc0265..c057fb068 100644 --- a/app/src/main/res/values-ml/strings.xml +++ b/app/src/main/res/values-ml/strings.xml @@ -50,8 +50,6 @@ ഈ പ്രമാണത്തിന് ഒരു തലക്കെട്ട് നൽകുക. വിവരണം പ്രവേശിക്കാനായില്ല - നെറ്റ്‌വർക്ക് പരാജയപ്പെട്ടു - പ്രവേശിക്കാനായില്ല - ദയവായി താങ്കളുടെ ഉപയോക്തൃനാമം പരിശോധിക്കുക - പ്രവേശിക്കാനായില്ല - ദയവായി താങ്കളുടെ രഹസ്യവാക്ക് പരിശോധിക്കുക നിരവധി വിജയകരമല്ലാത്ത ശ്രമങ്ങൾ നടന്നിരിക്കുന്നു. വീണ്ടും ശ്രമിക്കുന്നതിനു മുമ്പ് ഏതാനം മിനിറ്റുകൾ വിശ്രമിക്കുക. ക്ഷമിക്കുക, ഈ ഉപയോക്താവ് കോമൺസിൽ നിന്ന് തടയപ്പെട്ടിരിക്കുകയാണ് താങ്കളുടെ ദ്വി-ഘടക സാധൂകരണ കോഡ് നൽകുക. diff --git a/app/src/main/res/values-mr/strings.xml b/app/src/main/res/values-mr/strings.xml index b88e021e7..e0a15ad36 100644 --- a/app/src/main/res/values-mr/strings.xml +++ b/app/src/main/res/values-mr/strings.xml @@ -54,8 +54,6 @@ कृपया या फाईलसाठी शीर्षक प्रदान करा वर्णन सनोंद प्रवेश अशक्य - नेटवर्क नाही - सनोंद प्रवेश अशक्य - कृपया आपले सदस्यनाव तपासा - सनोंद प्रवेश अशक्य - कृपया आपला परवलीचा शब्द तपासा अनेक अयशस्वी प्रयत्न.काही मिनीटांनंतर पुन्हा प्रयत्न करा. माफ करा, कॉमन्सवर हा सदस्य प्रतिबंधित आहे आपण आपल्या दोन कारक प्रमाणिकरण कोड प्रदान करणे आवश्यक आहे. diff --git a/app/src/main/res/values-ms/strings.xml b/app/src/main/res/values-ms/strings.xml index c5c0f18ab..ef244d049 100644 --- a/app/src/main/res/values-ms/strings.xml +++ b/app/src/main/res/values-ms/strings.xml @@ -37,8 +37,6 @@ Tajuk Keterangan Tidak boleh log masuk - kegagalan rangkaian - Tidak dapat log masuk - Sila semak nama pengguna anda - Tidak dapat log masuk - Sila semak kata laluan anda Terlalu banyak cubaan yang tidak berjaya. Sila cuba lagi dalam beberapa minit Maaf, pengguna ini telah disekat di Commons Log masuk gagal diff --git a/app/src/main/res/values-nb/strings.xml b/app/src/main/res/values-nb/strings.xml index 9774035ee..d2f622fce 100644 --- a/app/src/main/res/values-nb/strings.xml +++ b/app/src/main/res/values-nb/strings.xml @@ -49,8 +49,6 @@ Tittel Beskrivelse Innlogging feilet - nettverksproblem - Innlogging feilet - sjekk brukernavnet ditt - Innlogging feilet - sjekk passordet ditt For mange misslykkede forsøk. Vennligst prøv igjen om noen få minutter. Beklager, denne brukeren har blitt blokkert på Commons Du må oppgi tofaktorautentiseringskoden din. diff --git a/app/src/main/res/values-ne/strings.xml b/app/src/main/res/values-ne/strings.xml index be0d2f69f..512a655eb 100644 --- a/app/src/main/res/values-ne/strings.xml +++ b/app/src/main/res/values-ne/strings.xml @@ -39,8 +39,6 @@ शीर्षक वर्णन प्रवेश गर्न असमर्थ - जडान खराबी - प्रवेश गर्न असमर्थ - कृपया तपाईंको प्रयोगकर्ता नाम जाँच गर्नुहोस् - प्रवेश गर्न असमर्थ - कृपया आफ्नो पासवर्ड जाँच गर्नुहोस धेरै असफल प्रयासहरू भए । कृपया केही मिनेट पछि पुन: प्रयास गर्नुहोस माफ गर्नुहोस, यो प्रयोगकर्तालाई कमोन्समा ब्लक गरिएको छ प्रवेश सफल हुन सकेन @@ -55,7 +53,7 @@ श्रेणीहरू सेटिङ्गहरू बारेमा - <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/COPYING\">अपाचे लाइसेन्स संस्करण२</a> को अाधारमा खुला स्रोत सफ्टवेयर जारी + विकिमिडिया कमन्स याप एक स्वतन्त्र स्रोत याप हो। यो याप विकिमिडिया समुदायका अनुदानप्राप्तकर्ताहरू र स्वयंसेवकहरू द्वारा निर्मित एवं प्रबन्धित छ। विकिमीडिया फाउण्डेसन यस यापको निर्माण, विकास र प्रबन्धनमा कुनै पनि प्रकारले संलग्न छैन। <a href=\"https://github.com/commons-app/apps-android-commons\">गिटहब</a> मा स्रोत। <a href=\" https://github.com/commons-app/apps-android-commons/issues\">बगजिल्ला</a> मा बग छ। <a href=\"https://wikimediafoundation.org/wiki/Privacy_policy\">गोपनीयता नीति</a> बारेमा diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index f2688cffa..b6cec0ebd 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -47,8 +47,6 @@ Naam Beschrijving Aanmelden niet mogelijk. Er is een probleem met het netwerk - Aanmelden niet mogelijk. Controleer uw gebruikersnaam - Aanmelden niet mogelijk. Controleer uw wachtwoord U hebt te vaak geprobeerd aan te melden. Probeer het over een aantal minuten opnieuw. Deze gebruiker is helaas geblokkeerd op Wikimedia Commons Aanmelden mislukt diff --git a/app/src/main/res/values-oc/strings.xml b/app/src/main/res/values-oc/strings.xml index 803293a55..2c2d94d70 100644 --- a/app/src/main/res/values-oc/strings.xml +++ b/app/src/main/res/values-oc/strings.xml @@ -43,8 +43,6 @@ Títol Descripcion Impossible de se connectar — pana de ret - Impossible de se connectar — verificatz vòstre nom d’utilizaire - Impossible de se connectar — verificatz vòstre senhal Tròp de temptativas infructuosas. Ensajatz tornarmai dins qualques minutas. O planhèm, aqueste utilizaire es estat blocat dins Commons Error de connexion diff --git a/app/src/main/res/values-or/strings.xml b/app/src/main/res/values-or/strings.xml index c1bc2b73f..a1e08984a 100644 --- a/app/src/main/res/values-or/strings.xml +++ b/app/src/main/res/values-or/strings.xml @@ -35,8 +35,6 @@ ଶିରୋନାମ ବିବରଣୀ ଲଗ ଇନ କରିବାରେ ବିଫଳ - ନେଟୱାର୍କରେ ଅସୁବିଧା - ଲଗ ଇନ କରିବାରେ ବିଫଳ - ଦୟାକରି ନିଜର ସଭ୍ୟ ନାମ ପରଖିନିଅନ୍ତୁ - ଲଗ ଇନ କରିବାରେ ବିଫଳ - ଦୟାକରି ନିଜର ପାସୱାର୍ଡ଼ ପରଖିନିଅନ୍ତୁ ଖୁବ ଅଧିକ ଅସଫଳ ଚେଷ୍ଟା । ଦୟାକରି କେଇ ମିନିଟ ଛାଡ଼ି ଚେଷ୍ଟା କରନ୍ତୁ କ୍ଷମା ଘେନିବେ, ଏହି ସଭ୍ୟଙ୍କୁ କମନ୍ସରେ ଅଟକାଯାଇଛି ଲଗଇନ ହେଲାନାହିଁ diff --git a/app/src/main/res/values-pa/strings.xml b/app/src/main/res/values-pa/strings.xml index 6937ab75d..952ad877f 100644 --- a/app/src/main/res/values-pa/strings.xml +++ b/app/src/main/res/values-pa/strings.xml @@ -43,8 +43,6 @@ ਸਿਰਲੇਖ ਵੇਰਵਾ ਦਾਖ਼ਲਾ ਨਹੀਂ ਹੋ ਰਿਹਾ - ਨੈੱਟਵਰਕ ਫੇਲ੍ਹ ਹੋਇਆ ਹੈ - ਦਾਖ਼ਲਾ ਨਹੀਂ ਹੋ ਰਿਹਾ - ਆਪਣਾ ਵਰਤੋਂਕਾਰ ਨਾਂ ਚੈੱਕ ਕਰੋ - ਦਾਖ਼ਲਾ ਨਹੀਂ ਹੋ ਰਿਹਾ - ਆਪਣਾ ਪਾਸਵਰਡ ਚੈੱਕ ਕਰੋ ਜੀ ਬਹੁਤ ਸਾਰੀਆਂ ਅਸਫ਼ਲ ਕੋਸ਼ਿਸ਼ਾਂ। ਥੋੜ੍ਹੀ ਦੇਰ ਬਾਅਦ ਕੋਸ਼ਿਸ਼ ਕਰੋ ਜੀ। ਅਫ਼ਸੋਸ, ਇਹ ਵਰਤੋਂਕਾਰ ਕਾਮਨਜ਼ ਉੱਤੇ ਬਲਾਕ ਕਰ ਦਿੱਤਾ ਗਿਆ ਹੈ ਦਾਖ਼ਲਾ ਫੇਲ੍ਹ ਹੋਇਆ diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index ccc5f374f..be40b9f8d 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -60,8 +60,7 @@ Tytuł Opis Nie można zalogować - błąd sieci - Nie można zalogować - sprawdź nazwę użytkownika - Nie można zalogować - sprawdź hasło + Nie można się zalogować - sprawdź swoją nazwę użytkownika i hasło Zbyt wiele nieudanych prób zalogowania. Spróbuj ponownie za kilka minut. Przepraszamy, ten użytkownik został zablokowany na Commons Wprowadź swój kod dla dwuetapowej autoryzacji. diff --git a/app/src/main/res/values-pms/strings.xml b/app/src/main/res/values-pms/strings.xml index 8b2bd292c..fd1fe3d22 100644 --- a/app/src/main/res/values-pms/strings.xml +++ b/app/src/main/res/values-pms/strings.xml @@ -49,8 +49,7 @@ Për piasì, ch\'a-j buta \'n tìtol a s\'archivi Descrission Impossìbil rintré ant ël sistema - la rej a marcia nen - Impossìbil rintré ant ël sistema - për piasì, ch\'a verìfica sò stranòm - Impossìbil rintré ant ël sistema - për piasì, ch\'a contròla soa ciav + Impossìbil rintré ant ël sistema - për piasì ch\'a contròla sò stranòm e soa ciav Tròpi tentativ falì. Për piasì, ch\'a preuva torna da-sì chèiche minute. An dëspias, s\'utent-sì a l\'é stàit blocà ansima a Commons A dev fornì sò còdes d\'autentificassion a doi fator. diff --git a/app/src/main/res/values-ps/strings.xml b/app/src/main/res/values-ps/strings.xml index 3e2b499e6..2010b9bd5 100644 --- a/app/src/main/res/values-ps/strings.xml +++ b/app/src/main/res/values-ps/strings.xml @@ -37,8 +37,6 @@ مهرباني وکړئ د دې دوتنې لپاره سرلیک چمتو کړئ څرگندونه د ننوتلو توان نلري - د شبکې ناکامي - د ننوتلو توان نلري - لطفاً خپل کارن نوم وګورئ - د ننوتلو توان نلري - لطفاً خپل پټنوم وګورئ ډیری ناکامه هڅې. لطفا څو دقیقې وروسته بیا هڅه وکړئ. بخښنه غواړو، په دي کارن د کامنز لخوا بنديز ولګول شو غونډال کې ننوتنه نابريالې شوه diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 849c4e6b1..e7b70a35b 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -61,8 +61,7 @@ Forneça um título para este arquivo Descrição Erro ao efetuar o login - falha na rede - Erro ao efetuar o login - confira seu nome de usuário - Erro ao efetuar o login - confira sua senha + Não é possível fazer o login - verifique seu nome de usuário e senha Muitas tentativas malsucedidas. Tente de novo daqui alguns minutos. Desculpe, esse usuário foi banido do Commons Você precisa fornecer o seu código de ativação de dois fatores. diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index e59582fa0..b995ae220 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -58,8 +58,7 @@ Forneça um título para este ficheiro, por favor Descrição Não foi possível iniciar sessão - falha de rede - Não foi possível iniciar sessão - verifique o seu nome de utilizador(a) - Não foi possível iniciar sessão - verifique a sua palavra-passe + Não foi possível iniciar sessão - verifique o seu nome de utilizador e a palavra-passe Demasiadas tentativas malsucedidas. Por favor, tente de novo dentro de alguns minutos. Desculpe, este utilizador foi bloqueado no Commons Precisa fornecer o seu código de ativação de dois fatores. @@ -222,7 +221,7 @@ Configurações Comentários Sair - Tutorial + Explicação Notificações Destacadas Os sítios aqui perto não podem ser apresentados sem permissões de localização diff --git a/app/src/main/res/values-qq/strings.xml b/app/src/main/res/values-qq/strings.xml index d84ce08ab..fde276f7c 100644 --- a/app/src/main/res/values-qq/strings.xml +++ b/app/src/main/res/values-qq/strings.xml @@ -50,8 +50,6 @@ {{Identical|Title}} {{Identical|Description}} Error message shown to user when login can not be completed due to network issues. - Error message shown to user when login can not be completed because the user name is wrong. - Error message shown to user when login can not be completed beause the password is wrong Error message shown to user when login can not be completed because the user has attempted to login too many times in a short period of time, and hence been throttled. Error message shown to user when login can not be completed because the user is blocked on Wikimedia Commons {{Identical|Login failed}} diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index b87abfbbf..52b301fc8 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -44,8 +44,6 @@ Titlu Descriere Autentificare nereușită – defecțiune de rețea - Autentificare nereușită – verificați-vă numele de utilizator - Autentificare nereușită – verificați-vă parola Prea multe încercări nereușite. Încercați din nou peste câteva minute. Ne pare rău, acest utilizator a fost blocat la Commons Trebuie să introduceți tokenul de autentificare. diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 0d5a0ee3e..747f368d5 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -62,8 +62,7 @@ Пожалуйста, укажите название этого файла Описание Не удаётся войти — сбой сети - Не удалось войти — пожалуйста, проверьте своё имя пользователя - Не удалось войти — пожалуйста, проверьте свой пароль + Не удаётся войти — проверьте ваше имя пользователя и пароль Слишком много неудачных попыток. Пожалуйста, попробуйте ещё раз через несколько минут. Извините, но участник с таким именем был заблокирован на Викискладе Вы должны ввести код двухфакторной аутентификации. diff --git a/app/src/main/res/values-sd/strings.xml b/app/src/main/res/values-sd/strings.xml index 3ccc39dd3..07043e1bd 100644 --- a/app/src/main/res/values-sd/strings.xml +++ b/app/src/main/res/values-sd/strings.xml @@ -42,8 +42,6 @@ عنوان تشريح ناقابلِ داخل ٿيڻ - باھمڄار ناڪامي - ناقابلِ داخل ٿيڻ - براءِ مھرباني پنھنجو واپرائيندڙ-نانءُ چڪاسيو - ناقابل داخل ٿيڻ - براءِ مھرباني پنھنجو ڳجھولفظ چڪاسيو ھيڪانديون ناڪام ڪوششون. براءِ مھرباني ڪجھ منٽن کانپوءِ ٻيھر ڪوشش ڪريو. افسوس، ھي واپرائيندڙ العام تي بندشيل آھي داخل ٿيڻ ناڪام diff --git a/app/src/main/res/values-si/strings.xml b/app/src/main/res/values-si/strings.xml index 4ae0db17c..cb553b304 100644 --- a/app/src/main/res/values-si/strings.xml +++ b/app/src/main/res/values-si/strings.xml @@ -44,8 +44,6 @@ මාතෘකාව විස්තරය පිවිසීමට නොහැකිය-ජාලය ඇනහිටීමක් - පිවිසීමට නොහැකිය-කරුණාකර ඔබගේ පිවිසුම්-නාමය පරික්ෂා කරන්න - පිවිසීමට නොහැකිය-කරුණාකර ඔබගේ මුරපදය පරික්ෂා කරන්න. බොහෝ අසාර්ථක උත්සාහයන් කර ඇත. කරුණාකර මිනිත්තු කිහිපයකට පසුව උත්සාහ කරන්න කණගාටුයි,මෙම පරිශීලක වාරණයට ලක්කර ඇත. ඔබ ඔබගේ ද්විත්ව සහතික කිරීමේ කේතය ඇතුලත් කළ යුතුය. diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 90fac7f16..9ad6857ef 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -51,8 +51,6 @@ Prosím, dajte tomuto súboru názov Opis prihlásenie zlyhalo - zlyhanie siete - Prihlásenie zlyhalo - skontrolujte vaše používateľské meno - Prihlásenie zlyhalo - skontrolujte vaše heslo Príliš veľa neúspešných pokusov. Skúste to znova o niekoľko minút. Ospravedlňujeme sa, tento užívateľ bol na Commons zablokovaný Prihlásenie zlyhalo diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 925b8a5ce..312cccb62 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -57,8 +57,6 @@ Унесите наслов за ову датотеку Опис Неуспешно пријављивање – грешка на мрежи - Неуспешно пријављивање – проверите Ваше корисничко име - Неуспешно пријављивање – проверите Вашу лозинку Превише неуспешних покушаја. Пробајте поново за неколико минута. Нажалост, овај корисник је блокиран на Остави Морате унети Ваш двофакторски код за аутентификацију. diff --git a/app/src/main/res/values-su/strings.xml b/app/src/main/res/values-su/strings.xml index b2604eefd..3fff0ed27 100644 --- a/app/src/main/res/values-su/strings.xml +++ b/app/src/main/res/values-su/strings.xml @@ -43,8 +43,6 @@ Judul Pedaran Teu bisa login - gangguan jaringan - Teu bisa login - pariksa sandiasma - Teu bisa login - pariksa kecap sandi Loba teuing nu gagalna. Mangga cobian sababaraha menit deui mah Punten, ieu kontributor geus diblokir di Commons Anjeun kudu nyayagakeun kodeu oténtikasi dua faktor. diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 1d2fc868e..8c9e8a478 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -55,8 +55,7 @@ Var god ange en titel för denna fil Beskrivning Det gick inte att logga in - nätverksfel - Det gick inte att logga in - var god kontrollera ditt användarnamn - Det gick inte att logga in - var god kontrollera ditt lösenord + Kunde inte logga in - kontrollera ditt användarnamn och lösenord För många misslyckade försök. Var god försök igen om några minuter. Tyvärr, denna användare har blockerats på Commons Du måste ange din tvåstegsverifieringskod. diff --git a/app/src/main/res/values-te/strings.xml b/app/src/main/res/values-te/strings.xml index b2ad478b0..59c919d35 100644 --- a/app/src/main/res/values-te/strings.xml +++ b/app/src/main/res/values-te/strings.xml @@ -38,8 +38,6 @@ శీర్షిక వివరణ లాగిన్ చెయ్యలేకపోయాం - నెట్‍వర్కు విఫలం - లాగిన్ చెయ్యలేకపోయాం - మీ వాడుకరిపేరును సరిచూసుకోండి - లాగిన్ చెయ్యలేకపోయాం - మీ సంకేతపదాన్ని సరిచూసుకోండి మరీ ఎక్కువ విఫల యత్నాలు చేసారు. కొద్ది నిముషాలాగి ప్రయత్నించండి ఈ వాడుకరి కామన్స్ లో నిరోధించబడ్డారు, సారీ. లాగిన్ విఫలమైంది diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml index 29b29d804..933f0c2d4 100644 --- a/app/src/main/res/values-th/strings.xml +++ b/app/src/main/res/values-th/strings.xml @@ -48,8 +48,6 @@ กรุณาระบุชืิ่อเรื่องของไฟล์นี้ คำอธิบาย ไม่สามารถเข้าสู่ระบบได้ - ความล้มเหลวของเครือข่าย - ไม่สามารถเข้าสู่ระบบได้ - กรุณาตรวจสอบชื่อผู้ใช้ของคุณ - ไม่สามารถเข้าสู่ระบบได้ - กรุณาตรวจสอบรหัสผ่านของคุณ จำนวนครั้งที่พยายามไม่สำเร็จมากเกินไป กรุณาลองอีกครั้งในอีกสักครู่ ขออภัย ผู้ใช้นี้ถูกบล็อกบนคอมมอนส์อยู่ คุณต้องระบุโค้ดการตรวจสอบความถูกต้องสองปัจจัยของคุณ diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index c9dd60b41..784458cfa 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -57,8 +57,6 @@ Lütfen bu dosya için bir başlık ekleyin Açıklama Oturum açılamıyor - ağ hatası - Oturum açılamıyor - lütfen kullanıcı adınızı kontrol edin - Oturum açılamıyor - lütfen parolanızı kontrol edin Çok sayıda başarısız girişimde bulundunuz. Birkaç dakika sonra tekrar deneyin. Üzgünüz, bu kullanıcı Commons\'ta engellendi İki faktörlü kimlik doğrulama kodunu sağlamalısınız. diff --git a/app/src/main/res/values-ug/strings.xml b/app/src/main/res/values-ug/strings.xml index 3c180fbf2..4c55cb548 100644 --- a/app/src/main/res/values-ug/strings.xml +++ b/app/src/main/res/values-ug/strings.xml @@ -39,8 +39,6 @@ ماۋزۇ چۈشەندۈرۈش تىزىملىتىش - تور كاشىلىسى - تىزىملاشقا ئامالسىز - سىزنىڭ ئابونت نامىڭىزنى تەكشۈرۈپ بېقىڭ - تىزىملاشقا ئامالسىز مەخپىي نومۇرىڭىزنى تەكشۈرۈپ بېقىڭ مەغلۇپ بولغان قېتىم سانى بەك كۆپ . نەچچە مىنۇتتىن كېيىن قايتا سىناڭ . كەچۈرۈڭ، بۇ ئابونت ئاللىقاچان ئورتاق بەھرىمەن بولىدىغان بايلىق مەنبەسى دائىرىلىك سىز چوقۇم سىزنىڭ قوش ئامىل تەكشۈرۈش كودىنى تاپشۇرىسىز . diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 1aba51e02..cf6ed0896 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -58,8 +58,7 @@ Будь ласка, вкажіть назву цього файлу Опис Неможливо увійти — збій у мережі - Неможливо увійти — будь ласка, перевірте своє ім\'я користувача - Неможливо увійти — будь ласка, перевірте свій пароль + Неможливо увійти — будь ласка перевірте ім\'я користувача та пароль Надто багато невдалих спроб. Будь ласка, спробуйте знову через кілька хвилин. Вибачте, цього користувача було заблоковано на Вікісховищі Ви повинні надати код двофакторної автентифікації. @@ -150,7 +149,7 @@ Корисні об\'єкти (велосипеди, залізничні станції) Відомі люди (ваш мер, спортсмен-олімпієць, якого ви зустріли) Будь ласка, НЕ завантажуйте: - u2022 Селфі або фото своїх друзів \nu2022 Зображення, які Ви завантажили з інтернету \nu2022 Скріншоти патентованих програм + - Селфі або фото своїх друзів \n- Зображення, які Ви завантажили з інтернету \n- Знімки екрану пропрієтарних програм Селфі чи фото ваших друзів Зображення, які ви завантажили з інтернету Знімки екрану пропрієтарних програм @@ -162,9 +161,10 @@ Надсилайте Ваші зображення. Допоможіть оживити статті Вікіпедії! Зображення у Вікіпедії надходять з Вікісховища. Ваші зображення допомагають освіті людей у всьому світі. - Уникайте захищених авторським правом матеріалів, знайдених в Інтернеті, а також зображень плакатів, обкладинок книг і т. п. + Уникайте захищених авторським правом матеріалів, знайдених в Інтернеті, а також зображень плакатів, обкладинок книг, тощо. Ви це зрозуміли? Так! + Категорії Завантаження… Нічого не обрано @@ -186,7 +186,7 @@ Опис Сюди потрапляє опис медіафайлу. Він потенційно може бути досить довгим і розтягнутися на декілька рядків. Однак ми сподіваємось, що він виглядатиме гарно. Автор - Тут вказується ім\'я автора вибраного зображеня + Тут вказується ім\'я автора вибраного зображення Дата завантаження Ліцензія Координати @@ -202,7 +202,7 @@ Ви справді хочете вийти із системи? Логотип Вікісховища Веб-сайт Commons - Фейсбук сторінка Commons + Facebook-сторінка Commons Програмний код Commons на GitHub Фонове зображення Помилка медіазображення @@ -237,15 +237,15 @@ Стаття Вікіпедії Помилка кешування зображень Унікальна описова назва файлу. Ви можете використовувати простий текст з пробілами. Не вказуйте розширення файлу - Будь ласка, докладно опишіть файл: де його було зроблено? що на ньому зображено? який контекст? Будь ласка, опишіть об\'єкти чи осіб. Додайте інформацію, яку не можна легко здогадатися, наприклад, пору доби для фотографії пейзажу. Якщо зображено щось незвичайне, постарайтеся пояснити, що робить його незвичайним. + Будь ласка, докладно опишіть файл: де його було зроблено? що на ньому зображено? який контекст? Будь ласка, опишіть об\'єкти чи осіб. Додайте інформацію, яку не можна легко здогадатися, наприклад, пору доби для фотографії пейзажу. Якщо зображено щось незвичайне, спробуйте пояснити, що робить його незвичайним. Це зображення надто темне. Ви упевнені, що хочете його завантажити? Вікісховище призначене лише для зображень, що мають енциклопедичну цінність. Це зображення розмите. Ви упевнені, що хочете його завантажити? Вікісховище призначене лише для зображень, що мають енциклопедичну цінність. Надати дозвіл Використовувати зовнішнє сховище Зберігати зображення, виконані вбудованою камерою Вашого пристрою Увійдіть у свій обліковий запис - Надіслати лог-файл - Надіслати лог-файл розробникам електронною поштою + Надіслати файл журналу + Надіслати файл журналу розробникам електронною поштою Не знайдено браузера, щоб відкрити посилання Помилка! Посилання не знайдено Номінувати на вилучення @@ -257,9 +257,9 @@ Потрібний дозвіл для показу списку місць поблизу Показати на мапі у зовнішній програмі ЧИТАТИ СТАТТЮ - Вітаємо у Wikimedia Commons, %1$s! Раді вас бачити. + Вітаємо у Вікісховищі, %1$s! Раді вас бачити. %1$s залишив повідомлення на вашій сторінці обговорення - Дякуємо за правку + Дякуємо за редагування %1$s згадав вас на %2$s. Перемкнути режим перегляду НАПРЯМКИ @@ -280,10 +280,13 @@ Скасувати Повторити Зрозуміло + Це місця поблизу, про які є статті Вікіпедії, але які потребують ілюстрацій Натискання цієї кнопки згенерує список таких місць + Ви можете завантажити зображення для любого з цих місць, зробивши знімок камерою або вибравши зображення з галереї Зображень не знайдено! Сталася помилка при завантаженні зображень. Завантажено: %1$s Поділитися програмою + Під час вибору зображення не були вказані координати Помилка отримання місць поблизу. diff --git a/app/src/main/res/values-ur/strings.xml b/app/src/main/res/values-ur/strings.xml index 4fdd67514..2620412d6 100644 --- a/app/src/main/res/values-ur/strings.xml +++ b/app/src/main/res/values-ur/strings.xml @@ -45,8 +45,6 @@ عنوان وضاحت لاگ ان ہونے میں ناکام - نیٹ ورک ناکامی - لاگ ان ہونے میں ناکام - براہ مہربانی اپنا صارف نام کی جانچ کریں - لاگ ان ہونے میں ناکام - براہ مہربانی - اپنے پاس ورڈ کی جانچ کریں بے شمار ناکام کوششیں کچھ منٹوں میں دوبارہ کوشش کریں۔ معذرت، یہ صارف کومنز پر بلاک کردیا گیا ہے آپ کو اپنے دو عامل کے تصدیق کوڈ فراہم کرنا چاہیے۔ diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 4cff15064..5b7fd430c 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -1,16 +1,22 @@ + Phản hồi + Vị trí Commons + Thiết lập Tên người dùng Mật khẩu + Đăng nhập vào tài khoản Commons Beta của bạn Đăng nhập + Quên mật khẩu? Mở tài khoản Đang đăng nhập Vui lòng chờ… @@ -26,7 +32,10 @@ Đang hoàn thành việc tải lên tập tin %1$s Tải lên tập tin %1$s thất bại Chạm để xem - %d tập tin đang được tải lên + + %1$d tập tin đang được tải lên + %1$d tập tin đang được tải lên + Tập tin Tôi đã Tải lên Gần đây Đang chờ Thất bại @@ -39,10 +48,9 @@ Chia sẻ Mở trong Trình duyệt Tên + Xin hãy đặt tiêu đề cho tập tin này Miêu tả Không thể đăng nhập – có lỗi mạng - Không thể đăng nhập – xin vui lòng kiểm tra tên người dùng - Không thể đăng nhập – xin vui lòng kiểm tra mật khẩu Đã đăng nhập thất bại quá nhiều lần. Xin vui lòng thử lại trong vòng vài phút. Rất tiếc, người dùng này đã bị cấm tại Commons Bạn phải cung cấp mã xác thực dùng hai nhân tố. @@ -54,25 +62,31 @@ Tìm thể loại Lưu Làm mới + Danh sách Chức năng GPS đang tắt trên thiết bị của bạn. Bạn có muốn bật nó lên? Bật GPS Chưa có tập tin tải lên - + \@string/contributions_subtitle_zero - %1$d tập tin tải lên + %1$d tập tin đã tải lên + %1$d tập tin đã tải lên Đang bắt đầu tải lên %1$d tập tin - %1$d tập tin tải lên + + %1$d tập tin đã tải lên + %1$d tập tin đã tải lên + Không tìm thấy thể loại khớp với %1$s - Xếp các hình ảnh vào thể loại để cho chúng dễ tìm kiếm hơn trên Wikimedia Commons.\n\nHãy bắt đầu nhập tên thể loại để tìm kiếm.\nChạm vào thông điệp này (hoặc bấm Quay lại) để bỏ qua bước này. + Xếp các hình ảnh vào thể loại để giúp chúng dễ tìm kiếm hơn trên Wikimedia Commons.\nHãy bắt đầu nhập để thêm thể loại. Thể loại Cài đặt Mở tài khoản + Hình ảnh chọn lọc Giới thiệu - Phần mềm mã nguồn mở được phát hành theo <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/COPYING\">Giấy phép Apache v2</a>. %1$s và biểu trưng của nó là nhãn hiệu của Quỹ Wikimedia và được sử dụng do Quỹ Wikimedia cho phép. Chúng tôi không được Quỹ Wikimedia ủng hộ hoặc nhận làm chi nhánh. - <a href=\"https://github.com/commons-app/apps-android-commons\">Mã nguồn</a> và <a href=\"https://commons-app.github.io/\">trang chủ</a> tại GitHub. <a href=\"https://github.com/commons-app/apps-android-commons/issues\">Tạo vấn đề GitHub mới</a> để báo cáo lỗi hoặc gợi ý thay đổi. - - <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\">Công trạng</a> + Ứng dụng Wikimedia Commons là ứng dụng mã nguồn mở được sáng tạo và quản lý bởi các tình nguyện viên và những người được tin tưởng của cộng đồng Wikipedia. Wikimedia Foundation không tham gia vào sự tạo lập, phát triển cũng như quản lý của ứng dụng. + Tạo một <a href=\"https://github.com/commons-app/apps-android-commons/issues\">thảo luận (issue) mới trên GitHub</a> để báo cáo lỗi cũng như đưa ra các ý tưởng. + <u>Chính sách riêng tư</u> + <u>Công trạng</u> Giới thiệu Gửi Phản hồi (qua Thư điện tử) Không có chương trình thư điện tử nào được cài đặt @@ -84,7 +98,7 @@ Hình này sẽ được phát hành theo giấy phép %1$s Với việc đăng hình này, tôi tuyên bố rằng nó là tác phẩm của chính mình, rằng nó không chứa nội dung có bản quyền hoặc ảnh tự chụp, và về mặt khác thì hoàn toàn tuân theo <a href=\"https://commons.wikimedia.org/wiki/Commons:Policies_and_guidelines?uselang=vi\">các quy định Wikimedia Commons</a>. Tải về - Giấy phép + Giấy phép mặc định Sử dụng tiêu đề/miêu tả trước Lấy vị trí hiện tại tự động Định vị hiện tại để nhận gợi ý thể loại trong trường hợp hình ảnh chưa được gắn thẻ địa lý diff --git a/app/src/main/res/values-xmf/strings.xml b/app/src/main/res/values-xmf/strings.xml index b9689f9e2..d9c0b8f9d 100644 --- a/app/src/main/res/values-xmf/strings.xml +++ b/app/src/main/res/values-xmf/strings.xml @@ -41,8 +41,6 @@ დუდჯოხო ეჭარუა მიშულაქ ვემიხუჯინუ - რშვილიშ ჩილათა - მიშულაქ ვემიხუჯინუ - ქორთხინთ გეგნაჯინით ჯოხოს - მიშულაქ ვემიხუჯინუ - ქორთხინთ გეგნაჯინით პაროლს ძალამ მიარე უმწუძინუ ცადება. ქორთხინ, მუხირენ წუთშა ხოლო ქოცადით. მორდება, თე მახვარებუ ბლოკირი რე ვიკიოწკარუეს თქვა გემშიონათ ოკო ჟირფაქტორიანი ავტორიზაციაშ კოდი. diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 4581d45ce..c57406c80 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -4,6 +4,7 @@ * Kly * LNDDYL * Liuxinyu970226 +* S099001 * Simon Shek * StephDC * Wwycheuk @@ -28,7 +29,7 @@ 請稍候… 登入成功! 登入失敗! - 找不到檔案。請嘗試其它檔案看看。 + 找不到檔案。請試試看其它檔案。 未能核對身分! 開始上傳! 已上傳%1$s! @@ -42,7 +43,7 @@ 正在上載 %1$d 個檔案 正在上載 %1$d 個檔案 - 我的最近上傳 + 我最近的上傳 已佇列 失敗 %1$d%%完成 @@ -57,8 +58,7 @@ 請提供此檔案的標題 說明 無法登入-網路故障 - 無法登入-請檢查您的使用者名稱 - 無法登入-請檢查您的密碼 + 無法登入 - 請檢查您的使用者名稱與密碼 失敗次數過多。請於幾分鐘後重試。 很抱歉,該使用者已被維基共享資源封禁 必須提供您的雙重因素身分核對代碼。 @@ -110,7 +110,7 @@ 透過提交此圖片,我宣佈這是我個人創作的成品,且不包含受版權保護或自拍內容,並除此之外遵守<a href=\"https://commons.wikimedia.org/wiki/Commons:Policies_and_guidelines\">維基媒體共享資源方針</a>。 下載 預設授權條款 - 使用先前標題/說明 + 使用先前標題、說明 自動獲取目前位置 若圖片未有地理標記,就以目前位置來作為分類建議。 夜間模式 @@ -155,9 +155,10 @@ 貢獻您的圖片,使維基百科的文章更加生動! 維基百科的圖片,來自維基共享資源。 您的圖片可以幫助教育世界各地的人。 - 避免使用受版權保護的材料,例如從互聯網找來的圖片、海報、書籍封面等 + 避免使用受版權保護的材料,例如從網際網路找來的圖片、海報、書籍封面等 明白了嗎? 是! + 此提示為空,可能無效。請見錯誤報告: https://github.com/commons-app/apps-android-commons/issues/1333 。 分類 載入中… 未選擇 @@ -243,6 +244,7 @@ 錯誤!查無 URL 提名刪除 此圖片已被提名刪除。 + 此提示為空,可能無效。請見錯誤報告: https://github.com/commons-app/apps-android-commons/issues/1333 。 於瀏覽器檢視 位置無法更改。 位置無效。 diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 2079eb925..ab638cb87 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -55,8 +55,6 @@ 请提供此文件的标题 说明 无法登录 - 网络故障 - 无法登录 - 请检查您的用户名 - 无法登录 - 请检查您的密码 失败次数过多。请在几分钟后重试。 对不起,该用户已经被共享资源封禁 您必须提供您的双因素验证代码。 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 60a977f0b..25934ab0c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -46,8 +46,7 @@ Please provide a title for this file Description Unable to login - network failure - Unable to login - please check your username - Unable to login - please check your password + Unable to login - please check your username and password Too many unsuccessful attempts. Please try again in a few minutes. Sorry, this user has been blocked on Commons You must provide your two factor authentication code. @@ -286,4 +285,6 @@ Image successfully added to %1$s on Wikidata! Failed to update corresponding wiki data entity! + Set wallpaper + Wallpaper set successfully! diff --git a/app/src/main/resources/queries/nearby_query.rq b/app/src/main/resources/queries/nearby_query.rq index 0453005e8..b11f0985a 100644 --- a/app/src/main/resources/queries/nearby_query.rq +++ b/app/src/main/resources/queries/nearby_query.rq @@ -39,6 +39,11 @@ SELECT # Get emoji OPTIONAL { ?classId wdt:P487 ?emoji0. } OPTIONAL { ?classId wdt:P279*/wdt:P487 ?emoji1. } + + OPTIONAL { + ?wikipediaArticle schema:about ?item ; + schema:isPartOf . + } OPTIONAL { ?wikipediaArticle schema:about ?item ; schema:isPartOf . diff --git a/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt b/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt index b1de29143..292073bbf 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt @@ -1,5 +1,6 @@ package fr.free.nrw.commons +import android.content.ContentProviderClient import android.content.Context import android.content.SharedPreferences import android.support.v4.util.LruCache @@ -8,7 +9,6 @@ import com.nhaarman.mockito_kotlin.mock import com.squareup.leakcanary.RefWatcher import fr.free.nrw.commons.auth.AccountUtil import fr.free.nrw.commons.auth.SessionManager -import fr.free.nrw.commons.caching.CacheController import fr.free.nrw.commons.data.DBOpenHelper import fr.free.nrw.commons.di.CommonsApplicationComponent import fr.free.nrw.commons.di.CommonsApplicationModule @@ -33,6 +33,7 @@ class TestCommonsApplication : CommonsApplication() { override fun setupLeakCanary(): RefWatcher = RefWatcher.DISABLED } +@Suppress("MemberVisibilityCanBePrivate") class MockCommonsApplicationModule(appContext: Context) : CommonsApplicationModule(appContext) { val accountUtil: AccountUtil = mock() val appSharedPreferences: SharedPreferences = mock() @@ -41,13 +42,23 @@ class MockCommonsApplicationModule(appContext: Context) : CommonsApplicationModu val otherSharedPreferences: SharedPreferences = mock() val uploadController: UploadController = mock() val mockSessionManager: SessionManager = mock() - val mediaWikiApi: MediaWikiApi = mock() val locationServiceManager: LocationServiceManager = mock() - val cacheController: CacheController = mock() val mockDbOpenHelper: DBOpenHelper = mock() val nearbyPlaces: NearbyPlaces = mock() val lruCache: LruCache = mock() val gson: Gson = Gson() + val categoryClient: ContentProviderClient = mock() + val contributionClient: ContentProviderClient = mock() + val modificationClient: ContentProviderClient = mock() + val uploadPrefs: SharedPreferences = mock() + + override fun provideCategoryContentProviderClient(context: Context?): ContentProviderClient = categoryClient + + override fun provideContributionContentProviderClient(context: Context?): ContentProviderClient = contributionClient + + override fun provideModificationContentProviderClient(context: Context?): ContentProviderClient = modificationClient + + override fun providesDirectNearbyUploadPreferences(context: Context?): SharedPreferences = uploadPrefs override fun providesAccountUtil(context: Context): AccountUtil = accountUtil @@ -65,8 +76,6 @@ class MockCommonsApplicationModule(appContext: Context) : CommonsApplicationModu override fun provideLocationServiceManager(context: Context): LocationServiceManager = locationServiceManager - override fun provideCacheController(): CacheController = cacheController - override fun provideDBOpenHelper(context: Context): DBOpenHelper = mockDbOpenHelper override fun provideNearbyPlaces(): NearbyPlaces = nearbyPlaces diff --git a/app/src/test/kotlin/fr/free/nrw/commons/mwapi/CategoryApiTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/mwapi/CategoryApiTest.kt new file mode 100644 index 000000000..76f34d55d --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/mwapi/CategoryApiTest.kt @@ -0,0 +1,178 @@ +package fr.free.nrw.commons.mwapi + +import com.google.gson.Gson +import fr.free.nrw.commons.mwapi.model.Page +import fr.free.nrw.commons.mwapi.model.PageCategory +import okhttp3.HttpUrl +import okhttp3.OkHttpClient +import okhttp3.mockwebserver.MockResponse +import okhttp3.mockwebserver.MockWebServer +import org.junit.After +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test + +class CategoryApiTest { + private lateinit var server: MockWebServer + private lateinit var url: String + private lateinit var categoryApi: CategoryApi + + @Before + fun setUp() { + server = MockWebServer() + url = "http://${server.hostName}:${server.port}/" + categoryApi = CategoryApi(OkHttpClient.Builder().build(), Gson(), HttpUrl.parse(url)) + } + + @After + fun teardown() { + server.shutdown() + } + + @Test + fun apiReturnsEmptyListWhenError() { + server.enqueue(MockResponse().setResponseCode(400).setBody("")) + + assertTrue(categoryApi.request("foo").blockingGet().isEmpty()) + } + + @Test + fun apiReturnsEmptyWhenTheresNoQuery() { + server.success(emptyMap()) + + assertTrue(categoryApi.request("foo").blockingGet().isEmpty()) + } + + @Test + fun apiReturnsEmptyWhenQueryHasNoPages() { + server.success(mapOf("query" to emptyMap())) + + assertTrue(categoryApi.request("foo").blockingGet().isEmpty()) + } + + @Test + fun apiReturnsEmptyWhenQueryHasPagesButTheyreEmpty() { + server.success(mapOf("query" to + mapOf("pages" to emptyList()))) + + assertTrue(categoryApi.request("foo").blockingGet().isEmpty()) + } + + @Test + fun singlePageSingleCategory() { + server.success(mapOf("query" to + mapOf("pages" to listOf( + page(listOf("one")) + )))) + + val response = categoryApi.request("foo").blockingGet() + + assertEquals(1, response.size) + assertEquals("one", response[0]) + } + + @Test + fun multiplePagesSingleCategory() { + server.success(mapOf("query" to + mapOf("pages" to listOf( + page(listOf("one")), + page(listOf("two")) + )))) + + val response = categoryApi.request("foo").blockingGet() + + assertEquals(2, response.size) + assertEquals("one", response[0]) + assertEquals("two", response[1]) + } + + @Test + fun singlePageMultipleCategories() { + server.success(mapOf("query" to + mapOf("pages" to listOf( + page(listOf("one", "two")) + )))) + + val response = categoryApi.request("foo").blockingGet() + + assertEquals(2, response.size) + assertEquals("one", response[0]) + assertEquals("two", response[1]) + } + + @Test + fun multiplePagesMultipleCategories() { + server.success(mapOf("query" to + mapOf("pages" to listOf( + page(listOf("one", "two")), + page(listOf("three", "four")) + )))) + + val response = categoryApi.request("foo").blockingGet() + + assertEquals(4, response.size) + assertEquals("one", response[0]) + assertEquals("two", response[1]) + assertEquals("three", response[2]) + assertEquals("four", response[3]) + } + + @Test + fun multiplePagesMultipleCategories_duplicatesRemoved() { + server.success(mapOf("query" to + mapOf("pages" to listOf( + page(listOf("one", "two", "three")), + page(listOf("three", "four", "one")) + )))) + + val response = categoryApi.request("foo").blockingGet() + + assertEquals(4, response.size) + assertEquals("one", response[0]) + assertEquals("two", response[1]) + assertEquals("three", response[2]) + assertEquals("four", response[3]) + } + + @Test + fun requestSendsWhatWeExpect() { + server.success(mapOf("query" to mapOf("pages" to emptyList()))) + + val coords = "foo,bar" + categoryApi.request(coords).blockingGet() + + server.takeRequest().let { request -> + assertEquals("GET", request.method) + assertEquals("/w/api.php", request.requestUrl.encodedPath()) + request.requestUrl.let { url -> + assertEquals("query", url.queryParameter("action")) + assertEquals("categories|coordinates|pageprops", url.queryParameter("prop")) + assertEquals("json", url.queryParameter("format")) + assertEquals("!hidden", url.queryParameter("clshow")) + assertEquals("type|name|dim|country|region|globe", url.queryParameter("coprop")) + assertEquals(coords, url.queryParameter("codistancefrompoint")) + assertEquals("geosearch", url.queryParameter("generator")) + assertEquals(coords, url.queryParameter("ggscoord")) + assertEquals("10000", url.queryParameter("ggsradius")) + assertEquals("10", url.queryParameter("ggslimit")) + assertEquals("6", url.queryParameter("ggsnamespace")) + assertEquals("type|name|dim|country|region|globe", url.queryParameter("ggsprop")) + assertEquals("all", url.queryParameter("ggsprimary")) + assertEquals("2", url.queryParameter("formatversion")) + } + } + } + + private fun page(catList: List) = Page().apply { + categories = catList.map { + PageCategory().apply { + title = "Category:$it" + } + }.toTypedArray() + } +} + +fun MockWebServer.success(response: Map) { + enqueue(MockResponse().setResponseCode(200).setBody(Gson().toJson(response))) +} \ No newline at end of file diff --git a/app/src/test/kotlin/fr/free/nrw/commons/mwapi/model/ApiResponseTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/mwapi/model/ApiResponseTest.kt new file mode 100644 index 000000000..41406a894 --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/mwapi/model/ApiResponseTest.kt @@ -0,0 +1,28 @@ +package fr.free.nrw.commons.mwapi.model + +import org.junit.Assert.* +import org.junit.Test + +class ApiResponseTest { + @Test + fun hasPages_whenQueryIsNull() { + val response = ApiResponse() + assertFalse(response.hasPages()) + } + + @Test + fun hasPages_whenPagesIsNull() { + val response = ApiResponse() + response.query = Query() + response.query.pages = null + assertFalse(response.hasPages()) + } + + @Test + fun hasPages_defaultsToSafeValue() { + val response = ApiResponse() + response.query = Query() + assertNotNull(response.query.pages) + assertTrue(response.hasPages()) + } +} \ No newline at end of file diff --git a/app/src/test/kotlin/fr/free/nrw/commons/mwapi/model/PageCategoryTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/mwapi/model/PageCategoryTest.kt new file mode 100644 index 000000000..fcc3d408f --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/mwapi/model/PageCategoryTest.kt @@ -0,0 +1,20 @@ +package fr.free.nrw.commons.mwapi.model + +import org.junit.Assert.assertEquals +import org.junit.Test + +class PageCategoryTest { + @Test + fun stripPrefix_whenPresent() { + val testObject = PageCategory() + testObject.title = "Category:Foo" + assertEquals("Foo", testObject.withoutPrefix()) + } + + @Test + fun stripPrefix_prefixAbsent() { + val testObject = PageCategory() + testObject.title = "Foo_Bar" + assertEquals("Foo_Bar", testObject.withoutPrefix()) + } +} \ No newline at end of file diff --git a/app/src/test/kotlin/fr/free/nrw/commons/mwapi/model/PageTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/mwapi/model/PageTest.kt new file mode 100644 index 000000000..4179b4fb5 --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/mwapi/model/PageTest.kt @@ -0,0 +1,12 @@ +package fr.free.nrw.commons.mwapi.model + +import org.junit.Assert.assertNotNull +import org.junit.Test + +class PageTest { + @Test + fun categoriesDefaultToSafeValue() { + val page = Page() + assertNotNull(page.getCategories()) + } +} \ No newline at end of file diff --git a/app/src/test/kotlin/fr/free/nrw/commons/upload/GpsCategoryModelTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/upload/GpsCategoryModelTest.kt new file mode 100644 index 000000000..cd2d77ada --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/upload/GpsCategoryModelTest.kt @@ -0,0 +1,77 @@ +package fr.free.nrw.commons.upload + +import org.junit.Assert.* +import org.junit.Before +import org.junit.Test + +class GpsCategoryModelTest { + + private lateinit var testObject : GpsCategoryModel + + @Before + fun setUp() { + testObject = GpsCategoryModel() + } + + @Test + fun initiallyTheModelIsEmpty() { + assertFalse(testObject.gpsCatExists) + assertTrue(testObject.categoryList.isEmpty()) + } + + @Test + fun addingCategoriesToTheModel() { + testObject.add("one") + assertTrue(testObject.gpsCatExists) + assertFalse(testObject.categoryList.isEmpty()) + assertEquals(listOf("one"), testObject.categoryList) + } + + @Test + fun duplicatesAreIgnored() { + testObject.add("one") + testObject.add("one") + assertEquals(listOf("one"), testObject.categoryList) + } + + @Test + fun modelProtectsAgainstExternalModification() { + testObject.add("one") + + val list = testObject.categoryList + list.add("two") + + assertEquals(listOf("one"), testObject.categoryList) + } + + @Test + fun clearingTheModel() { + testObject.add("one") + + testObject.clear() + assertFalse(testObject.gpsCatExists) + assertTrue(testObject.categoryList.isEmpty()) + + testObject.add("two") + assertEquals(listOf("two"), testObject.categoryList) + } + + @Test + fun settingTheListHandlesNull() { + testObject.add("one") + + testObject.categoryList = null + + assertFalse(testObject.gpsCatExists) + assertTrue(testObject.categoryList.isEmpty()) + } + + @Test + fun setttingTheListOverwritesExistingValues() { + testObject.add("one") + + testObject.categoryList = listOf("two") + + assertEquals(listOf("two"), testObject.categoryList) + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 850003852..05aa34949 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,17 +14,17 @@ # org.gradle.parallel=true #Thu Mar 01 15:28:48 IST 2018 systemProp.http.proxyPort=0 -compileSdkVersion=android-26 +compileSdkVersion=android-27 android.useDeprecatedNdk=true BUTTERKNIFE_VERSION=8.6.0 org.gradle.jvmargs=-Xmx1536M -buildToolsVersion=26.0.2 -targetSdkVersion=25 +buildToolsVersion=27.0.0 +targetSdkVersion=27 #TODO: Temporary disabled. https://developer.android.com/studio/build/gradle-plugin-3-0-0-migration.html#aapt2 #Refer to PR: https://github.com/commons-app/apps-android-commons/pull/932 android.enableAapt2=false -SUPPORT_LIB_VERSION=26.0.2 +SUPPORT_LIB_VERSION=27.1.1 minSdkVersion=15 systemProp.http.proxyHost= LEAK_CANARY=1.5.4