mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-28 21:33:53 +01:00
Merge branch 'master' into dependency-injection
This commit is contained in:
commit
02b5b9b680
148 changed files with 1169 additions and 364 deletions
|
|
@ -1,7 +1,5 @@
|
|||
package fr.free.nrw.commons;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.widget.TextView;
|
||||
|
||||
|
|
@ -27,9 +25,4 @@ public class AboutActivity extends NavigationBaseActivity {
|
|||
versionText.setText(BuildConfig.VERSION_NAME);
|
||||
initDrawer();
|
||||
}
|
||||
|
||||
public static void startYourself(Context context) {
|
||||
Intent settingsIntent = new Intent(context, AboutActivity.class);
|
||||
context.startActivity(settingsIntent);
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import android.database.sqlite.SQLiteDatabase;
|
|||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.stetho.Stetho;
|
||||
import com.squareup.leakcanary.LeakCanary;
|
||||
import com.squareup.leakcanary.RefWatcher;
|
||||
|
||||
import org.acra.ACRA;
|
||||
import org.acra.ReportingInteractionMode;
|
||||
|
|
@ -60,17 +61,15 @@ public class CommonsApplication extends DaggerApplication {
|
|||
public static final String FEEDBACK_EMAIL_SUBJECT = "Commons Android App (%s) Feedback";
|
||||
|
||||
private CommonsApplicationComponent component;
|
||||
private RefWatcher refWatcher;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
if (LeakCanary.isInAnalyzerProcess(this)) {
|
||||
// This process is dedicated to LeakCanary for heap analysis.
|
||||
// You should not init your app in this process.
|
||||
if (setupLeakCanary() == RefWatcher.DISABLED) {
|
||||
return;
|
||||
}
|
||||
LeakCanary.install(this);
|
||||
|
||||
Timber.plant(new Timber.DebugTree());
|
||||
|
||||
|
|
@ -86,6 +85,18 @@ public class CommonsApplication extends DaggerApplication {
|
|||
Fresco.initialize(this);
|
||||
}
|
||||
|
||||
protected RefWatcher setupLeakCanary() {
|
||||
if (LeakCanary.isInAnalyzerProcess(this)) {
|
||||
return RefWatcher.DISABLED;
|
||||
}
|
||||
return LeakCanary.install(this);
|
||||
}
|
||||
|
||||
public static RefWatcher getRefWatcher(Context context) {
|
||||
CommonsApplication application = (CommonsApplication) context.getApplicationContext();
|
||||
return application.refWatcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
|
||||
return injector();
|
||||
|
|
|
|||
|
|
@ -120,8 +120,9 @@ public class Media implements Parcelable {
|
|||
return localUri;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getImageUrl() {
|
||||
if (imageUrl == null) {
|
||||
if (imageUrl == null && this.getFilename() != null) {
|
||||
imageUrl = Utils.makeThumbBaseUrl(this.getFilename());
|
||||
}
|
||||
return imageUrl;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import org.xml.sax.SAXException;
|
|||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
|
|
@ -39,7 +38,6 @@ public class MediaDataExtractor {
|
|||
private String filename;
|
||||
private ArrayList<String> categories;
|
||||
private Map<String, String> descriptions;
|
||||
private Date date;
|
||||
private String license;
|
||||
private @Nullable LatLng coordinates;
|
||||
private LicenseList licenseList;
|
||||
|
|
@ -155,7 +153,7 @@ public class MediaDataExtractor {
|
|||
}
|
||||
|
||||
private Node findTemplate(Element parentNode, String title_) throws IOException {
|
||||
String title= new PageTitle(title_).getDisplayText();
|
||||
String title = new PageTitle(title_).getDisplayText();
|
||||
NodeList nodes = parentNode.getChildNodes();
|
||||
for (int i = 0, length = nodes.getLength(); i < length; i++) {
|
||||
Node node = nodes.item(i);
|
||||
|
|
@ -181,7 +179,7 @@ public class MediaDataExtractor {
|
|||
}
|
||||
|
||||
private static abstract class TemplateChildNodeComparator {
|
||||
abstract public boolean match(Node node);
|
||||
public abstract boolean match(Node node);
|
||||
}
|
||||
|
||||
private Node findTemplateParameter(Node templateNode, String name) throws IOException {
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ public class MediaWikiImageView extends SimpleDraweeView {
|
|||
if (currentThumbnailTask != null) {
|
||||
currentThumbnailTask.cancel(true);
|
||||
}
|
||||
if(media == null) {
|
||||
if (media == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,18 +2,22 @@ package fr.free.nrw.commons;
|
|||
|
||||
import android.content.Context;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import fr.free.nrw.commons.auth.LoginActivity;
|
||||
import fr.free.nrw.commons.settings.Prefs;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class Utils {
|
||||
|
||||
|
|
@ -33,7 +37,7 @@ public class Utils {
|
|||
}
|
||||
}
|
||||
|
||||
public static String makeThumbBaseUrl(String filename) {
|
||||
public static String makeThumbBaseUrl(@NonNull String filename) {
|
||||
String name = new PageTitle(filename).getPrefixedText();
|
||||
String sha = new String(Hex.encodeHex(DigestUtils.md5(name)));
|
||||
return String.format("%s/%s/%s/%s", BuildConfig.IMAGE_URL_BASE, sha.substring(0, 1), sha.substring(0, 2), urlEncode(name));
|
||||
|
|
@ -89,4 +93,37 @@ public class Utils {
|
|||
public static boolean isDarkTheme(Context context) {
|
||||
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("theme", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Will be used to fetch the logs generated by the app ever since the beginning of times....
|
||||
* i.e. since the time the app started.
|
||||
*
|
||||
* @return String containing all the logs since the time the app started
|
||||
*/
|
||||
public static String getAppLogs() {
|
||||
final String processId = Integer.toString(android.os.Process.myPid());
|
||||
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
try {
|
||||
String[] command = new String[] {"logcat","-d","-v","threadtime"};
|
||||
|
||||
Process process = Runtime.getRuntime().exec(command);
|
||||
|
||||
BufferedReader bufferedReader = new BufferedReader(
|
||||
new InputStreamReader(process.getInputStream())
|
||||
);
|
||||
|
||||
String line;
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
if (line.contains(processId)) {
|
||||
stringBuilder.append(line);
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
Timber.e("getAppLogs failed", ioe);
|
||||
}
|
||||
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import static android.accounts.AccountManager.KEY_ACCOUNT_TYPE;
|
|||
|
||||
public class AccountUtil {
|
||||
|
||||
static final String ACCOUNT_TYPE = "fr.free.nrw.commons";
|
||||
public static final String ACCOUNT_TYPE = "fr.free.nrw.commons";
|
||||
private final Context context;
|
||||
|
||||
public AccountUtil(Context context) {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import fr.free.nrw.commons.Utils;
|
|||
import fr.free.nrw.commons.WelcomeActivity;
|
||||
import fr.free.nrw.commons.contributions.ContributionsActivity;
|
||||
import fr.free.nrw.commons.mwapi.MediaWikiApi;
|
||||
import fr.free.nrw.commons.theme.NavigationBaseActivity;
|
||||
import timber.log.Timber;
|
||||
|
||||
import static android.view.KeyEvent.KEYCODE_ENTER;
|
||||
|
|
@ -199,7 +200,7 @@ public class LoginActivity extends AccountAuthenticatorActivity {
|
|||
}
|
||||
|
||||
public void startMainActivity() {
|
||||
ContributionsActivity.startYourself(this);
|
||||
NavigationBaseActivity.startActivityWithFlags(this, ContributionsActivity.class, Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
finish();
|
||||
}
|
||||
|
||||
|
|
@ -253,8 +254,8 @@ public class LoginActivity extends AccountAuthenticatorActivity {
|
|||
|
||||
@Override
|
||||
public void afterTextChanged(Editable editable) {
|
||||
boolean enabled = usernameEdit.getText().length() != 0 && passwordEdit.getText().length() != 0 &&
|
||||
(BuildConfig.DEBUG || twoFactorEdit.getText().length() != 0 || twoFactorEdit.getVisibility() != View.VISIBLE);
|
||||
boolean enabled = usernameEdit.getText().length() != 0 && passwordEdit.getText().length() != 0
|
||||
&& (BuildConfig.DEBUG || twoFactorEdit.getText().length() != 0 || twoFactorEdit.getVisibility() != View.VISIBLE);
|
||||
loginButton.setEnabled(enabled);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -149,10 +149,13 @@ public class ContributionsActivity
|
|||
if (savedInstanceState != null) {
|
||||
mediaDetails = (MediaDetailPagerFragment)supportFragmentManager
|
||||
.findFragmentById(R.id.contributionsFragmentContainer);
|
||||
|
||||
getSupportLoaderManager().initLoader(0, null, this);
|
||||
}
|
||||
requestAuthToken();
|
||||
initDrawer();
|
||||
setTitle(getString(R.string.title_activity_contributions));
|
||||
setUploadCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -242,6 +245,8 @@ public class ContributionsActivity
|
|||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
|
||||
contributionsList.changeProgressBarVisibility(false);
|
||||
|
||||
if (contributionsList.getAdapter() == null) {
|
||||
contributionsList.setAdapter(new ContributionsListAdapter(getApplicationContext(),
|
||||
cursor, 0));
|
||||
|
|
@ -249,8 +254,6 @@ public class ContributionsActivity
|
|||
((CursorAdapter) contributionsList.getAdapter()).swapCursor(cursor);
|
||||
}
|
||||
|
||||
setUploadCount();
|
||||
|
||||
contributionsList.clearSyncMessage();
|
||||
notifyAndMigrateDataSetObservers();
|
||||
}
|
||||
|
|
@ -281,18 +284,16 @@ public class ContributionsActivity
|
|||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private void setUploadCount() {
|
||||
compositeDisposable.add(
|
||||
mediaWikiApi
|
||||
.getUploadCount(sessionManager.getCurrentAccount().name)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
uploadCount -> getSupportActionBar().setSubtitle(getResources()
|
||||
.getQuantityString(R.plurals.contributions_subtitle,
|
||||
uploadCount, uploadCount)),
|
||||
t -> Timber.e(t, "Fetching upload count failed")
|
||||
)
|
||||
);
|
||||
compositeDisposable.add(mediaWikiApi
|
||||
.getUploadCount(sessionManager.getCurrentAccount().name)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
uploadCount -> getSupportActionBar().setSubtitle(getResources()
|
||||
.getQuantityString(R.plurals.contributions_subtitle,
|
||||
uploadCount, uploadCount)),
|
||||
t -> Timber.e(t, "Fetching upload count failed")
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -344,9 +345,4 @@ public class ContributionsActivity
|
|||
public void refreshSource() {
|
||||
getSupportLoaderManager().restartLoader(0, null, this);
|
||||
}
|
||||
|
||||
public static void startYourself(Context context) {
|
||||
context.startActivity(new Intent(context, ContributionsActivity.class));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class ContributionsListAdapter extends CursorAdapter {
|
|||
views.seqNumView.setText(String.valueOf(cursor.getPosition() + 1));
|
||||
views.seqNumView.setVisibility(View.VISIBLE);
|
||||
|
||||
switch(contribution.getState()) {
|
||||
switch (contribution.getState()) {
|
||||
case Contribution.STATE_COMPLETED:
|
||||
views.stateView.setVisibility(View.GONE);
|
||||
views.progressView.setVisibility(View.GONE);
|
||||
|
|
@ -50,7 +50,7 @@ class ContributionsListAdapter extends CursorAdapter {
|
|||
views.progressView.setVisibility(View.VISIBLE);
|
||||
long total = contribution.getDataLength();
|
||||
long transferred = contribution.getTransferred();
|
||||
if(transferred == 0 || transferred >= total) {
|
||||
if (transferred == 0 || transferred >= total) {
|
||||
views.progressView.setIndeterminate(true);
|
||||
} else {
|
||||
views.progressView.setProgress((int)(((double)transferred / (double)total) * 100));
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import android.content.SharedPreferences;
|
|||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
|
|
@ -18,6 +17,7 @@ import android.view.ViewGroup;
|
|||
import android.widget.AdapterView;
|
||||
import android.widget.GridView;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
|
@ -42,10 +42,12 @@ public class ContributionsListFragment extends DaggerFragment {
|
|||
GridView contributionsList;
|
||||
@BindView(R.id.waitingMessage)
|
||||
TextView waitingMessage;
|
||||
@BindView(R.id.emptyMessage)
|
||||
TextView emptyMessage;
|
||||
@BindView(R.id.loadingContributionsProgressBar)
|
||||
ProgressBar progressBar;
|
||||
|
||||
@Inject @Named("prefs") SharedPreferences prefs;
|
||||
@Inject @Named("default_preferences") SharedPreferences defaultPrefs;
|
||||
|
||||
private ContributionController controller;
|
||||
|
||||
@Override
|
||||
|
|
@ -69,6 +71,7 @@ public class ContributionsListFragment extends DaggerFragment {
|
|||
waitingMessage.setVisibility(GONE);
|
||||
}
|
||||
|
||||
changeProgressBarVisibility(true);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
|
@ -80,6 +83,10 @@ public class ContributionsListFragment extends DaggerFragment {
|
|||
this.contributionsList.setAdapter(adapter);
|
||||
}
|
||||
|
||||
public void changeProgressBarVisibility(boolean isVisible) {
|
||||
this.progressBar.setVisibility(isVisible ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
if (outState == null) {
|
||||
|
|
|
|||
|
|
@ -57,6 +57,9 @@ public class ContributionsSyncAdapter extends AbstractThreadedSyncAdapter {
|
|||
}
|
||||
|
||||
private boolean fileExists(ContentProviderClient client, String filename) {
|
||||
if (filename == null) {
|
||||
return false;
|
||||
}
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = client.query(BASE_URI,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import android.database.sqlite.SQLiteOpenHelper;
|
|||
import fr.free.nrw.commons.contributions.Contribution;
|
||||
import fr.free.nrw.commons.modifications.ModifierSequence;
|
||||
|
||||
public class DBOpenHelper extends SQLiteOpenHelper{
|
||||
public class DBOpenHelper extends SQLiteOpenHelper {
|
||||
|
||||
private static final String DATABASE_NAME = "commons.db";
|
||||
private static final int DATABASE_VERSION = 6;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import fr.free.nrw.commons.auth.AccountUtil;
|
|||
import fr.free.nrw.commons.auth.SessionManager;
|
||||
import fr.free.nrw.commons.caching.CacheController;
|
||||
import fr.free.nrw.commons.data.DBOpenHelper;
|
||||
import fr.free.nrw.commons.location.LocationServiceManager;
|
||||
import fr.free.nrw.commons.mwapi.ApacheHttpClientMediaWikiApi;
|
||||
import fr.free.nrw.commons.mwapi.MediaWikiApi;
|
||||
import fr.free.nrw.commons.nearby.NearbyPlaces;
|
||||
|
|
@ -71,6 +72,12 @@ public class CommonsApplicationModule {
|
|||
return new ApacheHttpClientMediaWikiApi(BuildConfig.WIKIMEDIA_API_HOST);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public LocationServiceManager provideLocationServiceManager() {
|
||||
return new LocationServiceManager(application);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public CacheController provideCacheController() {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ public class LatLng {
|
|||
* @param longitude double value
|
||||
*/
|
||||
public LatLng(double latitude, double longitude, float accuracy) {
|
||||
if(-180.0D <= longitude && longitude < 180.0D) {
|
||||
if (-180.0D <= longitude && longitude < 180.0D) {
|
||||
this.longitude = longitude;
|
||||
} else {
|
||||
this.longitude = ((longitude - 180.0D) % 360.0D + 360.0D) % 360.0D - 180.0D;
|
||||
|
|
@ -33,9 +33,9 @@ public class LatLng {
|
|||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if(this == o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if(!(o instanceof LatLng)) {
|
||||
} else if (!(o instanceof LatLng)) {
|
||||
return false;
|
||||
} else {
|
||||
LatLng var2 = (LatLng)o;
|
||||
|
|
|
|||
|
|
@ -7,22 +7,33 @@ import android.location.LocationListener;
|
|||
import android.location.LocationManager;
|
||||
import android.os.Bundle;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
public class LocationServiceManager implements LocationListener {
|
||||
|
||||
private String provider;
|
||||
private LocationManager locationManager;
|
||||
private LatLng latestLocation;
|
||||
private LatLng lastLocation;
|
||||
private Float latestLocationAccuracy;
|
||||
private final List<LocationUpdateListener> locationListeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
public LocationServiceManager(Context context) {
|
||||
this.locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
||||
provider = locationManager.getBestProvider(new Criteria(), true);
|
||||
}
|
||||
|
||||
public LatLng getLatestLocation() {
|
||||
return latestLocation;
|
||||
public boolean isProviderEnabled() {
|
||||
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
|
||||
}
|
||||
|
||||
public LatLng getLastLocation() {
|
||||
return lastLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -64,6 +75,16 @@ public class LocationServiceManager implements LocationListener {
|
|||
}
|
||||
}
|
||||
|
||||
public void addLocationListener(LocationUpdateListener listener) {
|
||||
if (!locationListeners.contains(listener)) {
|
||||
locationListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeLocationListener(LocationUpdateListener listener) {
|
||||
locationListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationChanged(Location location) {
|
||||
double currentLatitude = location.getLatitude();
|
||||
|
|
@ -71,8 +92,11 @@ public class LocationServiceManager implements LocationListener {
|
|||
latestLocationAccuracy = location.getAccuracy();
|
||||
Timber.d("Latitude: %f Longitude: %f Accuracy %f",
|
||||
currentLatitude, currentLongitude, latestLocationAccuracy);
|
||||
lastLocation = new LatLng(currentLatitude, currentLongitude, latestLocationAccuracy);
|
||||
|
||||
latestLocation = new LatLng(currentLatitude, currentLongitude, latestLocationAccuracy);
|
||||
for (LocationUpdateListener listener : locationListeners) {
|
||||
listener.onLocationChanged(lastLocation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
package fr.free.nrw.commons.location;
|
||||
|
||||
public interface LocationUpdateListener {
|
||||
void onLocationChanged(LatLng latLng);
|
||||
}
|
||||
|
|
@ -152,8 +152,14 @@ public class MediaDetailPagerFragment extends DaggerFragment implements ViewPage
|
|||
private void downloadMedia(Media m) {
|
||||
String imageUrl = m.getImageUrl(),
|
||||
fileName = m.getFilename();
|
||||
|
||||
if (imageUrl == null || fileName == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Strip 'File:' from beginning of filename, we really shouldn't store it
|
||||
fileName = fileName.replaceFirst("^File:", "");
|
||||
|
||||
Uri imageUri = Uri.parse(imageUrl);
|
||||
|
||||
DownloadManager.Request req = new DownloadManager.Request(imageUri);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ public class CategoryModifier extends PageModifier {
|
|||
public CategoryModifier(String... categories) {
|
||||
super(MODIFIER_NAME);
|
||||
JSONArray categoriesArray = new JSONArray();
|
||||
for(String category: categories) {
|
||||
for (String category: categories) {
|
||||
categoriesArray.put(category);
|
||||
}
|
||||
try {
|
||||
|
|
@ -34,7 +34,7 @@ public class CategoryModifier extends PageModifier {
|
|||
categories = params.optJSONArray(PARAM_CATEGORIES);
|
||||
|
||||
StringBuilder categoriesString = new StringBuilder();
|
||||
for(int i=0; i < categories.length(); i++) {
|
||||
for (int i = 0; i < categories.length(); i++) {
|
||||
String category = categories.optString(i);
|
||||
categoriesString.append("\n[[Category:").append(category).append("]]");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import dagger.android.AndroidInjection;
|
|||
import fr.free.nrw.commons.data.DBOpenHelper;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class ModificationsContentProvider extends ContentProvider{
|
||||
public class ModificationsContentProvider extends ContentProvider {
|
||||
|
||||
private static final int MODIFICATIONS = 1;
|
||||
private static final int MODIFICATIONS_ID = 2;
|
||||
|
|
@ -51,7 +51,7 @@ public class ModificationsContentProvider extends ContentProvider{
|
|||
|
||||
int uriType = uriMatcher.match(uri);
|
||||
|
||||
switch(uriType) {
|
||||
switch (uriType) {
|
||||
case MODIFICATIONS:
|
||||
break;
|
||||
default:
|
||||
|
|
@ -112,7 +112,7 @@ public class ModificationsContentProvider extends ContentProvider{
|
|||
sqlDB.beginTransaction();
|
||||
switch (uriType) {
|
||||
case MODIFICATIONS:
|
||||
for(ContentValues value: values) {
|
||||
for (ContentValues value: values) {
|
||||
Timber.d("Inserting! %s", value);
|
||||
sqlDB.insert(ModifierSequence.Table.TABLE_NAME, null, value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ public class ModifierSequence {
|
|||
public ModifierSequence(Uri mediaUri, JSONObject data) {
|
||||
this(mediaUri);
|
||||
JSONArray modifiersJSON = data.optJSONArray("modifiers");
|
||||
for (int i=0; i< modifiersJSON.length(); i++) {
|
||||
for (int i = 0; i < modifiersJSON.length(); i++) {
|
||||
modifiers.add(PageModifier.fromJSON(modifiersJSON.optJSONObject(i)));
|
||||
}
|
||||
}
|
||||
|
|
@ -49,7 +49,7 @@ public class ModifierSequence {
|
|||
|
||||
public String getEditSummary() {
|
||||
StringBuilder editSummary = new StringBuilder();
|
||||
for(PageModifier modifier: modifiers) {
|
||||
for (PageModifier modifier: modifiers) {
|
||||
editSummary.append(modifier.getEditSumary()).append(" ");
|
||||
}
|
||||
editSummary.append("Via Commons Mobile App");
|
||||
|
|
@ -93,12 +93,12 @@ public class ModifierSequence {
|
|||
|
||||
public void save() {
|
||||
try {
|
||||
if(contentUri == null) {
|
||||
if (contentUri == null) {
|
||||
contentUri = client.insert(ModificationsContentProvider.BASE_URI, this.toContentValues());
|
||||
} else {
|
||||
client.update(contentUri, toContentValues(), null, null);
|
||||
}
|
||||
} catch(RemoteException e) {
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ public abstract class PageModifier {
|
|||
|
||||
public static PageModifier fromJSON(JSONObject data) {
|
||||
String name = data.optString("name");
|
||||
if(name.equals(CategoryModifier.MODIFIER_NAME)) {
|
||||
if (name.equals(CategoryModifier.MODIFIER_NAME)) {
|
||||
return new CategoryModifier(data.optJSONObject("data"));
|
||||
} else if(name.equals(TemplateRemoveModifier.MODIFIER_NAME)) {
|
||||
} else if (name.equals(TemplateRemoveModifier.MODIFIER_NAME)) {
|
||||
return new TemplateRemoveModifier(data.optJSONObject("data"));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,18 +41,18 @@ public class TemplateRemoveModifier extends PageModifier {
|
|||
Pattern templateStartPattern = Pattern.compile("\\{\\{" + templateNormalized, Pattern.CASE_INSENSITIVE);
|
||||
Matcher matcher = templateStartPattern.matcher(pageContents);
|
||||
|
||||
while(matcher.find()) {
|
||||
while (matcher.find()) {
|
||||
int braceCount = 1;
|
||||
int startIndex = matcher.start();
|
||||
int curIndex = matcher.end();
|
||||
Matcher openMatch = PATTERN_TEMPLATE_OPEN.matcher(pageContents);
|
||||
Matcher closeMatch = PATTERN_TEMPLATE_CLOSE.matcher(pageContents);
|
||||
|
||||
while(curIndex < pageContents.length()) {
|
||||
while (curIndex < pageContents.length()) {
|
||||
boolean openFound = openMatch.find(curIndex);
|
||||
boolean closeFound = closeMatch.find(curIndex);
|
||||
|
||||
if(openFound && (!closeFound || openMatch.start() < closeMatch.start())) {
|
||||
if (openFound && (!closeFound || openMatch.start() < closeMatch.start())) {
|
||||
braceCount++;
|
||||
curIndex = openMatch.end();
|
||||
} else if (closeFound) {
|
||||
|
|
@ -71,8 +71,8 @@ public class TemplateRemoveModifier extends PageModifier {
|
|||
}
|
||||
|
||||
// Strip trailing whitespace
|
||||
while(curIndex < pageContents.length()) {
|
||||
if(pageContents.charAt(curIndex) == ' ' || pageContents.charAt(curIndex) == '\n') {
|
||||
while (curIndex < pageContents.length()) {
|
||||
if (pageContents.charAt(curIndex) == ' ' || pageContents.charAt(curIndex) == '\n') {
|
||||
curIndex++;
|
||||
} else {
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -388,10 +388,15 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
|
|||
|
||||
@Override
|
||||
@NonNull
|
||||
public UploadResult uploadFile(String filename, InputStream file, long dataLength, String pageContents, String editSummary, final ProgressListener progressListener) throws IOException {
|
||||
public UploadResult uploadFile(String filename,
|
||||
@NonNull InputStream file,
|
||||
long dataLength,
|
||||
String pageContents,
|
||||
String editSummary,
|
||||
final ProgressListener progressListener) throws IOException {
|
||||
ApiResult result = api.upload(filename, file, dataLength, pageContents, editSummary, progressListener::onProgress);
|
||||
|
||||
Log.e("WTF", "Result: " +result.toString());
|
||||
Log.e("WTF", "Result: " + result.toString());
|
||||
|
||||
String resultStatus = result.getString("/api/upload/@result");
|
||||
if (!resultStatus.equals("Success")) {
|
||||
|
|
|
|||
|
|
@ -5,9 +5,7 @@ import android.content.Context;
|
|||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.location.LocationManager;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
|
|
@ -30,34 +28,42 @@ import com.google.gson.GsonBuilder;
|
|||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.location.LatLng;
|
||||
import fr.free.nrw.commons.location.LocationServiceManager;
|
||||
import fr.free.nrw.commons.location.LocationUpdateListener;
|
||||
import fr.free.nrw.commons.theme.NavigationBaseActivity;
|
||||
import fr.free.nrw.commons.utils.UriSerializer;
|
||||
import fr.free.nrw.commons.utils.ViewUtil;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class NearbyActivity extends NavigationBaseActivity {
|
||||
|
||||
@BindView(R.id.progressBar)
|
||||
ProgressBar progressBar;
|
||||
@Inject NearbyPlaces nearbyPlaces;
|
||||
@Inject @Named("default_preferences") SharedPreferences prefs;
|
||||
public class NearbyActivity extends NavigationBaseActivity implements LocationUpdateListener {
|
||||
|
||||
private boolean isMapViewActive = false;
|
||||
private static final int LOCATION_REQUEST = 1;
|
||||
private static final String MAP_LAST_USED_PREFERENCE = "mapLastUsed";
|
||||
|
||||
private LocationServiceManager locationManager;
|
||||
@BindView(R.id.progressBar)
|
||||
ProgressBar progressBar;
|
||||
|
||||
@Inject
|
||||
LocationServiceManager locationManager;
|
||||
@Inject
|
||||
NearbyController nearbyController;
|
||||
|
||||
private LatLng curLatLang;
|
||||
private Bundle bundle;
|
||||
private NearbyAsyncTask nearbyAsyncTask;
|
||||
private SharedPreferences sharedPreferences;
|
||||
private NearbyActivityMode viewMode;
|
||||
private Disposable placesDisposable;
|
||||
private boolean lockNearbyView; //Determines if the nearby places needs to be refreshed
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
|
@ -97,7 +103,8 @@ public class NearbyActivity extends NavigationBaseActivity {
|
|||
// Handle item selection
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_refresh:
|
||||
refreshView();
|
||||
lockNearbyView = false;
|
||||
refreshView(true);
|
||||
return true;
|
||||
case R.id.action_toggle_view:
|
||||
viewMode = viewMode.toggle();
|
||||
|
|
@ -109,19 +116,11 @@ public class NearbyActivity extends NavigationBaseActivity {
|
|||
}
|
||||
}
|
||||
|
||||
private void startLookingForNearby() {
|
||||
locationManager = new LocationServiceManager(this);
|
||||
locationManager.registerLocationManager();
|
||||
curLatLang = locationManager.getLatestLocation();
|
||||
nearbyAsyncTask = new NearbyAsyncTask(this, new NearbyController(nearbyPlaces, prefs));
|
||||
nearbyAsyncTask.execute();
|
||||
}
|
||||
|
||||
private void checkLocationPermission() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (ContextCompat.checkSelfPermission(this,
|
||||
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
|
||||
startLookingForNearby();
|
||||
refreshView(false);
|
||||
} else {
|
||||
if (ContextCompat.checkSelfPermission(this,
|
||||
Manifest.permission.ACCESS_FINE_LOCATION)
|
||||
|
|
@ -162,7 +161,7 @@ public class NearbyActivity extends NavigationBaseActivity {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
startLookingForNearby();
|
||||
refreshView(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -171,16 +170,10 @@ public class NearbyActivity extends NavigationBaseActivity {
|
|||
switch (requestCode) {
|
||||
case LOCATION_REQUEST: {
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
startLookingForNearby();
|
||||
refreshView(false);
|
||||
} else {
|
||||
//If permission not granted, go to page that says Nearby Places cannot be displayed
|
||||
if (nearbyAsyncTask != null) {
|
||||
nearbyAsyncTask.cancel(true);
|
||||
}
|
||||
if (progressBar != null) {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
hideProgressBar();
|
||||
showLocationPermissionDeniedErrorDialog();
|
||||
}
|
||||
}
|
||||
|
|
@ -205,8 +198,7 @@ public class NearbyActivity extends NavigationBaseActivity {
|
|||
}
|
||||
|
||||
private void checkGps() {
|
||||
LocationManager manager = (LocationManager) getSystemService(LOCATION_SERVICE);
|
||||
if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
|
||||
if (!locationManager.isProviderEnabled()) {
|
||||
Timber.d("GPS is not enabled");
|
||||
new AlertDialog.Builder(this)
|
||||
.setMessage(R.string.gps_disabled)
|
||||
|
|
@ -231,104 +223,106 @@ public class NearbyActivity extends NavigationBaseActivity {
|
|||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (requestCode == 1) {
|
||||
Timber.d("User is back from Settings page");
|
||||
refreshView();
|
||||
refreshView(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void toggleView() {
|
||||
if (nearbyAsyncTask != null) {
|
||||
if (nearbyAsyncTask.getStatus() == AsyncTask.Status.FINISHED) {
|
||||
if (viewMode.isMap()) {
|
||||
setMapFragment();
|
||||
} else {
|
||||
setListFragment();
|
||||
}
|
||||
}
|
||||
sharedPreferences.edit().putBoolean(MAP_LAST_USED_PREFERENCE, viewMode.isMap()).apply();
|
||||
if (viewMode.isMap()) {
|
||||
setMapFragment();
|
||||
} else {
|
||||
setListFragment();
|
||||
}
|
||||
sharedPreferences.edit().putBoolean(MAP_LAST_USED_PREFERENCE, viewMode.isMap()).apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
locationManager.registerLocationManager();
|
||||
locationManager.addLocationListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
locationManager.removeLocationListener(this);
|
||||
locationManager.unregisterLocationManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (placesDisposable != null) {
|
||||
placesDisposable.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
lockNearbyView = false;
|
||||
checkGps();
|
||||
refreshView(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
if (nearbyAsyncTask != null) {
|
||||
nearbyAsyncTask.cancel(true);
|
||||
private void refreshView(boolean isHardRefresh) {
|
||||
if (lockNearbyView) {
|
||||
return;
|
||||
}
|
||||
LatLng lastLocation = locationManager.getLastLocation();
|
||||
if (curLatLang != null && curLatLang.equals(lastLocation)) { //refresh view only if location has changed
|
||||
if (isHardRefresh) {
|
||||
ViewUtil.showLongToast(this, R.string.nearby_location_has_not_changed);
|
||||
}
|
||||
return;
|
||||
}
|
||||
curLatLang = lastLocation;
|
||||
|
||||
if (curLatLang == null) {
|
||||
Timber.d("Skipping update of nearby places as location is unavailable");
|
||||
return;
|
||||
}
|
||||
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
placesDisposable = Observable.fromCallable(() -> nearbyController
|
||||
.loadAttractionsFromLocation(curLatLang, this))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(this::populatePlaces);
|
||||
}
|
||||
|
||||
private void refreshView() {
|
||||
nearbyAsyncTask = new NearbyAsyncTask(this, new NearbyController(nearbyPlaces, prefs));
|
||||
nearbyAsyncTask.execute();
|
||||
private void populatePlaces(List<Place> placeList) {
|
||||
Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapter(Uri.class, new UriSerializer())
|
||||
.create();
|
||||
String gsonPlaceList = gson.toJson(placeList);
|
||||
String gsonCurLatLng = gson.toJson(curLatLang);
|
||||
|
||||
if (placeList.size() == 0) {
|
||||
int duration = Toast.LENGTH_SHORT;
|
||||
Toast toast = Toast.makeText(this, R.string.no_nearby, duration);
|
||||
toast.show();
|
||||
}
|
||||
|
||||
bundle.clear();
|
||||
bundle.putString("PlaceList", gsonPlaceList);
|
||||
bundle.putString("CurLatLng", gsonCurLatLng);
|
||||
|
||||
lockNearbyView = true;
|
||||
// Begin the transaction
|
||||
if (viewMode.isMap()) {
|
||||
setMapFragment();
|
||||
} else {
|
||||
setListFragment();
|
||||
}
|
||||
|
||||
hideProgressBar();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (locationManager != null) {
|
||||
locationManager.unregisterLocationManager();
|
||||
}
|
||||
}
|
||||
|
||||
private class NearbyAsyncTask extends AsyncTask<Void, Integer, List<Place>> {
|
||||
|
||||
private final Context mContext;
|
||||
private final NearbyController nearbyController;
|
||||
|
||||
private NearbyAsyncTask(Context context, NearbyController nearbyController) {
|
||||
this.mContext = context;
|
||||
this.nearbyController = nearbyController;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(Integer... values) {
|
||||
super.onProgressUpdate(values);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Place> doInBackground(Void... params) {
|
||||
return nearbyController.loadAttractionsFromLocation(curLatLang, NearbyActivity.this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(List<Place> placeList) {
|
||||
super.onPostExecute(placeList);
|
||||
|
||||
if (isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapter(Uri.class, new UriSerializer())
|
||||
.create();
|
||||
String gsonPlaceList = gson.toJson(placeList);
|
||||
String gsonCurLatLng = gson.toJson(curLatLang);
|
||||
|
||||
if (placeList.size() == 0) {
|
||||
int duration = Toast.LENGTH_SHORT;
|
||||
Toast toast = Toast.makeText(mContext, R.string.no_nearby, duration);
|
||||
toast.show();
|
||||
}
|
||||
|
||||
bundle.clear();
|
||||
bundle.putString("PlaceList", gsonPlaceList);
|
||||
bundle.putString("CurLatLng", gsonCurLatLng);
|
||||
|
||||
// Begin the transaction
|
||||
if (viewMode.isMap()) {
|
||||
setMapFragment();
|
||||
} else {
|
||||
setListFragment();
|
||||
}
|
||||
|
||||
if (progressBar != null) {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
}
|
||||
private void hideProgressBar() {
|
||||
if (progressBar != null) {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -354,8 +348,8 @@ public class NearbyActivity extends NavigationBaseActivity {
|
|||
fragmentTransaction.commitAllowingStateLoss();
|
||||
}
|
||||
|
||||
public static void startYourself(Context context) {
|
||||
Intent settingsIntent = new Intent(context, NearbyActivity.class);
|
||||
context.startActivity(settingsIntent);
|
||||
@Override
|
||||
public void onLocationChanged(LatLng latLng) {
|
||||
refreshView(false);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.location.LatLng;
|
||||
import fr.free.nrw.commons.utils.UiUtils;
|
||||
|
|
@ -22,13 +25,14 @@ import timber.log.Timber;
|
|||
import static fr.free.nrw.commons.utils.LengthUtils.computeDistanceBetween;
|
||||
import static fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween;
|
||||
|
||||
|
||||
public class NearbyController {
|
||||
private static final int MAX_RESULTS = 1000;
|
||||
private final NearbyPlaces nearbyPlaces;
|
||||
private final SharedPreferences prefs;
|
||||
|
||||
public NearbyController(NearbyPlaces nearbyPlaces, SharedPreferences prefs) {
|
||||
@Inject
|
||||
public NearbyController(NearbyPlaces nearbyPlaces,
|
||||
@Named("default_preferences") SharedPreferences prefs) {
|
||||
this.nearbyPlaces = nearbyPlaces;
|
||||
this.prefs = prefs;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ public class NearbyPlaces {
|
|||
|
||||
try {
|
||||
// increase the radius gradually to find a satisfactory number of nearby places
|
||||
while (radius < MAX_RADIUS) {
|
||||
while (radius <= MAX_RADIUS) {
|
||||
places = getFromWikidataQuery(curLatLng, lang, radius);
|
||||
Timber.d("%d results at radius: %f", places.size(), radius);
|
||||
if (places.size() >= MIN_RESULTS) {
|
||||
|
|
@ -62,6 +62,11 @@ public class NearbyPlaces {
|
|||
Timber.d("back to initial radius: %f", radius);
|
||||
radius = INITIAL_RADIUS;
|
||||
}
|
||||
// make sure we will be able to send at least one request next time
|
||||
if (radius > MAX_RADIUS) {
|
||||
radius = MAX_RADIUS;
|
||||
}
|
||||
|
||||
return places;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
package fr.free.nrw.commons.settings;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v7.app.AppCompatDelegate;
|
||||
|
|
@ -54,9 +52,4 @@ public class SettingsActivity extends NavigationBaseActivity {
|
|||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
public static void startYourself(Context context) {
|
||||
Intent settingsIntent = new Intent(context, SettingsActivity.class);
|
||||
context.startActivity(settingsIntent);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +1,41 @@
|
|||
package fr.free.nrw.commons.settings;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.preference.CheckBoxPreference;
|
||||
import android.preference.EditTextPreference;
|
||||
import android.preference.ListPreference;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceFragment;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.content.FileProvider;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import dagger.android.AndroidInjection;
|
||||
import fr.free.nrw.commons.BuildConfig;
|
||||
import fr.free.nrw.commons.CommonsApplication;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.Utils;
|
||||
import fr.free.nrw.commons.utils.FileUtils;
|
||||
|
||||
public class SettingsFragment extends PreferenceFragment {
|
||||
|
||||
private static final int REQUEST_CODE_WRITE_EXTERNAL_STORAGE = 100;
|
||||
|
||||
@Inject @Named("default_preferences") SharedPreferences prefs;
|
||||
|
||||
@Override
|
||||
|
|
@ -76,6 +94,63 @@ public class SettingsFragment extends PreferenceFragment {
|
|||
return true;
|
||||
});
|
||||
|
||||
Preference sendLogsPreference = findPreference("sendLogFile");
|
||||
sendLogsPreference.setOnPreferenceClickListener(preference -> {
|
||||
//first we need to check if we have the necessary permissions
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (ContextCompat.checkSelfPermission(
|
||||
getActivity(),
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
==
|
||||
PackageManager.PERMISSION_GRANTED) {
|
||||
sendAppLogsViaEmail();
|
||||
} else {
|
||||
//first get the necessary permission
|
||||
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
||||
REQUEST_CODE_WRITE_EXTERNAL_STORAGE);
|
||||
}
|
||||
} else {
|
||||
sendAppLogsViaEmail();
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
if (requestCode == REQUEST_CODE_WRITE_EXTERNAL_STORAGE) {
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
sendAppLogsViaEmail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendAppLogsViaEmail() {
|
||||
String appLogs = Utils.getAppLogs();
|
||||
File appLogsFile = FileUtils.createAndGetAppLogsFile(appLogs);
|
||||
|
||||
Context applicationContext = getActivity().getApplicationContext();
|
||||
Uri appLogsFilePath = FileProvider.getUriForFile(
|
||||
getActivity(),
|
||||
applicationContext.getPackageName() + ".provider",
|
||||
appLogsFile
|
||||
);
|
||||
|
||||
Intent feedbackIntent = new Intent(Intent.ACTION_SEND);
|
||||
feedbackIntent.setType("message/rfc822");
|
||||
feedbackIntent.putExtra(Intent.EXTRA_EMAIL,
|
||||
new String[]{CommonsApplication.FEEDBACK_EMAIL});
|
||||
feedbackIntent.putExtra(Intent.EXTRA_SUBJECT,
|
||||
String.format(CommonsApplication.FEEDBACK_EMAIL_SUBJECT,
|
||||
BuildConfig.VERSION_NAME));
|
||||
feedbackIntent.putExtra(Intent.EXTRA_STREAM,appLogsFilePath);
|
||||
|
||||
try {
|
||||
startActivity(feedbackIntent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Toast.makeText(getActivity(), R.string.no_email_client, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ public abstract class BaseActivity extends DaggerAppCompatActivity {
|
|||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
boolean currentThemeIsDark = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("theme", false);
|
||||
if (currentThemeIsDark) {
|
||||
if (currentThemeIsDark){
|
||||
currentTheme = true;
|
||||
setTheme(R.style.DarkAppTheme);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
package fr.free.nrw.commons.theme;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.NavigationView;
|
||||
|
|
@ -9,7 +12,9 @@ import android.support.v7.app.ActionBarDrawerToggle;
|
|||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import butterknife.BindView;
|
||||
|
|
@ -18,6 +23,7 @@ import fr.free.nrw.commons.BuildConfig;
|
|||
import fr.free.nrw.commons.CommonsApplication;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.WelcomeActivity;
|
||||
import fr.free.nrw.commons.auth.AccountUtil;
|
||||
import fr.free.nrw.commons.auth.LoginActivity;
|
||||
import fr.free.nrw.commons.contributions.ContributionsActivity;
|
||||
import fr.free.nrw.commons.nearby.NearbyActivity;
|
||||
|
|
@ -47,6 +53,22 @@ public abstract class NavigationBaseActivity extends BaseActivity
|
|||
toggle.setDrawerIndicatorEnabled(true);
|
||||
toggle.syncState();
|
||||
setDrawerPaneWidth();
|
||||
setUserName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the username in navigationHeader.
|
||||
*/
|
||||
private void setUserName() {
|
||||
|
||||
View navHeaderView = navigationView.getHeaderView(0);
|
||||
TextView username = navHeaderView.findViewById(R.id.username);
|
||||
|
||||
AccountManager accountManager = AccountManager.get(this);
|
||||
Account[] allAccounts = accountManager.getAccountsByType(AccountUtil.ACCOUNT_TYPE);
|
||||
if (allAccounts.length != 0) {
|
||||
username.setText(allAccounts[0].name);
|
||||
}
|
||||
}
|
||||
|
||||
public void initBackButton() {
|
||||
|
|
@ -70,30 +92,25 @@ public abstract class NavigationBaseActivity extends BaseActivity
|
|||
|
||||
@Override
|
||||
public boolean onNavigationItemSelected(@NonNull final MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
final int itemId = item.getItemId();
|
||||
switch (itemId) {
|
||||
case R.id.action_home:
|
||||
drawerLayout.closeDrawer(navigationView);
|
||||
if (!(this instanceof ContributionsActivity)) {
|
||||
ContributionsActivity.startYourself(this);
|
||||
}
|
||||
startActivityWithFlags(
|
||||
this, ContributionsActivity.class, Intent.FLAG_ACTIVITY_CLEAR_TOP,
|
||||
Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
return true;
|
||||
case R.id.action_nearby:
|
||||
drawerLayout.closeDrawer(navigationView);
|
||||
if (!(this instanceof NearbyActivity)) {
|
||||
NearbyActivity.startYourself(this);
|
||||
}
|
||||
startActivityWithFlags(this, NearbyActivity.class, Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||
return true;
|
||||
case R.id.action_about:
|
||||
drawerLayout.closeDrawer(navigationView);
|
||||
if (!(this instanceof AboutActivity)) {
|
||||
AboutActivity.startYourself(this);
|
||||
}
|
||||
startActivityWithFlags(this, AboutActivity.class, Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||
return true;
|
||||
case R.id.action_settings:
|
||||
drawerLayout.closeDrawer(navigationView);
|
||||
if (!(this instanceof SettingsActivity)) {
|
||||
SettingsActivity.startYourself(this);
|
||||
}
|
||||
startActivityWithFlags(this, SettingsActivity.class, Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||
return true;
|
||||
case R.id.action_introduction:
|
||||
drawerLayout.closeDrawer(navigationView);
|
||||
|
|
@ -127,6 +144,7 @@ public abstract class NavigationBaseActivity extends BaseActivity
|
|||
.show();
|
||||
return true;
|
||||
default:
|
||||
Timber.e("Unknown option [%s] selected from the navigation menu", itemId);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -143,4 +161,12 @@ public abstract class NavigationBaseActivity extends BaseActivity
|
|||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> void startActivityWithFlags(Context context, Class<T> cls, int... flags) {
|
||||
Intent intent = new Intent(context, cls);
|
||||
for (int flag: flags) {
|
||||
intent.addFlags(flag);
|
||||
}
|
||||
context.startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,8 +123,9 @@ public class FileUtils {
|
|||
} catch (IllegalArgumentException e) {
|
||||
Timber.d(e);
|
||||
} finally {
|
||||
if (cursor != null)
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ public class GPSExtractor {
|
|||
return decimalCoords;
|
||||
}
|
||||
|
||||
private double convertToDegree(String stringDMS){
|
||||
private double convertToDegree(String stringDMS) {
|
||||
double result;
|
||||
String[] DMS = stringDMS.split(",", 3);
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ public class MwVolleyApi {
|
|||
* @param coords Coordinates to build query with
|
||||
* @return URL for API query
|
||||
*/
|
||||
private String buildUrl (String coords){
|
||||
private String buildUrl(String coords) {
|
||||
|
||||
Uri.Builder builder = Uri.parse(MWURL).buildUpon();
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ public class UploadController {
|
|||
}
|
||||
|
||||
public void cleanup() {
|
||||
if(isUploadServiceConnected) {
|
||||
if (isUploadServiceConnected) {
|
||||
context.unbindService(uploadServiceConnection);
|
||||
}
|
||||
}
|
||||
|
|
@ -87,11 +87,11 @@ public class UploadController {
|
|||
|
||||
public void startUpload(final Contribution contribution, final ContributionUploadProgress onComplete) {
|
||||
//Set creator, desc, and license
|
||||
if(TextUtils.isEmpty(contribution.getCreator())) {
|
||||
if (TextUtils.isEmpty(contribution.getCreator())) {
|
||||
contribution.setCreator(sessionManager.getCurrentAccount().name);
|
||||
}
|
||||
|
||||
if(contribution.getDescription() == null) {
|
||||
if (contribution.getDescription() == null) {
|
||||
contribution.setDescription("");
|
||||
}
|
||||
|
||||
|
|
@ -109,11 +109,11 @@ public class UploadController {
|
|||
long length;
|
||||
ContentResolver contentResolver = context.getContentResolver();
|
||||
try {
|
||||
if(contribution.getDataLength() <= 0) {
|
||||
if (contribution.getDataLength() <= 0) {
|
||||
length = contentResolver
|
||||
.openAssetFileDescriptor(contribution.getLocalUri(), "r")
|
||||
.getLength();
|
||||
if(length == -1) {
|
||||
if (length == -1) {
|
||||
// Let us find out the long way!
|
||||
length = countBytes(contentResolver
|
||||
.openInputStream(contribution.getLocalUri()));
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ public class UploadService extends HandlerService<Contribution> {
|
|||
|
||||
@SuppressLint("StringFormatInvalid")
|
||||
private void uploadContribution(Contribution contribution) {
|
||||
InputStream file = null;
|
||||
InputStream file;
|
||||
|
||||
String notificationTag = contribution.getLocalUri().toString();
|
||||
|
||||
|
|
@ -196,6 +196,14 @@ public class UploadService extends HandlerService<Contribution> {
|
|||
Timber.d("File not found");
|
||||
Toast fileNotFound = Toast.makeText(this, R.string.upload_failed, Toast.LENGTH_LONG);
|
||||
fileNotFound.show();
|
||||
return;
|
||||
}
|
||||
|
||||
//As the file is null there's no point in continuing the upload process
|
||||
//mwapi.upload accepts a NonNull input stream
|
||||
if(file == null) {
|
||||
Timber.d("File not found");
|
||||
return;
|
||||
}
|
||||
|
||||
Timber.d("Before execution!");
|
||||
|
|
|
|||
|
|
@ -15,6 +15,6 @@ public class ExecutorUtils {
|
|||
}
|
||||
};
|
||||
|
||||
public static Executor uiExecutor () { return uiExecutor;}
|
||||
public static Executor uiExecutor() { return uiExecutor; }
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,16 @@
|
|||
package fr.free.nrw.commons.utils;
|
||||
|
||||
import android.os.Environment;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
|
||||
import fr.free.nrw.commons.CommonsApplication;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class FileUtils {
|
||||
/**
|
||||
|
|
@ -53,5 +58,32 @@ public class FileUtils {
|
|||
return deletedAll;
|
||||
}
|
||||
|
||||
public static File createAndGetAppLogsFile(String logs) {
|
||||
try {
|
||||
File commonsAppDirectory = new File(Environment.getExternalStorageDirectory().toString() + "/CommonsApp");
|
||||
if (!commonsAppDirectory.exists()) {
|
||||
commonsAppDirectory.mkdir();
|
||||
}
|
||||
|
||||
File logsFile = new File(commonsAppDirectory,"logs.txt");
|
||||
if (logsFile.exists()) {
|
||||
//old logs file is useless
|
||||
logsFile.delete();
|
||||
}
|
||||
|
||||
logsFile.createNewFile();
|
||||
|
||||
FileOutputStream outputStream = new FileOutputStream(logsFile);
|
||||
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
|
||||
outputStreamWriter.append(logs);
|
||||
outputStreamWriter.close();
|
||||
outputStream.flush();
|
||||
outputStream.close();
|
||||
|
||||
return logsFile;
|
||||
} catch (IOException ioe) {
|
||||
Timber.e(ioe);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ public class FragmentUtils {
|
|||
.commitNow();
|
||||
return true;
|
||||
} catch (IllegalStateException e) {
|
||||
Timber.e(e, "Could not add & commit fragment. " +
|
||||
"Did you mean to call commitAllowingStateLoss?");
|
||||
Timber.e(e, "Could not add & commit fragment. "
|
||||
+ "Did you mean to call commitAllowingStateLoss?");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
17
app/src/main/java/fr/free/nrw/commons/utils/ViewUtil.java
Normal file
17
app/src/main/java/fr/free/nrw/commons/utils/ViewUtil.java
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
package fr.free.nrw.commons.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class ViewUtil {
|
||||
|
||||
public static void showLongToast(final Context context, @StringRes final int stringResId) {
|
||||
ExecutorUtils.uiExecutor().execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(context, context.getString(stringResId), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue