diff --git a/.travis.yml b/.travis.yml index 7c7f76eaa..debcd6f5d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,14 +17,17 @@ jdk: android: components: - - platform-tools - tools - - build-tools-26.0.1 + - platform-tools + - build-tools-26.0.2 - extra-google-m2repository - extra-android-m2repository - ${ANDROID_TARGET} - android-25 + - android-26 - sys-img-${ANDROID_ABI}-${ANDROID_TARGET} + licenses: + - 'android-sdk-license-.+' before_script: - echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI @@ -38,8 +41,10 @@ after_success: - bash <(curl -s https://codecov.io/bash) after_failure: - - echo '*** Connected Test Rsults ***' - - w3m -dump ${TRAVIS_BUILD_DIR}/app/build/reports/androidTests/connected/*Test.html + - echo '*** Debug Unit Test Results ***' + - w3m -dump ${TRAVIS_BUILD_DIR}/app/build/reports/tests/*/classes/*Test.html + - echo '*** Connected Test Results ***' + - w3m -dump ${TRAVIS_BUILD_DIR}/app/build/reports/androidTests/connected/flavors/*/*Test.html before_cache: - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock diff --git a/CREDITS b/CREDITS index b404302fb..29264b99d 100644 --- a/CREDITS +++ b/CREDITS @@ -29,6 +29,7 @@ their contribution to the product. * Jan Piotrowski * Bruke Mekuria Mulugeta * Paul Hawke +* Vishan Seru 3rd party open source libraries used: * Butterknife diff --git a/README.md b/README.md index 6ac8dc892..696201029 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,7 @@ The Wikimedia Commons Android app allows users to upload pictures from their Android phone/tablet to Wikimedia Commons. Download the app [here][1], or view our [website][2]. -Initially started by the Wikimedia Foundation, this app is now maintained by volunteers. Anyone is welcome to improve it, just choose among the [open issues][3] and send us a pull request :-) - -We are currently applying for an [IEG renewal][10] to work on the app for the next 6 months. Feedback is very much welcomed. +Initially started by the Wikimedia Foundation, this app is now maintained by grantees and volunteers of the Wikimedia community. Anyone is welcome to improve it, just choose among the [open issues][3] and send us a pull request :-) Get it on F-Droid diff --git a/app/build.gradle b/app/build.gradle index ec9ab5643..540c17b42 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,65 +1,75 @@ +apply from: '../gitutils.gradle' apply plugin: 'com.android.application' -apply plugin: 'me.tatarka.retrolambda' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-kapt' apply plugin: 'jacoco-android' apply from: 'quality.gradle' apply plugin: 'com.getkeepsafe.dexcount' dependencies { - compile 'com.github.nicolas-raoul:Quadtree:ac16ea8035bf07' - compile 'fr.avianey.com.viewpagerindicator:library:2.4.1.1@aar' - compile 'in.yuvi:http.fluent:1.3' - compile 'com.android.volley:volley:1.0.0' - compile 'ch.acra:acra:4.7.0' - compile 'org.mediawiki:api:1.3' - compile 'commons-codec:commons-codec:1.10' - compile 'com.github.pedrovgs:renderers:3.3.3' - compile 'com.google.code.gson:gson:2.8.1' - compile 'com.jakewharton.timber:timber:4.5.1' - compile 'info.debatty:java-string-similarity:0.24' - compile ('com.mapbox.mapboxsdk:mapbox-android-sdk:5.1.0@aar'){ + implementation 'com.github.nicolas-raoul:Quadtree:ac16ea8035bf07' + implementation 'fr.avianey.com.viewpagerindicator:library:2.4.1.1@aar' + implementation 'in.yuvi:http.fluent:1.3' + implementation 'com.android.volley:volley:1.0.0' + implementation 'ch.acra:acra:4.7.0' + implementation 'org.mediawiki:api:1.3' + implementation 'commons-codec:commons-codec:1.10' + implementation 'com.github.pedrovgs:renderers:3.3.3' + implementation 'com.google.code.gson:gson:2.8.1' + implementation 'com.jakewharton.timber:timber:4.5.1' + implementation 'info.debatty:java-string-similarity:0.24' + implementation ('com.mapbox.mapboxsdk:mapbox-android-sdk:5.1.0@aar'){ transitive=true } - compile "com.android.support:support-v4:${project.supportLibVersion}" - compile "com.android.support:appcompat-v7:${project.supportLibVersion}" - compile "com.android.support:design:${project.supportLibVersion}" - compile "com.android.support:cardview-v7:${project.supportLibVersion}" + implementation "com.android.support:support-v4:${project.supportLibVersion}" + implementation "com.android.support:appcompat-v7:${project.supportLibVersion}" + implementation "com.android.support:design:${project.supportLibVersion}" - compile "com.jakewharton:butterknife:$BUTTERKNIFE_VERSION" - annotationProcessor "com.jakewharton:butterknife-compiler:$BUTTERKNIFE_VERSION" + implementation "com.android.support:cardview-v7:${project.supportLibVersion}" - compile 'com.squareup.okhttp3:okhttp:3.8.1' - compile 'com.squareup.okio:okio:1.13.0' + implementation "com.jakewharton:butterknife:$BUTTERKNIFE_VERSION" + kapt "com.jakewharton:butterknife-compiler:$BUTTERKNIFE_VERSION" - compile 'io.reactivex.rxjava2:rxandroid:2.0.1' + implementation 'com.squareup.okhttp3:okhttp:3.8.1' + implementation 'com.squareup.okio:okio:1.13.0' + + implementation 'io.reactivex.rxjava2:rxandroid:2.0.1' // Because RxAndroid releases are few and far between, it is recommended you also // explicitly depend on RxJava's latest version for bug fixes and new features. - compile 'io.reactivex.rxjava2:rxjava:2.1.2' - compile 'com.jakewharton.rxbinding2:rxbinding:2.0.0' - compile 'com.jakewharton.rxbinding2:rxbinding-support-v4:2.0.0' - compile 'com.jakewharton.rxbinding2:rxbinding-appcompat-v7:2.0.0' - compile 'com.jakewharton.rxbinding2:rxbinding-design:2.0.0' + implementation 'io.reactivex.rxjava2:rxjava:2.1.2' + implementation 'com.jakewharton.rxbinding2:rxbinding:2.0.0' + implementation 'com.jakewharton.rxbinding2:rxbinding-support-v4:2.0.0' + implementation 'com.jakewharton.rxbinding2:rxbinding-appcompat-v7:2.0.0' + implementation 'com.jakewharton.rxbinding2:rxbinding-design:2.0.0' - compile 'com.facebook.fresco:fresco:1.3.0' - compile 'com.facebook.stetho:stetho:1.5.0' + implementation 'com.facebook.fresco:fresco:1.3.0' + implementation 'com.facebook.stetho:stetho:1.5.0' - testCompile 'junit:junit:4.12' - testCompile 'org.robolectric:robolectric:3.4' + implementation "com.google.dagger:dagger:$DAGGER_VERSION" + implementation "com.google.dagger:dagger-android-support:$DAGGER_VERSION" - testCompile 'com.squareup.okhttp3:mockwebserver:3.8.1' - androidTestCompile 'com.squareup.okhttp3:mockwebserver:3.8.1' - androidTestCompile "com.android.support:support-annotations:${project.supportLibVersion}" - androidTestCompile ('com.android.support.test.espresso:espresso-core:3.0.1'){ - exclude group: 'com.google.code.findbugs' - } + kapt "com.google.dagger:dagger-android-processor:$DAGGER_VERSION" + kapt "com.google.dagger:dagger-compiler:$DAGGER_VERSION" - debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.1' - releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1' - testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1' + testImplementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" + androidTestImplementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" - compile 'com.google.dagger:dagger:2.11' - compile 'com.google.dagger:dagger-android-support:2.11' + testImplementation 'junit:junit:4.12' + testImplementation 'org.robolectric:robolectric:3.4' + + testImplementation 'com.squareup.okhttp3:mockwebserver:3.8.1' + androidTestImplementation 'com.squareup.okhttp3:mockwebserver:3.8.1' + androidTestImplementation "com.android.support:support-annotations:${project.supportLibVersion}" + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' + + debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.5.1' + releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1' + testImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1' + + implementation 'com.google.dagger:dagger:2.11' + implementation 'com.google.dagger:dagger-android-support:2.11' annotationProcessor 'com.google.dagger:dagger-compiler:2.11' annotationProcessor 'com.google.dagger:dagger-android-processor:2.11' } @@ -74,12 +84,17 @@ android { applicationId 'fr.free.nrw.commons' versionCode 74 versionName '2.5.0' + setProperty("archivesBaseName", "app-commons-v$versionName-" + getBranchName()) minSdkVersion project.minSdkVersion targetSdkVersion project.targetSdkVersion testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true } + sourceSets { + test.java.srcDirs += 'src/test/kotlin' + } + 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. @@ -87,9 +102,11 @@ android { } debug { testCoverageEnabled true + versionNameSuffix "-debug-" + getBranchName() + "~" + getBuildVersion() } } + flavorDimensions 'tier' productFlavors { prod { buildConfigField "String", "WIKIMEDIA_API_HOST", "\"https://commons.wikimedia.org/w/api.php\"" @@ -101,6 +118,7 @@ android { buildConfigField "String", "EVENTLOG_WIKI", "\"commonswiki\"" buildConfigField "String", "SIGNUP_LANDING_URL", "\"https://commons.m.wikimedia.org/w/index.php?title=Special:CreateAccount&returnto=Main+Page&returntoquery=welcome%3Dyes\"" buildConfigField "String", "SIGNUP_SUCCESS_REDIRECTION_URL", "\"https://commons.m.wikimedia.org/w/index.php?title=Main_Page&welcome=yes\"" + dimension 'tier' } beta { @@ -114,6 +132,7 @@ android { buildConfigField "String", "EVENTLOG_WIKI", "\"commonswiki\"" buildConfigField "String", "SIGNUP_LANDING_URL", "\"https://commons.m.wikimedia.beta.wmflabs.org/w/index.php?title=Special:CreateAccount&returnto=Main+Page&returntoquery=welcome%3Dyes\"" buildConfigField "String", "SIGNUP_SUCCESS_REDIRECTION_URL", "\"https://commons.m.wikimedia.beta.wmflabs.org/w/index.php?title=Main_Page&welcome=yes\"" + dimension 'tier' } } @@ -132,4 +151,5 @@ android { configurations.all { resolutionStrategy.force 'com.android.support:support-annotations:25.2.0' } + buildToolsVersion buildToolsVersion } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 44577db4c..9e502689f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -14,6 +14,7 @@ + applicationInjector() { return injector(); diff --git a/app/src/main/java/fr/free/nrw/commons/Media.java b/app/src/main/java/fr/free/nrw/commons/Media.java index 26a1d038b..21e6cfe9e 100644 --- a/app/src/main/java/fr/free/nrw/commons/Media.java +++ b/app/src/main/java/fr/free/nrw/commons/Media.java @@ -120,8 +120,9 @@ public class Media implements Parcelable { return localUri; } + @Nullable public String getImageUrl() { - if (imageUrl == null) { + if (imageUrl == null && this.getFilename() != null) { imageUrl = Utils.makeThumbBaseUrl(this.getFilename()); } return imageUrl; diff --git a/app/src/main/java/fr/free/nrw/commons/MediaDataExtractor.java b/app/src/main/java/fr/free/nrw/commons/MediaDataExtractor.java index 68ba02297..104798518 100644 --- a/app/src/main/java/fr/free/nrw/commons/MediaDataExtractor.java +++ b/app/src/main/java/fr/free/nrw/commons/MediaDataExtractor.java @@ -11,7 +11,6 @@ import org.xml.sax.SAXException; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.ArrayList; -import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; @@ -39,7 +38,6 @@ public class MediaDataExtractor { private String filename; private ArrayList categories; private Map descriptions; - private Date date; private String license; private @Nullable LatLng coordinates; private LicenseList licenseList; @@ -155,7 +153,7 @@ public class MediaDataExtractor { } private Node findTemplate(Element parentNode, String title_) throws IOException { - String title= new PageTitle(title_).getDisplayText(); + String title = new PageTitle(title_).getDisplayText(); NodeList nodes = parentNode.getChildNodes(); for (int i = 0, length = nodes.getLength(); i < length; i++) { Node node = nodes.item(i); @@ -181,7 +179,7 @@ public class MediaDataExtractor { } private static abstract class TemplateChildNodeComparator { - abstract public boolean match(Node node); + public abstract boolean match(Node node); } private Node findTemplateParameter(Node templateNode, String name) throws IOException { diff --git a/app/src/main/java/fr/free/nrw/commons/MediaWikiImageView.java b/app/src/main/java/fr/free/nrw/commons/MediaWikiImageView.java index 7ffe498b8..aa7ea8a15 100644 --- a/app/src/main/java/fr/free/nrw/commons/MediaWikiImageView.java +++ b/app/src/main/java/fr/free/nrw/commons/MediaWikiImageView.java @@ -42,7 +42,7 @@ public class MediaWikiImageView extends SimpleDraweeView { if (currentThumbnailTask != null) { currentThumbnailTask.cancel(true); } - if(media == null) { + if (media == null) { return; } diff --git a/app/src/main/java/fr/free/nrw/commons/Utils.java b/app/src/main/java/fr/free/nrw/commons/Utils.java index 88a3f929f..3f5eb2105 100644 --- a/app/src/main/java/fr/free/nrw/commons/Utils.java +++ b/app/src/main/java/fr/free/nrw/commons/Utils.java @@ -2,18 +2,22 @@ package fr.free.nrw.commons; import android.content.Context; import android.preference.PreferenceManager; +import android.support.annotation.NonNull; import org.apache.commons.codec.binary.Hex; import org.apache.commons.codec.digest.DigestUtils; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; -import fr.free.nrw.commons.auth.LoginActivity; import fr.free.nrw.commons.settings.Prefs; +import timber.log.Timber; public class Utils { @@ -33,7 +37,7 @@ public class Utils { } } - public static String makeThumbBaseUrl(String filename) { + public static String makeThumbBaseUrl(@NonNull String filename) { String name = new PageTitle(filename).getPrefixedText(); String sha = new String(Hex.encodeHex(DigestUtils.md5(name))); return String.format("%s/%s/%s/%s", BuildConfig.IMAGE_URL_BASE, sha.substring(0, 1), sha.substring(0, 2), urlEncode(name)); @@ -89,4 +93,37 @@ public class Utils { public static boolean isDarkTheme(Context context) { return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("theme", false); } + + /** + * Will be used to fetch the logs generated by the app ever since the beginning of times.... + * i.e. since the time the app started. + * + * @return String containing all the logs since the time the app started + */ + public static String getAppLogs() { + final String processId = Integer.toString(android.os.Process.myPid()); + + StringBuilder stringBuilder = new StringBuilder(); + + try { + String[] command = new String[] {"logcat","-d","-v","threadtime"}; + + Process process = Runtime.getRuntime().exec(command); + + BufferedReader bufferedReader = new BufferedReader( + new InputStreamReader(process.getInputStream()) + ); + + String line; + while ((line = bufferedReader.readLine()) != null) { + if (line.contains(processId)) { + stringBuilder.append(line); + } + } + } catch (IOException ioe) { + Timber.e("getAppLogs failed", ioe); + } + + return stringBuilder.toString(); + } } diff --git a/app/src/main/java/fr/free/nrw/commons/auth/AccountUtil.java b/app/src/main/java/fr/free/nrw/commons/auth/AccountUtil.java index e5b76c0f9..4114b19a9 100644 --- a/app/src/main/java/fr/free/nrw/commons/auth/AccountUtil.java +++ b/app/src/main/java/fr/free/nrw/commons/auth/AccountUtil.java @@ -18,7 +18,7 @@ import static android.accounts.AccountManager.KEY_ACCOUNT_TYPE; public class AccountUtil { - static final String ACCOUNT_TYPE = "fr.free.nrw.commons"; + public static final String ACCOUNT_TYPE = "fr.free.nrw.commons"; private final Context context; public AccountUtil(Context context) { 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 44dc4b3a7..d17120106 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 @@ -34,6 +34,7 @@ import fr.free.nrw.commons.Utils; import fr.free.nrw.commons.WelcomeActivity; import fr.free.nrw.commons.contributions.ContributionsActivity; import fr.free.nrw.commons.mwapi.MediaWikiApi; +import fr.free.nrw.commons.theme.NavigationBaseActivity; import timber.log.Timber; import static android.view.KeyEvent.KEYCODE_ENTER; @@ -199,7 +200,7 @@ public class LoginActivity extends AccountAuthenticatorActivity { } public void startMainActivity() { - ContributionsActivity.startYourself(this); + NavigationBaseActivity.startActivityWithFlags(this, ContributionsActivity.class, Intent.FLAG_ACTIVITY_CLEAR_TOP); finish(); } @@ -253,8 +254,8 @@ public class LoginActivity extends AccountAuthenticatorActivity { @Override public void afterTextChanged(Editable editable) { - boolean enabled = usernameEdit.getText().length() != 0 && passwordEdit.getText().length() != 0 && - (BuildConfig.DEBUG || twoFactorEdit.getText().length() != 0 || twoFactorEdit.getVisibility() != View.VISIBLE); + boolean enabled = usernameEdit.getText().length() != 0 && passwordEdit.getText().length() != 0 + && (BuildConfig.DEBUG || twoFactorEdit.getText().length() != 0 || twoFactorEdit.getVisibility() != View.VISIBLE); loginButton.setEnabled(enabled); } } diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsActivity.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsActivity.java index 42ffd5a97..6cda47d2e 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsActivity.java @@ -149,10 +149,13 @@ public class ContributionsActivity if (savedInstanceState != null) { mediaDetails = (MediaDetailPagerFragment)supportFragmentManager .findFragmentById(R.id.contributionsFragmentContainer); + + getSupportLoaderManager().initLoader(0, null, this); } requestAuthToken(); initDrawer(); setTitle(getString(R.string.title_activity_contributions)); + setUploadCount(); } @Override @@ -242,6 +245,8 @@ public class ContributionsActivity @Override public void onLoadFinished(Loader cursorLoader, Cursor cursor) { + contributionsList.changeProgressBarVisibility(false); + if (contributionsList.getAdapter() == null) { contributionsList.setAdapter(new ContributionsListAdapter(getApplicationContext(), cursor, 0)); @@ -249,8 +254,6 @@ public class ContributionsActivity ((CursorAdapter) contributionsList.getAdapter()).swapCursor(cursor); } - setUploadCount(); - contributionsList.clearSyncMessage(); notifyAndMigrateDataSetObservers(); } @@ -281,18 +284,16 @@ public class ContributionsActivity @SuppressWarnings("ConstantConditions") private void setUploadCount() { - compositeDisposable.add( - mediaWikiApi - .getUploadCount(sessionManager.getCurrentAccount().name) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - uploadCount -> getSupportActionBar().setSubtitle(getResources() - .getQuantityString(R.plurals.contributions_subtitle, - uploadCount, uploadCount)), - t -> Timber.e(t, "Fetching upload count failed") - ) - ); + compositeDisposable.add(mediaWikiApi + .getUploadCount(sessionManager.getCurrentAccount().name) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + uploadCount -> getSupportActionBar().setSubtitle(getResources() + .getQuantityString(R.plurals.contributions_subtitle, + uploadCount, uploadCount)), + t -> Timber.e(t, "Fetching upload count failed") + )); } @Override @@ -344,9 +345,4 @@ public class ContributionsActivity public void refreshSource() { getSupportLoaderManager().restartLoader(0, null, this); } - - public static void startYourself(Context context) { - context.startActivity(new Intent(context, ContributionsActivity.class)); - } - } diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListAdapter.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListAdapter.java index 0882d09c4..7be6dd663 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListAdapter.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListAdapter.java @@ -34,7 +34,7 @@ class ContributionsListAdapter extends CursorAdapter { views.seqNumView.setText(String.valueOf(cursor.getPosition() + 1)); views.seqNumView.setVisibility(View.VISIBLE); - switch(contribution.getState()) { + switch (contribution.getState()) { case Contribution.STATE_COMPLETED: views.stateView.setVisibility(View.GONE); views.progressView.setVisibility(View.GONE); @@ -50,7 +50,7 @@ class ContributionsListAdapter extends CursorAdapter { views.progressView.setVisibility(View.VISIBLE); long total = contribution.getDataLength(); long transferred = contribution.getTransferred(); - if(transferred == 0 || transferred >= total) { + if (transferred == 0 || transferred >= total) { views.progressView.setIndeterminate(true); } else { views.progressView.setProgress((int)(((double)transferred / (double)total) * 100)); diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java index 041790b0d..590d4e6ad 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java @@ -5,7 +5,6 @@ import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; -import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.support.v4.content.ContextCompat; import android.support.v7.app.AlertDialog; @@ -18,6 +17,7 @@ import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.GridView; import android.widget.ListAdapter; +import android.widget.ProgressBar; import android.widget.TextView; import javax.inject.Inject; @@ -42,10 +42,12 @@ public class ContributionsListFragment extends DaggerFragment { GridView contributionsList; @BindView(R.id.waitingMessage) TextView waitingMessage; - @BindView(R.id.emptyMessage) - TextView emptyMessage; + @BindView(R.id.loadingContributionsProgressBar) + ProgressBar progressBar; + @Inject @Named("prefs") SharedPreferences prefs; @Inject @Named("default_preferences") SharedPreferences defaultPrefs; + private ContributionController controller; @Override @@ -69,6 +71,7 @@ public class ContributionsListFragment extends DaggerFragment { waitingMessage.setVisibility(GONE); } + changeProgressBarVisibility(true); return v; } @@ -80,6 +83,10 @@ public class ContributionsListFragment extends DaggerFragment { this.contributionsList.setAdapter(adapter); } + public void changeProgressBarVisibility(boolean isVisible) { + this.progressBar.setVisibility(isVisible ? View.VISIBLE : View.GONE); + } + @Override public void onSaveInstanceState(Bundle outState) { if (outState == null) { diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsSyncAdapter.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsSyncAdapter.java index a99cbf933..e67b164a8 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsSyncAdapter.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsSyncAdapter.java @@ -57,6 +57,9 @@ public class ContributionsSyncAdapter extends AbstractThreadedSyncAdapter { } private boolean fileExists(ContentProviderClient client, String filename) { + if (filename == null) { + return false; + } Cursor cursor = null; try { cursor = client.query(BASE_URI, diff --git a/app/src/main/java/fr/free/nrw/commons/data/DBOpenHelper.java b/app/src/main/java/fr/free/nrw/commons/data/DBOpenHelper.java index 8ef9f336c..5e28a8a32 100644 --- a/app/src/main/java/fr/free/nrw/commons/data/DBOpenHelper.java +++ b/app/src/main/java/fr/free/nrw/commons/data/DBOpenHelper.java @@ -7,7 +7,7 @@ import android.database.sqlite.SQLiteOpenHelper; import fr.free.nrw.commons.contributions.Contribution; import fr.free.nrw.commons.modifications.ModifierSequence; -public class DBOpenHelper extends SQLiteOpenHelper{ +public class DBOpenHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME = "commons.db"; private static final int DATABASE_VERSION = 6; 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 4da020059..99d3235e7 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 @@ -15,6 +15,7 @@ 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; @@ -71,6 +72,12 @@ public class CommonsApplicationModule { return new ApacheHttpClientMediaWikiApi(BuildConfig.WIKIMEDIA_API_HOST); } + @Provides + @Singleton + public LocationServiceManager provideLocationServiceManager() { + return new LocationServiceManager(application); + } + @Provides @Singleton public CacheController provideCacheController() { diff --git a/app/src/main/java/fr/free/nrw/commons/location/LatLng.java b/app/src/main/java/fr/free/nrw/commons/location/LatLng.java index 1e3202914..787c8c8a5 100644 --- a/app/src/main/java/fr/free/nrw/commons/location/LatLng.java +++ b/app/src/main/java/fr/free/nrw/commons/location/LatLng.java @@ -13,7 +13,7 @@ public class LatLng { * @param longitude double value */ public LatLng(double latitude, double longitude, float accuracy) { - if(-180.0D <= longitude && longitude < 180.0D) { + if (-180.0D <= longitude && longitude < 180.0D) { this.longitude = longitude; } else { this.longitude = ((longitude - 180.0D) % 360.0D + 360.0D) % 360.0D - 180.0D; @@ -33,9 +33,9 @@ public class LatLng { } public boolean equals(Object o) { - if(this == o) { + if (this == o) { return true; - } else if(!(o instanceof LatLng)) { + } else if (!(o instanceof LatLng)) { return false; } else { LatLng var2 = (LatLng)o; diff --git a/app/src/main/java/fr/free/nrw/commons/location/LocationServiceManager.java b/app/src/main/java/fr/free/nrw/commons/location/LocationServiceManager.java index e87eaf92e..2c70e5070 100644 --- a/app/src/main/java/fr/free/nrw/commons/location/LocationServiceManager.java +++ b/app/src/main/java/fr/free/nrw/commons/location/LocationServiceManager.java @@ -7,22 +7,33 @@ import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import javax.inject.Inject; +import javax.inject.Singleton; + import timber.log.Timber; public class LocationServiceManager implements LocationListener { private String provider; private LocationManager locationManager; - private LatLng latestLocation; + private LatLng lastLocation; private Float latestLocationAccuracy; + private final List locationListeners = new CopyOnWriteArrayList<>(); public LocationServiceManager(Context context) { this.locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); provider = locationManager.getBestProvider(new Criteria(), true); } - public LatLng getLatestLocation() { - return latestLocation; + public boolean isProviderEnabled() { + return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); + } + + public LatLng getLastLocation() { + return lastLocation; } /** @@ -64,6 +75,16 @@ public class LocationServiceManager implements LocationListener { } } + public void addLocationListener(LocationUpdateListener listener) { + if (!locationListeners.contains(listener)) { + locationListeners.add(listener); + } + } + + public void removeLocationListener(LocationUpdateListener listener) { + locationListeners.remove(listener); + } + @Override public void onLocationChanged(Location location) { double currentLatitude = location.getLatitude(); @@ -71,8 +92,11 @@ public class LocationServiceManager implements LocationListener { latestLocationAccuracy = location.getAccuracy(); Timber.d("Latitude: %f Longitude: %f Accuracy %f", currentLatitude, currentLongitude, latestLocationAccuracy); + lastLocation = new LatLng(currentLatitude, currentLongitude, latestLocationAccuracy); - latestLocation = new LatLng(currentLatitude, currentLongitude, latestLocationAccuracy); + for (LocationUpdateListener listener : locationListeners) { + listener.onLocationChanged(lastLocation); + } } @Override diff --git a/app/src/main/java/fr/free/nrw/commons/location/LocationUpdateListener.java b/app/src/main/java/fr/free/nrw/commons/location/LocationUpdateListener.java new file mode 100644 index 000000000..69d3048a1 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/location/LocationUpdateListener.java @@ -0,0 +1,5 @@ +package fr.free.nrw.commons.location; + +public interface LocationUpdateListener { + void onLocationChanged(LatLng latLng); +} 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 145848919..85d598b9d 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 @@ -152,8 +152,14 @@ public class MediaDetailPagerFragment extends DaggerFragment implements ViewPage private void downloadMedia(Media m) { String imageUrl = m.getImageUrl(), fileName = m.getFilename(); + + if (imageUrl == null || fileName == null) { + return; + } + // Strip 'File:' from beginning of filename, we really shouldn't store it fileName = fileName.replaceFirst("^File:", ""); + Uri imageUri = Uri.parse(imageUrl); DownloadManager.Request req = new DownloadManager.Request(imageUri); diff --git a/app/src/main/java/fr/free/nrw/commons/modifications/CategoryModifier.java b/app/src/main/java/fr/free/nrw/commons/modifications/CategoryModifier.java index bb650513b..556815a97 100644 --- a/app/src/main/java/fr/free/nrw/commons/modifications/CategoryModifier.java +++ b/app/src/main/java/fr/free/nrw/commons/modifications/CategoryModifier.java @@ -13,7 +13,7 @@ public class CategoryModifier extends PageModifier { public CategoryModifier(String... categories) { super(MODIFIER_NAME); JSONArray categoriesArray = new JSONArray(); - for(String category: categories) { + for (String category: categories) { categoriesArray.put(category); } try { @@ -34,7 +34,7 @@ public class CategoryModifier extends PageModifier { categories = params.optJSONArray(PARAM_CATEGORIES); StringBuilder categoriesString = new StringBuilder(); - for(int i=0; i < categories.length(); i++) { + for (int i = 0; i < categories.length(); i++) { String category = categories.optString(i); categoriesString.append("\n[[Category:").append(category).append("]]"); } diff --git a/app/src/main/java/fr/free/nrw/commons/modifications/ModificationsContentProvider.java b/app/src/main/java/fr/free/nrw/commons/modifications/ModificationsContentProvider.java index 8bd3049a8..6dc993c9e 100644 --- a/app/src/main/java/fr/free/nrw/commons/modifications/ModificationsContentProvider.java +++ b/app/src/main/java/fr/free/nrw/commons/modifications/ModificationsContentProvider.java @@ -16,7 +16,7 @@ import dagger.android.AndroidInjection; import fr.free.nrw.commons.data.DBOpenHelper; import timber.log.Timber; -public class ModificationsContentProvider extends ContentProvider{ +public class ModificationsContentProvider extends ContentProvider { private static final int MODIFICATIONS = 1; private static final int MODIFICATIONS_ID = 2; @@ -51,7 +51,7 @@ public class ModificationsContentProvider extends ContentProvider{ int uriType = uriMatcher.match(uri); - switch(uriType) { + switch (uriType) { case MODIFICATIONS: break; default: @@ -112,7 +112,7 @@ public class ModificationsContentProvider extends ContentProvider{ sqlDB.beginTransaction(); switch (uriType) { case MODIFICATIONS: - for(ContentValues value: values) { + for (ContentValues value: values) { Timber.d("Inserting! %s", value); sqlDB.insert(ModifierSequence.Table.TABLE_NAME, null, value); } diff --git a/app/src/main/java/fr/free/nrw/commons/modifications/ModifierSequence.java b/app/src/main/java/fr/free/nrw/commons/modifications/ModifierSequence.java index 36012e55e..880b53313 100644 --- a/app/src/main/java/fr/free/nrw/commons/modifications/ModifierSequence.java +++ b/app/src/main/java/fr/free/nrw/commons/modifications/ModifierSequence.java @@ -27,7 +27,7 @@ public class ModifierSequence { public ModifierSequence(Uri mediaUri, JSONObject data) { this(mediaUri); JSONArray modifiersJSON = data.optJSONArray("modifiers"); - for (int i=0; i< modifiersJSON.length(); i++) { + for (int i = 0; i < modifiersJSON.length(); i++) { modifiers.add(PageModifier.fromJSON(modifiersJSON.optJSONObject(i))); } } @@ -49,7 +49,7 @@ public class ModifierSequence { public String getEditSummary() { StringBuilder editSummary = new StringBuilder(); - for(PageModifier modifier: modifiers) { + for (PageModifier modifier: modifiers) { editSummary.append(modifier.getEditSumary()).append(" "); } editSummary.append("Via Commons Mobile App"); @@ -93,12 +93,12 @@ public class ModifierSequence { public void save() { try { - if(contentUri == null) { + if (contentUri == null) { contentUri = client.insert(ModificationsContentProvider.BASE_URI, this.toContentValues()); } else { client.update(contentUri, toContentValues(), null, null); } - } catch(RemoteException e) { + } catch (RemoteException e) { throw new RuntimeException(e); } } diff --git a/app/src/main/java/fr/free/nrw/commons/modifications/PageModifier.java b/app/src/main/java/fr/free/nrw/commons/modifications/PageModifier.java index f4b3c7359..0da25d9a6 100644 --- a/app/src/main/java/fr/free/nrw/commons/modifications/PageModifier.java +++ b/app/src/main/java/fr/free/nrw/commons/modifications/PageModifier.java @@ -7,9 +7,9 @@ public abstract class PageModifier { public static PageModifier fromJSON(JSONObject data) { String name = data.optString("name"); - if(name.equals(CategoryModifier.MODIFIER_NAME)) { + if (name.equals(CategoryModifier.MODIFIER_NAME)) { return new CategoryModifier(data.optJSONObject("data")); - } else if(name.equals(TemplateRemoveModifier.MODIFIER_NAME)) { + } else if (name.equals(TemplateRemoveModifier.MODIFIER_NAME)) { return new TemplateRemoveModifier(data.optJSONObject("data")); } diff --git a/app/src/main/java/fr/free/nrw/commons/modifications/TemplateRemoveModifier.java b/app/src/main/java/fr/free/nrw/commons/modifications/TemplateRemoveModifier.java index 6149084c1..f9942b007 100644 --- a/app/src/main/java/fr/free/nrw/commons/modifications/TemplateRemoveModifier.java +++ b/app/src/main/java/fr/free/nrw/commons/modifications/TemplateRemoveModifier.java @@ -41,18 +41,18 @@ public class TemplateRemoveModifier extends PageModifier { Pattern templateStartPattern = Pattern.compile("\\{\\{" + templateNormalized, Pattern.CASE_INSENSITIVE); Matcher matcher = templateStartPattern.matcher(pageContents); - while(matcher.find()) { + while (matcher.find()) { int braceCount = 1; int startIndex = matcher.start(); int curIndex = matcher.end(); Matcher openMatch = PATTERN_TEMPLATE_OPEN.matcher(pageContents); Matcher closeMatch = PATTERN_TEMPLATE_CLOSE.matcher(pageContents); - while(curIndex < pageContents.length()) { + while (curIndex < pageContents.length()) { boolean openFound = openMatch.find(curIndex); boolean closeFound = closeMatch.find(curIndex); - if(openFound && (!closeFound || openMatch.start() < closeMatch.start())) { + if (openFound && (!closeFound || openMatch.start() < closeMatch.start())) { braceCount++; curIndex = openMatch.end(); } else if (closeFound) { @@ -71,8 +71,8 @@ public class TemplateRemoveModifier extends PageModifier { } // Strip trailing whitespace - while(curIndex < pageContents.length()) { - if(pageContents.charAt(curIndex) == ' ' || pageContents.charAt(curIndex) == '\n') { + while (curIndex < pageContents.length()) { + if (pageContents.charAt(curIndex) == ' ' || pageContents.charAt(curIndex) == '\n') { curIndex++; } else { break; 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 ef99b7382..19425a0c3 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 @@ -388,10 +388,15 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi { @Override @NonNull - public UploadResult uploadFile(String filename, InputStream file, long dataLength, String pageContents, String editSummary, final ProgressListener progressListener) throws IOException { + public UploadResult uploadFile(String filename, + @NonNull InputStream file, + long dataLength, + String pageContents, + String editSummary, + final ProgressListener progressListener) throws IOException { ApiResult result = api.upload(filename, file, dataLength, pageContents, editSummary, progressListener::onProgress); - Log.e("WTF", "Result: " +result.toString()); + Log.e("WTF", "Result: " + result.toString()); String resultStatus = result.getString("/api/upload/@result"); if (!resultStatus.equals("Success")) { diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java index c8693a76f..28cd9820b 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java @@ -5,9 +5,7 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; -import android.location.LocationManager; import android.net.Uri; -import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.preference.PreferenceManager; @@ -30,34 +28,42 @@ import com.google.gson.GsonBuilder; import java.util.List; import javax.inject.Inject; -import javax.inject.Named; import butterknife.BindView; import butterknife.ButterKnife; import fr.free.nrw.commons.R; import fr.free.nrw.commons.location.LatLng; import fr.free.nrw.commons.location.LocationServiceManager; +import fr.free.nrw.commons.location.LocationUpdateListener; import fr.free.nrw.commons.theme.NavigationBaseActivity; import fr.free.nrw.commons.utils.UriSerializer; +import fr.free.nrw.commons.utils.ViewUtil; +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; import timber.log.Timber; -public class NearbyActivity extends NavigationBaseActivity { - @BindView(R.id.progressBar) - ProgressBar progressBar; - @Inject NearbyPlaces nearbyPlaces; - @Inject @Named("default_preferences") SharedPreferences prefs; +public class NearbyActivity extends NavigationBaseActivity implements LocationUpdateListener { - private boolean isMapViewActive = false; private static final int LOCATION_REQUEST = 1; private static final String MAP_LAST_USED_PREFERENCE = "mapLastUsed"; - private LocationServiceManager locationManager; + @BindView(R.id.progressBar) + ProgressBar progressBar; + + @Inject + LocationServiceManager locationManager; + @Inject + NearbyController nearbyController; + private LatLng curLatLang; private Bundle bundle; - private NearbyAsyncTask nearbyAsyncTask; private SharedPreferences sharedPreferences; private NearbyActivityMode viewMode; + private Disposable placesDisposable; + private boolean lockNearbyView; //Determines if the nearby places needs to be refreshed @Override protected void onCreate(Bundle savedInstanceState) { @@ -97,7 +103,8 @@ public class NearbyActivity extends NavigationBaseActivity { // Handle item selection switch (item.getItemId()) { case R.id.action_refresh: - refreshView(); + lockNearbyView = false; + refreshView(true); return true; case R.id.action_toggle_view: viewMode = viewMode.toggle(); @@ -109,19 +116,11 @@ public class NearbyActivity extends NavigationBaseActivity { } } - private void startLookingForNearby() { - locationManager = new LocationServiceManager(this); - locationManager.registerLocationManager(); - curLatLang = locationManager.getLatestLocation(); - nearbyAsyncTask = new NearbyAsyncTask(this, new NearbyController(nearbyPlaces, prefs)); - nearbyAsyncTask.execute(); - } - private void checkLocationPermission() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { - startLookingForNearby(); + refreshView(false); } else { if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) @@ -162,7 +161,7 @@ public class NearbyActivity extends NavigationBaseActivity { } } } else { - startLookingForNearby(); + refreshView(false); } } @@ -171,16 +170,10 @@ public class NearbyActivity extends NavigationBaseActivity { switch (requestCode) { case LOCATION_REQUEST: { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - startLookingForNearby(); + refreshView(false); } else { //If permission not granted, go to page that says Nearby Places cannot be displayed - if (nearbyAsyncTask != null) { - nearbyAsyncTask.cancel(true); - } - if (progressBar != null) { - progressBar.setVisibility(View.GONE); - } - + hideProgressBar(); showLocationPermissionDeniedErrorDialog(); } } @@ -205,8 +198,7 @@ public class NearbyActivity extends NavigationBaseActivity { } private void checkGps() { - LocationManager manager = (LocationManager) getSystemService(LOCATION_SERVICE); - if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { + if (!locationManager.isProviderEnabled()) { Timber.d("GPS is not enabled"); new AlertDialog.Builder(this) .setMessage(R.string.gps_disabled) @@ -231,104 +223,106 @@ public class NearbyActivity extends NavigationBaseActivity { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 1) { Timber.d("User is back from Settings page"); - refreshView(); + refreshView(false); } } private void toggleView() { - if (nearbyAsyncTask != null) { - if (nearbyAsyncTask.getStatus() == AsyncTask.Status.FINISHED) { - if (viewMode.isMap()) { - setMapFragment(); - } else { - setListFragment(); - } - } - sharedPreferences.edit().putBoolean(MAP_LAST_USED_PREFERENCE, viewMode.isMap()).apply(); + if (viewMode.isMap()) { + setMapFragment(); + } else { + setListFragment(); + } + sharedPreferences.edit().putBoolean(MAP_LAST_USED_PREFERENCE, viewMode.isMap()).apply(); + } + + @Override + protected void onStart() { + super.onStart(); + locationManager.registerLocationManager(); + locationManager.addLocationListener(this); + } + + @Override + protected void onStop() { + super.onStop(); + locationManager.removeLocationListener(this); + locationManager.unregisterLocationManager(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (placesDisposable != null) { + placesDisposable.dispose(); } } @Override protected void onResume() { super.onResume(); + lockNearbyView = false; checkGps(); + refreshView(false); } - @Override - protected void onPause() { - super.onPause(); - if (nearbyAsyncTask != null) { - nearbyAsyncTask.cancel(true); + private void refreshView(boolean isHardRefresh) { + if (lockNearbyView) { + return; } + LatLng lastLocation = locationManager.getLastLocation(); + if (curLatLang != null && curLatLang.equals(lastLocation)) { //refresh view only if location has changed + if (isHardRefresh) { + ViewUtil.showLongToast(this, R.string.nearby_location_has_not_changed); + } + return; + } + curLatLang = lastLocation; + + if (curLatLang == null) { + Timber.d("Skipping update of nearby places as location is unavailable"); + return; + } + + progressBar.setVisibility(View.VISIBLE); + placesDisposable = Observable.fromCallable(() -> nearbyController + .loadAttractionsFromLocation(curLatLang, this)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(this::populatePlaces); } - private void refreshView() { - nearbyAsyncTask = new NearbyAsyncTask(this, new NearbyController(nearbyPlaces, prefs)); - nearbyAsyncTask.execute(); + private void populatePlaces(List placeList) { + Gson gson = new GsonBuilder() + .registerTypeAdapter(Uri.class, new UriSerializer()) + .create(); + String gsonPlaceList = gson.toJson(placeList); + String gsonCurLatLng = gson.toJson(curLatLang); + + if (placeList.size() == 0) { + int duration = Toast.LENGTH_SHORT; + Toast toast = Toast.makeText(this, R.string.no_nearby, duration); + toast.show(); + } + + bundle.clear(); + bundle.putString("PlaceList", gsonPlaceList); + bundle.putString("CurLatLng", gsonCurLatLng); + + lockNearbyView = true; + // Begin the transaction + if (viewMode.isMap()) { + setMapFragment(); + } else { + setListFragment(); + } + + hideProgressBar(); } - @Override - protected void onDestroy() { - super.onDestroy(); - if (locationManager != null) { - locationManager.unregisterLocationManager(); - } - } - - private class NearbyAsyncTask extends AsyncTask> { - - private final Context mContext; - private final NearbyController nearbyController; - - private NearbyAsyncTask(Context context, NearbyController nearbyController) { - this.mContext = context; - this.nearbyController = nearbyController; - } - - @Override - protected void onProgressUpdate(Integer... values) { - super.onProgressUpdate(values); - } - - @Override - protected List doInBackground(Void... params) { - return nearbyController.loadAttractionsFromLocation(curLatLang, NearbyActivity.this); - } - - @Override - protected void onPostExecute(List placeList) { - super.onPostExecute(placeList); - - if (isCancelled()) { - return; - } - - Gson gson = new GsonBuilder() - .registerTypeAdapter(Uri.class, new UriSerializer()) - .create(); - String gsonPlaceList = gson.toJson(placeList); - String gsonCurLatLng = gson.toJson(curLatLang); - - if (placeList.size() == 0) { - int duration = Toast.LENGTH_SHORT; - Toast toast = Toast.makeText(mContext, R.string.no_nearby, duration); - toast.show(); - } - - bundle.clear(); - bundle.putString("PlaceList", gsonPlaceList); - bundle.putString("CurLatLng", gsonCurLatLng); - - // Begin the transaction - if (viewMode.isMap()) { - setMapFragment(); - } else { - setListFragment(); - } - - if (progressBar != null) { - progressBar.setVisibility(View.GONE); - } + private void hideProgressBar() { + if (progressBar != null) { + progressBar.setVisibility(View.GONE); } } @@ -354,8 +348,8 @@ public class NearbyActivity extends NavigationBaseActivity { fragmentTransaction.commitAllowingStateLoss(); } - public static void startYourself(Context context) { - Intent settingsIntent = new Intent(context, NearbyActivity.class); - context.startActivity(settingsIntent); + @Override + public void onLocationChanged(LatLng latLng) { + refreshView(false); } } diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyController.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyController.java index f1be66d00..624a0de0f 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyController.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyController.java @@ -14,6 +14,9 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import javax.inject.Inject; +import javax.inject.Named; + import fr.free.nrw.commons.R; import fr.free.nrw.commons.location.LatLng; import fr.free.nrw.commons.utils.UiUtils; @@ -22,13 +25,14 @@ import timber.log.Timber; import static fr.free.nrw.commons.utils.LengthUtils.computeDistanceBetween; import static fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween; - public class NearbyController { private static final int MAX_RESULTS = 1000; private final NearbyPlaces nearbyPlaces; private final SharedPreferences prefs; - public NearbyController(NearbyPlaces nearbyPlaces, SharedPreferences prefs) { + @Inject + public NearbyController(NearbyPlaces nearbyPlaces, + @Named("default_preferences") SharedPreferences prefs) { this.nearbyPlaces = nearbyPlaces; this.prefs = prefs; } diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyPlaces.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyPlaces.java index 50d661ef6..de14a2ef8 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyPlaces.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyPlaces.java @@ -46,7 +46,7 @@ public class NearbyPlaces { try { // increase the radius gradually to find a satisfactory number of nearby places - while (radius < MAX_RADIUS) { + while (radius <= MAX_RADIUS) { places = getFromWikidataQuery(curLatLng, lang, radius); Timber.d("%d results at radius: %f", places.size(), radius); if (places.size() >= MIN_RESULTS) { @@ -62,6 +62,11 @@ public class NearbyPlaces { Timber.d("back to initial radius: %f", radius); radius = INITIAL_RADIUS; } + // make sure we will be able to send at least one request next time + if (radius > MAX_RADIUS) { + radius = MAX_RADIUS; + } + return places; } diff --git a/app/src/main/java/fr/free/nrw/commons/settings/SettingsActivity.java b/app/src/main/java/fr/free/nrw/commons/settings/SettingsActivity.java index 5814ec904..d731c70d1 100644 --- a/app/src/main/java/fr/free/nrw/commons/settings/SettingsActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/settings/SettingsActivity.java @@ -1,7 +1,5 @@ package fr.free.nrw.commons.settings; -import android.content.Context; -import android.content.Intent; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v7.app.AppCompatDelegate; @@ -54,9 +52,4 @@ public class SettingsActivity extends NavigationBaseActivity { return super.onOptionsItemSelected(item); } } - - public static void startYourself(Context context) { - Intent settingsIntent = new Intent(context, SettingsActivity.class); - context.startActivity(settingsIntent); - } } \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java b/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java index 9422d0b25..a78bb8bbb 100644 --- a/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java @@ -1,23 +1,41 @@ package fr.free.nrw.commons.settings; +import android.Manifest; import android.app.AlertDialog; +import android.content.ActivityNotFoundException; import android.content.Context; +import android.content.Intent; import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.preference.CheckBoxPreference; import android.preference.EditTextPreference; import android.preference.ListPreference; +import android.preference.Preference; import android.preference.PreferenceFragment; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.support.v4.content.FileProvider; +import android.widget.Toast; + +import java.io.File; import javax.inject.Inject; import javax.inject.Named; import dagger.android.AndroidInjection; +import fr.free.nrw.commons.BuildConfig; +import fr.free.nrw.commons.CommonsApplication; import fr.free.nrw.commons.R; import fr.free.nrw.commons.Utils; +import fr.free.nrw.commons.utils.FileUtils; public class SettingsFragment extends PreferenceFragment { + private static final int REQUEST_CODE_WRITE_EXTERNAL_STORAGE = 100; + @Inject @Named("default_preferences") SharedPreferences prefs; @Override @@ -76,6 +94,63 @@ public class SettingsFragment extends PreferenceFragment { return true; }); + Preference sendLogsPreference = findPreference("sendLogFile"); + sendLogsPreference.setOnPreferenceClickListener(preference -> { + //first we need to check if we have the necessary permissions + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (ContextCompat.checkSelfPermission( + getActivity(), + Manifest.permission.WRITE_EXTERNAL_STORAGE) + == + PackageManager.PERMISSION_GRANTED) { + sendAppLogsViaEmail(); + } else { + //first get the necessary permission + requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, + REQUEST_CODE_WRITE_EXTERNAL_STORAGE); + } + } else { + sendAppLogsViaEmail(); + } + return true; + }); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == REQUEST_CODE_WRITE_EXTERNAL_STORAGE) { + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + sendAppLogsViaEmail(); + } + } + } + + private void sendAppLogsViaEmail() { + String appLogs = Utils.getAppLogs(); + File appLogsFile = FileUtils.createAndGetAppLogsFile(appLogs); + + Context applicationContext = getActivity().getApplicationContext(); + Uri appLogsFilePath = FileProvider.getUriForFile( + getActivity(), + applicationContext.getPackageName() + ".provider", + appLogsFile + ); + + Intent feedbackIntent = new Intent(Intent.ACTION_SEND); + feedbackIntent.setType("message/rfc822"); + feedbackIntent.putExtra(Intent.EXTRA_EMAIL, + new String[]{CommonsApplication.FEEDBACK_EMAIL}); + feedbackIntent.putExtra(Intent.EXTRA_SUBJECT, + String.format(CommonsApplication.FEEDBACK_EMAIL_SUBJECT, + BuildConfig.VERSION_NAME)); + feedbackIntent.putExtra(Intent.EXTRA_STREAM,appLogsFilePath); + + try { + startActivity(feedbackIntent); + } catch (ActivityNotFoundException e) { + Toast.makeText(getActivity(), R.string.no_email_client, Toast.LENGTH_SHORT).show(); + } } } diff --git a/app/src/main/java/fr/free/nrw/commons/theme/BaseActivity.java b/app/src/main/java/fr/free/nrw/commons/theme/BaseActivity.java index 3f4bfba33..f08496914 100644 --- a/app/src/main/java/fr/free/nrw/commons/theme/BaseActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/theme/BaseActivity.java @@ -13,7 +13,7 @@ public abstract class BaseActivity extends DaggerAppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { boolean currentThemeIsDark = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("theme", false); - if (currentThemeIsDark) { + if (currentThemeIsDark){ currentTheme = true; setTheme(R.style.DarkAppTheme); } else { diff --git a/app/src/main/java/fr/free/nrw/commons/theme/NavigationBaseActivity.java b/app/src/main/java/fr/free/nrw/commons/theme/NavigationBaseActivity.java index 3537e4a1d..60ea325e4 100644 --- a/app/src/main/java/fr/free/nrw/commons/theme/NavigationBaseActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/theme/NavigationBaseActivity.java @@ -1,6 +1,9 @@ package fr.free.nrw.commons.theme; +import android.accounts.Account; +import android.accounts.AccountManager; import android.content.ActivityNotFoundException; +import android.content.Context; import android.content.Intent; import android.support.annotation.NonNull; import android.support.design.widget.NavigationView; @@ -9,7 +12,9 @@ import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.app.AlertDialog; import android.support.v7.widget.Toolbar; import android.view.MenuItem; +import android.view.View; import android.view.ViewGroup; +import android.widget.TextView; import android.widget.Toast; import butterknife.BindView; @@ -18,6 +23,7 @@ import fr.free.nrw.commons.BuildConfig; import fr.free.nrw.commons.CommonsApplication; import fr.free.nrw.commons.R; import fr.free.nrw.commons.WelcomeActivity; +import fr.free.nrw.commons.auth.AccountUtil; import fr.free.nrw.commons.auth.LoginActivity; import fr.free.nrw.commons.contributions.ContributionsActivity; import fr.free.nrw.commons.nearby.NearbyActivity; @@ -47,6 +53,22 @@ public abstract class NavigationBaseActivity extends BaseActivity toggle.setDrawerIndicatorEnabled(true); toggle.syncState(); setDrawerPaneWidth(); + setUserName(); + } + + /** + * Set the username in navigationHeader. + */ + private void setUserName() { + + View navHeaderView = navigationView.getHeaderView(0); + TextView username = navHeaderView.findViewById(R.id.username); + + AccountManager accountManager = AccountManager.get(this); + Account[] allAccounts = accountManager.getAccountsByType(AccountUtil.ACCOUNT_TYPE); + if (allAccounts.length != 0) { + username.setText(allAccounts[0].name); + } } public void initBackButton() { @@ -70,30 +92,25 @@ public abstract class NavigationBaseActivity extends BaseActivity @Override public boolean onNavigationItemSelected(@NonNull final MenuItem item) { - switch (item.getItemId()) { + final int itemId = item.getItemId(); + switch (itemId) { case R.id.action_home: drawerLayout.closeDrawer(navigationView); - if (!(this instanceof ContributionsActivity)) { - ContributionsActivity.startYourself(this); - } + startActivityWithFlags( + this, ContributionsActivity.class, Intent.FLAG_ACTIVITY_CLEAR_TOP, + Intent.FLAG_ACTIVITY_SINGLE_TOP); return true; case R.id.action_nearby: drawerLayout.closeDrawer(navigationView); - if (!(this instanceof NearbyActivity)) { - NearbyActivity.startYourself(this); - } + startActivityWithFlags(this, NearbyActivity.class, Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); return true; case R.id.action_about: drawerLayout.closeDrawer(navigationView); - if (!(this instanceof AboutActivity)) { - AboutActivity.startYourself(this); - } + startActivityWithFlags(this, AboutActivity.class, Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); return true; case R.id.action_settings: drawerLayout.closeDrawer(navigationView); - if (!(this instanceof SettingsActivity)) { - SettingsActivity.startYourself(this); - } + startActivityWithFlags(this, SettingsActivity.class, Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); return true; case R.id.action_introduction: drawerLayout.closeDrawer(navigationView); @@ -127,6 +144,7 @@ public abstract class NavigationBaseActivity extends BaseActivity .show(); return true; default: + Timber.e("Unknown option [%s] selected from the navigation menu", itemId); return false; } } @@ -143,4 +161,12 @@ public abstract class NavigationBaseActivity extends BaseActivity finish(); } } + + public static void startActivityWithFlags(Context context, Class cls, int... flags) { + Intent intent = new Intent(context, cls); + for (int flag: flags) { + intent.addFlags(flag); + } + context.startActivity(intent); + } } diff --git a/app/src/main/java/fr/free/nrw/commons/upload/FileUtils.java b/app/src/main/java/fr/free/nrw/commons/upload/FileUtils.java index a20aa6186..6d304aa07 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/FileUtils.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/FileUtils.java @@ -123,8 +123,9 @@ public class FileUtils { } catch (IllegalArgumentException e) { Timber.d(e); } finally { - if (cursor != null) + if (cursor != null) { cursor.close(); + } } return null; } diff --git a/app/src/main/java/fr/free/nrw/commons/upload/GPSExtractor.java b/app/src/main/java/fr/free/nrw/commons/upload/GPSExtractor.java index 340598678..404177032 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/GPSExtractor.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/GPSExtractor.java @@ -224,7 +224,7 @@ public class GPSExtractor { return decimalCoords; } - private double convertToDegree(String stringDMS){ + private double convertToDegree(String stringDMS) { double result; String[] DMS = stringDMS.split(",", 3); 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 index f4cf5eecb..a530e79e6 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/MwVolleyApi.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/MwVolleyApi.java @@ -69,7 +69,7 @@ public class MwVolleyApi { * @param coords Coordinates to build query with * @return URL for API query */ - private String buildUrl (String coords){ + private String buildUrl(String coords) { Uri.Builder builder = Uri.parse(MWURL).buildUpon(); diff --git a/app/src/main/java/fr/free/nrw/commons/upload/UploadController.java b/app/src/main/java/fr/free/nrw/commons/upload/UploadController.java index 79648258a..1d080e78f 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/UploadController.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/UploadController.java @@ -65,7 +65,7 @@ public class UploadController { } public void cleanup() { - if(isUploadServiceConnected) { + if (isUploadServiceConnected) { context.unbindService(uploadServiceConnection); } } @@ -87,11 +87,11 @@ public class UploadController { public void startUpload(final Contribution contribution, final ContributionUploadProgress onComplete) { //Set creator, desc, and license - if(TextUtils.isEmpty(contribution.getCreator())) { + if (TextUtils.isEmpty(contribution.getCreator())) { contribution.setCreator(sessionManager.getCurrentAccount().name); } - if(contribution.getDescription() == null) { + if (contribution.getDescription() == null) { contribution.setDescription(""); } @@ -109,11 +109,11 @@ public class UploadController { long length; ContentResolver contentResolver = context.getContentResolver(); try { - if(contribution.getDataLength() <= 0) { + if (contribution.getDataLength() <= 0) { length = contentResolver .openAssetFileDescriptor(contribution.getLocalUri(), "r") .getLength(); - if(length == -1) { + if (length == -1) { // Let us find out the long way! length = countBytes(contentResolver .openInputStream(contribution.getLocalUri())); diff --git a/app/src/main/java/fr/free/nrw/commons/upload/UploadService.java b/app/src/main/java/fr/free/nrw/commons/upload/UploadService.java index 5fa7c1902..215819d12 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/UploadService.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/UploadService.java @@ -185,7 +185,7 @@ public class UploadService extends HandlerService { @SuppressLint("StringFormatInvalid") private void uploadContribution(Contribution contribution) { - InputStream file = null; + InputStream file; String notificationTag = contribution.getLocalUri().toString(); @@ -196,6 +196,14 @@ public class UploadService extends HandlerService { Timber.d("File not found"); Toast fileNotFound = Toast.makeText(this, R.string.upload_failed, Toast.LENGTH_LONG); fileNotFound.show(); + return; + } + + //As the file is null there's no point in continuing the upload process + //mwapi.upload accepts a NonNull input stream + if(file == null) { + Timber.d("File not found"); + return; } Timber.d("Before execution!"); diff --git a/app/src/main/java/fr/free/nrw/commons/utils/ExecutorUtils.java b/app/src/main/java/fr/free/nrw/commons/utils/ExecutorUtils.java index df67cfea7..15f18ee5e 100644 --- a/app/src/main/java/fr/free/nrw/commons/utils/ExecutorUtils.java +++ b/app/src/main/java/fr/free/nrw/commons/utils/ExecutorUtils.java @@ -15,6 +15,6 @@ public class ExecutorUtils { } }; - public static Executor uiExecutor () { return uiExecutor;} + public static Executor uiExecutor() { return uiExecutor; } } diff --git a/app/src/main/java/fr/free/nrw/commons/utils/FileUtils.java b/app/src/main/java/fr/free/nrw/commons/utils/FileUtils.java index 1c816b9e1..4191f9d6f 100644 --- a/app/src/main/java/fr/free/nrw/commons/utils/FileUtils.java +++ b/app/src/main/java/fr/free/nrw/commons/utils/FileUtils.java @@ -1,11 +1,16 @@ package fr.free.nrw.commons.utils; +import android.os.Environment; + import java.io.BufferedReader; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; +import java.io.OutputStreamWriter; import fr.free.nrw.commons.CommonsApplication; +import timber.log.Timber; public class FileUtils { /** @@ -53,5 +58,32 @@ public class FileUtils { return deletedAll; } + public static File createAndGetAppLogsFile(String logs) { + try { + File commonsAppDirectory = new File(Environment.getExternalStorageDirectory().toString() + "/CommonsApp"); + if (!commonsAppDirectory.exists()) { + commonsAppDirectory.mkdir(); + } + File logsFile = new File(commonsAppDirectory,"logs.txt"); + if (logsFile.exists()) { + //old logs file is useless + logsFile.delete(); + } + + logsFile.createNewFile(); + + FileOutputStream outputStream = new FileOutputStream(logsFile); + OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream); + outputStreamWriter.append(logs); + outputStreamWriter.close(); + outputStream.flush(); + outputStream.close(); + + return logsFile; + } catch (IOException ioe) { + Timber.e(ioe); + return null; + } + } } diff --git a/app/src/main/java/fr/free/nrw/commons/utils/FragmentUtils.java b/app/src/main/java/fr/free/nrw/commons/utils/FragmentUtils.java index aa79513e8..d0e432c33 100644 --- a/app/src/main/java/fr/free/nrw/commons/utils/FragmentUtils.java +++ b/app/src/main/java/fr/free/nrw/commons/utils/FragmentUtils.java @@ -23,8 +23,8 @@ public class FragmentUtils { .commitNow(); return true; } catch (IllegalStateException e) { - Timber.e(e, "Could not add & commit fragment. " + - "Did you mean to call commitAllowingStateLoss?"); + Timber.e(e, "Could not add & commit fragment. " + + "Did you mean to call commitAllowingStateLoss?"); } return false; } diff --git a/app/src/main/java/fr/free/nrw/commons/utils/ViewUtil.java b/app/src/main/java/fr/free/nrw/commons/utils/ViewUtil.java new file mode 100644 index 000000000..947c70eb6 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/utils/ViewUtil.java @@ -0,0 +1,17 @@ +package fr.free.nrw.commons.utils; + +import android.content.Context; +import android.support.annotation.StringRes; +import android.widget.Toast; + +public class ViewUtil { + + public static void showLongToast(final Context context, @StringRes final int stringResId) { + ExecutorUtils.uiExecutor().execute(new Runnable() { + @Override + public void run() { + Toast.makeText(context, context.getString(stringResId), Toast.LENGTH_LONG).show(); + } + }); + } +} diff --git a/app/src/main/res/drawable-hdpi/welcome_copyright.png b/app/src/main/res/drawable-hdpi/welcome_copyright.png deleted file mode 100644 index 48f90bfde..000000000 Binary files a/app/src/main/res/drawable-hdpi/welcome_copyright.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/welcome_copyright.webp b/app/src/main/res/drawable-hdpi/welcome_copyright.webp new file mode 100644 index 000000000..34b5327cf Binary files /dev/null and b/app/src/main/res/drawable-hdpi/welcome_copyright.webp differ diff --git a/app/src/main/res/drawable-hdpi/welcome_wikipedia.png b/app/src/main/res/drawable-hdpi/welcome_wikipedia.png deleted file mode 100644 index 6e1a8ae8c..000000000 Binary files a/app/src/main/res/drawable-hdpi/welcome_wikipedia.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/welcome_wikipedia.webp b/app/src/main/res/drawable-hdpi/welcome_wikipedia.webp new file mode 100644 index 000000000..96ce4e276 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/welcome_wikipedia.webp differ diff --git a/app/src/main/res/drawable-ldpi/welcome_copyright.png b/app/src/main/res/drawable-ldpi/welcome_copyright.png deleted file mode 100644 index 6cdf2520e..000000000 Binary files a/app/src/main/res/drawable-ldpi/welcome_copyright.png and /dev/null differ diff --git a/app/src/main/res/drawable-ldpi/welcome_copyright.webp b/app/src/main/res/drawable-ldpi/welcome_copyright.webp new file mode 100644 index 000000000..c1bd8a976 Binary files /dev/null and b/app/src/main/res/drawable-ldpi/welcome_copyright.webp differ diff --git a/app/src/main/res/drawable-ldpi/welcome_wikipedia.png b/app/src/main/res/drawable-ldpi/welcome_wikipedia.png deleted file mode 100644 index e55b56421..000000000 Binary files a/app/src/main/res/drawable-ldpi/welcome_wikipedia.png and /dev/null differ diff --git a/app/src/main/res/drawable-ldpi/welcome_wikipedia.webp b/app/src/main/res/drawable-ldpi/welcome_wikipedia.webp new file mode 100644 index 000000000..dd8090b75 Binary files /dev/null and b/app/src/main/res/drawable-ldpi/welcome_wikipedia.webp differ diff --git a/app/src/main/res/drawable-mdpi/welcome_copyright.png b/app/src/main/res/drawable-mdpi/welcome_copyright.png deleted file mode 100644 index 65462b967..000000000 Binary files a/app/src/main/res/drawable-mdpi/welcome_copyright.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/welcome_copyright.webp b/app/src/main/res/drawable-mdpi/welcome_copyright.webp new file mode 100644 index 000000000..69e238747 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/welcome_copyright.webp differ diff --git a/app/src/main/res/drawable-mdpi/welcome_wikipedia.png b/app/src/main/res/drawable-mdpi/welcome_wikipedia.png deleted file mode 100644 index 8d1e8e322..000000000 Binary files a/app/src/main/res/drawable-mdpi/welcome_wikipedia.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/welcome_wikipedia.webp b/app/src/main/res/drawable-mdpi/welcome_wikipedia.webp new file mode 100644 index 000000000..5a50f5757 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/welcome_wikipedia.webp differ diff --git a/app/src/main/res/drawable-xhdpi/welcome_copyright.png b/app/src/main/res/drawable-xhdpi/welcome_copyright.png deleted file mode 100644 index 973fb4598..000000000 Binary files a/app/src/main/res/drawable-xhdpi/welcome_copyright.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/welcome_copyright.webp b/app/src/main/res/drawable-xhdpi/welcome_copyright.webp new file mode 100644 index 000000000..2feb197d2 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/welcome_copyright.webp differ diff --git a/app/src/main/res/drawable-xhdpi/welcome_wikipedia.png b/app/src/main/res/drawable-xhdpi/welcome_wikipedia.png deleted file mode 100644 index 2f8dfb364..000000000 Binary files a/app/src/main/res/drawable-xhdpi/welcome_wikipedia.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/welcome_wikipedia.webp b/app/src/main/res/drawable-xhdpi/welcome_wikipedia.webp new file mode 100644 index 000000000..48e83d760 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/welcome_wikipedia.webp differ diff --git a/app/src/main/res/drawable/empty_photo.png b/app/src/main/res/drawable/empty_photo.png deleted file mode 100644 index 2ad718194..000000000 Binary files a/app/src/main/res/drawable/empty_photo.png and /dev/null differ diff --git a/app/src/main/res/drawable/empty_photo.webp b/app/src/main/res/drawable/empty_photo.webp new file mode 100644 index 000000000..3f749936a Binary files /dev/null and b/app/src/main/res/drawable/empty_photo.webp differ diff --git a/app/src/main/res/drawable/llamas.png b/app/src/main/res/drawable/llamas.png deleted file mode 100644 index fc3e258d5..000000000 Binary files a/app/src/main/res/drawable/llamas.png and /dev/null differ diff --git a/app/src/main/res/drawable/llamas.webp b/app/src/main/res/drawable/llamas.webp new file mode 100644 index 000000000..6e9b013d6 Binary files /dev/null and b/app/src/main/res/drawable/llamas.webp differ diff --git a/app/src/main/res/drawable/mount_zao.png b/app/src/main/res/drawable/mount_zao.png deleted file mode 100644 index 86b98661e..000000000 Binary files a/app/src/main/res/drawable/mount_zao.png and /dev/null differ diff --git a/app/src/main/res/drawable/mount_zao.webp b/app/src/main/res/drawable/mount_zao.webp new file mode 100644 index 000000000..83fd07b30 Binary files /dev/null and b/app/src/main/res/drawable/mount_zao.webp differ diff --git a/app/src/main/res/drawable/rainbow_bridge.png b/app/src/main/res/drawable/rainbow_bridge.png deleted file mode 100644 index a3f78efe6..000000000 Binary files a/app/src/main/res/drawable/rainbow_bridge.png and /dev/null differ diff --git a/app/src/main/res/drawable/rainbow_bridge.webp b/app/src/main/res/drawable/rainbow_bridge.webp new file mode 100644 index 000000000..890ebbca5 Binary files /dev/null and b/app/src/main/res/drawable/rainbow_bridge.webp differ diff --git a/app/src/main/res/drawable/selfie_x.png b/app/src/main/res/drawable/selfie_x.png deleted file mode 100644 index c049e2f18..000000000 Binary files a/app/src/main/res/drawable/selfie_x.png and /dev/null differ diff --git a/app/src/main/res/drawable/selfie_x.webp b/app/src/main/res/drawable/selfie_x.webp new file mode 100644 index 000000000..35c6c0c25 Binary files /dev/null and b/app/src/main/res/drawable/selfie_x.webp differ diff --git a/app/src/main/res/drawable/sydney_opera_house.png b/app/src/main/res/drawable/sydney_opera_house.png deleted file mode 100644 index fc1009cd1..000000000 Binary files a/app/src/main/res/drawable/sydney_opera_house.png and /dev/null differ diff --git a/app/src/main/res/drawable/sydney_opera_house.webp b/app/src/main/res/drawable/sydney_opera_house.webp new file mode 100644 index 000000000..fd7453004 Binary files /dev/null and b/app/src/main/res/drawable/sydney_opera_house.webp differ diff --git a/app/src/main/res/drawable/tulip.png b/app/src/main/res/drawable/tulip.png deleted file mode 100644 index 6467a0701..000000000 Binary files a/app/src/main/res/drawable/tulip.png and /dev/null differ diff --git a/app/src/main/res/drawable/tulip.webp b/app/src/main/res/drawable/tulip.webp new file mode 100644 index 000000000..21a8a21df Binary files /dev/null and b/app/src/main/res/drawable/tulip.webp differ diff --git a/app/src/main/res/layout-land/activity_login.xml b/app/src/main/res/layout-land/activity_login.xml index d96106f18..7265ba671 100644 --- a/app/src/main/res/layout-land/activity_login.xml +++ b/app/src/main/res/layout-land/activity_login.xml @@ -137,6 +137,7 @@ + + + + + + diff --git a/app/src/main/res/layout-xlarge/activity_login.xml b/app/src/main/res/layout-xlarge/activity_login.xml index c6293fbe3..90bef2423 100644 --- a/app/src/main/res/layout-xlarge/activity_login.xml +++ b/app/src/main/res/layout-xlarge/activity_login.xml @@ -137,6 +137,7 @@ + + + + + + diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index 660e02ecf..b1bc7152d 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -137,6 +137,7 @@ + + + + + + diff --git a/app/src/main/res/layout/drawer_header.xml b/app/src/main/res/layout/drawer_header.xml index 5ea1160d9..c27cab1ba 100644 --- a/app/src/main/res/layout/drawer_header.xml +++ b/app/src/main/res/layout/drawer_header.xml @@ -1,8 +1,28 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_contributions.xml b/app/src/main/res/layout/fragment_contributions.xml index 2be422005..fa53d9721 100644 --- a/app/src/main/res/layout/fragment_contributions.xml +++ b/app/src/main/res/layout/fragment_contributions.xml @@ -1,5 +1,6 @@ - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 9700f1bb1..a48a39660 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -20,7 +20,10 @@ اكتمال رفع %1$s فشل رفع %1$s انقر لتشاهد - متبقى %d + + %d رفع ملف + %d رفع ملفات + مرفوعاتي الأخيرة في قائمة الانتظار فشل @@ -39,6 +42,7 @@ لا يمكن تسجيل الدخول - فضلا تحقق من كلمة السر الكثير من المحاولات غير الناجحة. الرجاء المحاولة مرة أخرى في بضع دقائق. عذراً، لقد تم منع هذا المستخدم على كومنز + يجب توفير رمز التحقق المزدوج. فشل تسجيل الدخول ارفع اسم هذه المجموعة @@ -47,6 +51,7 @@ تصنيفات البحث احفظ أنعش + عطل نظام الملاحة العالمي GPS بجهازك. أترغب في التنشيط؟ تفعيل GPS لا مرفوعات بعد لا توجد تصنيفات تطابق %1$s @@ -61,6 +66,7 @@ <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\">CREDITS</a> حول إرسال ملاحظات (عبر البريد الإلكتروني) + عميل البريد الإلكتروني غير مثبت التصانيف المستخدمة مؤخرا ينتظر أول مزامنة… لم ترفع بعد أية صور. @@ -70,6 +76,10 @@ نزّل الرخصة الوضع الليلي + استخدم النمط الغامق + الرجاء عدم رفع + - صور ذاتية أو صور لأصدقاء\n- صور محملة من الانترنت\n- لقطات شاشة ذات ملكية خاصة + مثال رفع: ساهم بصورك. أنعش مقالات ويكيبيديا! تأتي صور ويكيبيديا من ويكيميديا كومنز. صورك تساعد الناس في شتى أنحاء العالم على التعلم. @@ -84,16 +94,26 @@ تحديث موافق الأماكن القريبة + الأماكن القريبة غير متوفرة تحذير نعم لا العنوان عنوان الوسيط الوصف + تاريخ الرفع الترخيص الإحداثيات + غير متوفر + انضم لمختبري اصدارات Beta (بيتا) استخدم ويكي بيانات + رمز التحقق المزدوج 2FA + حد الرفع الحالي الحد الأقصى + لا يمكن عرض أكثر من 500 + تحديد حد الرفع الحالي + التحقق المزدودج 2FA غير مدعوم حاليا + أترغب فعلا في الخروج؟ الرئيسية رفع بالقرب من هنا diff --git a/app/src/main/res/values-ast/strings.xml b/app/src/main/res/values-ast/strings.xml index 0a9e52d6e..9bca1524a 100644 --- a/app/src/main/res/values-ast/strings.xml +++ b/app/src/main/res/values-ast/strings.xml @@ -73,9 +73,9 @@ Configuración Date d\'alta Tocante a - Software de códigu abiertu lliberáu baxo la <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/COPYING\">Llicencia Apache v2</a>. %1$s ya\'l so logotipu son marques rexistraes de la Fundación Wikimedia y utilícense col so permisu. Nun tamos acreditaos pola Fundación Wikimedia nin tamos afiliaos con ella. + La app de Wikimedia Commons ye software de códigu abiertu, creáu y calteníu por becaos y voluntarios de la comunidá de Wikimedia. La Fundación Wikimedia nun participa na creación, desendolcu nin caltenimientu de la app. El <a href=\"https://github.com/commons-app/apps-android-commons\">códigu fonte</a> ya\'l <a href=\"https://commons-app.github.io/\">sitiu web</a> tán en GitHub. Crea una nueva <a href=\"https://github.com/commons-app/apps-android-commons/issues\">incidencia en GitHub</a> pa informar de problemes y suxerencies. - Wikimedia:Commons-android-strings-about privacy policy/ast + <a href=\"https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\">Política d\'intimidá</a> <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\">Créditos</a> Tocante a Unviar comentarios (per corréu) @@ -147,7 +147,7 @@ Títulu Títulu del mediu Descripción - Equí va la descripción del mediu. Posiblemente pué ser llargo enforma, y necesitará espardese per delles llinies. Sicasí, esperamos que se vea guapo. + Equí va la descripción del mediu. Esto pué ser llargo enforma, y necesitará espardese per delles llinies. Sicasí, esperamos que se vea bien. Data d\'unviu Llicencia Coordenaes @@ -198,4 +198,7 @@ Dar permisu Usar almacenamientu esternu Guardar nel preséu les imaxes tomaes cola cámara de la app + Unviar ficheru de rexistru + Unviar ficheru de rexistru a los desendolcadores per corréu electrónicu + Anicia sesión na to cuenta diff --git a/app/src/main/res/values-bn/strings.xml b/app/src/main/res/values-bn/strings.xml index f2c8ff2e6..4aaa0bcba 100644 --- a/app/src/main/res/values-bn/strings.xml +++ b/app/src/main/res/values-bn/strings.xml @@ -42,6 +42,7 @@ প্রবেশ করা যাচ্ছে না - অনুগ্রহ করে আপনার পাসওয়ার্ড পরীক্ষা করুন খুব বেশি অসফল প্রচেষ্টা। অনুগ্রহ করে কয়েক মিনিট পরে আবারও চেষ্টা করুন। দুঃখিত, এই ব্যবহারকারীকে কমন্সে বাধা দেয়া হয়েছে + অাপনাকে অবশ্যই অাপনার দু\'স্তরের সত্যায়নকরণ কোড দিতে হবে। প্রবেশ ব্যর্থ আপলোড এই সেটের নাম @@ -72,7 +73,7 @@ সেটিং নিবন্ধন করুন পরিচিতি - ওপেন সোর্স সফটওয়্যার <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/COPYING\">এ্যাপাচি লাইসেন্স v2</a> অধীনে প্রকাশিত + উইকিমিডিয়া কমন্স অ্যাপ হচ্ছে একটি উন্মুক্ত উৎস সম্বলিত অ্যাপ যা উইকিমিডিয়া সম্প্রদায়ের ব্যবহারকারী ও সেচ্ছাসেবকবৃন্দ কর্তৃক তৈরিকৃত এবং পরিচালিত। উইকিমিডিয়া ফাউন্ডেশন এই অ্যাপ তৈরি, উন্নয়ন বা রক্ষণাবেক্ষণে জড়িত নয়। <a href=\"https://github.com/commons-app/apps-android-commons\">উৎস</a> ও <a href=\"https://commons-app.github.io/\">ওয়েবসাইট</a> GitHub এ</a>। কোন সমস্যা ও পরামর্শের জন্য <a href=\"https://github.com/commons-app/apps-android-commons/issues\">গিটহাব ইস্যু</a> তৈরি করুন। <a href=\"https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\">গোপনীয়তার নীতি</a> <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\">কৃতিত্ব</a> @@ -134,6 +135,7 @@ অজানা লাইসেন্স পুনঃসতেজ প্রয়োজনীয় অনুমতি: বহিঃস্ত সঞ্চয়স্থান পড়া। এটি ছাড়া অ্যাপ কাজ করবে না। + অনুমতি প্রয়োজন: অালাদাভাবে সংযুক্ত স্টোরেজ লিখুন। এটি ছাড়া অ্যাপটি চলতে পারেনা। ঐচ্ছিক অনুমতি: বিষয়শ্রেণী পরামর্শের জন্য বর্তমান অবস্থান নেয় ঠিক আছে কাছাকাছি স্থান @@ -151,12 +153,15 @@ স্থানাঙ্কসমূহ কিছু দেয়া হয়নি বিটা টেস্টার হোন + গুগল প্লেতে আমাদের বেটা চ্যানেলে যুক্ত হন! এতে নতুন বৈশিষ্ট্যের পাশাপাশি পুরানো বাগগুলো\'র সংশোধিত রুপ সবার আগে ব্যবহারের সুযোগ পাবেন উইকিউপাত্ত ব্যবহার করুন (সতর্কতা: এটি নিষ্ক্রিয় করা অধিক পরিমাণে মোবাইল ডেটা খরচ হওয়ার কারণ হতে পারে) + 2FA কোড আমার সাম্প্রতিক আপলোড সীমা সর্বোচ্চ সীমা ৫০০টির বেশি প্রদর্শন করা সম্ভব নয় সাম্প্রতিক আপলোড সীমা নির্ধারন করুন + দুটি স্তরের প্রমাণীকরণ বর্তমানে সমর্থিত নয়। আপনি কি সত্যিই প্রস্থান করতে চান? কমন্সের লোগো পটভূমির চিত্র @@ -187,7 +192,13 @@ কোন বিবরণ পাওয়া যায়নি কমন্সে ফাইলের পাতা উইকিউপাত্ত পদ + ছবি আনার সময় ত্রুটি + ফাইলের একটি স্বতন্ত্র বর্ণনামূলক নাম যা ফাইলের নাম হিসাবে কাজ করবে। অাপনি সাধারণ ভাষা ব্যবহার করতে পারেন শূন্যস্থানসহ। ফাইলের এক্সটেনশন যুক্ত করবেন না। + যতটা সম্ভব মিডিয়াটি বর্ণনা করুন: এটি কোথায় ধারণ করা হয়েছিল? এটি কি প্রদর্শন করে? এটির প্রসঙ্গ কি? ধারণকৃত বস্তু অথবা ব্যক্তির বর্ণনা করুন। সহজে অনুমান করা যায়না সেরকম তথ্য উদঘাটন করুন, উদাহরণস্বরূপ, যদি ল্যান্ডস্কেপ হয় তাহলে দিবসকালের সময় দিন। অনুমতি দিন বাহ্যিক সঞ্চয়স্থান ব্যবহার করুন + অাপনার ডিভাইসের নিজস্ব ক্যামেরায় ধারণকৃত ছবি সংরক্ষণ করুন + লগ ফাইল পাঠান + ইমেইলের মাধ্যমে উন্নয়নকারীর কাছে লগ ফাইল পাঠান আপনার অ্যাকাউন্টে প্রবেশ করুন diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index 4b3fe1c9c..855e42539 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -20,11 +20,11 @@ Acabant la càrrega al servidor de %1$s Error al carregar %1$s Prem per veure-ho - + s\'està carregant 1 fitxer s\'estan carregant %d fitxers - Les meves càrregues + Les meves càrregues recents En cua Ha fallat %1$d%% completat @@ -42,6 +42,7 @@ 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. Ha fallat l\'inici de sessió Carrega Anomena aquest conjunt @@ -50,17 +51,19 @@ Categories de cerca Desa Refresca + El vostre dispositiu no té el GPS habilitat. El voleu habilitar? + Habilita el GPS Encara no hi ha cap càrrega - - No hi ha cap càrrega encara - 1 càrrega + + \@string/contributions_subtitle_zero + %d càrrega %d càrregues - - S\'està iniciant 1 càrrega + + S\'està iniciant %d càrrega S\'estan iniciant %d càrregues - + 1 càrrega %d càrregues @@ -85,8 +88,10 @@ Llicència Mode nocturn Utilitza el tema fosc - CC Reconeixement-CompartirIgual 3.0 - CC Reconeixement 3.0 + Reconeixement-CompartirIgual 4.0 + Reconeixement 4.0 + Reconeixement-CompartirIgual 3.0 + Reconeixement 3.0 CC0 CC BY-SA 3.0 CC BY-SA 3.0 (Àustria) @@ -100,7 +105,10 @@ CC BY-SA 3.0 (Polònia) CC BY-SA 3.0 (Romania) CC BY 3.0 + CC BY-SA 4.0 + CC BY 4.0 CC Zero + NO carregueu: Exemple de càrrega: Doneu les vostres imatges. Ajudeu a donar vida als articles de la Viquipèdia! Les imatges de la Viquipèdia vénen de la Wikimedia Commons. @@ -116,14 +124,20 @@ Refresca D\'acord Llocs propers + No s\'han trobat llocs propers Avís + El fitxer ja existeix a Commons. Segur que voleu procedir? No Títol Títol del fitxer multimèdia Descripció Data de càrrega + Llicència + Coordenades + No s\'ha proporcionat cap Utilitza Wikidata + Codi 2FA Límit màxim Realment voleu finalitzar la sessió? Logo de Commons @@ -142,6 +156,6 @@ Comentaris Finalitza la sessió no s\'ha trobat cap descripció - Article al Commons + Article del fitxer a Commons Element del Wikidata diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index 055de35df..49b2e9d2c 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -198,5 +198,7 @@ Giv tilladelse Brug eksternt lager Gem billeder taget med din enheds program på kameraet + Send logfil + Send logfil til udviklerne via e-post Log ind på din konto diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 264bfa72a..0147104d0 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -198,5 +198,7 @@ Berechtigung geben Externen Speicher verwenden Mit der In-App-Kamera aufgenommene Bilder auf deinem Gerät speichern + Logdatei senden + Logdatei an die Entwickler per E-Mail senden Bei deinem Benutzerkonto anmelden diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 2fe7f7b89..6dadbe0d1 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -20,11 +20,11 @@ Αποπεράτωση επιφόρτωσης %1$s Ανέβασμα του %1$s απέτυχε Πατήστε για να δείτε - + 1 αρχείο επιφορτώνεται %d αρχεία επιφορτώνονται - Οι επιφορτώσεις μου + Οι Πρόσφατες Φορτώσεις Μου Στην ουρά Απέτυχε %1$d%% ολοκληρώθηκε @@ -42,6 +42,7 @@ Δεν είναι δυνατή η σύνδεση - παρακαλούμε ελέγξτε τον κωδικό σας Πάρα πολλές ανεπιτυχείς προσπάθειες. Παρακαλώ δοκιμάστε ξανά σε λίγα λεπτά. Συγνώμη, αυτός ο χρήστης έχει αποκλειστεί από τα Commons + Πρέπει να δώσετε τον κωδικό πιστοποίησης με δύο παράγοντες Η είσοδος απέτυχε Ανέβασμα Ονομάστε το σύνολο @@ -50,6 +51,9 @@ Αναζήτηση κατηγοριών Αποθήκευση Ανανέωση + Το GPS στην συσκευή είναι απενεργοποιημένο. Θέλετε να το ενεργοποιήσετε; + Ενεργοποιήσετε το GPS + Δεν υπάρχουν ακόμα φορτωμένα αρχεία Δεν υπάρχουν επιφορτώσεις ακόμη 1 επιφόρτωση @@ -69,9 +73,9 @@ Ρυθμίσεις Εγγραφή Σχετικά - Λογισμικό ανοικτού κώδικα και κυκλοφορεί υπό την <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/COPYING\">Άδεια Apache v2</a>. Το Wikimedia Commons και το λογότυπο είναι εμπορικά σήματα του Ιδρύματος Wikimedia και χρησιμοποιούνται με άδεια από το Ίδρυμα Wikimedia. Δεν προτεινόμαστε ή συνδεόμαστε με το Ίδρυμα Wikimedia. + Λογισμικό ανοικτού κωδικού που κυκλοφορεί υπό την <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/COPYING\">Άδεια Apache v2</a>. Το Wikimedia Commons και το λογότυπο είναι εμπορικά σήματα του Ιδρύματος Wikimedia και χρησιμοποιούνται με άδεια από το Ίδρυμα Wikimedia. Δεν συμμετέχουμε στην δημιουργία, ανάπτυξη ή συντήρηση του Ιδρύματος Wikimedia. <a href=\"https://github.com/commons-app/apps-android-commons\">Πηγή</a> και <a href=\"https://commons-app.github.io/\">ιστοσελίδα</a> στο GitHub. Δημιουργήστε ένα νέο <a href=\"https://github.com/commons-app/apps-android-commons/issues\">GitHub θέμα</a> για αναφορές σφαλμάτων και προτάσεις. - <a href=\"https://wikimediafoundation.org/wiki/Privacy_policy\">Πολιτική προσωπικών δεδομένων</a> + <a href=\"https://wikimediafoundation.org/wiki/Privacy_policy\">Πολιτική Απορρήτου και προσωπικών δεδομένων</a> <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\">CREDITS</a> Σχετικά Αποστολή σχολίων (μέσω Email) @@ -82,6 +86,7 @@ Ξαναπροσπαθήστε Ακύρωση Αυτή η εικόνα θα έχει άδεια στα πλαίσια του %1$s + Αποστέλλοντας αυτήν την εικόνα, δηλώνω πως αυτή η εργασία είναι δική μου, και δεν περιέχει υλικό άλλου συγγραφέα, και εκτός αυτού πρόσκειται στο , thathref=\"https://commons.wikimedia.org/wiki/Commons:Policies_and_guidelines\">Κοινές πολιτικές της Wikipedia</a>. Λήψη Άδεια χρήσης Χρήση προηγούμενου τίτλου/περιγραφής @@ -124,15 +129,17 @@ Νομίζεις ότι έχεις; Ναι! Κατηγορίες - Φόρτωση… + Φόρτωση… Καμία επιλεγμένη Καμία περιγραφή Άγνωστη άδεια Ανανέωση Απαιτούμενη άδεια: Ανάγνωση εξωτερικής αποθήκευσης. Η εφαρμογή δεν μπορεί να λειτουργήσει χωρίς αυτή. + Απαιτούμενη άδεια: Με εξωτερική αποθήκευση.Το πρόγραμμα δεν μπορεί να λειτουργήσει με αυτήν. Προαιρετική άδεια: Ανάκτηση τρέχουσας θέσης σας για προτάσεις κατηγοριών Εντάξει Κοντινοί Τόποι + Δεν βρέθηκαν τόποι εδώ κοντά Προειδοποίηση Αυτό το αρχείο υπάρχει ήδη στα Commons. Είστε σίγουρος ότι θέλετε να συνεχίσετε; Ναι @@ -141,8 +148,55 @@ Τίτλος πολυμέσου Περιγραφή Η περιγραφή του πολυμέσου μπαίνει εδώ. Αυτή μπορεί να είναι σχετικά μεγάλη, και θα χρειαστεί να αναδιπλωθεί σε πολλές γραμμές. Ελπίζουμε ωστόσο ότι θα φαίνεται όμορφα. + Ημερομηνία φόρτωσης + Άδεια + Συντεταγμένες + Δεν δόθηκε τίποτα Γίνετε Δοκιμαστής Beta Συμμετέχετε στο κανάλι beta μας στο Google Play και αποκτήστε πρώιμη πρόσβαση σε νέες λειτουργίες και διορθώσεις σφαλμάτων χρήση wikidata (Προσοχή: η απενεργοποίηση αυτή μπορεί να προκαλέσει μεγάλη κατανάλωση κινητὠν δεδομένων) + Κωδικός 2FA + To Όριο του Πρόσφατα Φορτωμένου Αρχείου μου + Μέγιστο Όριο + Δεν μπορεί να προβάλλει περισσότερα από 500 αρχεία + Ορίσετε το Όριο της Πρόσφατης Επιφόρτωσης + Πιστοποίηση με δύο παράγοντες δεν υποστηρίζεται προς το παρόν. + Θέλετε πράγματι να αποσυνδεθείτε; + Κοινό Λογότυπο + Εικόνα Υποβάθρου + Η Εικόνα των Μέσων Απέτυχε (δεν μπορεί να φορτωθεί) + Δεν Βρέθηκε καμία Εικόνα + Φορτώστε την Εικόνα + Mount Zao + Llamas + Γέφυρα Ουρανίου Τόξου + Τουλίπα + Ιδιόκτητη Εικόνα + Καλωσόρισες Βικιπαίδεια + Καλωσορίστε το Δικαίωμα Αντιγραφής + Κτίρια Όπερας Sidney + Ακυρώστε + Ανοίξετε + Κλείσετε + Αρχική Σελίδα + Φορτώστε + Εδώ Κοντά + Γύρω από + Ρυθμίσεις + Σχόλια + Αποσύνδεση + Σεμινάριο + Οι κοντινές τοποθεσίες δεν μπορούν να προβληθούν δίχως τις άδειες τοποθεσίας + δεν βρέθηκε περιγραφή + Σελίδα φακέλλου κοινής χρήσης + Τεμάχιο Wikidata + Υπήρξε σφάλμα κατά την σκίαση εικόνων + Ένας μοναδικός τίτλος περιγραφής του φακέλλου, που θα χρησιμεύσει ως όνομα φακέλλου. Μπορείτε να χρησιμοποιήσετε τις ήδη υπάρχουσες γλώσσες με διαστήματα. Μην συμπεριλάβετε την επέκταση φακέλλου + \nΠαρακαλώ περιγράψετε τα μέσα το δυνατό περισσότερο : Πού οδηγήθηκε αυτό; Τι δείχνει; Ποιο είναι το περιεχόμενο του; Παρακαλώ περιγράψετε τα αντικείμενα ή τα πρόσωπα. Αποκαλύψετε πληροφορίες που δεν μπορούν εύκολο να μαντέψει κανείς, για παράδειγμα την ώρα εντός της ημέρας αν πρόκειται για τοπίο. Αν τα μέσα δείξουν κάτι ασύνηθες, παρακαλώ εξηγήστε τι το καθιστά μη συνηθισμένα. + Χορηγήστε άδεια + Χρησιμοποιήσετε την εξωτερική αποθήκευση + Αποθηκεύσετε εικόνες που παίρνονται στην κάμερα εφαρμογής στην συσκευή σας + Αποστείλατε τον φάκελλο σύνδεσης + Στείλατε τον φάκελλο σύνδεσης στους δημιουργούς μέσω email diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 57eca4e2c..d802b28bd 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -198,5 +198,7 @@ Otorgar permiso Utilizar almacenamiento externo Guardar en el dispositivo imágenes capturadas con la cámara de la aplicación + Enviar archivo de registro + Enviar archivo de registro a los desarrolladores por correo electrónico Accede a tu cuenta diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index ced580099..71da7c602 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -198,5 +198,7 @@ اجازه بده استفاده از حافظهٔ خارجی ذخیرهٔ تصویرهای گرفته شده توسط دوربین درونکار اپلیکیشن بر روی دستگاه شما + ارسال فایل سیاهه + ارسال فایل سیاهه به‌وسیلهٔ ایمیل برای توسعه‌دهندگان ورود به حساب کاربریتان diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 01ed93eb6..209478949 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -73,7 +73,7 @@ Paramètres S’inscrire À propos - L\'application Wikimedia Commons est une application open-source crée et maintenue par les bénéficiaires et volontaires de la communauté Wikimedia. La fondation Wikimedia n\'est pas associée à la création, le développement ou la maintenance de l\'application. + L’application Wikimedia Commons est une application ouverte créée et tenue à jour par les bénéficiaires et volontaires de la communauté Wikimedia. La fondation Wikimedia n’est pas associée à la création, le développement ou l’entretien de l’application. <a href=\"https://github.com/commons-app/apps-android-commons\">Sources</a> et <a href=\"https://commons-app.github.io/\">site web</a> sur GitHub. Créer un nouveau <a href=\"https://github.com/commons-app/apps-android-commons/issues\">signalement GitHub</a> pour signales des bogues ou des suggestions. <a href=\"https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\">Politique de confidentialité</a> <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\">Remerciements</a> @@ -198,5 +198,7 @@ Accorder le droit Utiliser le stockage externe Enregistrer les images prises avec l’appareil photo de votre appareil + Envoyer le journal + Envoyer le journal aux développeurs par courriel Connectez-vous à votre compte diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 1527a8d74..1c2063f2c 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -198,5 +198,7 @@ Outorgar permiso Usar o almacenamento externo Gardar as imaxes capturadas coa cámara do seu dispositivo + Enviar ficheiro de rexistro + Enviar ficheiro de rexistro ós desenvolvedores por correo electrónico Comezar sesión na súa conta diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 95ac9bb22..721ed066a 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -75,7 +75,7 @@ Névjegy A Wikimedia Commons applikáció egy nyílt forráskódú szoftver, amit a Wikimedia-közösség önkéntesei készítettek és tartanak karban. A Wikimédia Alapítvány nem vesz részt az applikáció megalkotásában, fejlesztésében és üzemeltetésében. <a href=\"https://github.com/commons-app/apps-android-commons\">Forráskód</a> és <a href=\"https://commons-app.github.io/\">weboldal</a> a GitHubon. Nyiss egy új <a href=\"https://github.com/commons-app/apps-android-commons/issues\">GitHub-problémát</a> hibabejelentéssel vagy fejlesztési javaslattal. - <a href=\"https://wikimediafoundation.org/wiki/Adatvédelmi_irányelv\">Adatvédelmi irányelvek</a> + <a href=\"https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\">Adatvédelmi irányelvek</a> <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\">Köszönetnyilvánítás</a> Névjegy Visszajelzés küldése (e-mailben) @@ -190,6 +190,7 @@ nincs leírás Commons leírólap Wikidata-elem + Egy egyedi, leíró cím a fájlnak, ami fájlnévként fog szolgálni. Egyszerű nyelvezetet használhatsz szóközökkel. Ne tedd bele a kiterjesztést. Kérlek a lehető legteljesebb módon írd le a fájlt: hol készült, mit ábrázol, mi a kontextus? Kérlek add meg az objektumokat vagy személyeket a képen, valamint a nehezen kitalálható információkat (például a kép készítésének dátumát, ha az egy tájkép). Amennyiben a média valami szokatlant ábrázol, kérlek fejtsd ki, hogy mi teszi szokatlanná. Engedély adása Külső tárhely használata diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index 5342b9f3f..ddc29c35d 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -72,9 +72,9 @@ הגדרות רישום אודות - תכנת קוד פתוח המתפרסמת לפי תנאי <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/COPYING\">Apache License v2</a>. השם %1$s והסמל שמשויך אליו הם סימני מסחר של קרן ויקימדיה ומשמשים באישור קרן ויקימדיה. איננו נתמכים על־ידי קרן ויקימדיה או קשורים אליה בשותפות. + יישום ויקישיתוף (Wikimedia Commons app) הוא יישום קוד פתוח שמפותח ומתוחזק על־ידי מקבלי מלגות ומתנדבים של קהילת ויקימדיה. קרן ויקימדיה אינה מעורבת ביצירה, פיתוח, או תחזוקה של היישום. <a href=\"https://github.com/commons-app/apps-android-commons\">קוד מקור</a> ו<a href=\"https://commons-app.github.io/\">אתר</a> בגיטהאב. נא ליצור <a href=\"https://github.com/commons-app/apps-android-commons/issues\">דיווח בגיטהאב</a> בשביל באגים והצעות. - + <a href=\"https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\">מדיניות פרטיות</a> <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\">יוצרים</a> אודות שליחת משוב (בדוא\"ל) @@ -172,6 +172,7 @@ צבעוני בלי תמונות סלפי תמונה קניינית + ברוך בואך ויקיפדיה בית האופרה של סידני ביטול פתיחה @@ -191,6 +192,10 @@ שגיאה במשירת תמונות במטמון כותרת מתארת ייחודית לקובץ, שתשמש שם קובץ. אפשר להשתמש בשפה פשוטה עם רווחים. אין לכלול סיומת קובץ נא לתאר את המדיה כמה שיותר: איפה היא נוצרה? מה היא מראה? מה ההקשר? נא לתאר את העצמים או את האנשים. נא לחשוף מידע שאי־אפשר לנחש בקלות, למשל, הזמן ביום אם זאת תמונת נוף. אם המדיה מציגה משהו בלתי־רגיל, נא להסביר מה מיוחד בה. + לתת הרשאה להשתמש באחסון חיצוני שמירת תמונות שצולמו באמצעות מצלמה בתוך היישום במכשיר שלך + שליחת קובץ יומן + שליחת קובץ יומן למפתחים בדואר אלקטרוני + כניסה לחשבון שלך diff --git a/app/src/main/res/values-kab/strings.xml b/app/src/main/res/values-kab/strings.xml index 761333d32..d9d79f16e 100644 --- a/app/src/main/res/values-kab/strings.xml +++ b/app/src/main/res/values-kab/strings.xml @@ -198,5 +198,7 @@ Mudd tasiregt Seqdec asekles azɣaray Sekles tiwlafin yettwaṭṭfen s tkamirat yellan deg ibenk + Azen afaylu n uɣmis + Azen afaylu n uɣmis i yinermisen s yimayl Qqen ar umiḍan-ik diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index d75e2c350..cc2794d5f 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -72,7 +72,7 @@ 설정 가입하기 정보 - 오픈 소스 소프트웨어는 <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/COPYING\">아파치 라이선스 v2</a>에 따라 공개됩니다. %1$s 및 관련 로고는 위키미디어 재단의 상표이며 위키미디어 재단의 허가를 통해 사용될 수 있습니다. 저희는 위키미디어 재단에 의해 보증되거나 제휴되어 있지 않습니다. + 위키미디어 공용 앱은 오픈 소스 애플리케이션이며 위키미디어 공동체 내의 자원봉사자에 의해 유지됩니다. 위키미디어 재단은 애플리케이션의 생성, 개발, 유지보수에 관여하지 않습니다. 소스 코드는 <a href=\"https://github.com/commons-app/apps-android-commons\">GitHub</a>에 있으며, 웹사이트는 <a href=\"https://commons-app.github.io/\">GitHub</a>에 있습니다. 버그나 기타 제안은 <a href=\" https://github.com/commons-app/apps-android-commons/issues\">GitHub</a>에 보고해주세요. <a href=\"https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\">개인정보 정책</a> <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\">제작진</a> @@ -195,5 +195,7 @@ 권한 부여 외부 저장소 사용하기 장치의 인앱 카메라로 찍은 사진 저장하기 + 로그 파일 보내기 + 이메일로 개발자에게 로그 파일 보내기 자신의 계정으로 로그인 diff --git a/app/src/main/res/values-lb/strings.xml b/app/src/main/res/values-lb/strings.xml index f07449353..1937a880e 100644 --- a/app/src/main/res/values-lb/strings.xml +++ b/app/src/main/res/values-lb/strings.xml @@ -72,7 +72,7 @@ Astellungen Mellt Iech un Iwwer - \'Open-Source-Software\' verëffentlecht ënner der <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/COPYING\">Apache Lizenz v2</a>. %1$s a säi Logo si Markenzeeche vun der Wikimedia Foundation a gi mat der Autorisatioun vun der Wikimedia Foundation benotzt. Mir sinn net confirméiert vun oder liéiert mat der Wikimedia Foundation. + D\'App Wikimedia Commons ass eng \'Open-Source-App\' déi vu Fräiwëllege vun der Wikimedia Foundation entwéckelt gouf an och vun hinnen ënnerhal gëtt. D\'Wikimedia Foundation ass net an d\'Entwécklung oder den Ënnerhalt vun der App implizéiert. <a href=\"https://github.com/commons-app/apps-android-commons\">Quell</a> an <a href=\"https://commons-app.github.io/\">Internetsite</a> vu GitHub.\nLeet w.e.g. <a href=\"https://github.com/commons-app/apps-android-commons/issues\"> e GitHub Problem</a> fir Problemer ze mellen a Proposen ze maachen. <a href=\"https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\">Dateschutzerklärung</a> <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\">Merci</a> @@ -188,5 +188,7 @@ Autorisatioun ginn Externe Späicher benotzen Biller späicheren déi mat der in-app Kamera vun Ärem Apparat gemaach goufen + Log-Fichier schécken + Log-Fichier per E-Mail un d\'Entwéckler schécken An Äre Benotzerkont aloggen diff --git a/app/src/main/res/values-lv/strings.xml b/app/src/main/res/values-lv/strings.xml index 1a1b71b31..d1492d1f3 100644 --- a/app/src/main/res/values-lv/strings.xml +++ b/app/src/main/res/values-lv/strings.xml @@ -42,8 +42,8 @@ Iestatījumi Reģistrēties Par - Izejas kods pieejams <a href=\"https://github.com/commons-app/apps-android-commons\">GitHub</a>. Kļūdas ziņot <a href=\" https://github.com/commons-app/apps-android-commons/issues\">Github</a>. - <a href=\"https://wikimediafoundation.org/wiki/Privacy_policy\">Privātuma politika</a> + <a href=\"https://github.com/commons-app/apps-android-commons\">Izejas kods</a> un <a href=\"https://commons-app.github.io/\">tīmekļa vietne</a> GitHub. Izveido jaunu <a href=\"https://github.com/commons-app/apps-android-commons/issues\">GitHub pieteikumu</a> kļūdas ziņojumam vai ieteikumam. + <a href=\"https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\">Privātuma politika</a> Par Nosūtīt atsauksmes (pa e-pastu) Nesen lietotās kategorijas diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml index 5557efef8..000d94051 100644 --- a/app/src/main/res/values-mk/strings.xml +++ b/app/src/main/res/values-mk/strings.xml @@ -198,5 +198,7 @@ Дај дозвола Користи надворешен склад Зачувување на направените слики во прилогот со камерата на вашиот уред + Испрати дневничка податотека + Испрати дневничка податотека на разработувачите по е-пошта Најавете се со вашата сметка diff --git a/app/src/main/res/values-nb/strings.xml b/app/src/main/res/values-nb/strings.xml index d68af6afa..1c7bcc54a 100644 --- a/app/src/main/res/values-nb/strings.xml +++ b/app/src/main/res/values-nb/strings.xml @@ -198,5 +198,7 @@ Gi tillatelse Bruk ekstern lagring Lagre bilder som er tatt med kameraet i appen på enheten din + Send loggfil + Send loggfil til utviklerne via epost Logg inn med kontoen din diff --git a/app/src/main/res/values-pms/strings.xml b/app/src/main/res/values-pms/strings.xml index 3c04b6370..890f688e8 100644 --- a/app/src/main/res/values-pms/strings.xml +++ b/app/src/main/res/values-pms/strings.xml @@ -198,5 +198,7 @@ Dé ël përmess Dovré n\'anmagasinament estern Argistré le plance pijà con la màchina fòto ëd sò angign + Mandé l\'archivi d\'argistr + Mandé l\'archivi d\'argistr ai dësvlupator për pòsta eletrònica Ch\'as colega a sò cont diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 840e7a4f1..02d794372 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -73,9 +73,9 @@ Configurações Criar conta Sobre - Software livre distribuído sob a <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/COPYING\">Apache License v2</a>. %1$s e seu logotipo são marcas registradas da Wikimedia Foundation e são usadas com a permissão da Wikimedia Foundation. Não somos endossados nem afiliados à Wikimedia Foundation. + O Wikimedia Commons é um aplicativo de código aberto criado e mantido por beneficiários e voluntários da comunidade Wikimedia. A Wikimedia Foundation não está envolvida na criação, desenvolvimento ou manutenção do aplicativo. <a href=\"https://github.com/commons-app/apps-android-commons\">Fonte</a> e <a href=\"https://commons-app.github.io/\">site</a> em GitHub. Crie um novo <a href=\"https://github.com/commons-app/apps-android-commons/issues\">GitHub issue</a> para relatórios de bugs e sugestões. - <a href=\"https://wikimediafoundation.org/wiki/Privacy_policy\">Política de privacidade</a> + <a href=\"https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\">Política de privacidade</a> <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\">Créditos</a> Sobre Enviar comentários (por e-mail) @@ -198,4 +198,7 @@ Dar permissão Usar o armazenamento externo Salvar as fotos tiradas com a câmera no aplicativo no seu dispositivo + Enviar arquivo de registro + Enviar arquivo de log para desenvolvedores por e-mail + Faça login na sua conta diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 8f5926878..918c760b7 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -8,7 +8,7 @@ Зарегистрироваться Вход в систему Пожалуйста, подождите… - Опознание прошло успешно + Вход выполнен успешно! Ошибка входа в систему! Файл не найден. Попробуйте другой файл. Ошибка аутентификации! @@ -26,7 +26,7 @@ %d файлов загружается Мои недавние загрузки - Очередь + В очереди Ошибка загрузки. Завершено %1$d%% Загрузка @@ -52,7 +52,7 @@ Выбор категорий Сохранить Обновить - GPS отключен в вашем устройстве. Вы хотите включить его? + GPS отключен в вашем устройстве. Хотите включить его? Включить GPS Загрузок пока нет @@ -77,7 +77,7 @@ Настройки Зарегистрироваться О приложении - Приложение с открытым исходным кодом, выпущено по лицензии <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/COPYING\">Apache License v2</a>. %1$s и его логотип являются товарными знаками Фонда Викимедиа и используются с разрешения Фонда Викимедиа. Мы не поддерживаемся и не связаны с Фондом Викимедиа. + Приложение «Викисклад» - это программа с открытым кодом, которую создали волонтёры и участники грантов Викимедиа. Фонд Викимедиа не участвует в создании, разработке или обслуживании этого приложения. <a href=\"https://github.com/commons-app/apps-android-commons\">Исходный код</a> и <a href=\"https://commons-app.github.io/\">сайт</a> на GitHub. Создайте новый <a href=\"https://github.com/commons-app/apps-android-commons/issues\">запрос на GitHub</a>, чтоб сообщить об ошибке или внести предложение. <a href=\"https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\">Политика конфиденциальности</a> <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\">Благодарности</a> @@ -90,11 +90,12 @@ Повторить Отмена Это изображение будет лицензировано под %1$s + Отправляя это изображение, я подтверждаю, что это моя собственная работа, которая не содержит защищённых авторским правом материалов или селфи, а также отвечает <a href=\"https://commons.wikimedia.org/wiki/Commons:Policies_and_guidelines/ru\">правилам Викисклада</a>. Скачать Лицензия Использовать предыдущие заголовок/описание Автоматически получить текущее местоположение - Получить текущее местоположение, чтобы получить предложения категорий, если изображение не содержит геотеги + Получить текущее местоположение, чтобы были предложены категории, если изображение не содержит геотегов Ночной режим Использовать тёмную тему Attribution-ShareAlike 4.0 @@ -120,7 +121,7 @@ Викисклад содержит большую часть изображений, которые используются в Википедии. Ваши изображения помогают образованию людей во всём мире! Пожалуйста, загрузите фотографии, которые были сняты или созданы исключительно вами: - — Природные объекты (цветы, животные, горы)\n— Полезные предметы (велосипеды, вокзалы)\n— Известные люди (ваш мэр, спортсмены-олимпийцы, которых вы встретили) + — Природные объекты (например, цветы, животные, горы)\n— Полезные предметы (например, велосипеды, вокзалы)\n— Известные люди (например, ваш мэр, спортсмены-олимпийцы, которых вы встретили) Пожалуйста, НЕ загружайте: — Селфи или фотографии ваших друзей\n— Фотографии, которые вы скачали из Интернета\n— Скриншоты несвободных приложений Пример загрузки: @@ -128,7 +129,7 @@ Загрузите свои изображения. Помогите Википедии оживить статьи! Изображения в Википедии хранятся на Викискладе. Ваши изображения помогают образованию людей во всём мире. - Избегайте материалов, найденных в Интернете и защищённых авторским правом, а также изображений плакатов, книжных обложек и т.п. + Избегайте материалов, защищённых авторским правом, например, найденных в Интернете, изображений плакатов, книжных обложек и т.п. Вам это понятно? Да! Категории @@ -158,7 +159,7 @@ Стать бета-тестером Подпишитесь на наш канал бета-версии на Google Play и получите ранний доступ к новым функциям и исправлениям ошибок Использовать Викиданные - (Предупреждение: отключение может привести к большому потреблению мобильных данных) + (Предупреждение: отключение может привести к значительному расходу мобильных данных) Код 2ФА Лимит моих недавних загрузок Максимальный лимит @@ -196,7 +197,12 @@ Страница файла на Викискладе Элемент Викиданных Ошибка при кэшировании картинок + Уникальное описание, которое будет сохранено как имя файла. Вы можете использовать естественный язык, разделяя слова пробелами. Пожалуйста, не указывайте расширение файла. + Пожалуйста, подробно опишите загружаемый файл: где он был снят? что на нём изображено? каков его контекст? Пожалуйста опишите изображённых персон или объекты. Добавьте информацию, о которой нельзя легко догадаться, например, время суток, когда снимался файл. Если снято что-то необычное, постарайтесь пояснить, что именно в этом необычного. Дать разрешение Использовать внешнее хранилище Сохранять изображения, сделанные с помощью встроенной камеры на устройстве + Выслать лог-файл + Выслать лог-файл разработчикам по е-мейлу + Войдите в свою учётную запись diff --git a/app/src/main/res/values-skr/strings.xml b/app/src/main/res/values-skr/strings.xml index 9e898ec99..83f7fba67 100644 --- a/app/src/main/res/values-skr/strings.xml +++ b/app/src/main/res/values-skr/strings.xml @@ -11,6 +11,7 @@ لاگ ان کامیاب! لاگ ان ناکام! فائل کائنی لبھی،ٻئی فائل کیتے کوشش کرو۔ + تصدیق ناکام! اپ لوڈ شروع! %1$s اپ لوڈ تھی ڳیا! اپ لوڈ %1$s شروع تھیندا پئے @@ -98,7 +99,9 @@ ترتیباں تہاڈی رائے لاگ آؤٹ + ٹیٹوریل وکی ڈیٹا آئٹم اجازت ݙیوو + لاگ فائل بھیجو آپݨے کھاتے وچ لاگ ان تھیوو diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 04ea46ecf..b85e6fce8 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -198,4 +198,7 @@ Давање дозволе Употреба спољашњег складишта Спремање слика направљених камером апликације на Вашем уређају + Пошаљи дневничку датотеку + Пошаљи дневничку датотеку девелоперима преко имејла + Пријавите се на свој налог diff --git a/app/src/main/res/values-su/strings.xml b/app/src/main/res/values-su/strings.xml index 9900c5de7..8737deb52 100644 --- a/app/src/main/res/values-su/strings.xml +++ b/app/src/main/res/values-su/strings.xml @@ -73,9 +73,9 @@ Séting Daptar Ngeunaan - Pakakas lemes kodeu nembrak dirilis di handapeun <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/COPYING\">Lisénsi Apache v2</a>. %1$s sarta logona téh mérk dagang anu Yayasan Wikimédia ogé dipakéna kudu meunang widi ti Yayasan Wikimédia. Kami teu disatujuan ku atawa digawé bareng jeung Yayasan Wikimédia. + Aplikasi Wikimédia Commons mangrupa aplikasi sumber nembrak nu dijieun jeung dikokolakeun ku panampa hibah sarta rélawan komunitas Wikimédia. Wikimedia Foundation teu pépérodeun dina nyieun, ngamekarkeun, atawa mulasara ieu aplikasi. <a href=\"https://github.com/commons-app/apps-android-commons\">Sumber</a> sarta <a href=\"https://commons-app.github.io/\">situ wéb</a> dina GitHub. Jieun anyar <a href=\"https://github.com/commons-app/apps-android-commons/issues\">perkara GitHub</a> pikeun saran jeung laporan kutu. - <a href=\"https://wikimediafoundation.org/wiki/Privacy_policy\">Kawijakan privasi</a> + <a href=\"https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\">Kawijakan privasi</a> <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\">Pangajén</a> Ngeunaan Kirim eupan balik (via Surélék) @@ -195,6 +195,10 @@ Kasalahan nalika muat gambar Judul déskriptif anu unik pikeun berkas, anu bakal miboga fungsi minangka ngaran berkas. Anjeun bisa maké basa basajan kalawan spasi. Ulah ngawuwuhkeun éksténsi berkas Pék émbarkeun wincikan média saloba-lobabana: Dimana éta dicokot? Naon nu titojokeunna? Naon kontéksna? Pék jéntrékeun obyék atawa jalmana. Ébré informasi anu teu gampang kajudi, kawas wayah mun éta mangrupa pamandangan. Ari média nu némbongkeun perkara nu teu guyub, pék jéntrékeun naon nu ngabalukarkeun éta téh teu guyub. + Béré idin Paké panyimpenan éksternal Simpen gambar nu nyomotna ku aplikasi kaména na parangkat anjeun + Kirim berkas log + Kirim berkas log ka pamekar liwat surélék + Asup log kana akun anjeun diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 416a776eb..a77c2ade6 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -198,5 +198,7 @@ Ge behörighet Använd extern lagring Spara bilder som tas med kameran i appen på din enhet + Skicka loggfil + Skicka loggfilen till utvecklarna via e-post Logga in på ditt konto diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml new file mode 100644 index 000000000..04b2ffc6e --- /dev/null +++ b/app/src/main/res/values-th/strings.xml @@ -0,0 +1,109 @@ + + + คอมมอนส์ + การตั้งค่า + ชื่อผู้ใช้ + รหัสผ่าน + เข้าสู่ระบบ + สมัครสมาชิก + กำลังเข้าสู่ระบบ + กรุณารอสักครู่… + การเข้าสู่ระบบสำเร็จแล้ว! + การเข้าสู่ระบบล้มเหลว! + ไม่พบไฟล์ กรุณาลองใช้ไฟล์อื่น + การตรวจสอบความถูกต้องล้มเหลว! + เริ่มการอัปโหลดแล้ว! + อัปโหลด %1$s แล้ว! + แตะเพื่อดูการอัปโหลดของคุณ + กำลังเริ่มการอัปโหลด %1$s + กำลังอัปโหลด %1$s + กำลังเสร็จสิ้นการอัปโหลด %1$s + การอัปโหลด %1$s ล้มเหลว + แตะเพื่อดู + กำลังอัปโหลดไฟล์ %d ไฟล์ + การอัปโหลดล่าสุดของฉัน + อยู่ในคิว + ล้มเหลว + %1$d%% เสร็จสมบูรณ์ + กำลังอัปโหลด + จากคลังภาพ + ถ่ายรูปภาพ + ใกล้เคียง + การอัปโหลดของฉัน + แชร์ + ดูในเบราว์เซอร์ + ชื่อเรื่อง + คำอธิบาย + ไม่สามารถเข้าสู่ระบบได้ - ความล้มเหลวของเครือข่าย + ไม่สามารถเข้าสู่ระบบได้ - กรุณาตรวจสอบชื่อผู้ใช้ของคุณ + ไม่สามารถเข้าสู่ระบบได้ - กรุณาตรวจสอบรหัสผ่านของคุณ + จำนวนครั้งที่พยายามไม่สำเร็จมากเกินไป กรุณาลองอีกครั้งในอีกสักครู่ + ขออภัย ผู้ใช้นี้ถูกบล็อกบนคอมมอนส์อยู่ + คุณต้องระบุโค้ดการตรวจสอบความถูกต้องสองปัจจัยของคุณ + การเข้าสู่ระบบล้มเหลว + อัปโหลด + ตั้งชื่อชุดนี้ + การแก้ไข + อัปโหลด + ค้นหาหมวดหมู่ + บันทึก + รีเฟรช + GPS ถูกปิดใช้งานในอุปกรณ์ของคุณอยู่ คุณต้องการเปิดใช้งานหรือไม่? + เปิดใช้งาน GPS + ยังไม่มีการอัปโหลด + การอัปโหลด %d รายการ + กำลังเริ่มการอัปโหลด %d รายการ + + การอัปโหลด %d รายการ + การอัปโหลด %d รายการ + + ไม่พบหมวดหมู่ที่ตรงกับ %$1s + เพิ่มหมวดหมู่เพื่อทำให้รูปภาพของคุณค้นพบได้ง่ายขึ้นบน Wikimedia Commons\n\nเริ่มพิมพ์เพื่อเพิ่มหมวดหมู่\nแตะข้อความนี้ (หรือกดปุ่มย้อนกลับ) เพื่อข้ามขั้นตอนนี้ + หมวดหมู่ + การตั้งค่า + สมัครใช้งาน + เกี่ยวกับ + แอป Wikimedia Commons เป็นแอปโอเพนซอร์สที่สร้างขึ้นและดูแลโดยผู้มีสิทธิและอาสาสมัครของชุมชนวิกิมีเดีย มูลนิธิวิกิมีเดียไม่มีส่วนเกี่ยวข้องในการสร้าง พัฒนา หรือการบำรุงรักษาแอปใดๆ ทั้งสิ้น + <a href=\"https://github.com/commons-app/apps-android-commons\">ซอร์สโค้ด</a>และ<a href=\"https://commons-app.github.io/\">เว็บไซต์</a>บน GitHub สร้าง <a href=\"https://github.com/commons-app/apps-android-commons/issues\">GitHub issue</a> ใหม่เพื่อรายงานบั๊กและส่งข้อเสนอแนะ + <a href=\"https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\">นโยบายความเป็นส่วนตัว</a> + <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\">เครดิต</a> + เกี่ยวกับ + ส่งคำติชม (ผ่านทางอีเมล) + ไม่ได้ติดตั้งไคลเอนต์อีเมล + หมวดหมู่ที่ใช้ล่าสุด + กำลังรอการซิงค์ครั้งแรก… + คุณยังไม่ได้อัปโหลดรูปภาพใดๆ + ลองใหม่ + ยกเลิก + รูปภาพนี้จะอนุญาตให้ใช้ได้ภายใต้สัญญาอนุญาต %1$s + โดยการส่งรูปภาพนี้ ฉันยืนยันว่านี่เป็นงานของฉันเอง ซึ่งไม่ประกอบด้วยเนื้อหาที่ละเมิดลิขสิทธิ์หรือภาพเซลฟี หรืออื่นๆ ตามที่ระบุใน<a href=\"https://commons.wikimedia.org/wiki/Commons:Policies_and_guidelines\">นโยบายของ Wikimedia Commons</a> + ดาวน์โหลด + สัญญาอนุญาต + ใช้ชื่อเรื่อง/คำอธิบายก่อนหน้านี้ + รับข้อมูลตำแหน่งที่ตั้งปัจจุบันโดยอัตโนมัติ + ดึงข้อมูลตำแหน่งที่ตั้งปัจจุบันเพื่อรับข้อเสนอแนะเกี่ยวกับหมวดหมู่ถ้ารูปภาพไม่ได้ติดแท็กตำแหน่งที่ตั้งเอาไว้ + โหมดกลางคืน + ใช้ธีมสีเข้ม + โปรดอัปโหลดรูปภาพที่ถ่ายหรือสร้างด้วยตัวคุณเองทั้งหมด: + - วัตถุธรรมชาติ (ดอกไม้ สัตว์ ภูเขา)\n- วัตถุที่สามารถใช้งานได้ (จักรยาน สถานีรถไฟ)\n- บุคคลที่มีชื่อเสียง (นายกเทศมนตรีของคุณ นักกีฬาโอลิมปิกที่คุณรู้จัก) + โปรดอย่าอัปโหลด: + - ภาพเซลฟีหรือภาพที่มีเพื่อนของคุณ\n- ภาพที่คุณดาวน์โหลดจากอินเทอร์เน็ต\n- ภาพหน้าจอแอปที่เป็นซอฟต์แวร์กรรมสิทธิ์ + ตัวอย่างการอัปโหลด: + ใช่! + หมวดหมู่ + กำลังโหลด… + ไม่ได้เลือกไว้ + ไม่มีคำอธิบาย + สัญญาอนุญาตที่ไม่รู้จัก + รีเฟรช + สิทธิที่ต้องการ: อ่านที่เก็บข้อมูลภายนอก แอปไม่สามารถทำงานได้โดยไม่มีสิทธินี้ + สิทธิที่ต้องการ: เขียนที่เก็บข้อมูลภายนอก แอปไม่สามารถทำงานได้โดยไม่มีสิทธินี้ + สิทธิทางเลือก: รับข้อมูลตำแหน่งที่ตั้งปัจจุบันสำหรับข้อเสนอแนะหมวดหมู่ + ตกลง + สถานที่ใกล้เคียง + ไม่พบสถานที่ใกล้เคียง + คำเตือน + ไฟล์นี้มีอยู่แล้วบนคอมมอนส์ คุณแน่ใจหรือว่าคุณต้องการดำเนินการต่อ? + ใช่ + ไม่ + diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 55ba0f144..ef173708d 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -206,5 +206,7 @@ Надати дозвіл Використовувати зовнішнє сховище Зберігати зображення, виконані вбудованою в додатку камерою Вашого пристрою + Надіслати лог-файл + Надіслати лог-файл розробникам електронною поштою Увійдіть у свій обліковий запис diff --git a/app/src/main/res/values-ur/strings.xml b/app/src/main/res/values-ur/strings.xml new file mode 100644 index 000000000..7af596a8b --- /dev/null +++ b/app/src/main/res/values-ur/strings.xml @@ -0,0 +1,121 @@ + + + کامنز + ترتیبات + صارف نام + پاس ورڈ + داخل ہوں + کھاتہ بنائیں + لاگ آن + براہ مہربانی کچھ دیر انتظار کریں۔۔۔ + لاگ ان کامیاب۔ + داخل ہونے میں ناکامی ہوئی! + فائل نہیں ملی، براہ کرم دوسری فائل آزمائیں۔ + تصدیق ناکام! + اپلوڈ شروع! + %1$s اپلوڈ شد! + اپنی اپلوڈ دیکھنے کے لیے ٹیپ کریں۔ + %1$s کی اپلوڈنگ شروع ہو رہی ہے + %1$s اپلوڈ جاری + %1$s کی اپلوڈنگ مکمل ہو رہی ہے + اپلوڈ %1$s ہونے میں ناکام + دیکھنے کے لیے ٹیپ کریں + + %d فائل اپلوڈ ہورہی ہے + %d فائلیں اپلوڈ ہورہی ہے + + میں حالیہ اپلوڈ + قطار + ناکام + %1$d%% مکمل + اپلوڈ جاری ہے + از نگار خانہ + تصویر لیں + قریبی + میری اپلوڈ + شیئر + براؤزر میں کھولیں + عنوان + وضاحت + لاگ ان ہونے میں ناکام - نیٹ ورک ناکامی + لاگ ان ہونے میں ناکام - براہ مہربانی اپنا صارف نام کی جانچ کریں + لاگ ان ہونے میں ناکام - براہ مہربانی - اپنے پاس ورڈ کی جانچ کریں + بے شمار ناکام کوششیں کچھ منٹوں میں دوبارہ کوشش کریں۔ + معذرت، یہ صارف کومنز پر بلاک کردیا گیا ہے + آپ کو اپنے دو عامل کے تصدیق کوڈ فراہم کرنا چاہیے۔ + داخل ہونے میں ناکام + اپلوڈ کریں + سیٹ کو نام دیں + اصلاحات + اپلوڈ کریں + زمرہ جات تلاش کریں + محفوظ کریں + تازہ کریں + جی پی ایس آپ کے آلے میں غیر فعال ہے۔ آپ اس کو فعال کرنا چاہینگے؟ + جی پی ایس فعال کریں + ابھی تک کوئی اپلوڈ نہیں + + \@string/contributions_subtitle_zero + %d اپلوڈ + %d اپلوڈ + + + شروع %d اپلوڈ + شروع %d اپلوڈ + + + %d اپلوڈ + %d اپلوڈ + + %1$s سے کوئی زمرہ جات میل نہیں کھاتے + ویکیمیڈیا کامنز پر اپنی تصاویر کو قابل دریافت بنانے کے لیے زمرے شامل کریں۔\n\nزمرے شامل کرنے کے لیے لکھنا شروع کریں۔\n\nاس مرحلے کو نظر انداز کرنے کے لیے اس پیغام یا (یا پیچھے) پر ٹیپ کریں۔ + زمرہ جات + ترتیبات + کھاتہ بنائیں + بابت + ویکیمیڈیا کامنز ایپ ایک اوپن سورس ایپ ہے جو موہوب الیہ اور رضاکاروں کی جانب سے برقرار رکھی جاتی اور بنائی گئی ہے۔ ویکیمیڈیا فاؤنڈیش کا اس ایپ کی برقراری اور تخلیق سے کوئی واسطہ نہیں ہے۔ + <a href=\"https://github.com/commons-app/apps-android-commons\">ماخذ</a> اور <a href=\"https://commons-app.github.io/\">ویب سائٹ</a> در گٹ ہب۔<a href=\"https://github.com/commons-app/apps-android-commons/issues\">نیا گٹ ہب اجرا بنائیں</a> تاکہ آپ bug شکایتیں اور تجایز دیں سکیں + <a href=\"https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\">سرگرمی کی تدبیر</a> + <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\">کریڈٹ</a> + تعارف + فیڈبیک بھیجیے (براستہ ای میل) + ای میل کلائنٹ انسٹال نہیں + حال ہی میں استعمال کیے گئے زمرے + سب سے پہلے sync کے انتظار میں۔۔۔ + آپ نے ابھی تک کوئی تصاویر اپلوڈ نہیں کی ہے۔ + دوبارہ کوشش کریں + منسوخ + %1$s تلے یہ تصویر لائسنس یافتہ ہو گی + اس تصویر کو درج کر کے، میں اقرار کرتا ہوں کہ یہ میرا اپنا کام ہے، اس ميں کاپی رائٹ مواد یا سیلفیاں نہیں ہیں، اور بصورت دیگر میں <a href=\"https://commons.wikimedia.org/wiki/Commons:Policies_and_guidelines\">ویکیمیڈیا کامنز پالیسیوں</a> کا پابند ہوں۔ + ڈاؤنلوڈ + اجازت نامہ + گزشتہ عنوان/وضاحت استعمال کریں + خودکارانہ طریقے سے حالیہ جگہ حاصل کریں + نائٹ موڈ + کالا تھیم استعمال کریں + CC BY-SA 3.0 (آسٹریا) + CC BY-SA 3.0 (جرمنی) + CC BY-SA 3.0 (اسٹونیا) + CC BY-SA 3.0 (اسپین) + CC BY-SA 3.0 (کرویئشا) + CC BY-SA 3.0 (لکسمبرگ) + ہاں! + زمرہ جات + لوڈ ہو رہا ہے۔۔۔ + غیر منتخب + کوئی وضاحت نہیں + نامعلوم اجازت نامہ + ریفریش کریں + ٹھیک ہے + جی + نہیں + اجازت نامہ + متناسقات + کامنز لوگو + کوئی سیلفی نہیں + تعارف + ترتیبات + آپ کی رائے + لاگ آوٹ + معلمی + diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index b5db7bb40..0d2d5a958 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -198,5 +198,7 @@ 給予權限 使用外部存儲裝置 在您的裝置上使用照相機應用程式來儲存照片 + 寄送日誌檔案 + 經由電子郵件寄送日誌檔案給開發人員 登入您的帳號 diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 3bed9e026..01b8c4511 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -198,5 +198,7 @@ 提供权限 使用外部存储 在您的设备上,使用应用中的照相机保存照片 + 发送日志文件 + 通过电子邮件将日志文件发送给开发人员 登录您的账户 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ba5cd955f..81da9000f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -207,5 +207,10 @@ Tap this message (or hit back) to skip this step. Give permission Use external storage Save pictures taken with the in-app camera on your device - Login to your account + Send log file + Send log file to developers via email + Login to your account + + Location has not changed. + Location not available. diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index fab5c93e7..b7b63d39c 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -53,4 +53,9 @@ android:summary="@string/use_external_storage_summary" /> + + \ No newline at end of file diff --git a/app/src/main/res/xml/provider_paths.xml b/app/src/main/res/xml/provider_paths.xml index ddfff67cc..696723b68 100644 --- a/app/src/main/res/xml/provider_paths.xml +++ b/app/src/main/res/xml/provider_paths.xml @@ -1,4 +1,5 @@ + \ No newline at end of file diff --git a/app/src/test/java/fr/free/nrw/commons/MediaTest.java b/app/src/test/java/fr/free/nrw/commons/MediaTest.java index 21cfc2c34..4f53351ad 100644 --- a/app/src/test/java/fr/free/nrw/commons/MediaTest.java +++ b/app/src/test/java/fr/free/nrw/commons/MediaTest.java @@ -9,7 +9,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = 21) +@Config(constants = BuildConfig.class, sdk = 21, application = TestCommonsApplication.class) public class MediaTest { @Test public void displayTitleShouldStripExtension() { diff --git a/app/src/test/java/fr/free/nrw/commons/NearbyControllerTest.java b/app/src/test/java/fr/free/nrw/commons/NearbyControllerTest.java index 6ae2063da..752b7404d 100644 --- a/app/src/test/java/fr/free/nrw/commons/NearbyControllerTest.java +++ b/app/src/test/java/fr/free/nrw/commons/NearbyControllerTest.java @@ -18,7 +18,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = 21) +@Config(constants = BuildConfig.class, sdk = 21, application = TestCommonsApplication.class) public class NearbyControllerTest { @Test diff --git a/app/src/test/java/fr/free/nrw/commons/PageTitleTest.java b/app/src/test/java/fr/free/nrw/commons/PageTitleTest.java index 455b3fbd0..16336b1b0 100644 --- a/app/src/test/java/fr/free/nrw/commons/PageTitleTest.java +++ b/app/src/test/java/fr/free/nrw/commons/PageTitleTest.java @@ -11,7 +11,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = 21) +@Config(constants = BuildConfig.class, sdk = 21, application = TestCommonsApplication.class) public class PageTitleTest { @Test public void displayTextShouldNotBeUnderscored() { diff --git a/app/src/test/java/fr/free/nrw/commons/TestCommonsApplication.java b/app/src/test/java/fr/free/nrw/commons/TestCommonsApplication.java new file mode 100644 index 000000000..af4d50a91 --- /dev/null +++ b/app/src/test/java/fr/free/nrw/commons/TestCommonsApplication.java @@ -0,0 +1,12 @@ +package fr.free.nrw.commons; + +import com.squareup.leakcanary.RefWatcher; + +// This class is automatically discovered by Robolectric +public class TestCommonsApplication extends CommonsApplication { + @Override + protected RefWatcher setupLeakCanary() { + // No leakcanary in unit tests. + return RefWatcher.DISABLED; + } +} diff --git a/app/src/test/java/fr/free/nrw/commons/UtilsTest.java b/app/src/test/java/fr/free/nrw/commons/UtilsTest.java deleted file mode 100644 index a51b7a19a..000000000 --- a/app/src/test/java/fr/free/nrw/commons/UtilsTest.java +++ /dev/null @@ -1,32 +0,0 @@ -package fr.free.nrw.commons; - -import org.junit.Assert; -import org.junit.Test; - -import static org.hamcrest.CoreMatchers.is; - -public class UtilsTest { - @Test public void stripLocalizedStringPass() { - Assert.assertThat(Utils.stripLocalizedString("Hello"), is("Hello")); - } - - @Test public void stripLocalizedStringJa() { - Assert.assertThat(Utils.stripLocalizedString("\"こんにちは\"@ja"), is("こんにちは")); - } - - @Test public void capitalizeLowercase() { - Assert.assertThat(Utils.capitalize("hello"), is("Hello")); - } - - @Test public void capitalizeFullCaps() { - Assert.assertThat(Utils.capitalize("HELLO"), is("HELLO")); - } - - @Test public void capitalizeNumbersPass() { - Assert.assertThat(Utils.capitalize("12x"), is("12x")); - } - - @Test public void capitalizeJaPass() { - Assert.assertThat(Utils.capitalize("こんにちは"), is("こんにちは")); - } -} diff --git a/app/src/test/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApiTest.java b/app/src/test/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApiTest.java index e27ca19ea..8e72b3252 100644 --- a/app/src/test/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApiTest.java +++ b/app/src/test/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApiTest.java @@ -17,6 +17,7 @@ import java.util.Map; import java.util.Set; import fr.free.nrw.commons.BuildConfig; +import fr.free.nrw.commons.TestCommonsApplication; import io.reactivex.observers.TestObserver; import okhttp3.HttpUrl; import okhttp3.mockwebserver.MockResponse; @@ -28,7 +29,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = 21) +@Config(constants = BuildConfig.class, sdk = 21, application = TestCommonsApplication.class) public class ApacheHttpClientMediaWikiApiTest { private ApacheHttpClientMediaWikiApi testObject; diff --git a/app/src/test/java/fr/free/nrw/commons/nearby/NearbyAdapterFactoryTest.java b/app/src/test/java/fr/free/nrw/commons/nearby/NearbyAdapterFactoryTest.java index 76125aa43..c86067ce6 100644 --- a/app/src/test/java/fr/free/nrw/commons/nearby/NearbyAdapterFactoryTest.java +++ b/app/src/test/java/fr/free/nrw/commons/nearby/NearbyAdapterFactoryTest.java @@ -20,13 +20,14 @@ import java.util.Collections; import fr.free.nrw.commons.BuildConfig; import fr.free.nrw.commons.R; +import fr.free.nrw.commons.TestCommonsApplication; import fr.free.nrw.commons.location.LatLng; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = 21) +@Config(constants = BuildConfig.class, sdk = 21, application = TestCommonsApplication.class) public class NearbyAdapterFactoryTest { private static final Place PLACE = new Place("name", Place.Description.AIRPORT, diff --git a/app/src/test/kotlin/fr/free/nrw/commons/UtilsTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/UtilsTest.kt new file mode 100644 index 000000000..7efb48c24 --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/UtilsTest.kt @@ -0,0 +1,31 @@ +package fr.free.nrw.commons + +import org.junit.Assert +import org.junit.Test +import org.hamcrest.CoreMatchers.`is` as _is + +class UtilsTest { + @Test fun `strip nothing from non-localized string`() { + Assert.assertThat(Utils.stripLocalizedString("Hello"), _is("Hello")) + } + + @Test fun `strip tag from Japanese string`() { + Assert.assertThat(Utils.stripLocalizedString("\"こんにちは\"@ja"), _is("こんにちは")) + } + + @Test fun `capitalize first letter`() { + Assert.assertThat(Utils.capitalize("hello"), _is("Hello")) + } + + @Test fun `capitalize - pass all-capital string as it is`() { + Assert.assertThat(Utils.capitalize("HELLO"), _is("HELLO")) + } + + @Test fun `capitalize - pass numbers`() { + Assert.assertThat(Utils.capitalize("12x"), _is("12x")) + } + + @Test fun `capitalize - pass Japanase characters`() { + Assert.assertThat(Utils.capitalize("こんにちは"), _is("こんにちは")) + } +} diff --git a/build.gradle b/build.gradle index 70023d85f..6b7e5dc00 100644 --- a/build.gradle +++ b/build.gradle @@ -1,14 +1,16 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { + ext.kotlin_version = '1.1.51' repositories { jcenter() mavenCentral() + google() } dependencies { classpath "com.android.tools.build:gradle:${project.gradleVersion}" classpath 'com.dicedmelon.gradle:jacoco-android:0.1.1' classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.7.1' - classpath 'me.tatarka:gradle-retrolambda:3.6.1' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } @@ -17,5 +19,6 @@ allprojects { jcenter() maven { url "https://jitpack.io" } maven { url "https://maven.google.com" } + google() } } diff --git a/design/screenshots/English en-US/car-categories.png b/design/screenshots/English en-US/car-categories.png new file mode 100755 index 000000000..931289d18 Binary files /dev/null and b/design/screenshots/English en-US/car-categories.png differ diff --git a/design/screenshots/English en-US/car-description.png b/design/screenshots/English en-US/car-description.png new file mode 100755 index 000000000..9ed27e3d0 Binary files /dev/null and b/design/screenshots/English en-US/car-description.png differ diff --git a/design/screenshots/English en-US/car-details.png b/design/screenshots/English en-US/car-details.png new file mode 100755 index 000000000..4a3852af5 Binary files /dev/null and b/design/screenshots/English en-US/car-details.png differ diff --git a/design/screenshots/English en-US/gallery.png b/design/screenshots/English en-US/gallery.png new file mode 100755 index 000000000..59d082658 Binary files /dev/null and b/design/screenshots/English en-US/gallery.png differ diff --git a/design/screenshots/English en-US/menu.png b/design/screenshots/English en-US/menu.png new file mode 100755 index 000000000..c2377a542 Binary files /dev/null and b/design/screenshots/English en-US/menu.png differ diff --git a/design/screenshots/English en-US/nearby-list.png b/design/screenshots/English en-US/nearby-list.png new file mode 100755 index 000000000..126ed3b4e Binary files /dev/null and b/design/screenshots/English en-US/nearby-list.png differ diff --git a/design/screenshots/English en-US/nearby-map.png b/design/screenshots/English en-US/nearby-map.png new file mode 100755 index 000000000..446ab52f5 Binary files /dev/null and b/design/screenshots/English en-US/nearby-map.png differ diff --git a/design/screenshots/English en-US/restaurant-categories.png b/design/screenshots/English en-US/restaurant-categories.png new file mode 100755 index 000000000..9df0074c5 Binary files /dev/null and b/design/screenshots/English en-US/restaurant-categories.png differ diff --git a/design/screenshots/English en-US/restaurant-description.png b/design/screenshots/English en-US/restaurant-description.png new file mode 100755 index 000000000..61ce5b25d Binary files /dev/null and b/design/screenshots/English en-US/restaurant-description.png differ diff --git a/design/screenshots/English en-US/restaurant-details.png b/design/screenshots/English en-US/restaurant-details.png new file mode 100755 index 000000000..bddc282c0 Binary files /dev/null and b/design/screenshots/English en-US/restaurant-details.png differ diff --git a/design/screenshots/English en-US/school-categories.png b/design/screenshots/English en-US/school-categories.png new file mode 100755 index 000000000..de62ae57a Binary files /dev/null and b/design/screenshots/English en-US/school-categories.png differ diff --git a/design/screenshots/English en-US/school-description.png b/design/screenshots/English en-US/school-description.png new file mode 100755 index 000000000..516cc0151 Binary files /dev/null and b/design/screenshots/English en-US/school-description.png differ diff --git a/design/screenshots/English en-US/school-details.png b/design/screenshots/English en-US/school-details.png new file mode 100755 index 000000000..f203b6b41 Binary files /dev/null and b/design/screenshots/English en-US/school-details.png differ diff --git a/design/screenshots/add-picture.png b/design/screenshots/add-picture.png deleted file mode 100644 index 36e2f4afe..000000000 Binary files a/design/screenshots/add-picture.png and /dev/null differ diff --git a/design/screenshots/add-picture2.png b/design/screenshots/add-picture2.png deleted file mode 100755 index b86f9271b..000000000 Binary files a/design/screenshots/add-picture2.png and /dev/null differ diff --git a/design/screenshots/license.png b/design/screenshots/license.png deleted file mode 100644 index a51fe6002..000000000 Binary files a/design/screenshots/license.png and /dev/null differ diff --git a/design/screenshots/my-uploads.png b/design/screenshots/my-uploads.png deleted file mode 100644 index 60b474ae7..000000000 Binary files a/design/screenshots/my-uploads.png and /dev/null differ diff --git a/design/screenshots/my-uploads2.png b/design/screenshots/my-uploads2.png deleted file mode 100644 index 6d889fd30..000000000 Binary files a/design/screenshots/my-uploads2.png and /dev/null differ diff --git a/design/screenshots/my-uploads3.png b/design/screenshots/my-uploads3.png deleted file mode 100755 index 924902f08..000000000 Binary files a/design/screenshots/my-uploads3.png and /dev/null differ diff --git a/design/screenshots/search-categories.png b/design/screenshots/search-categories.png deleted file mode 100755 index 59927301c..000000000 Binary files a/design/screenshots/search-categories.png and /dev/null differ diff --git a/design/screenshots/view-categories.png b/design/screenshots/view-categories.png deleted file mode 100644 index e164ce761..000000000 Binary files a/design/screenshots/view-categories.png and /dev/null differ diff --git a/gitutils.gradle b/gitutils.gradle new file mode 100644 index 000000000..e84cb1eda --- /dev/null +++ b/gitutils.gradle @@ -0,0 +1,21 @@ +ext.getBuildVersion = { -> + def stdout = new ByteArrayOutputStream() + exec { + commandLine 'git', 'rev-parse', '--short', 'HEAD' + standardOutput = stdout + } + return stdout.toString().trim() +} + +ext.getBranchName = { -> + try { + def stdOut = new ByteArrayOutputStream() + exec { + commandLine 'git', 'rev-parse', '--abbrev-ref', 'HEAD' + standardOutput = stdOut + } + return stdOut.toString().trim() + } catch (ignored) { + return null + } +} diff --git a/gradle.properties b/gradle.properties index 4b643d02b..07148a581 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,9 +1,9 @@ -gradleVersion = 2.3.3 +gradleVersion = 3.0.0 supportLibVersion = 26.1.0 compileSdkVersion = android-26 -buildToolsVersion = 26.0.1 +buildToolsVersion = 26.0.2 minSdkVersion = 15 @@ -12,5 +12,10 @@ android.useDeprecatedNdk=true # Library dependencies BUTTERKNIFE_VERSION=8.6.0 +DAGGER_VERSION=2.11 org.gradle.jvmargs=-Xmx1536M + +#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 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7d2af2435..7a3265ee9 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 4dde7c991..f16d26666 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.0.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-bin.zip