Merge branch 'master' into login-screen-improvement

This commit is contained in:
Paul Hawke 2017-10-10 22:13:25 -05:00
commit accd7edb7d
21 changed files with 161 additions and 67 deletions

View file

@ -147,10 +147,10 @@ public class CommonsApplication extends Application {
* @return Account|null * @return Account|null
*/ */
public Account getCurrentAccount() { public Account getCurrentAccount() {
if(currentAccount == null) { if (currentAccount == null) {
AccountManager accountManager = AccountManager.get(this); AccountManager accountManager = AccountManager.get(this);
Account[] allAccounts = accountManager.getAccountsByType(AccountUtil.accountType()); Account[] allAccounts = accountManager.getAccountsByType(AccountUtil.accountType());
if(allAccounts.length != 0) { if (allAccounts.length != 0) {
currentAccount = allAccounts[0]; currentAccount = allAccounts[0];
} }
} }
@ -161,7 +161,7 @@ public class CommonsApplication extends Application {
AccountManager accountManager = AccountManager.get(this); AccountManager accountManager = AccountManager.get(this);
Account curAccount = getCurrentAccount(); Account curAccount = getCurrentAccount();
if(curAccount == null) { if (curAccount == null) {
return false; // This should never happen return false; // This should never happen
} }
@ -224,11 +224,13 @@ public class CommonsApplication extends Application {
if (getIndex() == allAccounts.length) { if (getIndex() == allAccounts.length) {
Timber.d("All accounts have been removed"); Timber.d("All accounts have been removed");
//TODO: fix preference manager //TODO: fix preference manager
PreferenceManager.getDefaultSharedPreferences(getInstance()).edit().clear().commit(); PreferenceManager.getDefaultSharedPreferences(getInstance())
.edit().clear().commit();
SharedPreferences preferences = context SharedPreferences preferences = context
.getSharedPreferences("fr.free.nrw.commons", MODE_PRIVATE); .getSharedPreferences("fr.free.nrw.commons", MODE_PRIVATE);
preferences.edit().clear().commit(); preferences.edit().clear().commit();
context.getSharedPreferences("prefs", Context.MODE_PRIVATE).edit().clear().commit(); context.getSharedPreferences("prefs", Context.MODE_PRIVATE)
.edit().clear().commit();
preferences.edit().putBoolean("firstrun", false).apply(); preferences.edit().putBoolean("firstrun", false).apply();
updateAllDatabases(); updateAllDatabases();
currentAccount = null; currentAccount = null;

View file

@ -3,10 +3,10 @@ package fr.free.nrw.commons;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
public class License { public class License {
String key; private String key;
String template; private String template;
String url; private String url;
String name; private String name;
public License(String key, String template, String url, String name) { public License(String key, String template, String url, String name) {
if (key == null) { if (key == null) {

View file

@ -242,9 +242,9 @@ public class Utils {
public static boolean xmlFastForward(XmlPullParser parser, String namespace, String element) { public static boolean xmlFastForward(XmlPullParser parser, String namespace, String element) {
try { try {
while (parser.next() != XmlPullParser.END_DOCUMENT) { while (parser.next() != XmlPullParser.END_DOCUMENT) {
if (parser.getEventType() == XmlPullParser.START_TAG && if (parser.getEventType() == XmlPullParser.START_TAG
parser.getNamespace().equals(namespace) && && parser.getNamespace().equals(namespace)
parser.getName().equals(element)) { && parser.getName().equals(element)) {
// We found it! // We found it!
return true; return true;
} }
@ -267,7 +267,8 @@ public class Utils {
extension = "jpg"; extension = "jpg";
} }
title = jpegPattern.matcher(title).replaceFirst(".jpg"); title = jpegPattern.matcher(title).replaceFirst(".jpg");
if (extension != null && !title.toLowerCase(Locale.getDefault()).endsWith("." + extension.toLowerCase(Locale.ENGLISH))) { if (extension != null && !title.toLowerCase(Locale.getDefault())
.endsWith("." + extension.toLowerCase(Locale.ENGLISH))) {
title += "." + extension; title += "." + extension;
} }
return title; return title;

View file

@ -14,7 +14,7 @@ import timber.log.Timber;
public abstract class AuthenticatedActivity extends NavigationBaseActivity { public abstract class AuthenticatedActivity extends NavigationBaseActivity {
String accountType; private String accountType;
CommonsApplication app; CommonsApplication app;
private String authCookie; private String authCookie;

View file

@ -25,7 +25,8 @@ public class SignupActivity extends BaseActivity {
webView.setWebViewClient(new MyWebViewClient()); webView.setWebViewClient(new MyWebViewClient());
WebSettings webSettings = webView.getSettings(); WebSettings webSettings = webView.getSettings();
//Needed to refresh Captcha. Might introduce XSS vulnerabilities, but we can trust Wikimedia's site... right? /*Needed to refresh Captcha. Might introduce XSS vulnerabilities, but we can
trust Wikimedia's site... right?*/
webSettings.setJavaScriptEnabled(true); webSettings.setJavaScriptEnabled(true);
webView.loadUrl(BuildConfig.SIGNUP_LANDING_URL); webView.loadUrl(BuildConfig.SIGNUP_LANDING_URL);

View file

@ -32,7 +32,7 @@ public class CacheController {
public void cacheCategory() { public void cacheCategory() {
List<String> pointCatList = new ArrayList<>(); List<String> pointCatList = new ArrayList<>();
if (MwVolleyApi.GpsCatExists.getGpsCatExists()) { if (MwVolleyApi.GpsCatExists.getGpsCatExists()) {
pointCatList.addAll(MwVolleyApi.getGpsCat()); pointCatList.addAll(MwVolleyApi.getGpsCat());
Timber.d("Categories being cached: %s", pointCatList); Timber.d("Categories being cached: %s", pointCatList);
} else { } else {
Timber.d("No categories found, so no categories cached"); Timber.d("No categories found, so no categories cached");

View file

@ -197,7 +197,7 @@ public class CategorizationFragment extends Fragment {
.concatWith( .concatWith(
searchAll(filter) searchAll(filter)
.mergeWith(searchCategories(filter)) .mergeWith(searchCategories(filter))
.concatWith( TextUtils.isEmpty(filter) .concatWith(TextUtils.isEmpty(filter)
? defaultCategories() : Observable.empty()) ? defaultCategories() : Observable.empty())
) )
.filter(categoryItem -> !containsYear(categoryItem.getName())) .filter(categoryItem -> !containsYear(categoryItem.getName()))

View file

@ -142,11 +142,13 @@ public class CategoryContentProvider extends ContentProvider {
public int update(@NonNull Uri uri, ContentValues contentValues, String selection, public int update(@NonNull Uri uri, ContentValues contentValues, String selection,
String[] selectionArgs) { String[] selectionArgs) {
/* /*
SQL Injection warnings: First, note that we're not exposing this to the outside world (exported="false") SQL Injection warnings: First, note that we're not exposing this to the
Even then, we should make sure to sanitize all user input appropriately. Input that passes through ContentValues outside world (exported="false"). Even then, we should make sure to sanitize
all user input appropriately. Input that passes through ContentValues
should be fine. So only issues are those that pass in via concating. should be fine. So only issues are those that pass in via concating.
In here, the only concat created argument is for id. It is cast to an int, and will error out otherwise. In here, the only concat created argument is for id. It is cast to an int,
and will error out otherwise.
*/ */
int uriType = uriMatcher.match(uri); int uriType = uriMatcher.match(uri);
SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase(); SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase();

View file

@ -154,10 +154,12 @@ public class ContributionsContentProvider extends ContentProvider {
public int update(@NonNull Uri uri, ContentValues contentValues, String selection, String[] selectionArgs) { public int update(@NonNull Uri uri, ContentValues contentValues, String selection, String[] selectionArgs) {
/* /*
SQL Injection warnings: First, note that we're not exposing this to the outside world (exported="false") SQL Injection warnings: First, note that we're not exposing this to the outside world (exported="false")
Even then, we should make sure to sanitize all user input appropriately. Input that passes through ContentValues Even then, we should make sure to sanitize all user input appropriately.
should be fine. So only issues are those that pass in via concating. Input that passes through ContentValuesshould be fine. So only issues are those that pass
in via concating.
In here, the only concat created argument is for id. It is cast to an int, and will error out otherwise. In here, the only concat created argument is for id. It is cast to an int, and will
error out otherwise.
*/ */
int uriType = uriMatcher.match(uri); int uriType = uriMatcher.match(uri);
CommonsApplication app = (CommonsApplication) getContext().getApplicationContext(); CommonsApplication app = (CommonsApplication) getContext().getApplicationContext();

View file

@ -27,7 +27,7 @@ public class ModifierSequence {
public ModifierSequence(Uri mediaUri, JSONObject data) { public ModifierSequence(Uri mediaUri, JSONObject data) {
this(mediaUri); this(mediaUri);
JSONArray modifiersJSON = data.optJSONArray("modifiers"); JSONArray modifiersJSON = data.optJSONArray("modifiers");
for(int i=0; i< modifiersJSON.length(); i++) { for (int i=0; i< modifiersJSON.length(); i++) {
modifiers.add(PageModifier.fromJSON(modifiersJSON.optJSONObject(i))); modifiers.add(PageModifier.fromJSON(modifiersJSON.optJSONObject(i)));
} }
} }
@ -41,7 +41,7 @@ public class ModifierSequence {
} }
public String executeModifications(String pageName, String pageContents) { public String executeModifications(String pageName, String pageContents) {
for(PageModifier modifier: modifiers) { for (PageModifier modifier: modifiers) {
pageContents = modifier.doModification(pageName, pageContents); pageContents = modifier.doModification(pageName, pageContents);
} }
return pageContents; return pageContents;
@ -60,7 +60,7 @@ public class ModifierSequence {
JSONObject data = new JSONObject(); JSONObject data = new JSONObject();
try { try {
JSONArray modifiersJSON = new JSONArray(); JSONArray modifiersJSON = new JSONArray();
for(PageModifier modifier: modifiers) { for (PageModifier modifier: modifiers) {
modifiersJSON.put(modifier.toJSON()); modifiersJSON.put(modifier.toJSON());
} }
data.put("modifiers", modifiersJSON); data.put("modifiers", modifiersJSON);
@ -81,7 +81,8 @@ public class ModifierSequence {
// Hardcoding column positions! // Hardcoding column positions!
ModifierSequence ms = null; ModifierSequence ms = null;
try { try {
ms = new ModifierSequence(Uri.parse(cursor.getString(1)), new JSONObject(cursor.getString(2))); ms = new ModifierSequence(Uri.parse(cursor.getString(1)),
new JSONObject(cursor.getString(2)));
} catch (JSONException e) { } catch (JSONException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }

View file

@ -390,7 +390,7 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
public UploadResult uploadFile(String filename, InputStream file, long dataLength, String pageContents, String editSummary, final ProgressListener progressListener) throws IOException { public UploadResult uploadFile(String filename, InputStream file, long dataLength, String pageContents, String editSummary, final ProgressListener progressListener) throws IOException {
ApiResult result = api.upload(filename, file, dataLength, pageContents, editSummary, progressListener::onProgress); ApiResult result = api.upload(filename, file, dataLength, pageContents, editSummary, progressListener::onProgress);
Log.e("WTF", "Result: "+result.toString()); Log.e("WTF", "Result: " +result.toString());
String resultStatus = result.getString("/api/upload/@result"); String resultStatus = result.getString("/api/upload/@result");
if (!resultStatus.equals("Success")) { if (!resultStatus.equals("Success")) {

View file

@ -3,12 +3,14 @@ package fr.free.nrw.commons.nearby;
import android.Manifest; import android.Manifest;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.location.LocationManager; import android.location.LocationManager;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
@ -42,28 +44,46 @@ public class NearbyActivity extends NavigationBaseActivity {
@BindView(R.id.progressBar) @BindView(R.id.progressBar)
ProgressBar progressBar; ProgressBar progressBar;
private boolean isMapViewActive = false;
private static final int LOCATION_REQUEST = 1; private static final int LOCATION_REQUEST = 1;
private static final String MAP_LAST_USED_PREFERENCE = "mapLastUsed";
private LocationServiceManager locationManager; private LocationServiceManager locationManager;
private LatLng curLatLang; private LatLng curLatLang;
private Bundle bundle; private Bundle bundle;
private NearbyAsyncTask nearbyAsyncTask; private NearbyAsyncTask nearbyAsyncTask;
private SharedPreferences sharedPreferences;
private NearbyActivityMode viewMode;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
setContentView(R.layout.activity_nearby); setContentView(R.layout.activity_nearby);
ButterKnife.bind(this); ButterKnife.bind(this);
checkLocationPermission(); checkLocationPermission();
bundle = new Bundle(); bundle = new Bundle();
initDrawer(); initDrawer();
initViewState();
}
private void initViewState() {
if (sharedPreferences.getBoolean(MAP_LAST_USED_PREFERENCE, false)) {
viewMode = NearbyActivityMode.MAP;
} else {
viewMode = NearbyActivityMode.LIST;
}
} }
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater(); MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_nearby, menu); inflater.inflate(R.menu.menu_nearby, menu);
if (viewMode.isMap()) {
MenuItem item = menu.findItem(R.id.action_toggle_view);
item.setIcon(viewMode.getIcon());
}
return super.onCreateOptionsMenu(menu); return super.onCreateOptionsMenu(menu);
} }
@ -74,13 +94,10 @@ public class NearbyActivity extends NavigationBaseActivity {
case R.id.action_refresh: case R.id.action_refresh:
refreshView(); refreshView();
return true; return true;
case R.id.action_map: case R.id.action_toggle_view:
showMapView(); viewMode = viewMode.toggle();
if (isMapViewActive) { item.setIcon(viewMode.getIcon());
item.setIcon(R.drawable.ic_list_white_24dp); toggleView();
} else {
item.setIcon(R.drawable.ic_map_white_24dp);
}
return true; return true;
default: default:
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
@ -158,15 +175,30 @@ public class NearbyActivity extends NavigationBaseActivity {
if (progressBar != null) { if (progressBar != null) {
progressBar.setVisibility(View.GONE); progressBar.setVisibility(View.GONE);
} }
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
Fragment noPermissionsFragment = new NoPermissionsFragment(); showLocationPermissionDeniedErrorDialog();
fragmentTransaction.replace(R.id.container, noPermissionsFragment);
fragmentTransaction.commit();
} }
} }
} }
} }
private void showLocationPermissionDeniedErrorDialog() {
new AlertDialog.Builder(this)
.setMessage(R.string.nearby_needs_permissions)
.setCancelable(false)
.setPositiveButton(R.string.give_permission, (dialog, which) -> {
//will ask for the location permission again
checkLocationPermission();
})
.setNegativeButton(R.string.cancel, (dialog, which) -> {
//dismiss dialog and finish activity
dialog.cancel();
finish();
})
.create()
.show();
}
private void checkGps() { private void checkGps() {
LocationManager manager = (LocationManager) getSystemService(LOCATION_SERVICE); LocationManager manager = (LocationManager) getSystemService(LOCATION_SERVICE);
if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
@ -198,20 +230,16 @@ public class NearbyActivity extends NavigationBaseActivity {
} }
} }
private void showMapView() { private void toggleView() {
if (nearbyAsyncTask != null) { if (nearbyAsyncTask != null) {
if (!isMapViewActive) { if (nearbyAsyncTask.getStatus() == AsyncTask.Status.FINISHED) {
isMapViewActive = true; if (viewMode.isMap()) {
if (nearbyAsyncTask.getStatus() == AsyncTask.Status.FINISHED) {
setMapFragment(); setMapFragment();
} } else {
} else {
isMapViewActive = false;
if (nearbyAsyncTask.getStatus() == AsyncTask.Status.FINISHED) {
setListFragment(); setListFragment();
} }
} }
sharedPreferences.edit().putBoolean(MAP_LAST_USED_PREFERENCE, viewMode.isMap()).apply();
} }
} }
@ -287,7 +315,7 @@ public class NearbyActivity extends NavigationBaseActivity {
bundle.putString("CurLatLng", gsonCurLatLng); bundle.putString("CurLatLng", gsonCurLatLng);
// Begin the transaction // Begin the transaction
if (isMapViewActive) { if (viewMode.isMap()) {
setMapFragment(); setMapFragment();
} else { } else {
setListFragment(); setListFragment();

View file

@ -0,0 +1,30 @@
package fr.free.nrw.commons.nearby;
import android.support.annotation.DrawableRes;
import fr.free.nrw.commons.R;
enum NearbyActivityMode {
MAP(R.drawable.ic_list_white_24dp),
LIST(R.drawable.ic_map_white_24dp);
@DrawableRes
private final int icon;
NearbyActivityMode(int icon) {
this.icon = icon;
}
@DrawableRes
public int getIcon() {
return icon;
}
public NearbyActivityMode toggle() {
return isMap() ? LIST : MAP;
}
public boolean isMap() {
return MAP.equals(this);
}
}

View file

@ -63,7 +63,7 @@ public class MultipleShareActivity
@Override @Override
public int getTotalMediaCount() { public int getTotalMediaCount() {
if(photosList == null) { if (photosList == null) {
return 0; return 0;
} }
return photosList.size(); return photosList.size();
@ -71,7 +71,7 @@ public class MultipleShareActivity
@Override @Override
public void notifyDatasetChanged() { public void notifyDatasetChanged() {
if(uploadsList != null) { if (uploadsList != null) {
uploadsList.notifyDatasetChanged(); uploadsList.notifyDatasetChanged();
} }
} }
@ -145,7 +145,7 @@ public class MultipleShareActivity
uploadsList.setImageOnlyMode(true); uploadsList.setImageOnlyMode(true);
categorizationFragment = (CategorizationFragment) getSupportFragmentManager().findFragmentByTag("categorization"); categorizationFragment = (CategorizationFragment) getSupportFragmentManager().findFragmentByTag("categorization");
if(categorizationFragment == null) { if (categorizationFragment == null) {
categorizationFragment = new CategorizationFragment(); categorizationFragment = new CategorizationFragment();
} }
// FIXME: Stops the keyboard from being shown 'stale' while moving out of this fragment into the next // FIXME: Stops the keyboard from being shown 'stale' while moving out of this fragment into the next
@ -162,7 +162,7 @@ public class MultipleShareActivity
@Override @Override
public void onCategoriesSave(List<String> categories) { public void onCategoriesSave(List<String> categories) {
if(categories.size() > 0) { if (categories.size() > 0) {
ContentProviderClient client = getContentResolver().acquireContentProviderClient(ModificationsContentProvider.AUTHORITY); ContentProviderClient client = getContentResolver().acquireContentProviderClient(ModificationsContentProvider.AUTHORITY);
for(Contribution contribution: photosList) { for(Contribution contribution: photosList) {
ModifierSequence categoriesSequence = new ModifierSequence(contribution.getContentUri()); ModifierSequence categoriesSequence = new ModifierSequence(contribution.getContentUri());
@ -191,7 +191,7 @@ public class MultipleShareActivity
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) { switch(item.getItemId()) {
case android.R.id.home: case android.R.id.home:
if(mediaDetails.isVisible()) { if (mediaDetails.isVisible()) {
getSupportFragmentManager().popBackStack(); getSupportFragmentManager().popBackStack();
} }
return true; return true;
@ -209,7 +209,7 @@ public class MultipleShareActivity
ButterKnife.bind(this); ButterKnife.bind(this);
initDrawer(); initDrawer();
if(savedInstanceState != null) { if (savedInstanceState != null) {
photosList = savedInstanceState.getParcelableArrayList("uploadsList"); photosList = savedInstanceState.getParcelableArrayList("uploadsList");
} }
@ -225,7 +225,7 @@ public class MultipleShareActivity
} }
private void showDetail(int i) { private void showDetail(int i) {
if(mediaDetails == null ||!mediaDetails.isVisible()) { if (mediaDetails == null ||!mediaDetails.isVisible()) {
mediaDetails = new MediaDetailPagerFragment(true); mediaDetails = new MediaDetailPagerFragment(true);
getSupportFragmentManager() getSupportFragmentManager()
.beginTransaction() .beginTransaction()
@ -248,8 +248,8 @@ public class MultipleShareActivity
app.getMWApi().setAuthCookie(authCookie); app.getMWApi().setAuthCookie(authCookie);
Intent intent = getIntent(); Intent intent = getIntent();
if(intent.getAction().equals(Intent.ACTION_SEND_MULTIPLE)) { if (intent.getAction().equals(Intent.ACTION_SEND_MULTIPLE)) {
if(photosList == null) { if (photosList == null) {
photosList = new ArrayList<>(); photosList = new ArrayList<>();
ArrayList<Uri> urisList = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); ArrayList<Uri> urisList = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
for(int i=0; i < urisList.size(); i++) { for(int i=0; i < urisList.size(); i++) {
@ -265,7 +265,7 @@ public class MultipleShareActivity
} }
uploadsList = (MultipleUploadListFragment) getSupportFragmentManager().findFragmentByTag("uploadsList"); uploadsList = (MultipleUploadListFragment) getSupportFragmentManager().findFragmentByTag("uploadsList");
if(uploadsList == null) { if (uploadsList == null) {
uploadsList = new MultipleUploadListFragment(); uploadsList = new MultipleUploadListFragment();
getSupportFragmentManager() getSupportFragmentManager()
.beginTransaction() .beginTransaction()
@ -287,7 +287,7 @@ public class MultipleShareActivity
@Override @Override
public void onBackPressed() { public void onBackPressed() {
super.onBackPressed(); super.onBackPressed();
if(categorizationFragment != null && categorizationFragment.isVisible()) { if (categorizationFragment != null && categorizationFragment.isVisible()) {
EventLog.schema(CommonsApplication.EVENT_CATEGORIZATION_ATTEMPT) EventLog.schema(CommonsApplication.EVENT_CATEGORIZATION_ATTEMPT)
.param("username", app.getCurrentAccount().name) .param("username", app.getCurrentAccount().name)
.param("categories-count", categorizationFragment.getCurrentSelectedCount()) .param("categories-count", categorizationFragment.getCurrentSelectedCount())
@ -307,7 +307,7 @@ public class MultipleShareActivity
@Override @Override
public void onBackStackChanged() { public void onBackStackChanged() {
if(mediaDetails != null && mediaDetails.isVisible()) { if (mediaDetails != null && mediaDetails.isVisible()) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
} else { } else {
getSupportActionBar().setDisplayHomeAsUpEnabled(false); getSupportActionBar().setDisplayHomeAsUpEnabled(false);

View file

@ -86,7 +86,8 @@ public class SingleUploadFragment extends Fragment {
} }
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_single_upload, container, false); View rootView = inflater.inflate(R.layout.fragment_single_upload, container, false);
ButterKnife.bind(this, rootView); ButterKnife.bind(this, rootView);

View file

@ -3,7 +3,7 @@
xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity"> xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity">
<item <item
android:id="@+id/action_map" android:id="@+id/action_toggle_view"
android:title="@string/refresh_button" android:title="@string/refresh_button"
android:icon="@drawable/ic_map_white_24dp" android:icon="@drawable/ic_map_white_24dp"
android:orderInCategory="1" android:orderInCategory="1"

View file

@ -54,7 +54,10 @@
<string name="gps_disabled">आपके डिवाइस में जीपीएस अक्षम है। क्या आप इसे सक्षम करना चाहेंगे?</string> <string name="gps_disabled">आपके डिवाइस में जीपीएस अक्षम है। क्या आप इसे सक्षम करना चाहेंगे?</string>
<string name="enable_gps">जीपीएस सक्षम करें</string> <string name="enable_gps">जीपीएस सक्षम करें</string>
<string name="contributions_subtitle_zero">अभी तक कोई अपलोड नहीं</string> <string name="contributions_subtitle_zero">अभी तक कोई अपलोड नहीं</string>
<string name="contributions_subtitle" formatted="false">{{PLURAL | शून्य = @ स्ट्रिंग / योगदान_उपशीर्षक_शुन्य | एक =% d अपलोड |% d अपलोड्स}}</string> <plurals name="contributions_subtitle">
<item quantity="one">%d अपलोड</item>
<item quantity="other">%d अपलोड्स</item>
</plurals>
<plurals name="starting_multiple_uploads"> <plurals name="starting_multiple_uploads">
<item quantity="one">%d अपलोड शुरू</item> <item quantity="one">%d अपलोड शुरू</item>
<item quantity="other">%d अपलोड शुरू</item> <item quantity="other">%d अपलोड शुरू</item>

View file

@ -77,10 +77,10 @@ Tap this message (or hit back) to skip this step.</string>
<string name="title_activity_settings">Settings</string> <string name="title_activity_settings">Settings</string>
<string name="title_activity_signup">Sign Up</string> <string name="title_activity_signup">Sign Up</string>
<string name="menu_about">About</string> <string name="menu_about">About</string>
<string name="about_license">Open Source software released under the &lt;a href=\"https://github.com/commons-app/apps-android-commons/blob/master/COPYING\"&gt;Apache License v2&lt;/a&gt;. %1$s and its logo are trademarks of the Wikimedia Foundation and are used with the permission of the Wikimedia Foundation. We are not endorsed by or affiliated with the Wikimedia Foundation.</string> <string name="about_license">The Wikimedia Commons app is an open-source app created and maintained by grantees and volunteers of the Wikimedia community. The Wikimedia Foundation is not involved in the creation, development, or maintenance of the app. </string>
<string name="trademarked_name" translatable="false">Wikimedia Commons</string> <string name="trademarked_name" translatable="false">Wikimedia Commons</string>
<string name="about_improve">&lt;a href=\"https://github.com/commons-app/apps-android-commons\"&gt;Source&lt;/a&gt; and &lt;a href=\"https://commons-app.github.io/\"&gt;website&lt;/a&gt; on GitHub. Create a new &lt;a href=\"https://github.com/commons-app/apps-android-commons/issues\"&gt;GitHub issue&lt;/a&gt; for bug reports and suggestions.</string> <string name="about_improve">&lt;a href=\"https://github.com/commons-app/apps-android-commons\"&gt;Source&lt;/a&gt; and &lt;a href=\"https://commons-app.github.io/\"&gt;website&lt;/a&gt; on GitHub. Create a new &lt;a href=\"https://github.com/commons-app/apps-android-commons/issues\"&gt;GitHub issue&lt;/a&gt; for bug reports and suggestions.</string>
<string name="about_privacy_policy">&lt;a href=\"https://wikimediafoundation.org/wiki/Privacy_policy\"&gt;Privacy policy&lt;/a&gt;</string> <string name="about_privacy_policy">&lt;a href=\"https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\"&gt;Privacy policy&lt;/a&gt;</string>
<string name="about_credits">&lt;a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\"&gt;Credits&lt;/a&gt;</string> <string name="about_credits">&lt;a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\"&gt;Credits&lt;/a&gt;</string>
<string name="title_activity_about">About</string> <string name="title_activity_about">About</string>
<string name="menu_feedback">Send Feedback (via Email)</string> <string name="menu_feedback">Send Feedback (via Email)</string>
@ -204,6 +204,7 @@ Tap this message (or hit back) to skip this step.</string>
<string name="error_while_cache">Error while caching pictures</string> <string name="error_while_cache">Error while caching pictures</string>
<string name="title_info">A unique descriptive title for the file, which will serve as a filename. You may use plain language with spaces. Do not include the file extension</string> <string name="title_info">A unique descriptive title for the file, which will serve as a filename. You may use plain language with spaces. Do not include the file extension</string>
<string name="description_info">Please describe the media as much as possible: Where was it taken? What does it show? What is the context? Please describe the objects or persons. Reveal information that can not be easily guessed, for instance the time of day if it is a landscape. If the media shows something unusual, please explain what makes it unusual.</string> <string name="description_info">Please describe the media as much as possible: Where was it taken? What does it show? What is the context? Please describe the objects or persons. Reveal information that can not be easily guessed, for instance the time of day if it is a landscape. If the media shows something unusual, please explain what makes it unusual.</string>
<string name="give_permission">Give permission</string>
<string name="use_external_storage">Use external storage</string> <string name="use_external_storage">Use external storage</string>
<string name="use_external_storage_summary">Save pictures taken with the in-app camera on your device</string> <string name="use_external_storage_summary">Save pictures taken with the in-app camera on your device</string>
<string name="login_to_your_account">Login to your account</string> <string name="login_to_your_account">Login to your account</string>

22
design/Commons-logo.svg Normal file
View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1024" height="1376" viewBox="-305 -516 610 820">
<title>Wikimedia Commons Logo</title>
<defs>
<clipPath id="c"><circle r="298"/></clipPath>
</defs>
<circle r="100" fill="#900"/>
<g fill="#069">
<g id="arrow" clip-path="url(#c)">
<path d="m-11 180v118h22v-118"/>
<path d="m-43 185l43-75 43 75"/>
</g>
<g id="arrows3">
<use xlink:href="#arrow" transform="rotate(45)"/>
<use xlink:href="#arrow" transform="rotate(90)"/>
<use xlink:href="#arrow" transform="rotate(135)"/>
</g>
<use xlink:href="#arrows3" transform="scale(-1 1)"/>
<path id="blue_path" transform="rotate(-45)" stroke="#069" stroke-width="84" fill="none" d="M 0,-256 A 256 256 0 1 0 256,0 C 256,-100 155,-150 250,-275"/>
<path id="arrow_top" d="m-23-515s-36 135-80 185 116-62 170-5-90-180-90-180z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 932 B

BIN
design/adaptive-icon-bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
design/adaptive-icon-fg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 804 B