Merge branch 'master' into featuredImages

This commit is contained in:
Vivek Maskara 2018-04-19 23:44:33 +05:30 committed by GitHub
commit b108dff460
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
276 changed files with 4290 additions and 2539 deletions

View file

@ -1,5 +1,15 @@
# Wikimedia Commons for Android
## v2.7.0
- New Nearby Places UI with direct uploads (and associated category suggestions)
- Added two-factor authentication login
- Added Notifications activity to display user talk messages
- Added real-time location tracking in Nearby
- Added "rate us", "translate", and FB link in About
- Improvements to UI of navigation drawer, tutorial, media details view, login activity and Settings
- Added option to nominate picture for deletion in media details view
- Too many bug and crash fixes to mention!
## v2.6.7
- Added null checks to prevent frequent crashes in ModificationsSyncAdapter

View file

@ -1 +1,19 @@
Please see our guidelines in the wiki: https://github.com/commons-app/apps-android-commons/wiki/Volunteers-welcome%21
Thanks for considering to contribute to this project! A few guidelines for
people who want to contribute their code to this software are documented in
[this project's Wiki](https://github.com/commons-app/apps-android-commons/wiki/Contributing-Guidelines).
If you're not sure where to start head on to [this wiki page](https://github.com/commons-app/apps-android-commons/wiki/Volunteers-welcome!).
Here's a gist of the guidelines,
# Make separate commits for logically separate changes
# Describe your changes well in the commit message
The first line of the commit message should be a short description of what has
changed. It is also good to prefix the first line with "area: " where the "area"
is a filename or identifier for the general area of the code being modified.
The body should provide a meaningful commit message.
# Write tests for your code (if possible)
# Make sure the Wiki pages don't become stale by updating them (if needed)

10
CREDITS
View file

@ -30,6 +30,16 @@ their contribution to the product.
* Bruke Mekuria Mulugeta
* Paul Hawke
* Vishan Seru
* Abhishek Poonia
* Ayushi Negi
* Harisanker Pradeep
* Hassan Ismaeel
* Jatin Rao
* Meghna Gupta
* S Balakrishnan
* Suchit Kar
* Tanvi Dadu
* Ujjwal Agrawal
3rd party open source libraries used:
* Butterknife

View file

@ -11,18 +11,19 @@ dependencies {
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 'ch.acra:acra:4.9.2'
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.borjabravo:readmoretextview:2.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
implementation ('com.mapbox.mapboxsdk:mapbox-android-sdk:5.4.1@aar'){
transitive=true
}
implementation "com.android.support:support-v4:$SUPPORT_LIB_VERSION"
implementation "com.android.support:appcompat-v7:$SUPPORT_LIB_VERSION"
implementation "com.android.support:design:$SUPPORT_LIB_VERSION"
@ -41,8 +42,6 @@ dependencies {
// explicitly depend on RxJava's latest version for bug fixes and new features.
implementation 'com.android.support:multidex:1.0.3'
testImplementation "org.robolectric:multidex:3.4.2"
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'
@ -54,33 +53,25 @@ dependencies {
implementation "com.google.dagger:dagger:$DAGGER_VERSION"
implementation "com.google.dagger:dagger-android-support:$DAGGER_VERSION"
kapt "com.google.dagger:dagger-android-processor:$DAGGER_VERSION"
kapt "com.google.dagger:dagger-compiler:$DAGGER_VERSION"
testImplementation "org.robolectric:multidex:3.4.2"
testImplementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
androidTestImplementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
testImplementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
testImplementation 'junit:junit:4.12'
testImplementation 'org.robolectric:robolectric:3.7.1'
testImplementation 'org.mockito:mockito-all:1.10.19'
testImplementation 'com.nhaarman:mockito-kotlin:1.5.0'
testImplementation 'com.squareup.okhttp3:mockwebserver:3.8.1'
androidTestImplementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
androidTestImplementation 'com.squareup.okhttp3:mockwebserver:3.8.1'
androidTestImplementation "com.android.support:support-annotations:$SUPPORT_LIB_VERSION"
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2-alpha1'
debugImplementation "com.squareup.leakcanary:leakcanary-android:$LEAK_CANARY"
releaseImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$LEAK_CANARY"
testImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$LEAK_CANARY"
implementation "com.google.dagger:dagger:$DAGGER_VERSION"
implementation "com.google.dagger:dagger-android-support:$DAGGER_VERSION"
kapt "com.google.dagger:dagger-compiler:$DAGGER_VERSION"
kapt "com.google.dagger:dagger-android-processor:$DAGGER_VERSION"
implementation 'com.borjabravo:readmoretextview:2.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
}
android {
@ -91,8 +82,8 @@ android {
defaultConfig {
applicationId 'fr.free.nrw.commons'
versionCode 82
versionName '2.6.7'
versionCode 83
versionName '2.7.0'
setProperty("archivesBaseName", "app-commons-v$versionName-" + getBranchName())
minSdkVersion project.minSdkVersion
@ -137,6 +128,7 @@ android {
buildConfigField "String", "WIKIMEDIA_FORGE_API_HOST", "\"https://tools.wmflabs.org/\""
buildConfigField "String", "IMAGE_URL_BASE", "\"https://upload.wikimedia.org/wikipedia/commons\""
buildConfigField "String", "HOME_URL", "\"https://commons.wikimedia.org/wiki/\""
buildConfigField "String", "COMMONS_URL", "\"https://commons.wikimedia.org\""
buildConfigField "String", "MOBILE_HOME_URL", "\"https://commons.m.wikimedia.org/wiki/\""
buildConfigField "String", "EVENTLOG_URL", "\"https://www.wikimedia.org/beacon/event\""
buildConfigField "String", "EVENTLOG_WIKI", "\"commonswiki\""
@ -152,6 +144,7 @@ android {
buildConfigField "String", "WIKIMEDIA_FORGE_API_HOST", "\"https://tools.wmflabs.org/\""
buildConfigField "String", "IMAGE_URL_BASE", "\"https://upload.beta.wmflabs.org/wikipedia/commons\""
buildConfigField "String", "HOME_URL", "\"https://commons.wikimedia.beta.wmflabs.org/wiki/\""
buildConfigField "String", "COMMONS_URL", "\"https://commons.wikimedia.beta.wmflabs.org\""
buildConfigField "String", "MOBILE_HOME_URL", "\"https://commons.m.wikimedia.beta.wmflabs.org/wiki/\""
buildConfigField "String", "EVENTLOG_URL", "\"https://commons.wikimedia.beta.wmflabs.org/beacon/event\""
buildConfigField "String", "EVENTLOG_WIKI", "\"commonswiki\""

View file

@ -6,11 +6,15 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.text.Html;
import android.text.SpannableString;
import android.text.style.UnderlineSpan;
import android.util.Log;
import android.support.customtabs.CustomTabsIntent;
import android.support.v4.content.ContextCompat;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
@ -62,6 +66,18 @@ public class AboutActivity extends NavigationBaseActivity {
content.setSpan(new UnderlineSpan(), 0, content.length(), 0);
faqText.setText(content);
versionText.setText(BuildConfig.VERSION_NAME);
TextView rate_us = findViewById(R.id.about_rate_us);
TextView privacy_policy = findViewById(R.id.about_privacy_policy);
TextView translate = findViewById(R.id.about_translate);
TextView credits = findViewById(R.id.about_credits);
TextView faq = findViewById(R.id.about_faq);
rate_us.setText(Html.fromHtml(getString(R.string.about_rate_us)));
privacy_policy.setText(Html.fromHtml(getString(R.string.about_privacy_policy)));
translate.setText(Html.fromHtml(getString(R.string.about_translate)));
credits.setText(Html.fromHtml(getString(R.string.about_credits)));
faq.setText(Html.fromHtml(getString(R.string.about_faq)));
initDrawer();
}
@ -108,6 +124,28 @@ public class AboutActivity extends NavigationBaseActivity {
Utils.handleWebUrl(this,Uri.parse("https://github.com/commons-app/apps-android-commons/wiki/Frequently-Asked-Questions\\"));
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_about, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.share_app_icon:
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, "http://play.google.com/store/apps/details?id=fr.free.nrw.commons");
sendIntent.setType("text/plain");
startActivity(Intent.createChooser(sendIntent, "Share app via..."));
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@OnClick(R.id.about_translate)
public void launchTranslate(View view) {
final ArrayAdapter<String> languageAdapter = new ArrayAdapter<String>(AboutActivity.this,

View file

@ -54,9 +54,11 @@ public class CommonsApplication extends MultiDexApplication {
public static final String FEEDBACK_EMAIL = "commons-app-android@googlegroups.com";
public static final String FEEDBACK_EMAIL_SUBJECT = "Commons Android App (%s) Feedback";
public static final String LOGS_PRIVATE_EMAIL = "commons-app-android-private@googlegroups.com";
public static final String FEEDBACK_EMAIL_SUBJECT = "Commons Android App (%s) Feedback";
public static final String LOGS_PRIVATE_EMAIL_SUBJECT = "Commons Android App (%s) Logs";
private RefWatcher refWatcher;

View file

@ -43,6 +43,7 @@ public class Media implements Parcelable {
protected String license;
protected String creator;
protected ArrayList<String> categories; // as loaded at runtime?
protected boolean requestedDeletion;
private Map<String, String> descriptions; // multilingual descriptions as loaded
private HashMap<String, Object> tags = new HashMap<>();
private @Nullable LatLng coordinates;
@ -416,4 +417,12 @@ public class Media implements Parcelable {
parcel.writeStringList(categories);
parcel.writeMap(descriptions);
}
public void setRequestedDeletion(){
requestedDeletion = true;
}
public boolean getRequestedDeletion(){
return requestedDeletion;
}
}

View file

@ -35,6 +35,7 @@ import timber.log.Timber;
public class MediaDataExtractor {
private final MediaWikiApi mediaWikiApi;
private boolean fetched;
private boolean deletionStatus;
private ArrayList<String> categories;
private Map<String, String> descriptions;
private String license;
@ -59,6 +60,14 @@ public class MediaDataExtractor {
throw new IllegalStateException("Tried to call MediaDataExtractor.fetch() again.");
}
try{
Timber.d("Nominated for deletion: " + mediaWikiApi.pageExists("Commons:Deletion_requests/"+filename));
deletionStatus = mediaWikiApi.pageExists("Commons:Deletion_requests/"+filename);
}
catch (Exception e){
Timber.d(e.getMessage());
}
MediaResult result = mediaWikiApi.fetchMediaByFilename(filename);
// In-page category links are extracted from source, as XML doesn't cover [[links]]
@ -296,6 +305,9 @@ public class MediaDataExtractor {
if (license != null) {
media.setLicense(license);
}
if (deletionStatus){
media.setRequestedDeletion();
}
// add author, date, etc fields
}

View file

@ -177,7 +177,7 @@ public class Utils {
}
}
public static void handleWebUrl(Context context,Uri url){
public static void handleWebUrl(Context context, Uri url) {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, url);
if (browserIntent.resolveActivity(context.getPackageManager()) == null) {
Toast toast = Toast.makeText(context, context.getString(R.string.no_web_browser), LENGTH_SHORT);

View file

@ -280,8 +280,11 @@ public class CategorizationFragment extends CommonsDaggerSupportFragment {
private Observable<CategoryItem> directCategories() {
String directCategory = directPrefs.getString("Category", "");
// Strip newlines to prevent blank categories, and to tidy existing categories
directCategory = directCategory.replace("\n", "");
List<String> categoryList = new ArrayList<>();
Timber.d("Direct category found: " + directCategory);
Timber.d("Direct category found: " + "'" + directCategory + "'");
if (!directCategory.equals("")) {
hasDirectCategories = true;

View file

@ -105,6 +105,7 @@ public class CategoryDao {
return items;
}
@NonNull
Category fromCursor(Cursor cursor) {
// Hardcoding column positions!
return new Category(

View file

@ -1,10 +1,13 @@
package fr.free.nrw.commons.delete;
import android.app.AlertDialog;
import android.app.NotificationManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.AsyncTask;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationCompat.Builder;
import android.view.Gravity;
import android.widget.Toast;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
@ -18,17 +21,18 @@ import fr.free.nrw.commons.di.ApplicationlessInjection;
import fr.free.nrw.commons.mwapi.MediaWikiApi;
import timber.log.Timber;
import static android.support.v4.content.ContextCompat.startActivity;
import static android.support.v4.app.NotificationCompat.DEFAULT_ALL;
import static android.support.v4.app.NotificationCompat.PRIORITY_HIGH;
public class DeleteTask extends AsyncTask<Void, Void, Integer> {
private static final int SUCCESS = 0;
private static final int FAILED = -1;
private static final int ALREADY_DELETED = -2;
public class DeleteTask extends AsyncTask<Void, Integer, Boolean> {
@Inject MediaWikiApi mwApi;
@Inject SessionManager sessionManager;
public static final int NOTIFICATION_DELETE = 1;
private NotificationManager notificationManager;
private Builder notificationBuilder;
private Context context;
private Media media;
private String reason;
@ -45,10 +49,19 @@ public class DeleteTask extends AsyncTask<Void, Void, Integer> {
.getInstance(context.getApplicationContext())
.getCommonsApplicationComponent()
.inject(this);
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationBuilder = new NotificationCompat.Builder(context);
Toast toast = new Toast(context);
toast.setGravity(Gravity.CENTER,0,0);
toast = Toast.makeText(context,"Trying to nominate "+media.getDisplayTitle()+ " for deletion",Toast.LENGTH_SHORT);
toast.show();
}
@Override
protected Integer doInBackground(Void ...voids) {
protected Boolean doInBackground(Void ...voids) {
publishProgress(0);
String editToken;
String authCookie;
String summary = "Nominating " + media.getFilename() +" for deletion.";
@ -56,27 +69,6 @@ public class DeleteTask extends AsyncTask<Void, Void, Integer> {
authCookie = sessionManager.getAuthCookie();
mwApi.setAuthCookie(authCookie);
try{
if (mwApi.pageExists("Commons:Deletion_requests/"+media.getFilename())){
return ALREADY_DELETED;
}
}
catch (Exception e) {
Timber.d(e.getMessage());
return FAILED;
}
try {
editToken = mwApi.getEditToken();
}
catch (Exception e){
Timber.d(e.getMessage());
return FAILED;
}
if (editToken.equals("+\\")) {
return FAILED;
}
Calendar calendar = Calendar.getInstance();
String fileDeleteString = "{{delete|reason=" + reason +
"|subpage=" +media.getFilename() +
@ -84,91 +76,106 @@ public class DeleteTask extends AsyncTask<Void, Void, Integer> {
"|month=" + calendar.getDisplayName(Calendar.MONTH,Calendar.LONG, Locale.getDefault()) +
"|year=" + calendar.get(Calendar.YEAR) +
"}}";
try{
mwApi.prependEdit(editToken,fileDeleteString+"\n",
media.getFilename(),summary);
}
catch (Exception e) {
Timber.d(e.getMessage());
return FAILED;
}
String subpageString = "=== [[:" + media.getFilename() + "]] ===\n" +
reason +
" ~~~~";
try{
mwApi.edit(editToken,subpageString+"\n",
"Commons:Deletion_requests/"+media.getFilename(),summary);
}
catch (Exception e) {
Timber.d(e.getMessage());
return FAILED;
}
String logPageString = "\n{{Commons:Deletion requests/" + media.getFilename() +
"}}\n";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
String date = sdf.format(calendar.getTime());
try{
mwApi.appendEdit(editToken,logPageString+"\n",
"Commons:Deletion_requests/"+date,summary);
}
catch (Exception e) {
Timber.d(e.getMessage());
return FAILED;
}
String userPageString = "\n{{subst:idw|" + media.getFilename() +
"}} ~~~~";
try{
try {
editToken = mwApi.getEditToken();
if (editToken.equals("+\\")) {
return false;
}
publishProgress(1);
mwApi.prependEdit(editToken,fileDeleteString+"\n",
media.getFilename(),summary);
publishProgress(2);
mwApi.edit(editToken,subpageString+"\n",
"Commons:Deletion_requests/"+media.getFilename(),summary);
publishProgress(3);
mwApi.appendEdit(editToken,logPageString+"\n",
"Commons:Deletion_requests/"+date,summary);
publishProgress(4);
mwApi.appendEdit(editToken,userPageString+"\n",
"User_Talk:"+sessionManager.getCurrentAccount().name,summary);
publishProgress(5);
}
catch (Exception e) {
Timber.d(e.getMessage());
return FAILED;
return false;
}
return SUCCESS;
return true;
}
@Override
protected void onPostExecute(Integer result) {
protected void onProgressUpdate (Integer... values){
super.onProgressUpdate(values);
String message = "";
String title = "";
switch (result){
case SUCCESS:
title = "Success";
message = "Successfully nominated " + media.getDisplayTitle() + " deletion.\n" +
"Check the webpage for more details";
switch (values[0]){
case 0:
message = "Getting token";
break;
case FAILED:
title = "Failed";
message = "Could not request deletion. Something went wrong.";
case 1:
message = "Adding delete message to file";
break;
case ALREADY_DELETED:
title = "Already Nominated";
message = media.getDisplayTitle() + " has already been nominated for deletion.\n" +
"Check the webpage for more details";
case 2:
message = "Creating Delete requests sub-page";
break;
case 3:
message = "Adding file to Delete requests log";
break;
case 4:
message = "Notifying User on Talk page";
break;
case 5:
message = "Done";
break;
}
AlertDialog alert;
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(title);
builder.setMessage(message);
builder.setCancelable(true);
builder.setPositiveButton(
R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {}
});
builder.setNeutralButton(R.string.view_browser,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, media.getFilePageTitle().getMobileUri());
startActivity(context,browserIntent,null);
notificationBuilder.setContentTitle("Nominating "+media.getDisplayTitle()+" for deletion")
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(message))
.setSmallIcon(R.drawable.ic_launcher)
.setProgress(5, values[0], false)
.setOngoing(true);
notificationManager.notify(NOTIFICATION_DELETE, notificationBuilder.build());
}
});
alert = builder.create();
alert.show();
@Override
protected void onPostExecute(Boolean result) {
String message = "";
String title = "Nominating for Deletion";
if (result){
title += ": Success";
message = "Successfully nominated " + media.getDisplayTitle() + " deletion.";
}
else {
title += ": Failed";
message = "Could not request deletion.";
}
notificationBuilder.setDefaults(DEFAULT_ALL)
.setContentTitle(title)
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(message))
.setSmallIcon(R.drawable.ic_launcher)
.setProgress(0,0,false)
.setOngoing(false)
.setPriority(PRIORITY_HIGH);
notificationManager.notify(NOTIFICATION_DELETE, notificationBuilder.build());
}
}

View file

@ -15,7 +15,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
@ -42,6 +41,7 @@ import fr.free.nrw.commons.R;
import fr.free.nrw.commons.delete.DeleteTask;
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
import fr.free.nrw.commons.location.LatLng;
import fr.free.nrw.commons.mwapi.MediaWikiApi;
import fr.free.nrw.commons.ui.widget.CompatTextView;
import timber.log.Timber;
@ -71,6 +71,9 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
@Inject
Provider<MediaDataExtractor> mediaDataExtractorProvider;
@Inject
MediaWikiApi mwApi;
private MediaWikiImageView image;
private MediaDetailSpacer spacer;
@ -82,6 +85,8 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
private TextView license;
private TextView coordinates;
private TextView uploadedDate;
private TextView seeMore;
private LinearLayout nominatedforDeletion;
private LinearLayout categoryContainer;
private LinearLayout authorLayout;
private Button delete;
@ -142,6 +147,8 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
license = (TextView) view.findViewById(R.id.mediaDetailLicense);
coordinates = (TextView) view.findViewById(R.id.mediaDetailCoordinates);
uploadedDate = (TextView) view.findViewById(R.id.mediaDetailuploadeddate);
seeMore = (TextView) view.findViewById(R.id.seeMore);
nominatedforDeletion = (LinearLayout) view.findViewById(R.id.nominatedDeletionBanner);
delete = (Button) view.findViewById(R.id.nominateDeletion);
categoryContainer = (LinearLayout) view.findViewById(R.id.mediaDetailCategoryContainer);
authorLayout = (LinearLayout) view.findViewById(R.id.authorLinearLayout);
@ -247,7 +254,6 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
if (success) {
extractor.fill(media);
setTextFields(media);
setOnClickListeners(media);
} else {
@ -300,7 +306,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
}
rebuildCatList();
delete.setVisibility(View.VISIBLE);
checkDeletion(media);
}
private void setOnClickListeners(final Media media) {
@ -313,8 +319,11 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
if (media.getCoordinates() != null) {
coordinates.setOnClickListener(v -> openMap(media.getCoordinates()));
}
if (delete.getVisibility()==View.VISIBLE){
if (delete.getVisibility() == View.VISIBLE) {
enableDeleteButton(true);
delete.setOnClickListener(v -> {
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
alert.setMessage("Why should this file be deleted?");
final EditText input = new EditText(getActivity());
@ -325,6 +334,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
String reason = input.getText().toString();
DeleteTask deleteTask = new DeleteTask(getActivity(), media, reason);
deleteTask.execute();
enableDeleteButton(false);
}
});
alert.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@ -359,6 +369,20 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
d.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
});
}
if (nominatedforDeletion.getVisibility() == View.VISIBLE){
seeMore.setOnClickListener(v -> {
openWebBrowser(media.getFilePageTitle().getMobileUri().toString());
});
}
}
private void enableDeleteButton(boolean visibility) {
delete.setEnabled(visibility);
if(visibility) {
delete.setTextColor(getResources().getColor(R.color.primaryTextColor));
} else {
delete.setTextColor(getResources().getColor(R.color.deleteButtonLight));
}
}
private void rebuildCatList() {
@ -382,7 +406,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
viewIntent.setAction(Intent.ACTION_VIEW);
viewIntent.setData(new PageTitle(selectedCategoryTitle).getCanonicalUri());
//check if web browser available
if(viewIntent.resolveActivity(getActivity().getPackageManager()) != null){
if (viewIntent.resolveActivity(getActivity().getPackageManager()) != null) {
startActivity(viewIntent);
} else {
Toast toast = Toast.makeText(getContext(), getString(R.string.no_web_browser), LENGTH_SHORT);
@ -450,6 +474,16 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
return media.getCoordinates().getPrettyCoordinateString();
}
private void checkDeletion(Media media){
if (media.getRequestedDeletion()){
delete.setVisibility(View.GONE);
nominatedforDeletion.setVisibility(View.VISIBLE);
}
else{
delete.setVisibility(View.VISIBLE);
nominatedforDeletion.setVisibility(View.GONE);
}
}
private @Nullable
String licenseLink(Media media) {

View file

@ -23,7 +23,6 @@ import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.util.EntityUtils;
import org.mediawiki.api.ApiResult;
import org.mediawiki.api.MWApi;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.io.IOException;
@ -41,16 +40,12 @@ import java.util.concurrent.Callable;
import fr.free.nrw.commons.BuildConfig;
import fr.free.nrw.commons.PageTitle;
import fr.free.nrw.commons.notification.Notification;
import fr.free.nrw.commons.notification.NotificationUtils;
import in.yuvi.http.fluent.Http;
import io.reactivex.Observable;
import io.reactivex.Single;
import timber.log.Timber;
import static fr.free.nrw.commons.notification.NotificationType.UNKNOWN;
import static fr.free.nrw.commons.notification.NotificationUtils.getNotificationFromApiResult;
import static fr.free.nrw.commons.notification.NotificationUtils.getNotificationType;
import static fr.free.nrw.commons.notification.NotificationUtils.isCommonsNotification;
/**
* @author Addshore
*/
@ -434,32 +429,24 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
.param("notprop", "list")
.param("format", "xml")
.param("meta", "notifications")
.param("notfilter", "!read")
// .param("meta", "notifications")
.param("notformat", "model")
.get()
.getNode("/api/query/notifications/list");
} catch (IOException e) {
Timber.e("Failed to obtain searchCategories", e);
}
if (notificationNode == null) {
if (notificationNode == null
|| notificationNode.getDocument() == null
|| notificationNode.getDocument().getChildNodes() == null
|| notificationNode.getDocument().getChildNodes().getLength() == 0) {
return new ArrayList<>();
}
List<Notification> notifications = new ArrayList<>();
NodeList childNodes = notificationNode.getDocument().getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
if (isCommonsNotification(node)
&& !getNotificationType(node).equals(UNKNOWN)) {
notifications.add(getNotificationFromApiResult(context, node));
return NotificationUtils.getNotificationsFromList(context, childNodes);
}
}
return notifications;
}
@Override
public boolean existingFile(String fileSha1) throws IOException {

View file

@ -8,6 +8,7 @@ import android.support.v7.app.AlertDialog;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.contributions.ContributionController;
import timber.log.Timber;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
@ -23,46 +24,25 @@ class DirectUpload {
this.controller = controller;
}
void initiateCameraUpload() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(fragment.getActivity(), WRITE_EXTERNAL_STORAGE) != PERMISSION_GRANTED) {
if (fragment.getActivity().shouldShowRequestPermissionRationale(WRITE_EXTERNAL_STORAGE)) {
new AlertDialog.Builder(fragment.getActivity())
.setMessage(fragment.getActivity().getString(R.string.write_storage_permission_rationale))
.setPositiveButton("OK", (dialog, which) -> {
fragment.getActivity().requestPermissions(new String[]{WRITE_EXTERNAL_STORAGE}, 3);
dialog.dismiss();
})
.setNegativeButton("Cancel", null)
.create()
.show();
} else {
fragment.getActivity().requestPermissions(new String[]{WRITE_EXTERNAL_STORAGE}, 3);
}
} else {
controller.startCameraCapture();
}
} else {
controller.startCameraCapture();
}
}
// These permission requests will be handled by the Fragments.
// Do not use requestCode 1 as it will conflict with NearbyActivity's requestCodes
void initiateGalleryUpload() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(fragment.getActivity(), READ_EXTERNAL_STORAGE) != PERMISSION_GRANTED) {
if (fragment.getActivity().shouldShowRequestPermissionRationale(READ_EXTERNAL_STORAGE)) {
if (fragment.shouldShowRequestPermissionRationale(READ_EXTERNAL_STORAGE)) {
new AlertDialog.Builder(fragment.getActivity())
.setMessage(fragment.getActivity().getString(R.string.read_storage_permission_rationale))
.setPositiveButton("OK", (dialog, which) -> {
fragment.getActivity().requestPermissions(new String[]{READ_EXTERNAL_STORAGE}, 1);
Timber.d("Requesting permissions for read external storage");
fragment.requestPermissions(new String[]{READ_EXTERNAL_STORAGE}, 4);
dialog.dismiss();
})
.setNegativeButton("Cancel", null)
.create()
.show();
} else {
fragment.getActivity().requestPermissions(new String[]{READ_EXTERNAL_STORAGE},
1);
fragment.requestPermissions(new String[]{READ_EXTERNAL_STORAGE},
4);
}
} else {
controller.startGalleryPick();
@ -72,4 +52,28 @@ class DirectUpload {
controller.startGalleryPick();
}
}
void initiateCameraUpload() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(fragment.getActivity(), WRITE_EXTERNAL_STORAGE) != PERMISSION_GRANTED) {
if (fragment.shouldShowRequestPermissionRationale(WRITE_EXTERNAL_STORAGE)) {
new AlertDialog.Builder(fragment.getActivity())
.setMessage(fragment.getActivity().getString(R.string.write_storage_permission_rationale))
.setPositiveButton("OK", (dialog, which) -> {
fragment.requestPermissions(new String[]{WRITE_EXTERNAL_STORAGE}, 5);
dialog.dismiss();
})
.setNegativeButton("Cancel", null)
.create()
.show();
} else {
fragment.requestPermissions(new String[]{WRITE_EXTERNAL_STORAGE}, 5);
}
} else {
controller.startCameraCapture();
}
} else {
controller.startCameraCapture();
}
}
}

View file

@ -1,13 +1,15 @@
package fr.free.nrw.commons.nearby;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomSheetBehavior;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AlertDialog;
import android.view.Menu;
@ -16,7 +18,6 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@ -27,20 +28,18 @@ import javax.inject.Inject;
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.NetworkUtils;
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;
@ -63,17 +62,20 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
@Inject
NearbyController nearbyController;
private LatLng curLatLang;
private LatLng curLatLng;
private Bundle bundle;
private Disposable placesDisposable;
private boolean lockNearbyView; //Determines if the nearby places needs to be refreshed
private BottomSheetBehavior bottomSheetBehavior; // Behavior for list bottom sheet
private BottomSheetBehavior bottomSheetBehaviorForDetails; // Behavior for details bottom sheet
private NearbyMapFragment nearbyMapFragment;
public NearbyMapFragment nearbyMapFragment;
private NearbyListFragment nearbyListFragment;
private static final String TAG_RETAINED_MAP_FRAGMENT = NearbyMapFragment.class.getSimpleName();
private static final String TAG_RETAINED_LIST_FRAGMENT = NearbyListFragment.class.getSimpleName();
private final String NETWORK_INTENT_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
private BroadcastReceiver broadcastReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -128,11 +130,17 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.action_display_list:
if(bottomSheetBehavior.getState()==BottomSheetBehavior.STATE_COLLAPSED || bottomSheetBehavior.getState()==BottomSheetBehavior.STATE_HIDDEN){
bottomSheetBehaviorForDetails.setState(BottomSheetBehavior.STATE_HIDDEN);
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
}else if(bottomSheetBehavior.getState()==BottomSheetBehavior.STATE_EXPANDED){
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
return true;
default:
return super.onOptionsItemSelected(item);
@ -157,6 +165,11 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
showLocationPermissionDeniedErrorDialog();
}
}
break;
default:
// This is needed to allow the request codes from the Fragments to be routed appropriately
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
@ -254,8 +267,6 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
@Override
protected void onStop() {
super.onStop();
locationManager.removeLocationListener(this);
locationManager.unregisterLocationManager();
}
@Override
@ -271,6 +282,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
super.onResume();
lockNearbyView = false;
checkGps();
addNetworkBroadcastReceiver();
}
@Override
@ -283,9 +295,33 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
// to the retained fragment object to perform its own cleanup.
removeMapFragment();
removeListFragment();
}
unregisterReceiver(broadcastReceiver);
broadcastReceiver = null;
locationManager.removeLocationListener(this);
locationManager.unregisterLocationManager();
}
private void addNetworkBroadcastReceiver() {
IntentFilter intentFilter = new IntentFilter(NETWORK_INTENT_ACTION);
broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (NetworkUtils.isInternetConnectionEstablished(NearbyActivity.this)) {
refreshView(LocationServiceManager
.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED);
} else {
ViewUtil.showLongToast(NearbyActivity.this, getString(R.string.no_internet));
}
}
};
this.registerReceiver(broadcastReceiver, intentFilter);
}
/**
@ -297,15 +333,21 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
if (lockNearbyView) {
return;
}
if (!NetworkUtils.isInternetConnectionEstablished(this)) {
hideProgressBar();
return;
}
locationManager.registerLocationManager();
LatLng lastLocation = locationManager.getLastLocation();
if (curLatLang != null && curLatLang.equals(lastLocation)) { //refresh view only if location has changed
if (curLatLng != null && curLatLng.equals(lastLocation)) { //refresh view only if location has changed
return;
}
curLatLang = lastLocation;
curLatLng = lastLocation;
if (curLatLang == null) {
if (curLatLng == null) {
Timber.d("Skipping update of nearby places as location is unavailable");
return;
}
@ -314,7 +356,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
.equals(LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED)) {
progressBar.setVisibility(View.VISIBLE);
placesDisposable = Observable.fromCallable(() -> nearbyController
.loadAttractionsFromLocation(curLatLang))
.loadAttractionsFromLocation(curLatLng))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::populatePlaces);
@ -323,7 +365,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
Gson gson = new GsonBuilder()
.registerTypeAdapter(Uri.class, new UriSerializer())
.create();
String gsonCurLatLng = gson.toJson(curLatLang);
String gsonCurLatLng = gson.toJson(curLatLng);
bundle.putString("CurLatLng", gsonCurLatLng);
updateMapFragment(true);
}
@ -336,7 +378,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
.registerTypeAdapter(Uri.class, new UriSerializer())
.create();
String gsonPlaceList = gson.toJson(placeList);
String gsonCurLatLng = gson.toJson(curLatLang);
String gsonCurLatLng = gson.toJson(curLatLng);
String gsonBoundaryCoordinates = gson.toJson(boundaryCoordinates);
if (placeList.size() == 0) {
@ -388,6 +430,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
if (nearbyMapFragment != null) {
android.support.v4.app.FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction().remove(nearbyMapFragment).commit();
nearbyMapFragment = null;
}
}
@ -399,6 +442,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
if (nearbyListFragment != null) {
android.support.v4.app.FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction().remove(nearbyListFragment).commit();
nearbyListFragment = null;
}
}
@ -413,34 +457,34 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
NearbyMapFragment nearbyMapFragment = getMapFragment();
if (nearbyMapFragment != null && curLatLang != null) {
if (nearbyMapFragment != null && curLatLng != null) {
hideProgressBar(); // In case it is visible (this happens, not an impossible case)
/*
* If we are close to nearby places boundaries, we need a significant update to
* get new nearby places. Check order is south, north, west, east
* */
if (nearbyMapFragment.boundaryCoordinates != null
&& (curLatLang.getLatitude() <= nearbyMapFragment.boundaryCoordinates[0].getLatitude()
|| curLatLang.getLatitude() >= nearbyMapFragment.boundaryCoordinates[1].getLatitude()
|| curLatLang.getLongitude() <= nearbyMapFragment.boundaryCoordinates[2].getLongitude()
|| curLatLang.getLongitude() >= nearbyMapFragment.boundaryCoordinates[3].getLongitude())) {
&& (curLatLng.getLatitude() <= nearbyMapFragment.boundaryCoordinates[0].getLatitude()
|| curLatLng.getLatitude() >= nearbyMapFragment.boundaryCoordinates[1].getLatitude()
|| curLatLng.getLongitude() <= nearbyMapFragment.boundaryCoordinates[2].getLongitude()
|| curLatLng.getLongitude() >= nearbyMapFragment.boundaryCoordinates[3].getLongitude())) {
// populate places
placesDisposable = Observable.fromCallable(() -> nearbyController
.loadAttractionsFromLocation(curLatLang))
.loadAttractionsFromLocation(curLatLng))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::populatePlaces);
nearbyMapFragment.setArguments(bundle);
nearbyMapFragment.setBundleForUpdtes(bundle);
nearbyMapFragment.updateMapSignificantly();
updateListFragment();
return;
}
if (isSlightUpdate) {
nearbyMapFragment.setArguments(bundle);
nearbyMapFragment.setBundleForUpdtes(bundle);
nearbyMapFragment.updateMapSlightly();
} else {
nearbyMapFragment.setArguments(bundle);
nearbyMapFragment.setBundleForUpdtes(bundle);
nearbyMapFragment.updateMapSignificantly();
updateListFragment();
}
@ -454,7 +498,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
}
private void updateListFragment() {
nearbyListFragment.setArguments(bundle);
nearbyListFragment.setBundleForUpdates(bundle);
nearbyListFragment.updateNearbyListSignificantly();
}

View file

@ -54,15 +54,17 @@ public class NearbyController {
}
List<Place> places = nearbyPlaces.getFromWikidataQuery(curLatLng, Locale.getDefault().getLanguage());
if (places.size() > 0) {
LatLng[] boundaryCoordinates = {places.get(0).location, // south
places.get(0).location, // north
places.get(0).location, // west
places.get(0).location};// east, init with a random location
if (curLatLng != null) {
Timber.d("Sorting places by distance...");
final Map<Place, Double> distances = new HashMap<>();
for (Place place: places) {
for (Place place : places) {
distances.put(place, computeDistanceBetween(place.location, curLatLng));
// Find boundaries with basic find max approach
if (place.location.getLatitude() < boundaryCoordinates[0].getLatitude()) {
@ -90,6 +92,10 @@ public class NearbyController {
nearbyPlacesInfo.boundaryCoordinates = boundaryCoordinates;
return nearbyPlacesInfo;
}
else {
return null;
}
}
/**
* Loads attractions from location for list view, we need to return Place data type.

View file

@ -33,6 +33,8 @@ import static android.app.Activity.RESULT_OK;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
public class NearbyListFragment extends DaggerFragment {
private Bundle bundleForUpdates; // Carry information from activity about changed nearby places and current location
private static final Type LIST_TYPE = new TypeToken<List<Place>>() {
}.getType();
private static final Type CUR_LAT_LNG_TYPE = new TypeToken<LatLng>() {
@ -80,8 +82,7 @@ public class NearbyListFragment extends DaggerFragment {
}
public void updateNearbyListSignificantly() {
Bundle bundle = this.getArguments();
adapterFactory.updateAdapterData(getPlaceListFromBundle(bundle),
adapterFactory.updateAdapterData(getPlaceListFromBundle(bundleForUpdates),
(RVRendererAdapter<Place>) recyclerView.getAdapter());
}
@ -106,8 +107,8 @@ public class NearbyListFragment extends DaggerFragment {
Timber.d("onRequestPermissionsResult: req code = " + " perm = " + permissions + " grant =" + grantResults);
switch (requestCode) {
// 1 = "Read external storage" allowed when gallery selected
case 1: {
// 4 = "Read external storage" allowed when gallery selected
case 4: {
if (grantResults.length > 0 && grantResults[0] == PERMISSION_GRANTED) {
Timber.d("Call controller.startGalleryPick()");
controller.startGalleryPick();
@ -115,8 +116,8 @@ public class NearbyListFragment extends DaggerFragment {
}
break;
// 3 = "Write external storage" allowed when camera selected
case 3: {
// 5 = "Write external storage" allowed when camera selected
case 5: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Timber.d("Call controller.startCameraCapture()");
controller.startCameraCapture();
@ -140,4 +141,8 @@ public class NearbyListFragment extends DaggerFragment {
}
}
public void setBundleForUpdates(Bundle bundleForUpdates) {
this.bundleForUpdates = bundleForUpdates;
}
}

View file

@ -53,8 +53,10 @@ import javax.inject.Named;
import dagger.android.support.DaggerFragment;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.contributions.ContributionController;
import fr.free.nrw.commons.utils.UriDeserializer;
import fr.free.nrw.commons.utils.ViewUtil;
import timber.log.Timber;
import static android.app.Activity.RESULT_OK;
@ -97,6 +99,7 @@ public class NearbyMapFragment extends DaggerFragment {
private Animation fab_open;
private Animation rotate_forward;
private ContributionController controller;
private DirectUpload directUpload;
private Place place;
private Marker selected;
@ -105,7 +108,10 @@ public class NearbyMapFragment extends DaggerFragment {
private PolygonOptions currentLocationPolygonOptions;
private boolean isBottomListSheetExpanded;
private final double CAMERA_TARGET_SHIFT_FACTOR = 0.06;
private final double CAMERA_TARGET_SHIFT_FACTOR_PORTRAIT = 0.06;
private final double CAMERA_TARGET_SHIFT_FACTOR_LANDSCAPE = 0.04;
private Bundle bundleForUpdtes;// Carry information from activity about changed nearby places and current location
@Inject
@Named("prefs")
@ -120,6 +126,10 @@ public class NearbyMapFragment extends DaggerFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
controller = new ContributionController(this);
directUpload = new DirectUpload(this, controller);
Bundle bundle = this.getArguments();
Gson gson = new GsonBuilder()
.registerTypeAdapter(Uri.class, new UriDeserializer())
@ -184,14 +194,12 @@ public class NearbyMapFragment extends DaggerFragment {
}
public void updateMapSlightly() {
// Get arguments from bundle for new location
Bundle bundle = this.getArguments();
if (mapboxMap != null) {
Gson gson = new GsonBuilder()
.registerTypeAdapter(Uri.class, new UriDeserializer())
.create();
if (bundle != null) {
String gsonLatLng = bundle.getString("CurLatLng");
if (bundleForUpdtes != null) {
String gsonLatLng = bundleForUpdtes.getString("CurLatLng");
Type curLatLngType = new TypeToken<fr.free.nrw.commons.location.LatLng>() {}.getType();
curLatLng = gson.fromJson(gsonLatLng, curLatLngType);
}
@ -201,17 +209,15 @@ public class NearbyMapFragment extends DaggerFragment {
}
public void updateMapSignificantly() {
Bundle bundle = this.getArguments();
if (mapboxMap != null) {
if (bundle != null) {
if (bundleForUpdtes != null) {
Gson gson = new GsonBuilder()
.registerTypeAdapter(Uri.class, new UriDeserializer())
.create();
String gsonPlaceList = bundle.getString("PlaceList");
String gsonLatLng = bundle.getString("CurLatLng");
String gsonBoundaryCoordinates = bundle.getString("BoundaryCoord");
String gsonPlaceList = bundleForUpdtes.getString("PlaceList");
String gsonLatLng = bundleForUpdtes.getString("CurLatLng");
String gsonBoundaryCoordinates = bundleForUpdtes.getString("BoundaryCoord");
Type listType = new TypeToken<List<Place>>() {}.getType();
List<Place> placeList = gson.fromJson(gsonPlaceList, listType);
Type curLatLngType = new TypeToken<fr.free.nrw.commons.location.LatLng>() {}.getType();
@ -253,13 +259,28 @@ public class NearbyMapFragment extends DaggerFragment {
}
// Make camera to follow user on location change
CameraPosition position = new CameraPosition.Builder()
CameraPosition position ;
if(ViewUtil.isPortrait(getActivity())){
position = new CameraPosition.Builder()
.target(isBottomListSheetExpanded ?
new LatLng(curMapBoxLatLng.getLatitude()- CAMERA_TARGET_SHIFT_FACTOR,
new LatLng(curMapBoxLatLng.getLatitude()- CAMERA_TARGET_SHIFT_FACTOR_PORTRAIT,
curMapBoxLatLng.getLongitude())
: curMapBoxLatLng ) // Sets the new camera position
.zoom(mapboxMap.getCameraPosition().zoom) // Same zoom level
.zoom(isBottomListSheetExpanded ?
11 // zoom level is fixed to 11 when bottom sheet is expanded
:mapboxMap.getCameraPosition().zoom) // Same zoom level
.build();
}else {
position = new CameraPosition.Builder()
.target(isBottomListSheetExpanded ?
new LatLng(curMapBoxLatLng.getLatitude()- CAMERA_TARGET_SHIFT_FACTOR_LANDSCAPE,
curMapBoxLatLng.getLongitude())
: curMapBoxLatLng ) // Sets the new camera position
.zoom(isBottomListSheetExpanded ?
11 // zoom level is fixed to 11 when bottom sheet is expanded
:mapboxMap.getCameraPosition().zoom) // Same zoom level
.build();
}
mapboxMap.animateCamera(CameraUpdateFactory
.newCameraPosition(position), 1000);
@ -273,12 +294,21 @@ public class NearbyMapFragment extends DaggerFragment {
if (mapboxMap != null && curLatLng != null) {
if (isBottomListSheetExpanded) {
// Make camera to follow user on location change
if(ViewUtil.isPortrait(getActivity())) {
position = new CameraPosition.Builder()
.target(new LatLng(curLatLng.getLatitude() - CAMERA_TARGET_SHIFT_FACTOR,
.target(new LatLng(curLatLng.getLatitude() - CAMERA_TARGET_SHIFT_FACTOR_PORTRAIT,
curLatLng.getLongitude())) // Sets the new camera target above
// current to make it visible when sheet is expanded
.zoom(11) // Same zoom level
.zoom(11) // Fixed zoom level
.build();
} else {
position = new CameraPosition.Builder()
.target(new LatLng(curLatLng.getLatitude() - CAMERA_TARGET_SHIFT_FACTOR_LANDSCAPE,
curLatLng.getLongitude())) // Sets the new camera target above
// current to make it visible when sheet is expanded
.zoom(11) // Fixed zoom level
.build();
}
} else {
// Make camera to follow user on location change
@ -344,10 +374,29 @@ public class NearbyMapFragment extends DaggerFragment {
fabRecenter.setOnClickListener(view -> {
if (curLatLng != null) {
mapView.getMapAsync(mapboxMap -> {
CameraPosition position = new CameraPosition.Builder()
.target(new LatLng(curLatLng.getLatitude(), curLatLng.getLongitude())) // Sets the new camera position
.zoom(11) // Sets the zoom
.build(); // Creates a CameraPosition from the builder
CameraPosition position;
if(ViewUtil.isPortrait(getActivity())){
position = new CameraPosition.Builder()
.target(isBottomListSheetExpanded ?
new LatLng(curLatLng.getLatitude()- CAMERA_TARGET_SHIFT_FACTOR_PORTRAIT,
curLatLng.getLongitude())
: new LatLng(curLatLng.getLatitude(), curLatLng.getLongitude(), 0)) // Sets the new camera position
.zoom(isBottomListSheetExpanded ?
11 // zoom level is fixed to 11 when bottom sheet is expanded
:mapboxMap.getCameraPosition().zoom) // Same zoom level
.build();
}else {
position = new CameraPosition.Builder()
.target(isBottomListSheetExpanded ?
new LatLng(curLatLng.getLatitude()- CAMERA_TARGET_SHIFT_FACTOR_LANDSCAPE,
curLatLng.getLongitude())
: new LatLng(curLatLng.getLatitude(), curLatLng.getLongitude(), 0)) // Sets the new camera position
.zoom(isBottomListSheetExpanded ?
11 // zoom level is fixed to 11 when bottom sheet is expanded
:mapboxMap.getCameraPosition().zoom) // Same zoom level
.build();
}
mapboxMap.animateCamera(CameraUpdateFactory
.newCameraPosition(position), 1000);
@ -394,11 +443,9 @@ public class NearbyMapFragment extends DaggerFragment {
}
});
// Remove texts if it doesnt fit
if (wikipediaButtonText.getLineCount() > 1
|| wikidataButtonText.getLineCount() > 1
|| commonsButtonText.getLineCount() > 1
|| directionsButtonText.getLineCount() > 1) {
// Remove button text if they exceed 1 line or if internal layout has not been built
// Only need to check for directions button because it is the longest
if (directionsButtonText.getLineCount() > 1 || directionsButtonText.getLineCount() == 0) {
wikipediaButtonText.setVisibility(View.GONE);
wikidataButtonText.setVisibility(View.GONE);
commonsButtonText.setVisibility(View.GONE);
@ -408,6 +455,8 @@ public class NearbyMapFragment extends DaggerFragment {
private void setupMapView(Bundle savedInstanceState) {
MapboxMapOptions options = new MapboxMapOptions()
.compassGravity(Gravity.BOTTOM | Gravity.LEFT)
.compassMargins(new int[]{12, 0, 0, 24})
.styleUrl(Style.OUTDOORS)
.logoEnabled(false)
.attributionEnabled(false)
@ -536,7 +585,9 @@ public class NearbyMapFragment extends DaggerFragment {
transparentView.setAlpha(0);
closeFabs(isFabOpen);
hideFAB();
if (this.getView() != null) {
this.getView().requestFocus();
}
break;
}
}
@ -583,7 +634,7 @@ public class NearbyMapFragment extends DaggerFragment {
/*
* Add amnchors back before making them visible again.
* Add anchors back before making them visible again.
* */
private void addAnchorToBigFABs(FloatingActionButton floatingActionButton, int anchorID) {
CoordinatorLayout.LayoutParams params = new CoordinatorLayout.LayoutParams
@ -594,7 +645,7 @@ public class NearbyMapFragment extends DaggerFragment {
}
/*
* Add amnchors back before making them visible again. Big and small fabs have different anchor
* Add anchors back before making them visible again. Big and small fabs have different anchor
* gravities, therefore the are two methods.
* */
private void addAnchorToSmallFABs(FloatingActionButton floatingActionButton, int anchorID) {
@ -615,7 +666,7 @@ public class NearbyMapFragment extends DaggerFragment {
directionsButton.setOnClickListener(view -> {
//Open map app at given position
Intent mapIntent = new Intent(Intent.ACTION_VIEW, place.location.getGmmIntentUri());
Intent mapIntent = new Intent(Intent.ACTION_VIEW, this.place.location.getGmmIntentUri());
if (mapIntent.resolveActivity(getActivity().getPackageManager()) != null) {
startActivity(mapIntent);
}
@ -635,9 +686,6 @@ public class NearbyMapFragment extends DaggerFragment {
fabCamera.setOnClickListener(view -> {
if (fabCamera.isShown()) {
Timber.d("Camera button tapped. Image title: " + place.getName() + "Image desc: " + place.getLongDescription());
controller = new ContributionController(this);
DirectUpload directUpload = new DirectUpload(this, controller);
storeSharedPrefs();
directUpload.initiateCameraUpload();
}
@ -646,14 +694,8 @@ public class NearbyMapFragment extends DaggerFragment {
fabGallery.setOnClickListener(view -> {
if (fabGallery.isShown()) {
Timber.d("Gallery button tapped. Image title: " + place.getName() + "Image desc: " + place.getLongDescription());
controller = new ContributionController(this);
DirectUpload directUpload = new DirectUpload(this, controller);
storeSharedPrefs();
directUpload.initiateGalleryUpload();
//TODO: App crashes after image upload completes
//TODO: Handle onRequestPermissionsResult
}
});
}
@ -670,9 +712,10 @@ public class NearbyMapFragment extends DaggerFragment {
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
Timber.d("onRequestPermissionsResult: req code = " + " perm = " + permissions + " grant =" + grantResults);
// Do not use requestCode 1 as it will conflict with NearbyActivity's requestCodes
switch (requestCode) {
// 1 = "Read external storage" allowed when gallery selected
case 1: {
// 4 = "Read external storage" allowed when gallery selected
case 4: {
if (grantResults.length > 0 && grantResults[0] == PERMISSION_GRANTED) {
Timber.d("Call controller.startGalleryPick()");
controller.startGalleryPick();
@ -680,8 +723,8 @@ public class NearbyMapFragment extends DaggerFragment {
}
break;
// 3 = "Write external storage" allowed when camera selected
case 3: {
// 5 = "Write external storage" allowed when camera selected
case 5: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Timber.d("Call controller.startCameraCapture()");
controller.startCameraCapture();
@ -705,8 +748,7 @@ public class NearbyMapFragment extends DaggerFragment {
}
private void openWebView(Uri link) {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, link);
startActivity(browserIntent);
Utils.handleWebUrl(getContext(), link);
}
private void animateFAB(boolean isFabOpen) {
@ -740,6 +782,11 @@ public class NearbyMapFragment extends DaggerFragment {
}
}
public void setBundleForUpdtes(Bundle bundleForUpdtes) {
this.bundleForUpdtes = bundleForUpdtes;
}
@Override
public void onStart() {
if (mapView != null) {
@ -781,6 +828,9 @@ public class NearbyMapFragment extends DaggerFragment {
if (mapView != null) {
mapView.onDestroy();
}
selected = null;
currentLocationMarker = null;
super.onDestroyView();
}

View file

@ -27,6 +27,7 @@ import butterknife.BindView;
import butterknife.ButterKnife;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.contributions.ContributionController;
import fr.free.nrw.commons.di.ApplicationlessInjection;
import timber.log.Timber;
@ -200,8 +201,7 @@ public class PlaceRenderer extends Renderer<Place> {
}
private void openWebView(Uri link) {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, link);
view.getContext().startActivity(browserIntent);
Utils.handleWebUrl(getContext(), link);
}
private boolean showMenu() {

View file

@ -10,12 +10,14 @@ public class Notification {
public String date;
public String description;
public String link;
public String iconUrl;
public Notification(NotificationType notificationType, String notificationText, String date, String description, String link) {
public Notification(NotificationType notificationType, String notificationText, String date, String description, String link, String iconUrl) {
this.notificationType = notificationType;
this.notificationText = notificationText;
this.date = date;
this.description = description;
this.link = link;
this.iconUrl = iconUrl;
}
}

View file

@ -6,13 +6,18 @@ import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.widget.Toast;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import com.pedrogomez.renderers.RVRendererAdapter;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.List;
import javax.inject.Inject;
@ -20,14 +25,15 @@ import javax.inject.Inject;
import butterknife.BindView;
import butterknife.ButterKnife;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.theme.NavigationBaseActivity;
import fr.free.nrw.commons.utils.NetworkUtils;
import fr.free.nrw.commons.utils.ViewUtil;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import timber.log.Timber;
import static android.widget.Toast.LENGTH_SHORT;
/**
* Created by root on 18.12.2017.
*/
@ -36,6 +42,8 @@ public class NotificationActivity extends NavigationBaseActivity {
NotificationAdapterFactory notificationAdapterFactory;
@BindView(R.id.listView) RecyclerView recyclerView;
@BindView(R.id.progressBar) ProgressBar progressBar;
@BindView(R.id.container) RelativeLayout relativeLayout;
@Inject NotificationController controller;
@ -57,22 +65,44 @@ public class NotificationActivity extends NavigationBaseActivity {
recyclerView.setLayoutManager(new LinearLayoutManager(this));
DividerItemDecoration itemDecor = new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL);
recyclerView.addItemDecoration(itemDecor);
refresh();
}
private void refresh() {
if (!NetworkUtils.isInternetConnectionEstablished(this)) {
progressBar.setVisibility(View.GONE);
Snackbar.make(relativeLayout , R.string.no_internet, Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.retry, view -> {
refresh();
}).show();
}else {
progressBar.setVisibility(View.VISIBLE);
addNotifications();
}
}
@SuppressLint("CheckResult")
private void addNotifications() {
Timber.d("Add notifications");
if(mNotificationWorkerFragment == null){
Observable.fromCallable(() -> controller.getNotifications())
Observable.fromCallable(() -> {
progressBar.setVisibility(View.VISIBLE);
return controller.getNotifications();
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(notificationList -> {
Collections.reverse(notificationList);
Timber.d("Number of notifications is %d", notificationList.size());
initializeAndSetNotificationList(notificationList);
setAdapter(notificationList);
}, throwable -> Timber.e(throwable, "Error occurred while loading notifications"));
progressBar.setVisibility(View.GONE);
}, throwable -> {
Timber.e(throwable, "Error occurred while loading notifications");
ViewUtil.showSnackbar(relativeLayout, R.string.error_notifications);
progressBar.setVisibility(View.GONE);
});
} else {
setAdapter(mNotificationWorkerFragment.getNotificationList());
}
@ -82,17 +112,14 @@ public class NotificationActivity extends NavigationBaseActivity {
if (url == null || url.equals("")) {
return;
}
Intent browser = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
//check if web browser available
if(browser.resolveActivity(this.getPackageManager()) != null){
startActivity(browser);
} else {
Toast toast = Toast.makeText(this, getString(R.string.no_web_browser), LENGTH_SHORT);
toast.show();
}
Utils.handleWebUrl(this, Uri.parse(url));
}
private void setAdapter(List<Notification> notificationList) {
if(notificationList == null || notificationList.isEmpty()) {
ViewUtil.showSnackbar(relativeLayout, R.string.no_notifications);
return;
}
notificationAdapterFactory = new NotificationAdapterFactory(notification -> {
Timber.d("Notification clicked %s", notification.link);
handleUrl(notification.link);

View file

@ -20,7 +20,6 @@ import fr.free.nrw.commons.R;
public class NotificationRenderer extends Renderer<Notification> {
@BindView(R.id.title) ReadMoreTextView title;
@BindView(R.id.description) ReadMoreTextView description;
@BindView(R.id.time) TextView time;
@BindView(R.id.icon) ImageView icon;
private NotificationClicked listener;
@ -48,13 +47,10 @@ public class NotificationRenderer extends Renderer<Notification> {
@Override
public void render() {
Notification notification = getContent();
StringBuilder str = new StringBuilder(notification.notificationText);
str.append(" " );
String str = notification.notificationText.trim();
str = str.concat(" ");
title.setText(str);
time.setText(notification.date);
StringBuilder desc = new StringBuilder(notification.description);
desc.append(" ");
description.setText(desc);
switch (notification.notificationType) {
case THANK_YOU_EDIT:
icon.setImageResource(R.drawable.ic_edit_black_24dp);

View file

@ -1,16 +1,24 @@
package fr.free.nrw.commons.notification;
import android.annotation.SuppressLint;
import android.content.Context;
import android.support.annotation.NonNull;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
import fr.free.nrw.commons.BuildConfig;
import fr.free.nrw.commons.R;
import static fr.free.nrw.commons.notification.NotificationType.THANK_YOU_EDIT;
import static fr.free.nrw.commons.notification.NotificationType.UNKNOWN;
public class NotificationUtils {
private static final String COMMONS_WIKI = "commonswiki";
@ -29,27 +37,124 @@ public class NotificationUtils {
return NotificationType.handledValueOf(type);
}
public static List<Notification> getNotificationsFromBundle(Context context, Node document) {
Element bundledNotifications = getBundledNotifications(document);
NodeList childNodes = bundledNotifications.getChildNodes();
List<Notification> notifications = new ArrayList<>();
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
if (isUsefulNotification(node)) {
notifications.add(getNotificationFromApiResult(context, node));
}
}
return notifications;
}
@NonNull
public static List<Notification> getNotificationsFromList(Context context, NodeList childNodes) {
List<Notification> notifications = new ArrayList<>();
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
if (isUsefulNotification(node)) {
if (isBundledNotification(node)) {
notifications.addAll(getNotificationsFromBundle(context, node));
} else {
notifications.add(getNotificationFromApiResult(context, node));
}
}
}
return notifications;
}
private static boolean isUsefulNotification(Node node) {
return isCommonsNotification(node)
&& !getNotificationType(node).equals(UNKNOWN)
&& !getNotificationType(node).equals(THANK_YOU_EDIT);
}
public static boolean isBundledNotification(Node document) {
Element bundleElement = getBundledNotifications(document);
if (bundleElement == null) {
return false;
}
return bundleElement.getChildNodes().getLength() > 0;
}
private static Element getBundledNotifications(Node document) {
return (Element) getNode(document, "bundledNotifications");
}
public static Notification getNotificationFromApiResult(Context context, Node document) {
NotificationType type = getNotificationType(document);
String notificationText = "";
String link = getNotificationLink(document);
String link = getPrimaryLink(document);
String description = getNotificationDescription(document);
String iconUrl = getNotificationIconUrl(document);
switch (type) {
case THANK_YOU_EDIT:
notificationText = context.getString(R.string.notifications_thank_you_edit);
break;
case EDIT_USER_TALK:
notificationText = getUserTalkMessage(context, document);
notificationText = getNotificationText(document);
break;
case MENTION:
notificationText = getMentionMessage(context, document);
description = getMentionDescription(document);
break;
case WELCOME:
notificationText = getWelcomeMessage(context, document);
break;
}
return new Notification(type, notificationText, getTimestamp(document), description, link);
return new Notification(type, notificationText, getTimestamp(document), description, link, iconUrl);
}
private static String getNotificationText(Node document) {
String notificationBody = getNotificationBody(document);
if (notificationBody == null || notificationBody.trim().equals("")) {
return getNotificationHeader(document);
}
return notificationBody;
}
private static String getNotificationHeader(Node document) {
Node body = getNode(getModel(document), "header");
if (body != null) {
String textContent = body.getTextContent();
return textContent.replace("<strong>", "").replace("</strong>", "");
} else {
return "";
}
}
private static String getNotificationBody(Node document) {
Node body = getNode(getModel(document), "body");
if (body != null) {
String textContent = body.getTextContent();
return textContent.replace("<strong>", "").replace("</strong>", "");
} else {
return "";
}
}
private static String getMentionDescription(Node document) {
Node body = getNode(getModel(document), "body");
return body != null ? body.getTextContent() : "";
}
private static String getNotificationIconUrl(Node document) {
String format = "%s%s";
Node iconUrl = getNode(getModel(document), "iconUrl");
if(iconUrl == null) {
return null;
} else {
String url = iconUrl.getTextContent();
return String.format(format, BuildConfig.COMMONS_URL, url);
}
}
public static String getMentionMessage(Context context, Node document) {
@ -57,16 +162,31 @@ public class NotificationUtils {
return String.format(format, getAgent(document), getNotificationDescription(document));
}
@SuppressLint("StringFormatMatches")
public static String getUserTalkMessage(Context context, Node document) {
String format = context.getString(R.string.notifications_talk_page_message);
return String.format(format, getAgent(document));
}
@SuppressLint("StringFormatInvalid")
public static String getWelcomeMessage(Context context, Node document) {
String welcomeMessageFormat = context.getString(R.string.notifications_welcome);
return String.format(welcomeMessageFormat, getAgent(document));
}
private static String getPrimaryLink(Node document) {
Node links = getNode(getModel(document), "links");
Element primaryLink = (Element) getNode(links, "primary");
if (primaryLink != null) {
return primaryLink.getAttribute("url");
}
return "";
}
private static Node getModel(Node document) {
return getNode(document, "_.2A.");
}
private static String getAgent(Node document) {
Element agentElement = (Element) getNode(document, "agent");
if (agentElement != null) {
@ -83,16 +203,6 @@ public class NotificationUtils {
return "";
}
private static String getNotificationLink(Node document) {
String format = "%s%s";
Element titleElement = (Element) getNode(document, "title");
if (titleElement != null) {
String fullName = titleElement.getAttribute("full");
return String.format(format, BuildConfig.HOME_URL, fullName);
}
return "";
}
private static String getNotificationDescription(Node document) {
Element titleElement = (Element) getNode(document, "title");
if (titleElement != null) {

View file

@ -151,8 +151,9 @@ public class SettingsFragment extends PreferenceFragment {
emailSelectorIntent.setData(Uri.parse("mailto:"));
//initialize the emailIntent
final Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{CommonsApplication.FEEDBACK_EMAIL});
emailIntent.putExtra(Intent.EXTRA_SUBJECT, String.format(CommonsApplication.FEEDBACK_EMAIL_SUBJECT, BuildConfig.VERSION_NAME));
// Logs must be sent to the PRIVATE email. Please do not modify this without good reason!
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{CommonsApplication.LOGS_PRIVATE_EMAIL});
emailIntent.putExtra(Intent.EXTRA_SUBJECT, String.format(CommonsApplication.LOGS_PRIVATE_EMAIL_SUBJECT, BuildConfig.VERSION_NAME));
emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
emailIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
emailIntent.setSelector( emailSelectorIntent );

View file

@ -1,12 +1,18 @@
package fr.free.nrw.commons.upload;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapRegionDecoder;
import android.net.Uri;
import android.os.AsyncTask;
import android.support.v7.app.AlertDialog;
import java.io.IOException;
import java.lang.ref.WeakReference;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.contributions.ContributionsActivity;
import fr.free.nrw.commons.utils.ImageUtils;
import timber.log.Timber;
@ -21,16 +27,13 @@ import timber.log.Timber;
public class DetectUnwantedPicturesAsync extends AsyncTask<Void, Void, ImageUtils.Result> {
interface Callback {
void onResult(ImageUtils.Result result);
}
private final Callback callback;
private final String imageMediaFilePath;
public final WeakReference<Activity> activityWeakReference;
DetectUnwantedPicturesAsync(String imageMediaFilePath, Callback callback) {
this.callback = callback;
DetectUnwantedPicturesAsync(WeakReference<Activity> activityWeakReference, String imageMediaFilePath) {
//this.callback = callback;
this.imageMediaFilePath = imageMediaFilePath;
this.activityWeakReference = activityWeakReference;
}
@Override
@ -53,7 +56,29 @@ public class DetectUnwantedPicturesAsync extends AsyncTask<Void, Void, ImageUtil
@Override
protected void onPostExecute(ImageUtils.Result result) {
super.onPostExecute(result);
//callback to UI so that it can take necessary decision based on the result obtained
callback.onResult(result);
Activity activity = activityWeakReference.get();
if (result != ImageUtils.Result.IMAGE_OK) {
//show appropriate error message
String errorMessage = result == ImageUtils.Result.IMAGE_DARK ? activity.getString(R.string.upload_image_too_dark) : activity.getString(R.string.upload_image_blurry);
AlertDialog.Builder errorDialogBuilder = new AlertDialog.Builder(activity);
errorDialogBuilder.setMessage(errorMessage);
errorDialogBuilder.setTitle(activity.getString(R.string.warning));
errorDialogBuilder.setPositiveButton(activity.getString(R.string.no), (dialogInterface, i) -> {
//user does not wish to upload the picture, take them back to ContributionsActivity
Intent intent = new Intent(activity, ContributionsActivity.class);
dialogInterface.dismiss();
activity.startActivity(intent);
});
errorDialogBuilder.setNegativeButton(activity.getString(R.string.yes), (dialogInterface, i) -> {
//user wishes to go ahead with the upload of this picture, just dismiss this dialog
dialogInterface.dismiss();
});
AlertDialog errorDialog = errorDialogBuilder.create();
if (!activity.isFinishing()) {
errorDialog.show();
}
}
}
}

View file

@ -415,31 +415,9 @@ public class ShareActivity
private void performUnwantedPictureDetectionProcess() {
String imageMediaFilePath = FileUtils.getPath(this,mediaUri);
DetectUnwantedPicturesAsync detectUnwantedPicturesAsync = new DetectUnwantedPicturesAsync(imageMediaFilePath, result -> {
if (result != ImageUtils.Result.IMAGE_OK) {
//show appropriate error message
String errorMessage = result == ImageUtils.Result.IMAGE_DARK ? getString(R.string.upload_image_too_dark) : getString(R.string.upload_image_blurry);
AlertDialog.Builder errorDialogBuilder = new AlertDialog.Builder(this);
errorDialogBuilder.setMessage(errorMessage);
errorDialogBuilder.setTitle(getString(R.string.warning));
errorDialogBuilder.setPositiveButton(getString(R.string.no), (dialogInterface, i) -> {
//user does not wish to upload the picture, take them back to ContributionsActivity
Intent intent = new Intent(ShareActivity.this, ContributionsActivity.class);
dialogInterface.dismiss();
startActivity(intent);
});
errorDialogBuilder.setNegativeButton(getString(R.string.yes), (dialogInterface, i) -> {
//user wishes to go ahead with the upload of this picture, just dismiss this dialog
dialogInterface.dismiss();
});
AlertDialog errorDialog = errorDialogBuilder.create();
if (!isFinishing()) {
errorDialog.show();
}
}
});
DetectUnwantedPicturesAsync detectUnwantedPicturesAsync
= new DetectUnwantedPicturesAsync(new WeakReference<Activity>(this)
, imageMediaFilePath);
detectUnwantedPicturesAsync.execute();
}

View file

@ -14,7 +14,9 @@ import android.support.annotation.NonNull;
import android.support.v4.view.ViewCompat;
import android.support.v7.app.AlertDialog;
import android.text.Editable;
import android.text.Html;
import android.text.TextWatcher;
import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
@ -225,18 +227,6 @@ public class SingleUploadFragment extends CommonsDaggerSupportFragment {
.commit();
}
@OnTouch(R.id.share_license_summary)
boolean showLicence(View view, MotionEvent motionEvent) {
if (motionEvent.getActionMasked() == ACTION_DOWN) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse(licenseUrlFor(license)));
startActivity(intent);
return true;
} else {
return false;
}
}
@OnClick(R.id.titleDescButton)
void setTitleDescButton() {
@ -294,7 +284,9 @@ public class SingleUploadFragment extends CommonsDaggerSupportFragment {
@SuppressLint("StringFormatInvalid")
private void setLicenseSummary(String license) {
licenseSummaryView.setText(getString(R.string.share_license_summary, getString(Utils.licenseNameFor(license))));
String licenseHyperLink = "<a href='" + licenseUrlFor(license)+"'>"+ getString(Utils.licenseNameFor(license)) + "</a><br>";
licenseSummaryView.setMovementMethod(LinkMovementMethod.getInstance());
licenseSummaryView.setText(Html.fromHtml(getString(R.string.share_license_summary, licenseHyperLink)));
}
@Override

View file

@ -0,0 +1,18 @@
package fr.free.nrw.commons.utils;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
public class NetworkUtils {
public static boolean isInternetConnectionEstablished(Context context) {
ConnectivityManager cm =
(ConnectivityManager)context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
return activeNetwork != null &&
activeNetwork.isConnectedOrConnecting();
}
}

View file

@ -1,7 +1,11 @@
package fr.free.nrw.commons.utils;
import android.app.Activity;
import android.content.Context;
import android.support.design.widget.Snackbar;
import android.view.Display;
import android.view.View;
import android.widget.Toast;
public class ViewUtil {
@ -9,4 +13,18 @@ public class ViewUtil {
Snackbar.make(view, messageResourceId, Snackbar.LENGTH_SHORT).show();
}
public static void showLongToast(Context context, String text) {
Toast.makeText(context, text,
Toast.LENGTH_LONG).show();
}
public static boolean isPortrait(Context context) {
Display orientation = ((Activity)context).getWindowManager().getDefaultDisplay();
if(orientation.getWidth() < orientation.getHeight()){
return true;
} else {
return false;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<selector
android:layout_height="match_parent"
android:layout_width="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_enabled="true" >
<shape
android:shape="rectangle">
<solid
android:color="@color/deleteButton"/>
<corners
android:radius="3dp" />
<stroke
android:width="5px"
android:color="@color/deleteRed" />
</shape>
</item>
<item
android:state_enabled="false" >
<shape
android:shape="rectangle">
<solid
android:color="@color/deleteButtonDark"/>
<corners
android:radius="3dp" />
</shape>
</item>
</selector>

View file

@ -0,0 +1,5 @@
<vector android:alpha="0.84" android:height="32dp"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="32dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#ffffffff" android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/>
</vector>

View file

@ -111,7 +111,7 @@
android:layout_marginTop="@dimen/standard_gap"
android:gravity="center"
android:textColor="@color/primaryColor"
android:text="@string/about_rate_us" />
/>
<TextView
android:id="@+id/about_privacy_policy"
@ -121,7 +121,7 @@
android:layout_marginTop="@dimen/standard_gap"
android:textColor="@color/primaryColor"
android:gravity="center"
android:text="@string/about_privacy_policy" />
/>
<TextView
android:id="@+id/about_translate"
@ -131,7 +131,7 @@
android:textColor="@color/primaryColor"
android:layout_marginTop="@dimen/standard_gap"
android:gravity="center"
android:text="@string/about_translate" />
/>
<TextView
android:id="@+id/about_credits"
@ -141,7 +141,7 @@
android:textColor="@color/primaryColor"
android:layout_marginTop="@dimen/standard_gap"
android:gravity="center"
android:text="@string/about_credits" />
/>
<TextView
android:id="@+id/about_faq"
@ -153,15 +153,6 @@
android:gravity="center"
/>
<TextView
android:id="@+id/about_uploads_to"
style="?android:textAppearanceSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/large_gap"
android:alpha="0.2"
android:gravity="center" />
</LinearLayout>
</RelativeLayout>
</ScrollView>

View file

@ -5,7 +5,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
<android.support.design.widget.CoordinatorLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/coordinator_layout"
android:layout_width="match_parent"
@ -21,9 +21,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/toolbar"
android:gravity="center_vertical"
android:orientation="horizontal">
@ -38,32 +39,13 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:fabSize="mini"
android:layout_alignBottom="@id/toolbar"
android:layout_alignParentRight="true"
android:layout_marginRight="28dp"
android:layout_marginBottom="-96dp"
android:visibility="invisible"
app:elevation="6dp"
app:pressedTranslationZ="12dp"
app:backgroundTint="@color/button_blue"
android:clickable="true"
app:srcCompat="@drawable/ic_list_white_24dp"
android:scaleType="center"
/>
<View
android:id="@+id/transparentView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginTop="18dp"
android:layout_below="@id/toolbar"
android:background="#aa969696"
android:elevation="6dp">

View file

@ -6,6 +6,7 @@
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -15,6 +16,12 @@
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_height="wrap_content" />
<android.support.v7.widget.RecyclerView
android:id="@+id/listView"
android:layout_width="match_parent"

View file

@ -14,6 +14,7 @@
android:id="@+id/welcomePagerIndicator"
android:layout_height="@dimen/half_standard_height"
android:layout_width="match_parent"
android:layout_gravity="bottom" />
android:layout_gravity="bottom"
android:padding="5dp" />
</FrameLayout>

View file

@ -37,8 +37,11 @@
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp" />
android:textSize="16sp"
android:layout_marginRight="50dp"
android:maxLines="2"
android:ellipsize="end"
/>
<TextView
android:id="@+id/category"
android:layout_width="wrap_content"

View file

@ -284,10 +284,38 @@
android:layout_width="match_parent"
android:layout_height="@dimen/small_gap" />
<LinearLayout
android:id="@+id/nominatedDeletionBanner"
android:background="@color/deleteRed"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="@dimen/standard_gap"
android:visibility="gone">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/nominated_for_deletion"
android:textColor="@color/primaryTextColor"
android:textSize="@dimen/normal_text"
android:textStyle="bold"/>
<TextView
android:id="@+id/seeMore"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/nominated_see_more"
android:paddingTop="@dimen/standard_gap"
android:textColor="@color/primaryTextColor"
android:textSize="@dimen/normal_text"
android:textStyle="bold"/>
</LinearLayout>
<Button
android:id="@+id/nominateDeletion"
style="?android:attr/buttonBarButtonStyle"
android:textColor="@color/deleteTextColor"
android:background="@drawable/bg_delete_button"
android:textColor="@color/primaryTextColor"
android:layout_margin="@dimen/standard_gap"
android:layout_width="match_parent"
android:layout_height="wrap_content"

View file

@ -74,6 +74,8 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/standard_gap"
android:gravity="center"
android:clickable="true"
android:textColorLink="@color/button_blue"
android:text="@string/share_license_summary" />
<fr.free.nrw.commons.ui.widget.HtmlTextView

View file

@ -45,27 +45,12 @@
android:layout_toRightOf="@id/icon"
android:layout_toStartOf="@id/time"
android:ellipsize="end"
app:trimLines="2"
app:trimMode="trimModeLength"
app:trimLength="60"
android:layout_alignParentTop="true"
app:colorClickableText="#969494"
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
tools:text="@string/placeholder_place_name"
android:padding="12dp"
/>
<com.borjabravo.readmoretextview.ReadMoreTextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignEnd="@id/time"
android:layout_alignLeft="@id/title"
android:layout_alignRight="@id/time"
android:layout_alignStart="@id/title"
android:layout_below="@id/title"
android:layout_marginBottom="16dp"
android:ellipsize="end"
app:trimLines="2"
app:colorClickableText="#969494"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
tools:text="@string/placeholder_place_description"
/>
</RelativeLayout>

View file

@ -9,4 +9,5 @@
android:minHeight="?attr/actionBarSize"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
android:background="?attr/colorPrimaryDark">
</android.support.v7.widget.Toolbar>

View file

@ -1,47 +1,56 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:id="@+id/drawer_main">
<item
android:id="@+id/action_home"
android:icon="@drawable/ic_home_black_24dp"
android:title="@string/navigation_item_home"/>
android:title="@string/navigation_item_home" />
<item
android:id="@+id/action_nearby"
android:icon="@drawable/ic_location_black_24dp"
android:title="@string/navigation_item_nearby"/>
<item
android:id="@+id/action_notifications"
android:icon="@drawable/ic_notifications_black_24dp"
android:title="@string/navigation_item_notification"/>
<item
android:id="@+id/action_about"
android:icon="@drawable/ic_info_outline_black_24dp"
android:title="@string/navigation_item_about"/>
<item
android:id="@+id/action_settings"
android:icon="@drawable/ic_settings_black_24dp"
android:title="@string/navigation_item_settings"/>
<item
android:id="@+id/action_introduction"
android:icon="@drawable/ic_help_black_24dp"
android:title="@string/navigation_item_info"/>
<item
android:id="@+id/action_feedback"
android:icon="@drawable/ic_feedback_black_24dp"
android:title="@string/navigation_item_feedback"/>
<item
android:id="@+id/action_logout"
android:icon="@drawable/ic_exit_to_app_black_24dp"
android:title="@string/navigation_item_logout"/>
android:title="@string/navigation_item_nearby" />
<item
android:id="@+id/action_featured_images"
android:icon="@drawable/ic_star_black_24dp"
android:title="@string/navigation_item_featured_images"/>
</group>
<group android:id="@+id/drawer_account">
<item
android:id="@+id/action_notifications"
android:icon="@drawable/ic_notifications_black_24dp"
android:title="@string/navigation_item_notification" />
<item
android:id="@+id/action_settings"
android:icon="@drawable/ic_settings_black_24dp"
android:title="@string/navigation_item_settings" />
</group>
<group android:id="@+id/drawer_contact">
<item
android:id="@+id/action_about"
android:icon="@drawable/ic_info_outline_black_24dp"
android:title="@string/navigation_item_about" />
<item
android:id="@+id/action_introduction"
android:icon="@drawable/ic_help_black_24dp"
android:title="@string/navigation_item_info" />
<item
android:id="@+id/action_feedback"
android:icon="@drawable/ic_feedback_black_24dp"
android:title="@string/navigation_item_feedback" />
</group>
<group android:id="@+id/drawer_logout">
<item
android:id="@+id/action_logout"
android:icon="@drawable/ic_exit_to_app_black_24dp"
android:title="@string/navigation_item_logout" />
</group>
</menu>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainActivity"
>
<item
android:id="@+id/share_app_icon"
android:title="@string/refresh_button"
android:icon="@drawable/ic_share_black_24dp"
android:orderInCategory="1"
app:showAsAction="ifRoom"
/>
</menu>

View file

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Андрей
-->
<resources>
<string name="crash_dialog_title">Аиҧҟьара</string>
<string name="crash_dialog_ok_toast">Иҭабуп!</string>

View file

@ -1,4 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Envlh
* Андрей
-->
<resources>
<string name="menu_settings">Архиарақәа</string>
<string name="username">Ахархәаҩ ихьӡ</string>

View file

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Naudefj
-->
<resources>
<string name="crash_dialog_title">Commons het omgeval</string>
<string name="crash_dialog_text">Oeps. Er is iets misgegaan.</string>

View file

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Akamycoco
-->
<resources>
<string name="crash_dialog_ok_toast">kukay</string>
</resources>

View file

@ -1,4 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Ali1
* Mido
-->
<resources>
<string name="crash_dialog_title">لقد تعطل كومنز</string>
<string name="crash_dialog_text">عفوا. حدث خطأ!</string>

View file

@ -1,4 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Ali1
* Antime
* Azouz.anis
* ButterflyOfFire
* Claw eg
* Meno25
* Mido
* Monrokhoury
* Mr. Ibrahem
* OsamaK
* ترجمان05
* محمد أحمد عبد الفتاح
* مشعل الحربي
-->
<resources>
<string name="preference_category_general">عام</string>
<string name="app_name">كومنز</string>

View file

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Man2fly2002
-->
<resources>
<string name="crash_dialog_ok_toast">ܬܘܕܝ ܠܟ!</string>
</resources>

View file

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Xuacu
-->
<resources>
<string name="crash_dialog_title">Commons colgóse</string>
<string name="crash_dialog_text">Vaya. ¡Daqué funcionó mal!</string>

View file

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Xuacu
-->
<resources>
<string name="preference_category_appearance">Aspeutu</string>
<string name="preference_category_general">Xeneral</string>
@ -59,6 +62,7 @@
<string name="categories_search_text_hint">Guetar categoríes</string>
<string name="menu_save_categories">Guardar</string>
<string name="refresh_button">Refrescar</string>
<string name="display_list_button">Llista</string>
<string name="gps_disabled">El GPS ta desactiváu nel preséu. ¿Quiés activalu?</string>
<string name="enable_gps">Activar GPS</string>
<string name="contributions_subtitle_zero">Inda nun hai xubes</string>
@ -151,8 +155,8 @@
<string name="detail_description_empty">Ensin descripción</string>
<string name="detail_license_empty">Llicencia desconocida</string>
<string name="menu_refresh">Refrescar</string>
<string name="read_storage_permission_rationale">Permisu riquíu: llectura d\'almacenamientu esternu. L\'aplicación nun puede funcionar ensin él.</string>
<string name="write_storage_permission_rationale">Permisu riquíu: escritura d\'almacenamientu esternu. L\'aplicación nun puede funcionar ensin él.</string>
<string name="read_storage_permission_rationale" fuzzy="true">Permisu riquíu: llectura d\'almacenamientu esternu. L\'aplicación nun puede funcionar ensin él.</string>
<string name="write_storage_permission_rationale" fuzzy="true">Permisu riquíu: escritura d\'almacenamientu esternu. L\'aplicación nun puede funcionar ensin él.</string>
<string name="location_permission_rationale">Permisu opcional: llograr l\'allugamientu actual pa suxerir categoríes</string>
<string name="ok">Aceutar</string>
<string name="title_activity_nearby">Llugares cercanos</string>
@ -211,6 +215,7 @@
<string name="no_description_found">nun s\'atoparon descripciones</string>
<string name="nearby_info_menu_commons_article">Páxina del ficheru en Commons</string>
<string name="nearby_info_menu_wikidata_article">Elementu de WikiData</string>
<string name="nearby_info_menu_wikipedia_article">Artículu de Wikipedia</string>
<string name="error_while_cache">Error al poner les fotos na caché</string>
<string name="title_info">Un títulu descriptivu únicu pal ficheru, que sirvirá para da-y nome al ficheru. Se pue usar llinguax normal con espacios. Nun amiestes la estensión del ficheru</string>
<string name="description_info">Por favor, describi l\'elementu multimedia tantu como sía posible: ¿ónde se tomó?, ¿qué amuesa?, ¿cuál ye\'l contestu? Por favor, describi los oxetos o persones. Revela la información que nun pueda aldovinase de mou cenciellu, por casu el momentu del día si ye un paisaxe. Si\'l mediu amuesa daqué desacostumao, esplica qué lo fai raro.</string>
@ -224,6 +229,9 @@
<string name="send_log_file_description">Unviar ficheru de rexistru a los desendolcadores per corréu electrónicu</string>
<string name="no_web_browser">Nun s\'alcontró un restolador p\'abrir la URL</string>
<string name="null_url">¡Error! Nun s\'alcontró la URL</string>
<string name="nominate_deletion">Marcada pa desaniciar</string>
<string name="nominated_for_deletion">Esta imaxe marcóse pa desaniciar.</string>
<string name="view_browser">Ver nel restolador</string>
<string name="nearby_location_has_not_changed">L\'allugamientu nun camudó.</string>
<string name="nearby_location_not_available">L\'allugamientu nun ta disponible.</string>
<string name="location_permission_rationale_nearby">Ríquese permisu p\'amosar una llista de llugares cercanos</string>
@ -234,6 +242,21 @@
<string name="notifications_thank_you_edit">Gracies por facer una edición</string>
<string name="notifications_mention">%1$s te mentó en %2$s.</string>
<string name="toggle_view_button">Alternar vista</string>
<string name="about_faq">Entrugues más frecuentes</string>
<string name="nearby_directions">CÓMO LLEGAR</string>
<string name="nearby_wikidata">WIKIDATA</string>
<string name="nearby_wikipedia">WIKIPEDIA</string>
<string name="nearby_commons">COMMONS</string>
<string name="about_rate_us">&lt;u&gt;Puntúanos&lt;/u&gt;</string>
<string name="about_faq">&lt;u&gt;EMF&lt;/u&gt;</string>
<string name="welcome_skip_button">Saltar el tutorial</string>
<string name="no_internet">Internet nun ta disponible</string>
<string name="internet_established">Internet ta disponible</string>
<string name="error_notifications">Error al llograr les notificaciones</string>
<string name="no_notifications">Nun s\'alcontraron notificaciones</string>
<string name="about_translate">&lt;u&gt;Traducir&lt;/u&gt;</string>
<string name="about_translate_title">Llingües</string>
<string name="about_translate_message">Escueye l\'idioma pal que quies unviar traducciones</string>
<string name="about_translate_proceed">Siguir</string>
<string name="about_translate_cancel">Encaboxar</string>
<string name="retry">Retentar</string>
</resources>

View file

@ -1,4 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Dağlı95
* Khan27
-->
<resources>
<string name="crash_dialog_title">Nasazlıq</string>
<string name="crash_dialog_text">Uups. Nəsə düzgün çalışmır!</string>

View file

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Mousa
-->
<resources>
<string name="crash_dialog_title">کامانز ایشدن دوشدو</string>
<string name="crash_dialog_text">اوخ. بیر خطا قاباغا گلدی!</string>

View file

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Kareyac
-->
<resources>
<string name="crash_dialog_ok_toast">Дзякуем!</string>
</resources>

View file

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Thakurji
-->
<resources>
<string name="crash_dialog_title">Commons crash hoe gais</string>
<string name="crash_dialog_text">Oops, Koi chij wrong hoe gais</string>

View file

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Wikibilim
-->
<resources>
<string name="crash_dialog_ok_toast">Рақмет!</string>
</resources>

View file

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Servien
-->
<resources>
<string name="crash_dialog_title">Commons is vasteleupen</string>
<string name="crash_dialog_text">Oeps. Der gung iets mis.</string>

View file

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Joetaras
-->
<resources>
<string name="crash_dialog_title">Commons ha sckattate</string>
<string name="crash_dialog_text">Mudu. Quacchecose ha sciute male!</string>

View file

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Zoranzoki21
-->
<resources>
<string name="crash_dialog_title">Ostava se srušila</string>
<string name="crash_dialog_text">Ups! Nešto je pošlo naopako.</string>

View file

@ -1,4 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Ego and his own
* Milicevic01
* Zoranzoki21
-->
<resources>
<string name="app_name">Ostava</string>
<string name="menu_settings">Podešavanja</string>
@ -134,8 +139,8 @@
<string name="detail_description_empty">Nema opisa</string>
<string name="detail_license_empty">Nepoznata licenca</string>
<string name="menu_refresh">Osveži</string>
<string name="read_storage_permission_rationale">Potrebna dozvola: Provera spoljašnje memorije. Aplikacija bez ovoga ne može da funkcioniše.</string>
<string name="write_storage_permission_rationale">Neophodna dozvola: Pisanje spoljašnjeg skladišta. Aplikacija ne može da funkcioniše bez ovoga.</string>
<string name="read_storage_permission_rationale" fuzzy="true">Potrebna dozvola: Provera spoljašnje memorije. Aplikacija bez ovoga ne može da funkcioniše.</string>
<string name="write_storage_permission_rationale" fuzzy="true">Neophodna dozvola: Pisanje spoljašnjeg skladišta. Aplikacija ne može da funkcioniše bez ovoga.</string>
<string name="location_permission_rationale">Opciona dozvola: Preuzmi trenutnu lokaciju za predloge kategorija</string>
<string name="ok">U redu</string>
<string name="title_activity_nearby">Mesta u blizini</string>

View file

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Ibrahim
-->
<resources>
<string name="crash_dialog_ok_toast">Ташаккур!</string>
</resources>

View file

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Рустам Нурыев
-->
<resources>
<string name="crash_dialog_ok_toast">Рәхмәт!</string>
</resources>

View file

@ -1,4 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Lizalizaufa
* Sagan
* Рустам Нурыев
-->
<resources>
<string name="preference_category_appearance">Тышҡы күренеш</string>
<string name="preference_category_general">Ғәҙәти</string>
@ -149,8 +154,8 @@
<string name="detail_description_empty">Һүрәтләүе юҡ</string>
<string name="detail_license_empty">Билдәһеҙ лицензия</string>
<string name="menu_refresh">Яңыртып алыу</string>
<string name="read_storage_permission_rationale">Кәрәкле рөхсәт: тышҡы һаҡлағыстан алып уҡыу. Ҡушымта шунһыҙ эшләмәйәсәк.</string>
<string name="write_storage_permission_rationale">Кәрәкле рөхсәт: тышҡы һаҡлағысҡа яҙыу. Ҡушымта шунһыҙ эшләмәйәсәк.</string>
<string name="read_storage_permission_rationale" fuzzy="true">Кәрәкле рөхсәт: тышҡы һаҡлағыстан алып уҡыу. Ҡушымта шунһыҙ эшләмәйәсәк.</string>
<string name="write_storage_permission_rationale" fuzzy="true">Кәрәкле рөхсәт: тышҡы һаҡлағысҡа яҙыу. Ҡушымта шунһыҙ эшләмәйәсәк.</string>
<string name="location_permission_rationale">Мотлаҡ булмаған рөхсәт: категория тәҡдиме өсөн ошо урынды алыу</string>
<string name="title_activity_nearby">Яҡындағы урындар</string>
<string name="no_nearby">Яҡындағы урындар табылманы</string>

View file

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Geopoet
-->
<resources>
<string name="crash_dialog_title">Kagrugaringan nagkagarabá</string>
<string name="crash_dialog_text">Oops. May bagay an napasala!</string>

View file

@ -1,4 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* DCLXVI
* Vodnokon4e
-->
<resources>
<string name="crash_dialog_title">Неуспех с Общомедия</string>
<string name="crash_dialog_text">Опа. Нещо се обърка!</string>

View file

@ -1,4 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* DCLXVI
* MegaAlex
* StanProg
* Vodnokon4e
* АдмиралАнимЕ
-->
<resources>
<string name="app_name">Общомедия</string>
<string name="menu_settings">Настройки</string>

View file

@ -1,4 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Aftabuzzaman
* Bellayet
* Sankarshan
-->
<resources>
<string name="crash_dialog_title">কমন্স ক্র্যাশ করেছে</string>
<string name="crash_dialog_text">ওহ, কিছু একটা ত্রুটি হয়েছে!</string>

View file

@ -1,4 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Aftabuzzaman
* Bellayet
* Elias Ahmmad
* Leemon2010
* Mohammed Galib Hasan
* Muktogayn
* Rasal Lia
* Sankarshan
* Tauhid16
-->
<resources>
<string name="preference_category_appearance">অবয়ব</string>
<string name="preference_category_general">সাধারণ</string>
@ -59,6 +70,7 @@
<string name="categories_search_text_hint">বিষয়শ্রেণী অনুসন্ধান</string>
<string name="menu_save_categories">সংরক্ষণ</string>
<string name="refresh_button">পুনঃসতেজ</string>
<string name="display_list_button">তালিকা</string>
<string name="gps_disabled">GPS আপনার ডিভাইসে অক্ষম করা আছে। আপনি কি এটি সক্ষম করতে চান?</string>
<string name="enable_gps">GPS সক্রিয় করুন</string>
<string name="contributions_subtitle_zero">এখনো কোন আপলোড নেই</string>
@ -150,8 +162,8 @@
<string name="detail_description_empty">বিবরণ নেই</string>
<string name="detail_license_empty">অজানা লাইসেন্স</string>
<string name="menu_refresh">পুনঃসতেজ</string>
<string name="read_storage_permission_rationale">প্রয়োজনীয় অনুমতি: বহিঃস্ত সঞ্চয়স্থান পড়া। এটি ছাড়া অ্যাপ কাজ করবে না।</string>
<string name="write_storage_permission_rationale">অনুমতি প্রয়োজন: অালাদাভাবে সংযুক্ত স্টোরেজ লিখুন। এটি ছাড়া অ্যাপটি চলতে পারেনা।</string>
<string name="read_storage_permission_rationale" fuzzy="true">প্রয়োজনীয় অনুমতি: বহিঃস্ত সঞ্চয়স্থান পড়া। এটি ছাড়া অ্যাপ কাজ করবে না।</string>
<string name="write_storage_permission_rationale" fuzzy="true">অনুমতি প্রয়োজন: অালাদাভাবে সংযুক্ত স্টোরেজ লিখুন। এটি ছাড়া অ্যাপটি চলতে পারেনা।</string>
<string name="location_permission_rationale">ঐচ্ছিক অনুমতি: বিষয়শ্রেণী পরামর্শের জন্য বর্তমান অবস্থান নেয়</string>
<string name="ok">ঠিক আছে</string>
<string name="title_activity_nearby">কাছাকাছি স্থান</string>
@ -210,6 +222,7 @@
<string name="no_description_found">কোন বিবরণ পাওয়া যায়নি</string>
<string name="nearby_info_menu_commons_article">কমন্সে ফাইলের পাতা</string>
<string name="nearby_info_menu_wikidata_article">উইকিউপাত্ত পদ</string>
<string name="nearby_info_menu_wikipedia_article">উইকিপিডিয়া নিবন্ধ</string>
<string name="error_while_cache">ছবি আনার সময় ত্রুটি</string>
<string name="title_info">ফাইলের একটি স্বতন্ত্র বর্ণনামূলক নাম যা ফাইলের নাম হিসাবে কাজ করবে। অাপনি সাধারণ ভাষা ব্যবহার করতে পারেন শূন্যস্থানসহ। ফাইলের এক্সটেনশন যুক্ত করবেন না।</string>
<string name="description_info">যতটা সম্ভব মিডিয়াটি বর্ণনা করুন: এটি কোথায় ধারণ করা হয়েছিল? এটি কি প্রদর্শন করে? এটির প্রসঙ্গ কি? ধারণকৃত বস্তু অথবা ব্যক্তির বর্ণনা করুন। সহজে অনুমান করা যায়না সেরকম তথ্য উদঘাটন করুন, উদাহরণস্বরূপ, যদি ল্যান্ডস্কেপ হয় তাহলে দিবসকালের সময় দিন।</string>
@ -222,6 +235,8 @@
<string name="send_log_file">লগ ফাইল পাঠান</string>
<string name="send_log_file_description">ইমেইলের মাধ্যমে উন্নয়নকারীর কাছে লগ ফাইল পাঠান</string>
<string name="null_url">ত্রুটি! ইউআরএল পাওয়া যায়নি</string>
<string name="nominate_deletion">অপসারণের জন্য মনোনীত</string>
<string name="view_browser">ব্রাউজারে দেখুন</string>
<string name="nearby_location_has_not_changed">অবস্থান পরিবর্তন হয়নি।</string>
<string name="nearby_location_not_available">অবস্থান উপলব্ধ নয়।</string>
<string name="location_permission_rationale_nearby">কাছাকাছি স্থানসমূহের একটি তালিকা প্রদর্শন করতে অনুমতি প্রয়োজন</string>
@ -231,6 +246,14 @@
<string name="notifications_talk_page_message">%1$s আপনার আলাপ পাতায় একটি বার্তা দিয়েছেন</string>
<string name="notifications_thank_you_edit">একটি সম্পাদনা করার জন্য আপনাকে ধন্যবাদ</string>
<string name="notifications_mention">%1$s আপনাকে %2$s-এ উল্লেখ করেছেন।</string>
<string name="about_faq">প্রায়শই জিজ্ঞাসিত প্রশ্নসমূহ</string>
<string name="nearby_directions">দিকনির্দেশ</string>
<string name="nearby_wikidata">উইকিউপাত্ত</string>
<string name="nearby_wikipedia">উইকিপিডিয়া</string>
<string name="nearby_commons">কমন্স</string>
<string name="about_faq" fuzzy="true">প্রায়শই জিজ্ঞাসিত প্রশ্নসমূহ</string>
<string name="welcome_skip_button">টিউটোরিয়াল এড়ান</string>
<string name="no_internet">ইন্টারনেট অনুপলব্ধ</string>
<string name="internet_established">ইন্টারনেট উপলব্ধ</string>
<string name="no_notifications">কোন বিজ্ঞপ্তি পাওয়া যায়নি</string>
<string name="retry">পুনঃচেষ্টা করুন</string>
</resources>

View file

@ -1,4 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Fohanno
* Gwenn-Ael
-->
<resources>
<string name="crash_dialog_title">Commons zo aet er c\'hleuz</string>
<string name="crash_dialog_text">Hopala ! Un dra bennak a-dreuz zo bet !</string>

View file

@ -1,4 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Dishual
* Fohanno
* Fulup
* Gwenn-Ael
* Y-M D
-->
<resources>
<string name="preference_category_appearance">Neuz</string>
<string name="preference_category_general">Hollek</string>
@ -146,8 +153,8 @@
<string name="detail_description_empty">Deskrivadur ebet</string>
<string name="detail_license_empty">Aotre-implijout dizanv</string>
<string name="menu_refresh">Freskaat</string>
<string name="read_storage_permission_rationale">Aotre rekis : lenn ur stokañ diavaez. Hep se, n\'hall ket an arload mont en-dro.</string>
<string name="write_storage_permission_rationale">Aotre ret ; skrivañ war al lec\'h stokañ diavaez. Ne c\'hall ket an arload mont en-dro hep an dra-se.</string>
<string name="read_storage_permission_rationale" fuzzy="true">Aotre rekis : lenn ur stokañ diavaez. Hep se, n\'hall ket an arload mont en-dro.</string>
<string name="write_storage_permission_rationale" fuzzy="true">Aotre ret ; skrivañ war al lec\'h stokañ diavaez. Ne c\'hall ket an arload mont en-dro hep an dra-se.</string>
<string name="location_permission_rationale">Aotre diret : kaout al lec\'hiadur red evit kinnig rummadoù</string>
<string name="ok">Mat eo</string>
<string name="title_activity_nearby">Lec\'hioù nes</string>

View file

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Srdjan m
-->
<resources>
<string name="crash_dialog_title">Commons se srušio</string>
<string name="crash_dialog_text">Ups. Nešto je pošlo po zlu!</string>

View file

@ -1,4 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* CERminator
* DzWiki
* Srdjan m
-->
<resources>
<string name="app_name">Commons</string>
<string name="menu_settings">Postavke</string>
@ -133,7 +138,7 @@
<string name="detail_description_empty">Nema opisa</string>
<string name="detail_license_empty">Nepoznata licenca</string>
<string name="menu_refresh">Osvježi</string>
<string name="read_storage_permission_rationale">Potrebna dozvola: Čitanje vanjske memorije. Aplikacija ne može raditi bez ovog.</string>
<string name="read_storage_permission_rationale" fuzzy="true">Potrebna dozvola: Čitanje vanjske memorije. Aplikacija ne može raditi bez ovog.</string>
<string name="location_permission_rationale">Neobavezna dozvola: Dobavljanje trenutne lokacije za predlaganje kategorija</string>
<string name="ok">U redu</string>
<string name="title_activity_nearby">Mjesta u blizini</string>

View file

@ -1,4 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Toniher
* XVEC
-->
<resources>
<string name="crash_dialog_title">El Commons s\'ha penjat</string>
<string name="crash_dialog_text">Uups ! Quelcom ha anat malament !</string>

View file

@ -1,4 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Alvaro Vidal-Abarca
* Fitoschido
* Kippelboy
* MarionaDSR
* Pintor Smeargle
* Pitort
* Toniher
* XVEC
-->
<resources>
<string name="preference_category_appearance">Aparença</string>
<string name="preference_category_location">Ubicació</string>
@ -181,5 +191,5 @@
<string name="read_article">LLEGIU LARTICLE</string>
<string name="notifications_thank_you_edit">Gràcies per fer una modificació</string>
<string name="notifications_mention" fuzzy="true">%1$s us ha mencionat a %2$s.</string>
<string name="about_faq">Preguntes freqüents</string>
<string name="about_faq" fuzzy="true">Preguntes freqüents</string>
</resources>

View file

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Умар
-->
<resources>
<string name="crash_dialog_ok_toast">Баркалла!</string>
</resources>

View file

@ -1,6 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Chmee2
* Ilimanaq29
* Patriccck
-->
<resources>
<string name="crash_dialog_title">Commons spadly</string>
<string name="crash_dialog_title">Aplikace Commons spadla</string>
<string name="crash_dialog_text">Něco se pokazilo!</string>
<string name="crash_dialog_comment_prompt">Řekněte nám, co jste dělali a dejte nám to vědět e-mailem. Pomůže sjednat nápravu!</string>
<string name="crash_dialog_ok_toast">Děkujeme vám!</string>

View file

@ -1,4 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Aktron
* Chmee2
* Dvorapa
* Frettie
* Ilimanaq29
* Jkjk
* Leanes
* Matěj Suchánek
* Mormegil
* Patriccck
* Spotter
* Vojtěch Dostál
* Walter Klosse
-->
<resources>
<string name="preference_category_appearance">Vzhled</string>
<string name="preference_category_general">Obecné</string>
@ -59,6 +74,7 @@
<string name="categories_search_text_hint">Hledání kategorií</string>
<string name="menu_save_categories">Uložit</string>
<string name="refresh_button">Obnovit</string>
<string name="display_list_button">Seznam</string>
<string name="gps_disabled">GPS ve vašem zařízení není povoleno. Chtěli byste ho spustit?</string>
<string name="enable_gps">Spustit GPS</string>
<string name="contributions_subtitle_zero">Žádné nahrané soubory</string>
@ -151,8 +167,8 @@
<string name="detail_description_empty">Bez popisu</string>
<string name="detail_license_empty">Neznámá licence</string>
<string name="menu_refresh">Obnovit</string>
<string name="read_storage_permission_rationale">Požadováno oprávnění ke čtení externího úložiště. Aplikace bez toho nemůže pracovat.</string>
<string name="write_storage_permission_rationale">Požadováno oprávnění k zápisu do externího úložiště. Aplikace bez toho nemůže pracovat.</string>
<string name="read_storage_permission_rationale">Požadované oprávnění: Čtení externího úložiště. Aplikace bez toho nemůže pracovat.</string>
<string name="write_storage_permission_rationale">Požadované oprávnění: Zapisování do externího úložiště. Aplikace bez toho nemůže pracovat.</string>
<string name="location_permission_rationale">Volitelně: Umožněte aplikaci, aby získávala aktuální polohu a nabízela na jejím základě kategorie</string>
<string name="ok">OK</string>
<string name="title_activity_nearby">Místa v okolí</string>
@ -211,6 +227,7 @@
<string name="no_description_found">nebyl nalezen žádný popisek</string>
<string name="nearby_info_menu_commons_article">Stránka souboru na Commons</string>
<string name="nearby_info_menu_wikidata_article">Položka Wikidat</string>
<string name="nearby_info_menu_wikipedia_article">Článek na Wikipedii</string>
<string name="error_while_cache">Chyba při meziukládání obrázků</string>
<string name="title_info">Unikátní a popisný název pro daný soubor, který bude sloužit jako název souboru. Můžete použít běžný psaný jazyk s mezerami; nezahrnujte koncovku souboru.</string>
<string name="description_info">Popište prosím obrázek, jak jen to je možné: Kde byl pořízen? Co znázorňuje? Jaký je kontext obrázku? Popisujte prosím významné předměty nebo osoby na obrázku a nezapomeňte na informace, které není možné snadno odhadnout ze samotného obrázku, jako je například denní doba, pokud jde o krajinu. Pokud je na obrázku něco neobvyklého, popište, co to dělá neobvyklým.</string>
@ -225,6 +242,8 @@
<string name="no_web_browser">Nebyl nalezen žádný webový prohlížeč k otevření URL</string>
<string name="null_url">Chyba! URL nenalezeno</string>
<string name="nominate_deletion">Navrhnout na smazání</string>
<string name="nominated_for_deletion">Tento obrázek byl nominován na smazání.</string>
<string name="nominated_see_more"> .</string>
<string name="view_browser">Zobrazit v prohlížeči</string>
<string name="nearby_location_has_not_changed">Vaše umístění se nezměnilo.</string>
<string name="nearby_location_not_available">Umístění není dostupné.</string>
@ -236,6 +255,21 @@
<string name="notifications_thank_you_edit">Děkujeme za vaši editaci</string>
<string name="notifications_mention">%1$s vás zmínil na %2$s.</string>
<string name="toggle_view_button">Přepnout pohled</string>
<string name="about_faq">Často kladené dotazy</string>
<string name="nearby_directions">POKYNY</string>
<string name="nearby_wikidata">WIKIDATA</string>
<string name="nearby_wikipedia">WIKIPEDIE</string>
<string name="nearby_commons">COMMONS</string>
<string name="about_rate_us">&lt;u&gt;Ohodnoť nás&lt;/u&gt;</string>
<string name="about_faq">&lt;u&gt;Často kladené otázky&lt;/u&gt;</string>
<string name="welcome_skip_button">Přeskočit úvod</string>
<string name="no_internet">Internet je nedostupný</string>
<string name="internet_established">Internet je dostupný</string>
<string name="error_notifications">Při načítání oznámení došlo k chybě</string>
<string name="no_notifications">Nebyly nalezeny žádné oznámení</string>
<string name="about_translate">&lt;u&gt;Přeložit&lt;/u&gt;</string>
<string name="about_translate_title">Jazyky</string>
<string name="about_translate_message">Vyberte jazyk, pro který chcete odeslat překlady</string>
<string name="about_translate_proceed">Pokračovat</string>
<string name="about_translate_cancel">Zrušit</string>
<string name="retry">Zkusit znovu</string>
</resources>

View file

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Kaszeba
-->
<resources>
<string name="crash_dialog_title">Pókôza sã fela Commons.</string>
<string name="crash_dialog_text">Wejle! Cos je lëchò pòszłé!</string>

View file

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Kaszeba
-->
<resources>
<string name="app_name">Commons</string>
<string name="menu_settings">Nastôwë</string>

View file

@ -1,4 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Lloffiwr
* Robin Owain
-->
<resources>
<string name="crash_dialog_title">Aeth rhywbeth o\'i le yn Comin</string>
<string name="crash_dialog_text">Wwwwps. Aeth rhywbeth o\'i le!</string>

View file

@ -1,4 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Cymrodor
* Lloffiwr
* Robin Owain
-->
<resources>
<string name="app_name">Comin Wicimedia</string>
<string name="menu_settings">Gosodiadau</string>

View file

@ -1,4 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Christian List
* Jsmakaayb
-->
<resources>
<string name="crash_dialog_title">Commons gik ned</string>
<string name="crash_dialog_text">Ups. Noget gik galt!</string>

View file

@ -1,4 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Christian List
* Envlh
* Joedalton
* Jsmakaayb
* Luckas
* Overlaet
-->
<resources>
<string name="preference_category_appearance">Udseende</string>
<string name="preference_category_general">Generelt</string>
@ -151,8 +159,8 @@
<string name="detail_description_empty">Ingen beskrivelse</string>
<string name="detail_license_empty">Ukendt licens</string>
<string name="menu_refresh">Opdater</string>
<string name="read_storage_permission_rationale">Krævet tilladelse: Læs eksternt lager. Programmet kan ikke fungere uden denne tilladelse.</string>
<string name="write_storage_permission_rationale">Krævet tilladelse: Skriv til eksternt lager. Program kan ikke fungere uden denne funktion.</string>
<string name="read_storage_permission_rationale" fuzzy="true">Krævet tilladelse: Læs eksternt lager. Programmet kan ikke fungere uden denne tilladelse.</string>
<string name="write_storage_permission_rationale" fuzzy="true">Krævet tilladelse: Skriv til eksternt lager. Program kan ikke fungere uden denne funktion.</string>
<string name="location_permission_rationale">Valgfri tilladelse: Hent nuværende position for kategoriforslag</string>
<string name="ok">O.k.</string>
<string name="title_activity_nearby">Steder i nærheden</string>
@ -236,6 +244,6 @@
<string name="notifications_thank_you_edit">Tak fordi du lavede en redigering</string>
<string name="notifications_mention">%1$s nævnte dig på %2$s.</string>
<string name="toggle_view_button">Skift visning</string>
<string name="about_faq">Ofte stillede spørgsmål</string>
<string name="about_faq" fuzzy="true">Ofte stillede spørgsmål</string>
<string name="welcome_skip_button">Udelad øvelse</string>
</resources>

View file

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Metalhead64
-->
<resources>
<string name="crash_dialog_title">Commons ist abgestürzt</string>
<string name="crash_dialog_text">Huch! Etwas ist schiefgelaufen.</string>

View file

@ -1,4 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Envlh
* Inkowik
* Kghbln
* Metalhead64
* Sujan
-->
<resources>
<string name="preference_category_appearance">Erscheinung</string>
<string name="preference_category_general">Allgemein</string>
@ -152,8 +159,8 @@
<string name="detail_description_empty">Keine Beschreibung</string>
<string name="detail_license_empty">Unbekannte Lizenz</string>
<string name="menu_refresh">Aktualisieren</string>
<string name="read_storage_permission_rationale">Erforderliche Berechtigung: Externen Speicher lesen. Die App funktioniert ohne diese Berechtigung nicht.</string>
<string name="write_storage_permission_rationale">Erforderliche Berechtigung: Externen Speicher beschreiben. Die App kann ohne dies nicht funktionieren.</string>
<string name="read_storage_permission_rationale">Erforderliche Berechtigung: Externen Speicher lesen. Die App kann ohne diese Berechtigung nicht auf deine Galerie zugreifen.</string>
<string name="write_storage_permission_rationale">Erforderliche Berechtigung: Externen Speicher beschreiben. Die App kann ohne diese Berechtigung nicht auf deine Kamera zugreifen.</string>
<string name="location_permission_rationale">Optionale Berechtigung: Ruft den aktuellen Standort für Kategorievorschläge ab</string>
<string name="ok">Okay</string>
<string name="title_activity_nearby">Orte in der Nähe</string>
@ -227,6 +234,8 @@
<string name="no_web_browser">Zum Öffnen der URL wurde kein Webbrowser gefunden</string>
<string name="null_url">Fehler! URL nicht gefunden</string>
<string name="nominate_deletion">Zur Löschung vorschlagen</string>
<string name="nominated_for_deletion">Dieses Bild wurde zur Löschung vorgeschlagen.</string>
<string name="nominated_see_more"/>
<string name="view_browser">Im Browser ansehen</string>
<string name="nearby_location_has_not_changed">Der Standort hat sich nicht geändert.</string>
<string name="nearby_location_not_available">Der Standort ist nicht verfügbar.</string>
@ -242,7 +251,17 @@
<string name="nearby_wikidata">WIKIDATA</string>
<string name="nearby_wikipedia">WIKIPEDIA</string>
<string name="nearby_commons">COMMONS</string>
<string name="about_rate_us"/>
<string name="about_faq">Häufig gestellte Fragen</string>
<string name="about_rate_us">&lt;u&gt;Bewerte uns&lt;/u&gt;</string>
<string name="about_faq">&lt;u&gt;Häufig gestellte Fragen&lt;/u&gt;</string>
<string name="welcome_skip_button">Tutorial überspringen</string>
<string name="no_internet">Internet nicht verfügbar</string>
<string name="internet_established">Internet verfügbar</string>
<string name="error_notifications">Fehler beim Abruf der Benachrichtigungen</string>
<string name="no_notifications">Keine Benachrichtigungen gefunden</string>
<string name="about_translate">&lt;u&gt;Übersetzen&lt;/u&gt;</string>
<string name="about_translate_title">Sprachen</string>
<string name="about_translate_message">Wähle die Sprache aus, für die du Übersetzungen durchführen möchtest.</string>
<string name="about_translate_proceed">Fortfahren</string>
<string name="about_translate_cancel">Abbrechen</string>
<string name="retry">Erneut versuchen</string>
</resources>

View file

@ -1,7 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* 1917 Ekim Devrimi
* Gorizon
* Marmase
* Mirzali
-->
<resources>
<string name="crash_dialog_title">Commons lığiya</string>
<string name="crash_dialog_text">Oops. Thebayo nigurweyino!</string>
<string name="crash_dialog_comment_prompt">Şıma se kerd bı, marê vacê. Dıma e-posta ra bırışê marê. Ney timar kerdışi de marê beno desteg!</string>
<string name="crash_dialog_ok_toast">Teşekur kena</string>
<string name="crash_dialog_ok_toast">Teşekur kenan!</string>
</resources>

View file

@ -1,4 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* 1917 Ekim Devrimi
* Envlh
* Gambollar
* Gorizon
* Gırd
* Marmase
* Mirzali
-->
<resources>
<string name="app_name">Commons</string>
<string name="menu_settings">Eyari</string>
@ -26,7 +35,7 @@
</plurals>
<string name="title_activity_contributions">Barkerdışê mınê peyêni</string>
<string name="contribution_state_queued">Ratneya</string>
<string name="contribution_state_failed">Nêbı</string>
<string name="contribution_state_failed">Ebe ser nêkewt</string>
<string name="contribution_state_in_progress">%1$d%% temamya</string>
<string name="contribution_state_starting">Bar beno</string>
<string name="menu_from_gallery">Galeri ra</string>

View file

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Nirajan pant
-->
<resources>
<string name="crash_dialog_text">हैत्मरा। केइचीज गलत भयो।</string>
<string name="crash_dialog_ok_toast">धन्यवाद!</string>

View file

@ -1,4 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Auslaender
* Evropi
* Geraki
-->
<resources>
<string name="crash_dialog_title">Τα Commons παρουσίασαν σφάλμα</string>
<string name="crash_dialog_text">Ωχ. Κάτι πήγε στραβά!</string>

View file

@ -1,4 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Astralnet
* Evropi
* Geraki
* Glavkos
* KATRINE1992
* ManosHacker
* Nikosgranturismogt
* Nikosguard
* Tgkarounos
-->
<resources>
<string name="preference_category_appearance">Εμφάνιση</string>
<string name="preference_category_general">Γενικά</string>
@ -152,8 +163,8 @@
<string name="detail_description_empty">Καμία περιγραφή</string>
<string name="detail_license_empty">Άγνωστη άδεια</string>
<string name="menu_refresh">Ανανέωση</string>
<string name="read_storage_permission_rationale">Απαιτούμενη άδεια: Ανάγνωση εξωτερικής αποθήκευσης. Η εφαρμογή δεν μπορεί να λειτουργήσει χωρίς αυτή.</string>
<string name="write_storage_permission_rationale">Απαιτούμενη άδεια: Με εξωτερική αποθήκευση.Το πρόγραμμα δεν μπορεί να λειτουργήσει με αυτήν.</string>
<string name="read_storage_permission_rationale">Απαιτούμενη άδεια: Ανάγνωση εξωτερικής αποθήκευσης. Η εφαρμογή δεν μπορεί να έχει πρόσβαση στην συλλογή σας χωρίς αυτή.</string>
<string name="write_storage_permission_rationale">Απαιτούμενη άδεια: Με εξωτερική αποθήκευση. Το πρόγραμμα δεν μπορεί να έχει πρόσβαση στην κάμερα σας χωρίς αυτήν.</string>
<string name="location_permission_rationale">Προαιρετική άδεια: Ανάκτηση τρέχουσας θέσης σας για προτάσεις κατηγοριών</string>
<string name="ok">Εντάξει</string>
<string name="title_activity_nearby">Κοντινοί Τόποι</string>
@ -227,6 +238,8 @@
<string name="no_web_browser">Δεν βρέθηκε φυλλομετρητής για το άνοιγμα της διευθύνσεως URL</string>
<string name="null_url">Σφάλμα! Η διεύθυνση URL δεν βρέθηκε</string>
<string name="nominate_deletion">Προτείνετε για διαγραφή</string>
<string name="nominated_for_deletion">Αυτή εικόνα έχει προταθεί για διαγραφή.</string>
<string name="nominated_see_more"/>
<string name="view_browser">Προβολή στον περιηγητή</string>
<string name="nearby_location_has_not_changed">Ο εντοπισμός δεν έχει αλλάξει.</string>
<string name="nearby_location_not_available">Ο τόπος δεν είναι διαθέσιμος.</string>
@ -242,7 +255,17 @@
<string name="nearby_wikidata">Βικιδεδομένα</string>
<string name="nearby_wikipedia">Βικιπαίδεια</string>
<string name="nearby_commons">Κοινά</string>
<string name="about_rate_us"/>
<string name="about_faq">Συχνές ερωτήσεις</string>
<string name="about_rate_us">&lt;u&gt;Βαθμολογήστε μας&lt;/u&gt;</string>
<string name="about_faq">&lt;u&gt;Συχνές ερωτήσεις&lt;/u&gt;</string>
<string name="welcome_skip_button">Παράβλεψη εισαγωγής</string>
<string name="no_internet">Το διαδίκτυο δεν είναι διαθέσιμο</string>
<string name="internet_established">Το διαδίκτυο είναι διαθέσιμο</string>
<string name="error_notifications">Σφάλμα κατά την συγκέντρωση ειδοποιήσεων</string>
<string name="no_notifications">Δεν βρέθηκαν ειδοποιήσεις</string>
<string name="about_translate">&lt;u&gt;Μεταφράστε&lt;/u&gt;</string>
<string name="about_translate_title">Γλώσσες</string>
<string name="about_translate_message">Επιλέξτε την γλώσσα που θα θέλατε να υποβάλετε μεταφράσεις για αυτή</string>
<string name="about_translate_proceed">Συνέχεια</string>
<string name="about_translate_cancel">Ακύρωση</string>
<string name="retry">Ξαναπροσπαθήστε</string>
</resources>

View file

@ -1,4 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Fitoschido
* Jduranboger
* Vivaelcelta
-->
<resources>
<string name="crash_dialog_title">Commons falló</string>
<string name="crash_dialog_text">Vaya. ¡Algo salió mal!</string>

View file

@ -1,4 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* 2axterix2
* Benfutbol10
* Fitoschido
* Jduranboger
* Luisangelrg
* Macofe
* MarionaDSR
* Miguel2706
* Vivaelcelta
-->
<resources>
<string name="preference_category_appearance">Apariencia</string>
<string name="preference_category_general">Generales</string>
@ -59,6 +70,7 @@
<string name="categories_search_text_hint">Buscar categorías</string>
<string name="menu_save_categories">Guardar</string>
<string name="refresh_button">Actualizar</string>
<string name="display_list_button">Lista</string>
<string name="gps_disabled">El GPS está desactivado en tu dispositivo. ¿Quieres activarlo?</string>
<string name="enable_gps">Activar GPS</string>
<string name="contributions_subtitle_zero">No hay subidas aún</string>
@ -125,7 +137,7 @@
<string name="tutorial_1_text">Wikimedia Commons aloja la mayoría de las imágenes utilizadas en Wikipedia.</string>
<string name="tutorial_1_subtext">¡Tus imágenes ayudan a instruir a personas de todo el mundo!</string>
<string name="tutorial_2_text">Carga únicamente imágenes capturadas o creadas por ti.</string>
<string name="tutorial_2_subtext" fuzzy="true">- Objetos naturales (flores, animales, montañas)\n- Objetos útiles (bicicletas, estaciones de tren)\n- Personas famosas (tu alcalde, algún atleta olímpico que conociste)</string>
<string name="tutorial_2_subtext">Objetos naturales (flores, animales, montañas)\n• Objetos útiles (bicicletas, estaciones de tren)\n• Personas famosas (tu alcalde, algún atleta olímpico que conociste)</string>
<string name="tutorial_2_subtext_1">Naturaleza (flores, animales, montañas)</string>
<string name="tutorial_2_subtext_2">Objetos utilitarios (bicicletas, estaciones de tren)</string>
<string name="tutorial_2_subtext_3">Gente famosa (tu regente, algún atleta que hayas conocido…)</string>
@ -138,6 +150,7 @@
<string name="tutorial_4_subtext">- Título: Casa de la Ópera de Sídney\n- Descripción: Casa de la Ópera de Sídney vista desde el otro lado de la bahía\n- Categorías: Casa de la Ópera de Sídney desde el oeste, Vistas a distancia de la Casa de la Ópera de Sídney</string>
<string name="tutorial_4_subtext_1">Título: Ópera de Sídney</string>
<string name="tutorial_4_subtext_2">Descripción: La Ópera de Sídney, vista desde el otro lado de la bahía</string>
<string name="tutorial_4_subtext_3">Categorías: Ópera de Sídney desde el oeste, Vistas a distancia de la Ópera de Sídney</string>
<string name="welcome_wikipedia_text">Contribuye con tus imágenes.\n¡Ayuda a que los artículos de Wikipedia tengan vida!</string>
<string name="welcome_wikipedia_subtext">Las imágenes en Wikipedia proceden de\nWikimedia Commons.</string>
<string name="welcome_copyright_text">Tus imágenes ayudan a educar a la gente\nalrededor del mundo.</string>
@ -150,8 +163,8 @@
<string name="detail_description_empty">Sin descripción</string>
<string name="detail_license_empty">Licencia desconocida</string>
<string name="menu_refresh">Actualizar</string>
<string name="read_storage_permission_rationale">Permiso obligatorio: lectura de almacenamiento externo. La aplicación no puede funcionar sin él.</string>
<string name="write_storage_permission_rationale">Permiso necesario: Escribir en almacenamiento externo. La aplicación no puede funcionar sin él.</string>
<string name="read_storage_permission_rationale">Permiso obligatorio: lectura de almacenamiento externo. La aplicación no puede acceder a la galería sin él.</string>
<string name="write_storage_permission_rationale">Permiso necesario: Escribir en almacenamiento externo. La aplicación no puede acceder a la cámara sin él.</string>
<string name="location_permission_rationale">Permiso opcional: obtener la ubicación actual para sugerir categorías</string>
<string name="ok">Aceptar</string>
<string name="title_activity_nearby">Lugares cercanos</string>
@ -210,6 +223,7 @@
<string name="no_description_found">no se encontró ninguna descripción</string>
<string name="nearby_info_menu_commons_article">Página del archivo en Commons</string>
<string name="nearby_info_menu_wikidata_article">Elemento de Wikidata</string>
<string name="nearby_info_menu_wikipedia_article">Artículo de Wikipedia</string>
<string name="error_while_cache">Error al almacenar imágenes en la antememoria</string>
<string name="title_info">Un título único descriptivo para el archivo, que servirá como un nombre de archivo. Puede usar un lenguaje claro con espacios. No incluya la extensión del archivo.</string>
<string name="description_info">Por favor, describa el elemento multimedia tanto como sea posible: ¿dónde fue tomado?, ¿qué muestra?, ¿cuál es el contexto? Por favor, describa los objetos o personas. Ofrezca la información que no puede ser inferida tan fácilmente, por ejemplo el momento del día si es un paisaje. Si el medio muestra algo inusual, explique qué lo hace insual.</string>
@ -224,6 +238,7 @@
<string name="no_web_browser">No se encontró ningún navegador con el que abrir el URL</string>
<string name="null_url">Error: no se encontró el URL</string>
<string name="nominate_deletion">Nominar para borrado</string>
<string name="nominated_for_deletion">Se ha nominado esta imagen para su borrado.</string>
<string name="view_browser">Ver en navegador</string>
<string name="nearby_location_has_not_changed">La ubicación no ha cambiado.</string>
<string name="nearby_location_not_available">La ubicación no está disponible.</string>
@ -234,5 +249,19 @@
<string name="notifications_talk_page_message">%1$s dejó un mensaje en tu página de discusión</string>
<string name="notifications_thank_you_edit">Gracias por realizar una edición</string>
<string name="notifications_mention">%1$s te ha mencionado en %2$s.</string>
<string name="about_faq">Preguntas frecuentes</string>
<string name="nearby_directions">CÓMO LLEGAR</string>
<string name="nearby_wikidata">WIKIDATA</string>
<string name="nearby_wikipedia">WIKIPEDIA</string>
<string name="nearby_commons">COMMONS</string>
<string name="about_faq">&lt;u&gt;Preguntas frecuentes&lt;/u&gt;</string>
<string name="welcome_skip_button">Omitir tutorial</string>
<string name="no_internet">Internet no disponible</string>
<string name="internet_established">Internet disponible</string>
<string name="error_notifications">Error al recuperar las notificaciones</string>
<string name="no_notifications">No se encontró ninguna notificación</string>
<string name="about_translate">&lt;u&gt;Traducir&lt;/u&gt;</string>
<string name="about_translate_title">Idiomas</string>
<string name="about_translate_message">Selecciona el idioma en que quieres enviar traducciones</string>
<string name="about_translate_cancel">Cancelar</string>
<string name="retry">Reintentar</string>
</resources>

View file

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Theklan
-->
<resources>
<string name="crash_dialog_title">Commons apurtu da</string>
<string name="crash_dialog_text">Uiii. Zerbait gaizki dabil!</string>

View file

@ -1,4 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* An13sa
* Fitoschido
* Mikel Ibaiba
* Sator
* Subi
* Theklan
-->
<resources>
<string name="app_name">Commons</string>
<string name="menu_settings">Hobespenak</string>

View file

@ -1,4 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Ebraminio
* Mjbmr
* Reza1615
* جواد
-->
<resources>
<string name="crash_dialog_title">ویکی‌انبار متوقف شده‌است</string>
<string name="crash_dialog_text">اوه. خطایی در کار است!</string>

View file

@ -1,11 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Arash.pt
* Ebraminio
* Mjbmr
* Omidh
* Ommmmid
* Reza1615
* Yoosef Pooranvary
* جواد
-->
<resources>
<string name="preference_category_appearance">نمایش صفحه</string>
<string name="preference_category_general">عمومی</string>
<string name="preference_category_feedback">بازخورد</string>
<string name="preference_category_location">مکان</string>
<string name="app_name">ویکی‌انبار</string>
<string name="bullet"></string>
<string name="menu_settings">تنظیمات</string>
<string name="username">نام کاربری</string>
<string name="password">گذرواژه</string>
<string name="login_credential">به حساب کاربری ویکی‌انبار آزمایشی وارد شوید</string>
<string name="login">ورود</string>
<string name="forgot_password">رمز خود را فراموش کرده‌اید؟</string>
<string name="signup">ثبت نام</string>
<string name="logging_in_title">واردشدن</string>
<string name="logging_in_message">شکیبا باشید...</string>
@ -37,6 +53,7 @@
<string name="menu_share">به اشتراک‌گذاشتن</string>
<string name="menu_open_in_browser">مشاهده در مرورگر</string>
<string name="share_title_hint">عنوان</string>
<string name="add_title_toast">لطفاً نامی را برای این پرونده انتخاب کنید</string>
<string name="share_description_hint">توضیحات</string>
<string name="login_failed_network">قادر به ورود نیست - شکست شبکه‌ای</string>
<string name="login_failed_username">ناتوانی در ورود - لطفاً نام کاربریتان را بررسی کنید</string>
@ -52,6 +69,7 @@
<string name="categories_search_text_hint">جستجوی رده‌ها</string>
<string name="menu_save_categories">ذخیره</string>
<string name="refresh_button">تازه کردن</string>
<string name="display_list_button">فهرست</string>
<string name="gps_disabled">مکان‌یاب در دستگاه شما خاموش است. آیا دوست دارید فعال شود؟</string>
<string name="enable_gps">فعال کردن مکان‌یاب</string>
<string name="contributions_subtitle_zero">هنوز هیچ بارگذاری</string>
@ -72,8 +90,8 @@
<string name="menu_about">درباره</string>
<string name="about_license">اپلیکیشن ویکی‌انبار بنیاد ویکی‌مدیا یک نرم‌افزار آزاد است که توسط کاربران داوطلب و پاداش‌بگیر ایجاد و نگهداری می‌شود. بنیاد ویکی‌مدیا در ایجاد، نگهداری و توسعهٔ آن دخالتی ندارد.</string>
<string name="about_improve">ایجاد یک &lt;a href=\"https://github.com/commons-app/apps-android-commons/issues\"&gt;درخواست در گیت‌هاب&lt;/a&gt; برای گزارش باگ و یا پیشنهاد یک خصوصیت جدید.</string>
<string name="about_privacy_policy" fuzzy="true">&lt;a href=\"https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\"&gt;سیاست حفظ حریم خصوصی&lt;/a&gt;</string>
<string name="about_credits" fuzzy="true">&lt;a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\"&gt;مجوز&lt;/a&gt;</string>
<string name="about_privacy_policy">&lt;u&gt;سیاست حفظ حریم خصوصی&lt;/u&gt;</string>
<string name="about_credits">&lt;u&gt;مجوز&lt;/u&gt;</string>
<string name="title_activity_about">درباره</string>
<string name="menu_feedback">ارسال بازخورد (از طریق ایمیل)</string>
<string name="no_email_client">نرم‌افزار ایمیل نصب نیست</string>
@ -85,7 +103,7 @@
<string name="share_license_summary">این نگاره تحت مجوز %1$s است</string>
<string name="media_upload_policy">با بارگذاری این تصویر، تأیید می‌کنم که این اثر کار خودم است و از محتوای دارای حق تکثیر یا سلفی برای ایجاد آن استفاده نکرده‌ام و شرایط ذکر شده در By submitting this picture, I declare that this is my own work, that it does not contain copyrighted material or selfies, and otherwise adheres to &lt;a href=\"https://commons.wikimedia.org/wiki/Commons:Policies_and_guidelines\"&gt;سیاست‌های ویکی‌انبار&lt;/a&gt; را رعایت می‌کند.</string>
<string name="menu_download">دریافت</string>
<string name="preference_license" fuzzy="true">مجوز</string>
<string name="preference_license">مجوز پیش‌فرض</string>
<string name="use_previous">از عنوان/توضیحات پیشین استفاده کنید</string>
<string name="allow_gps">دریافت خودکار موقعیت کنونی</string>
<string name="allow_gps_summary">درحال دریافت موقعیت برای پیشنهاد رده در صورتی که برچسب جغرافیایی وجود نداشته باشد.</string>
@ -114,7 +132,7 @@
<string name="tutorial_1_text">ویکی‌انبار اکثر پرونده‌هایی که در ویکی‌پدیا استفاده می‌شوند را در خود نگه می‌دارد.</string>
<string name="tutorial_1_subtext">تصاویر شما به مردم در اقصی نقاط دنیا کمک می‌کند!</string>
<string name="tutorial_2_text">لطفاً تصاویری که توسط خودتان گرفته شده‌اند یا ایجاد شده‌اند را بارگذاری کنید:</string>
<string name="tutorial_2_subtext" fuzzy="true">-اجسام طبیعی (گیاه، جانور، کوه)\n-اجسام کاربردی (دوچرخه، ایستگاه قطار)\n-افراد مشهور (شهردار، قهرمانان المپیک)</string>
<string name="tutorial_2_subtext">•اجسام طبیعی (گیاه، جانور، کوه)\n•اجسام کاربردی (دوچرخه، ایستگاه قطار)\n•افراد مشهور (شهردار، قهرمانان المپیک)</string>
<string name="tutorial_3_text">لطفاً بارگذاری نکنید:</string>
<string name="tutorial_3_subtext">-سلفی خودتان یا تصویر دوستانتان\n-تصاویری که از اینترنت دانلود کردید\n-نماگرفت از دیگر اپلیکیشن‌‌ها</string>
<string name="tutorial_4_text">نمونه بارگذاری:</string>
@ -131,8 +149,8 @@
<string name="detail_description_empty">بدون توضیحات</string>
<string name="detail_license_empty">مجوز ناشناخته</string>
<string name="menu_refresh">تازه‌کردن</string>
<string name="read_storage_permission_rationale">اجازه‌های مورد نیاز: مطالعهٔ حافظهٔ خارجی. اپلیکیشن بدون آن نمی‌تواند کار کند.</string>
<string name="write_storage_permission_rationale">اجازه‌های مورد نیاز: نوشتن حافظهٔ خارجی. اپلیکیشن بدون آن نمی‌تواند کار کند.</string>
<string name="read_storage_permission_rationale" fuzzy="true">اجازه‌های مورد نیاز: مطالعهٔ حافظهٔ خارجی. اپلیکیشن بدون آن نمی‌تواند کار کند.</string>
<string name="write_storage_permission_rationale" fuzzy="true">اجازه‌های مورد نیاز: نوشتن حافظهٔ خارجی. اپلیکیشن بدون آن نمی‌تواند کار کند.</string>
<string name="location_permission_rationale">اجازه‌های اختیاری: دریافت موقعیت برای پیشنهاد رده</string>
<string name="ok">تأیید</string>
<string name="title_activity_nearby">مکان‌‌های اطراف</string>
@ -202,6 +220,8 @@
<string name="login_to_your_account">ورود به حساب کاربریتان</string>
<string name="send_log_file">ارسال فایل سیاهه</string>
<string name="send_log_file_description">ارسال فایل سیاهه به‌وسیلهٔ ایمیل برای توسعه‌دهندگان</string>
<string name="nominated_see_more"> .</string>
<string name="view_browser">مشاهده در مرورگر</string>
<string name="nearby_location_has_not_changed">مکان تغییر نکرده‌است.</string>
<string name="nearby_location_not_available">مکان موجود نیست.</string>
<string name="location_permission_rationale_nearby">برای نمایش مکان‌ّای اطراف نیاز به اجازه است.</string>
@ -212,4 +232,18 @@
<string name="notifications_thank_you_edit">برای ویرایش ممنون</string>
<string name="notifications_mention">%1$s در %2$s به شما اشاره کرده‌است.</string>
<string name="toggle_view_button">دکمه نمایش</string>
<string name="nearby_directions">جهت‌ها</string>
<string name="nearby_wikidata">ویکی‌داده</string>
<string name="nearby_wikipedia">ویکی‌پدیا</string>
<string name="nearby_commons">ویکی‌انبار</string>
<string name="about_rate_us">&lt;u&gt;رتبه ما&lt;/u&gt;</string>
<string name="about_faq">&lt;u&gt;سوال‌های متداول&lt;/u&gt;</string>
<string name="welcome_skip_button">رهاکردن آموزش</string>
<string name="no_internet">اینترنت در دسترس نیست</string>
<string name="internet_established">اینترنت در دسترس است</string>
<string name="about_translate">&lt;u&gt;ترجمه&lt;/u&gt;</string>
<string name="about_translate_title">زبان‌ها</string>
<string name="about_translate_proceed">ادامه</string>
<string name="about_translate_cancel">لغو</string>
<string name="retry">سعى دوباره</string>
</resources>

View file

@ -1,4 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Nike
* Olli
* Silvonen
-->
<resources>
<string name="crash_dialog_title">Commons app on kaatunut</string>
<string name="crash_dialog_text">Pahoittelemme, virhe tapahtui.</string>

View file

@ -1,4 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Alluk.
* Crt
* Nike
* Olli
* Pahkiqaz
* Pyscowicz
* SMAUG
* Samoasambia
* Silvonen
* Stryn
-->
<resources>
<string name="preference_category_appearance">Ulkoasu</string>
<string name="preference_category_general">Yleinen</string>
@ -149,8 +161,8 @@
<string name="detail_description_empty">Ei kuvausta</string>
<string name="detail_license_empty">Tuntematon lisenssi</string>
<string name="menu_refresh">Päivitä</string>
<string name="read_storage_permission_rationale">Vaadittu oikeus: Ulkoisen tallennustilan luku. Appi ei toimi ilman tätä oikeutta.</string>
<string name="write_storage_permission_rationale">Vaadittava lupa: Kirjoita ulkoiseen tallennustilaan. Sovellus ei voi toimia ilman tätä.</string>
<string name="read_storage_permission_rationale" fuzzy="true">Vaadittu oikeus: Ulkoisen tallennustilan luku. Appi ei toimi ilman tätä oikeutta.</string>
<string name="write_storage_permission_rationale" fuzzy="true">Vaadittava lupa: Kirjoita ulkoiseen tallennustilaan. Sovellus ei voi toimia ilman tätä.</string>
<string name="location_permission_rationale">Valinnainen lupa: Saada tämänhetkinen sijainti loukkasuosituksia varten.</string>
<string name="ok">OK</string>
<string name="title_activity_nearby">Lähellä olevat paikat</string>
@ -231,6 +243,6 @@
<string name="notifications_thank_you_edit">Kiitos muokkaamisestasi</string>
<string name="notifications_mention">%1$s mainitsi sinut %2$s.</string>
<string name="toggle_view_button">Vaihda näkymä</string>
<string name="about_faq">Usein Kysytyt Kysymykset</string>
<string name="about_faq" fuzzy="true">Usein Kysytyt Kysymykset</string>
<string name="welcome_skip_button">Ohita opetus</string>
</resources>

Some files were not shown because too many files have changed in this diff Show more