mirror of
				https://github.com/commons-app/apps-android-commons.git
				synced 2025-10-30 22:34:02 +01:00 
			
		
		
		
	Merge branch 'master' into dependency-injection
This commit is contained in:
		
						commit
						e33febf506
					
				
					 36 changed files with 706 additions and 446 deletions
				
			
		|  | @ -127,7 +127,7 @@ public class Contribution extends Media { | |||
|     } | ||||
| 
 | ||||
|     public String getPageContents() { | ||||
|         StringBuffer buffer = new StringBuffer(); | ||||
|         StringBuilder buffer = new StringBuilder(); | ||||
|         SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH); | ||||
| 
 | ||||
|         buffer | ||||
|  |  | |||
|  | @ -1,30 +1,39 @@ | |||
| package fr.free.nrw.commons.contributions; | ||||
| 
 | ||||
| import android.app.Activity; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.pm.PackageManager; | ||||
| import android.content.pm.ResolveInfo; | ||||
| import android.net.Uri; | ||||
| import android.os.Bundle; | ||||
| import android.provider.MediaStore; | ||||
| import android.support.v4.app.Fragment; | ||||
| import android.support.v4.app.FragmentActivity; | ||||
| import android.support.v4.content.FileProvider; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.util.Date; | ||||
| import java.util.List; | ||||
| 
 | ||||
| import fr.free.nrw.commons.upload.ShareActivity; | ||||
| import fr.free.nrw.commons.upload.UploadService; | ||||
| import timber.log.Timber; | ||||
| 
 | ||||
| public class ContributionController { | ||||
| import static android.content.Intent.ACTION_GET_CONTENT; | ||||
| import static android.content.Intent.ACTION_SEND; | ||||
| import static android.content.Intent.EXTRA_STREAM; | ||||
| import static fr.free.nrw.commons.contributions.Contribution.SOURCE_CAMERA; | ||||
| import static fr.free.nrw.commons.contributions.Contribution.SOURCE_GALLERY; | ||||
| import static fr.free.nrw.commons.upload.UploadService.EXTRA_SOURCE; | ||||
| 
 | ||||
| class ContributionController { | ||||
| 
 | ||||
|     private static final int SELECT_FROM_GALLERY = 1; | ||||
|     private static final int SELECT_FROM_CAMERA = 2; | ||||
| 
 | ||||
|     private Fragment fragment; | ||||
|     private Activity activity; | ||||
| 
 | ||||
|     private final static int SELECT_FROM_GALLERY = 1; | ||||
|     private final static int SELECT_FROM_CAMERA = 2; | ||||
| 
 | ||||
|     public ContributionController(Fragment fragment) { | ||||
|     ContributionController(Fragment fragment) { | ||||
|         this.fragment = fragment; | ||||
|         this.activity = fragment.getActivity(); | ||||
|     } | ||||
| 
 | ||||
|     // See http://stackoverflow.com/a/5054673/17865 for why this is done | ||||
|  | @ -34,43 +43,59 @@ public class ContributionController { | |||
|         File photoFile = new File(fragment.getContext().getCacheDir() + "/images", | ||||
|                 new Date().getTime() + ".jpg"); | ||||
|         photoFile.getParentFile().mkdirs(); | ||||
|         Context applicationContext = fragment.getActivity().getApplicationContext(); | ||||
|         return FileProvider.getUriForFile( | ||||
|                 fragment.getContext(), | ||||
|                 fragment.getActivity().getApplicationContext().getPackageName() + ".provider", | ||||
|                 applicationContext.getPackageName() + ".provider", | ||||
|                 photoFile); | ||||
|     } | ||||
| 
 | ||||
|     public void startCameraCapture() { | ||||
|     private static void requestWritePermission(Context context, Intent intent, Uri uri) { | ||||
| 
 | ||||
|         List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(intent, | ||||
|                 PackageManager.MATCH_DEFAULT_ONLY); | ||||
|         for (ResolveInfo resolveInfo : resInfoList) { | ||||
|             String packageName = resolveInfo.activityInfo.packageName; | ||||
|             context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | ||||
|                     | Intent.FLAG_GRANT_READ_URI_PERMISSION); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void startCameraCapture() { | ||||
| 
 | ||||
|         Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); | ||||
|         lastGeneratedCaptureUri = reGenerateImageCaptureUriInCache(); | ||||
|         takePictureIntent.setFlags( | ||||
|                 Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); | ||||
| 
 | ||||
|         // Intent.setFlags doesn't work for API level <20 | ||||
|         requestWritePermission(fragment.getContext(), takePictureIntent, lastGeneratedCaptureUri); | ||||
| 
 | ||||
|         takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, lastGeneratedCaptureUri); | ||||
|         fragment.startActivityForResult(takePictureIntent, SELECT_FROM_CAMERA); | ||||
|     } | ||||
| 
 | ||||
|     public void startGalleryPick() { | ||||
|         //FIXME: Starts gallery (opens Google Photos) | ||||
|         Intent pickImageIntent = new Intent(Intent.ACTION_GET_CONTENT); | ||||
|         Intent pickImageIntent = new Intent(ACTION_GET_CONTENT); | ||||
|         pickImageIntent.setType("image/*"); | ||||
|         fragment.startActivityForResult(pickImageIntent, SELECT_FROM_GALLERY); | ||||
|     } | ||||
| 
 | ||||
|     public void handleImagePicked(int requestCode, Intent data) { | ||||
|     void handleImagePicked(int requestCode, Intent data) { | ||||
|         FragmentActivity activity = fragment.getActivity(); | ||||
|         Intent shareIntent = new Intent(activity, ShareActivity.class); | ||||
|         shareIntent.setAction(Intent.ACTION_SEND); | ||||
|         switch(requestCode) { | ||||
|         shareIntent.setAction(ACTION_SEND); | ||||
|         switch (requestCode) { | ||||
|             case SELECT_FROM_GALLERY: | ||||
|                 //Handles image picked from gallery | ||||
|                 Uri imageData = data.getData(); | ||||
|                 shareIntent.setType(activity.getContentResolver().getType(imageData)); | ||||
|                 shareIntent.putExtra(Intent.EXTRA_STREAM, imageData); | ||||
|                 shareIntent.putExtra(UploadService.EXTRA_SOURCE, Contribution.SOURCE_GALLERY); | ||||
|                 shareIntent.putExtra(EXTRA_STREAM, imageData); | ||||
|                 shareIntent.putExtra(EXTRA_SOURCE, SOURCE_GALLERY); | ||||
|                 break; | ||||
|             case SELECT_FROM_CAMERA: | ||||
|                 shareIntent.setType("image/jpeg"); //FIXME: Find out appropriate mime type | ||||
|                 shareIntent.putExtra(Intent.EXTRA_STREAM, lastGeneratedCaptureUri); | ||||
|                 shareIntent.putExtra(UploadService.EXTRA_SOURCE, Contribution.SOURCE_CAMERA); | ||||
|                 shareIntent.putExtra(EXTRA_STREAM, lastGeneratedCaptureUri); | ||||
|                 shareIntent.putExtra(EXTRA_SOURCE, SOURCE_CAMERA); | ||||
|                 break; | ||||
|         } | ||||
|         Timber.i("Image selected"); | ||||
|  | @ -81,12 +106,14 @@ public class ContributionController { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void saveState(Bundle outState) { | ||||
|         outState.putParcelable("lastGeneratedCaptureURI", lastGeneratedCaptureUri); | ||||
|     void saveState(Bundle outState) { | ||||
|         if (outState != null) { | ||||
|             outState.putParcelable("lastGeneratedCaptureURI", lastGeneratedCaptureUri); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void loadState(Bundle savedInstanceState) { | ||||
|         if(savedInstanceState != null) { | ||||
|     void loadState(Bundle savedInstanceState) { | ||||
|         if (savedInstanceState != null) { | ||||
|             lastGeneratedCaptureUri = savedInstanceState.getParcelable("lastGeneratedCaptureURI"); | ||||
|         } | ||||
|     } | ||||
|  |  | |||
|  | @ -1,7 +1,6 @@ | |||
| package fr.free.nrw.commons.contributions; | ||||
| 
 | ||||
| import android.content.ComponentName; | ||||
| import android.content.ContentResolver; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.ServiceConnection; | ||||
|  | @ -41,12 +40,18 @@ import io.reactivex.disposables.CompositeDisposable; | |||
| import io.reactivex.schedulers.Schedulers; | ||||
| import timber.log.Timber; | ||||
| 
 | ||||
| public class ContributionsActivity extends AuthenticatedActivity | ||||
|         implements LoaderManager.LoaderCallbacks<Cursor>, | ||||
|         AdapterView.OnItemClickListener, | ||||
|         MediaDetailPagerFragment.MediaDetailProvider, | ||||
|         FragmentManager.OnBackStackChangedListener, | ||||
|         ContributionsListFragment.SourceRefresher { | ||||
| import static android.content.ContentResolver.requestSync; | ||||
| import static fr.free.nrw.commons.contributions.Contribution.STATE_FAILED; | ||||
| import static fr.free.nrw.commons.contributions.Contribution.Table.ALL_FIELDS; | ||||
| import static fr.free.nrw.commons.contributions.ContributionsContentProvider.AUTHORITY; | ||||
| import static fr.free.nrw.commons.contributions.ContributionsContentProvider.BASE_URI; | ||||
| import static fr.free.nrw.commons.settings.Prefs.UPLOADS_SHOWING;public  class       ContributionsActivity | ||||
|         extends     AuthenticatedActivity | ||||
|         implements  LoaderManager.LoaderCallbacks<Cursor>, | ||||
|                     AdapterView.OnItemClickListener, | ||||
|                     MediaDetailPagerFragment.MediaDetailProvider, | ||||
|                     FragmentManager.OnBackStackChangedListener, | ||||
|                     ContributionsListFragment.SourceRefresher { | ||||
| 
 | ||||
|     @Inject MediaWikiApi mediaWikiApi; | ||||
|     @Inject SessionManager sessionManager; | ||||
|  | @ -68,14 +73,18 @@ public class ContributionsActivity extends AuthenticatedActivity | |||
| 
 | ||||
|         This is why Contribution.STATE_COMPLETED is -1. | ||||
|      */ | ||||
|     private String CONTRIBUTION_SORT = Contribution.Table.COLUMN_STATE + " DESC, " + Contribution.Table.COLUMN_UPLOADED + " DESC , (" + Contribution.Table.COLUMN_TIMESTAMP + " * " + Contribution.Table.COLUMN_STATE + ")"; | ||||
|     private String CONTRIBUTION_SORT = Contribution.Table.COLUMN_STATE + " DESC, " | ||||
|             + Contribution.Table.COLUMN_UPLOADED + " DESC , (" | ||||
|             + Contribution.Table.COLUMN_TIMESTAMP + " * " | ||||
|             + Contribution.Table.COLUMN_STATE + ")"; | ||||
| 
 | ||||
|     private CompositeDisposable compositeDisposable = new CompositeDisposable(); | ||||
| 
 | ||||
|     private ServiceConnection uploadServiceConnection = new ServiceConnection() { | ||||
|         @Override | ||||
|         public void onServiceConnected(ComponentName componentName, IBinder binder) { | ||||
|             uploadService = (UploadService) ((HandlerService.HandlerServiceLocalBinder) binder).getService(); | ||||
|             uploadService = (UploadService) ((HandlerService.HandlerServiceLocalBinder) binder) | ||||
|                     .getService(); | ||||
|             isUploadServiceConnected = true; | ||||
|         } | ||||
| 
 | ||||
|  | @ -113,13 +122,14 @@ public class ContributionsActivity extends AuthenticatedActivity | |||
|     @Override | ||||
|     protected void onAuthCookieAcquired(String authCookie) { | ||||
|         // Do a sync everytime we get here! | ||||
|         ContentResolver.requestSync(sessionManager.getCurrentAccount(), ContributionsContentProvider.AUTHORITY, new Bundle()); | ||||
|         requestSync(sessionManager.getCurrentAccount(), ContributionsContentProvider.AUTHORITY, new Bundle()); | ||||
|         Intent uploadServiceIntent = new Intent(this, UploadService.class); | ||||
|         uploadServiceIntent.setAction(UploadService.ACTION_START_SERVICE); | ||||
|         startService(uploadServiceIntent); | ||||
|         bindService(uploadServiceIntent, uploadServiceConnection, Context.BIND_AUTO_CREATE); | ||||
| 
 | ||||
|         allContributions = getContentResolver().query(ContributionsContentProvider.BASE_URI, Contribution.Table.ALL_FIELDS, CONTRIBUTION_SELECTION, null, CONTRIBUTION_SORT); | ||||
|         allContributions = getContentResolver().query(BASE_URI, ALL_FIELDS, | ||||
|                 CONTRIBUTION_SELECTION, null, CONTRIBUTION_SORT); | ||||
| 
 | ||||
|         getSupportLoaderManager().initLoader(0, null, this); | ||||
|     } | ||||
|  | @ -132,12 +142,13 @@ public class ContributionsActivity extends AuthenticatedActivity | |||
| 
 | ||||
|         // Activity can call methods in the fragment by acquiring a | ||||
|         // reference to the Fragment from FragmentManager, using findFragmentById() | ||||
|         contributionsList = (ContributionsListFragment) getSupportFragmentManager() | ||||
|         FragmentManager supportFragmentManager = getSupportFragmentManager(); | ||||
|         contributionsList = (ContributionsListFragment)supportFragmentManager | ||||
|                 .findFragmentById(R.id.contributionsListFragment); | ||||
| 
 | ||||
|         getSupportFragmentManager().addOnBackStackChangedListener(this); | ||||
|         supportFragmentManager.addOnBackStackChangedListener(this); | ||||
|         if (savedInstanceState != null) { | ||||
|             mediaDetails = (MediaDetailPagerFragment) getSupportFragmentManager() | ||||
|             mediaDetails = (MediaDetailPagerFragment)supportFragmentManager | ||||
|                     .findFragmentById(R.id.contributionsFragmentContainer); | ||||
|         } | ||||
|         requestAuthToken(); | ||||
|  | @ -148,23 +159,25 @@ public class ContributionsActivity extends AuthenticatedActivity | |||
|     @Override | ||||
|     protected void onSaveInstanceState(Bundle outState) { | ||||
|         super.onSaveInstanceState(outState); | ||||
|         outState.putBoolean("mediaDetailsVisible", (mediaDetails != null && mediaDetails.isVisible())); | ||||
|         boolean mediaDetailsVisible = mediaDetails != null && mediaDetails.isVisible(); | ||||
|         outState.putBoolean("mediaDetailsVisible", mediaDetailsVisible); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Replace whatever is in the current contributionsFragmentContainer view with mediaDetailPagerFragment, | ||||
|      * /   and preserve previous state in back stack. | ||||
|      * /   Called when user selects a contribution. | ||||
|      * Replace whatever is in the current contributionsFragmentContainer view with | ||||
|      * mediaDetailPagerFragment, and preserve previous state in back stack. | ||||
|      * Called when user selects a contribution. | ||||
|      */ | ||||
|     private void showDetail(int i) { | ||||
|         if (mediaDetails == null || !mediaDetails.isVisible()) { | ||||
|             mediaDetails = new MediaDetailPagerFragment(); | ||||
|             this.getSupportFragmentManager() | ||||
|             FragmentManager supportFragmentManager = getSupportFragmentManager(); | ||||
|             supportFragmentManager | ||||
|                     .beginTransaction() | ||||
|                     .replace(R.id.contributionsFragmentContainer, mediaDetails) | ||||
|                     .addToBackStack(null) | ||||
|                     .commit(); | ||||
|             this.getSupportFragmentManager().executePendingTransactions(); | ||||
|             supportFragmentManager.executePendingTransactions(); | ||||
|         } | ||||
|         mediaDetails.showImage(i); | ||||
|     } | ||||
|  | @ -172,7 +185,7 @@ public class ContributionsActivity extends AuthenticatedActivity | |||
|     public void retryUpload(int i) { | ||||
|         allContributions.moveToPosition(i); | ||||
|         Contribution c = Contribution.fromCursor(allContributions); | ||||
|         if (c.getState() == Contribution.STATE_FAILED) { | ||||
|         if (c.getState() == STATE_FAILED) { | ||||
|             uploadService.queue(UploadService.ACTION_UPLOAD_FILE, c); | ||||
|             Timber.d("Restarting for %s", c.toContentValues()); | ||||
|         } else { | ||||
|  | @ -183,9 +196,9 @@ public class ContributionsActivity extends AuthenticatedActivity | |||
|     public void deleteUpload(int i) { | ||||
|         allContributions.moveToPosition(i); | ||||
|         Contribution c = Contribution.fromCursor(allContributions); | ||||
|         if (c.getState() == Contribution.STATE_FAILED) { | ||||
|         if (c.getState() == STATE_FAILED) { | ||||
|             Timber.d("Deleting failed contrib %s", c.toContentValues()); | ||||
|             c.setContentProviderClient(getContentResolver().acquireContentProviderClient(ContributionsContentProvider.AUTHORITY)); | ||||
|             c.setContentProviderClient(getContentResolver().acquireContentProviderClient(AUTHORITY)); | ||||
|             c.delete(); | ||||
|         } else { | ||||
|             Timber.d("Skipping deletion for non-failed contrib %s", c.toContentValues()); | ||||
|  | @ -222,19 +235,18 @@ public class ContributionsActivity extends AuthenticatedActivity | |||
| 
 | ||||
|     @Override | ||||
|     public Loader<Cursor> onCreateLoader(int i, Bundle bundle) { | ||||
|         SharedPreferences sharedPref = | ||||
|                 PreferenceManager.getDefaultSharedPreferences(this); | ||||
|         int uploads = sharedPref.getInt(Prefs.UPLOADS_SHOWING, 100); | ||||
|         return new CursorLoader(this, ContributionsContentProvider.BASE_URI, | ||||
|                 Contribution.Table.ALL_FIELDS, CONTRIBUTION_SELECTION, null, | ||||
|         SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); | ||||
|         int uploads = sharedPref.getInt(UPLOADS_SHOWING, 100); | ||||
|         return new CursorLoader(this, BASE_URI, | ||||
|                 ALL_FIELDS, CONTRIBUTION_SELECTION, null, | ||||
|                 CONTRIBUTION_SORT + "LIMIT " + uploads); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) { | ||||
|         if (contributionsList.getAdapter() == null) { | ||||
|             contributionsList | ||||
|                     .setAdapter(new ContributionsListAdapter(getApplicationContext(), cursor, 0)); | ||||
|             contributionsList.setAdapter(new ContributionsListAdapter(getApplicationContext(), | ||||
|                     cursor, 0)); | ||||
|         } else { | ||||
|             ((CursorAdapter) contributionsList.getAdapter()).swapCursor(cursor); | ||||
|         } | ||||
|  | @ -269,6 +281,7 @@ public class ContributionsActivity extends AuthenticatedActivity | |||
|         return contributionsList.getAdapter().getCount(); | ||||
|     } | ||||
| 
 | ||||
|     @SuppressWarnings("ConstantConditions") | ||||
|     private void setUploadCount() { | ||||
|         compositeDisposable.add( | ||||
|                 mediaWikiApi | ||||
|  | @ -276,12 +289,10 @@ public class ContributionsActivity extends AuthenticatedActivity | |||
|                         .subscribeOn(Schedulers.io()) | ||||
|                         .observeOn(AndroidSchedulers.mainThread()) | ||||
|                         .subscribe( | ||||
|                                 uploadCount -> | ||||
|                                         getSupportActionBar().setSubtitle(getResources() | ||||
|                                                 .getQuantityString(R.plurals.contributions_subtitle, | ||||
|                                                         uploadCount, | ||||
|                                                         uploadCount)), | ||||
|                                 throwable -> Timber.e(throwable, "Fetching upload count failed") | ||||
|                                 uploadCount -> getSupportActionBar().setSubtitle(getResources() | ||||
|                                         .getQuantityString(R.plurals.contributions_subtitle, | ||||
|                                                 uploadCount, uploadCount)), | ||||
|                                 t -> Timber.e(t, "Fetching upload count failed") | ||||
|                         ) | ||||
|         ); | ||||
|     } | ||||
|  | @ -337,8 +348,7 @@ public class ContributionsActivity extends AuthenticatedActivity | |||
|     } | ||||
| 
 | ||||
|     public static void startYourself(Context context) { | ||||
|         Intent contributionsIntent = new Intent(context, ContributionsActivity.class); | ||||
|         context.startActivity(contributionsIntent); | ||||
|         context.startActivity(new Intent(context, ContributionsActivity.class)); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -16,17 +16,20 @@ import dagger.android.AndroidInjection; | |||
| import fr.free.nrw.commons.data.DBOpenHelper; | ||||
| import timber.log.Timber; | ||||
| 
 | ||||
| public class ContributionsContentProvider extends ContentProvider{ | ||||
| import static android.content.UriMatcher.NO_MATCH; | ||||
| import static fr.free.nrw.commons.contributions.Contribution.Table.ALL_FIELDS; | ||||
| import static fr.free.nrw.commons.contributions.Contribution.Table.TABLE_NAME; | ||||
| 
 | ||||
| public class ContributionsContentProvider extends ContentProvider { | ||||
| 
 | ||||
|     private static final int CONTRIBUTIONS = 1; | ||||
|     private static final int CONTRIBUTIONS_ID = 2; | ||||
| 
 | ||||
|     public static final String AUTHORITY = "fr.free.nrw.commons.contributions.contentprovider"; | ||||
|     private static final String BASE_PATH = "contributions"; | ||||
|     private static final UriMatcher uriMatcher = new UriMatcher(NO_MATCH); | ||||
|     public static final String AUTHORITY = "fr.free.nrw.commons.contributions.contentprovider"; | ||||
| 
 | ||||
|     public static final Uri BASE_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH); | ||||
| 
 | ||||
|     private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); | ||||
|     static { | ||||
|         uriMatcher.addURI(AUTHORITY, BASE_PATH, CONTRIBUTIONS); | ||||
|         uriMatcher.addURI(AUTHORITY, BASE_PATH + "/#", CONTRIBUTIONS_ID); | ||||
|  | @ -44,25 +47,28 @@ public class ContributionsContentProvider extends ContentProvider{ | |||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     @SuppressWarnings("ConstantConditions") | ||||
|     @Override | ||||
|     public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { | ||||
|     public Cursor query(@NonNull Uri uri, String[] projection, String selection, | ||||
|                         String[] selectionArgs, String sortOrder) { | ||||
|         SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder(); | ||||
|         queryBuilder.setTables(Contribution.Table.TABLE_NAME); | ||||
|         queryBuilder.setTables(TABLE_NAME); | ||||
| 
 | ||||
|         int uriType = uriMatcher.match(uri); | ||||
| 
 | ||||
|         SQLiteDatabase db = dbOpenHelper.getReadableDatabase(); | ||||
|         Cursor cursor; | ||||
| 
 | ||||
|         switch(uriType) { | ||||
|         switch (uriType) { | ||||
|             case CONTRIBUTIONS: | ||||
|                 cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null, sortOrder); | ||||
|                 cursor = queryBuilder.query(db, projection, selection, selectionArgs, | ||||
|                         null, null, sortOrder); | ||||
|                 break; | ||||
|             case CONTRIBUTIONS_ID: | ||||
|                 cursor = queryBuilder.query(db, | ||||
|                         Contribution.Table.ALL_FIELDS, | ||||
|                         ALL_FIELDS, | ||||
|                         "_id = ?", | ||||
|                         new String[] { uri.getLastPathSegment() }, | ||||
|                         new String[]{uri.getLastPathSegment()}, | ||||
|                         null, | ||||
|                         null, | ||||
|                         sortOrder | ||||
|  | @ -82,6 +88,7 @@ public class ContributionsContentProvider extends ContentProvider{ | |||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     @SuppressWarnings("ConstantConditions") | ||||
|     @Override | ||||
|     public Uri insert(@NonNull Uri uri, ContentValues contentValues) { | ||||
|         int uriType = uriMatcher.match(uri); | ||||
|  | @ -89,7 +96,7 @@ public class ContributionsContentProvider extends ContentProvider{ | |||
|         long id = 0; | ||||
|         switch (uriType) { | ||||
|             case CONTRIBUTIONS: | ||||
|                 id = sqlDB.insert(Contribution.Table.TABLE_NAME, null, contentValues); | ||||
|                 id = sqlDB.insert(TABLE_NAME, null, contentValues); | ||||
|                 break; | ||||
|             default: | ||||
|                 throw new IllegalArgumentException("Unknown URI: " + uri); | ||||
|  | @ -98,19 +105,20 @@ public class ContributionsContentProvider extends ContentProvider{ | |||
|         return Uri.parse(BASE_URI + "/" + id); | ||||
|     } | ||||
| 
 | ||||
|     @SuppressWarnings("ConstantConditions") | ||||
|     @Override | ||||
|     public int delete(@NonNull Uri uri, String s, String[] strings) { | ||||
|         int rows = 0; | ||||
|         int rows; | ||||
|         int uriType = uriMatcher.match(uri); | ||||
| 
 | ||||
|         SQLiteDatabase db = dbOpenHelper.getReadableDatabase(); | ||||
| 
 | ||||
|         switch(uriType) { | ||||
|         switch (uriType) { | ||||
|             case CONTRIBUTIONS_ID: | ||||
|                 Timber.d("Deleting contribution id %s", uri.getLastPathSegment()); | ||||
|                 rows = db.delete(Contribution.Table.TABLE_NAME, | ||||
|                 rows = db.delete(TABLE_NAME, | ||||
|                         "_id = ?", | ||||
|                         new String[] { uri.getLastPathSegment() } | ||||
|                         new String[]{uri.getLastPathSegment()} | ||||
|                 ); | ||||
|                 break; | ||||
|             default: | ||||
|  | @ -120,6 +128,7 @@ public class ContributionsContentProvider extends ContentProvider{ | |||
|         return rows; | ||||
|     } | ||||
| 
 | ||||
|     @SuppressWarnings("ConstantConditions") | ||||
|     @Override | ||||
|     public int bulkInsert(@NonNull Uri uri, @NonNull ContentValues[] values) { | ||||
|         Timber.d("Hello, bulk insert! (ContributionsContentProvider)"); | ||||
|  | @ -128,9 +137,9 @@ public class ContributionsContentProvider extends ContentProvider{ | |||
|         sqlDB.beginTransaction(); | ||||
|         switch (uriType) { | ||||
|             case CONTRIBUTIONS: | ||||
|                 for(ContentValues value: values) { | ||||
|                 for (ContentValues value : values) { | ||||
|                     Timber.d("Inserting! %s", value); | ||||
|                     sqlDB.insert(Contribution.Table.TABLE_NAME, null, value); | ||||
|                     sqlDB.insert(TABLE_NAME, null, value); | ||||
|                 } | ||||
|                 break; | ||||
|             default: | ||||
|  | @ -142,6 +151,7 @@ public class ContributionsContentProvider extends ContentProvider{ | |||
|         return values.length; | ||||
|     } | ||||
| 
 | ||||
|     @SuppressWarnings("ConstantConditions") | ||||
|     @Override | ||||
|     public int update(@NonNull Uri uri, ContentValues contentValues, String selection, String[] selectionArgs) { | ||||
|         /* | ||||
|  | @ -156,21 +166,19 @@ public class ContributionsContentProvider extends ContentProvider{ | |||
|         int rowsUpdated = 0; | ||||
|         switch (uriType) { | ||||
|             case CONTRIBUTIONS: | ||||
|                 rowsUpdated = sqlDB.update(Contribution.Table.TABLE_NAME, | ||||
|                         contentValues, | ||||
|                         selection, | ||||
|                         selectionArgs); | ||||
|                 rowsUpdated = sqlDB.update(TABLE_NAME, contentValues, selection, selectionArgs); | ||||
|                 break; | ||||
|             case CONTRIBUTIONS_ID: | ||||
|                 int id = Integer.valueOf(uri.getLastPathSegment()); | ||||
| 
 | ||||
|                 if (TextUtils.isEmpty(selection)) { | ||||
|                     rowsUpdated = sqlDB.update(Contribution.Table.TABLE_NAME, | ||||
|                     rowsUpdated = sqlDB.update(TABLE_NAME, | ||||
|                             contentValues, | ||||
|                             Contribution.Table.COLUMN_ID + " = ?", | ||||
|                             new String[] { String.valueOf(id) } ); | ||||
|                             new String[]{String.valueOf(id)}); | ||||
|                 } else { | ||||
|                     throw new IllegalArgumentException("Parameter `selection` should be empty when updating an ID"); | ||||
|                     throw new IllegalArgumentException( | ||||
|                             "Parameter `selection` should be empty when updating an ID"); | ||||
|                 } | ||||
|                 break; | ||||
|             default: | ||||
|  |  | |||
|  | @ -1,6 +1,5 @@ | |||
| package fr.free.nrw.commons.contributions; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.SharedPreferences; | ||||
| import android.content.pm.PackageManager; | ||||
|  | @ -29,17 +28,15 @@ import timber.log.Timber; | |||
| 
 | ||||
| import static android.Manifest.permission.READ_EXTERNAL_STORAGE; | ||||
| import static android.app.Activity.RESULT_OK; | ||||
| import static android.content.Context.MODE_PRIVATE; | ||||
| import static android.content.pm.PackageManager.PERMISSION_GRANTED; | ||||
| import static android.view.View.GONE; | ||||
| 
 | ||||
| public class ContributionsListFragment extends DaggerFragment { | ||||
| 
 | ||||
|     public interface SourceRefresher { | ||||
|         void refreshSource(); | ||||
|     } | ||||
| 
 | ||||
|     @BindView(R.id.contributionsList) GridView contributionsList; | ||||
|     @BindView(R.id.waitingMessage) TextView waitingMessage; | ||||
|     @BindView(R.id.emptyMessage) TextView emptyMessage; | ||||
| 
 | ||||
|     private ContributionController controller; | ||||
| 
 | ||||
|     @Override | ||||
|  | @ -47,21 +44,21 @@ public class ContributionsListFragment extends DaggerFragment { | |||
|         View v = inflater.inflate(R.layout.fragment_contributions, container, false); | ||||
|         ButterKnife.bind(this, v); | ||||
| 
 | ||||
|         contributionsList.setOnItemClickListener((AdapterView.OnItemClickListener)getActivity()); | ||||
|         if(savedInstanceState != null) { | ||||
|         contributionsList.setOnItemClickListener((AdapterView.OnItemClickListener) getActivity()); | ||||
|         if (savedInstanceState != null) { | ||||
|             Timber.d("Scrolling to %d", savedInstanceState.getInt("grid-position")); | ||||
|             contributionsList.setSelection(savedInstanceState.getInt("grid-position")); | ||||
|         } | ||||
| 
 | ||||
|         //TODO: Should this be in onResume? | ||||
|         SharedPreferences prefs = this.getActivity().getSharedPreferences("prefs", Context.MODE_PRIVATE); | ||||
|         SharedPreferences prefs = getActivity().getSharedPreferences("prefs", MODE_PRIVATE); | ||||
|         String lastModified = prefs.getString("lastSyncTimestamp", ""); | ||||
|         Timber.d("Last Sync Timestamp: %s", lastModified); | ||||
| 
 | ||||
|         if (lastModified.equals("")) { | ||||
|             waitingMessage.setVisibility(View.VISIBLE); | ||||
|         } else { | ||||
|             waitingMessage.setVisibility(View.GONE); | ||||
|             waitingMessage.setVisibility(GONE); | ||||
|         } | ||||
| 
 | ||||
|         return v; | ||||
|  | @ -90,7 +87,7 @@ public class ContributionsListFragment extends DaggerFragment { | |||
|         //FIXME: must get the file data for Google Photos when receive the intent answer, in the onActivityResult method | ||||
|         super.onActivityResult(requestCode, resultCode, data); | ||||
| 
 | ||||
|         if ( resultCode == RESULT_OK ) { | ||||
|         if (resultCode == RESULT_OK) { | ||||
|             Timber.d("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s", | ||||
|                     requestCode, resultCode, data); | ||||
|             controller.handleImagePicked(requestCode, data); | ||||
|  | @ -102,7 +99,7 @@ public class ContributionsListFragment extends DaggerFragment { | |||
| 
 | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         switch(item.getItemId()) { | ||||
|         switch (item.getItemId()) { | ||||
|             case R.id.menu_from_gallery: | ||||
|                 //Gallery crashes before reach ShareActivity screen so must implement permissions check here | ||||
|                 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { | ||||
|  | @ -110,7 +107,7 @@ public class ContributionsListFragment extends DaggerFragment { | |||
|                     // Here, thisActivity is the current activity | ||||
|                     if (ContextCompat.checkSelfPermission(getActivity(), | ||||
|                             READ_EXTERNAL_STORAGE) | ||||
|                             != PackageManager.PERMISSION_GRANTED) { | ||||
|                             != PERMISSION_GRANTED) { | ||||
| 
 | ||||
|                         // Should we show an explanation? | ||||
|                         if (shouldShowRequestPermissionRationale(READ_EXTERNAL_STORAGE)) { | ||||
|  | @ -160,14 +157,15 @@ public class ContributionsListFragment extends DaggerFragment { | |||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { | ||||
| 
 | ||||
|         Timber.d("onRequestPermissionsResult: req code = " + " perm = " + permissions + " grant =" + grantResults); | ||||
|     public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, | ||||
|                                            @NonNull int[] grantResults) { | ||||
|         Timber.d("onRequestPermissionsResult: req code = " + " perm = " | ||||
|                 + permissions + " grant =" + grantResults); | ||||
| 
 | ||||
|         switch (requestCode) { | ||||
|             // 1 = Storage allowed when gallery selected | ||||
|             case 1: { | ||||
|                 if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { | ||||
|                 if (grantResults.length > 0 && grantResults[0] == PERMISSION_GRANTED) { | ||||
|                     Timber.d("Call controller.startGalleryPick()"); | ||||
|                     controller.startGalleryPick(); | ||||
|                 } | ||||
|  | @ -175,7 +173,7 @@ public class ContributionsListFragment extends DaggerFragment { | |||
|             break; | ||||
|             // 2 = Location allowed when 'nearby places' selected | ||||
|             case 2: { | ||||
|                 if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { | ||||
|                 if (grantResults.length > 0 && grantResults[0] == PERMISSION_GRANTED) { | ||||
|                     Timber.d("Location permission granted"); | ||||
|                     Intent nearbyIntent = new Intent(getActivity(), NearbyActivity.class); | ||||
|                     startActivity(nearbyIntent); | ||||
|  | @ -220,6 +218,10 @@ public class ContributionsListFragment extends DaggerFragment { | |||
|     } | ||||
| 
 | ||||
|     protected void clearSyncMessage() { | ||||
|         waitingMessage.setVisibility(View.GONE); | ||||
|         waitingMessage.setVisibility(GONE); | ||||
|     } | ||||
| 
 | ||||
|     public interface SourceRefresher { | ||||
|         void refreshSource(); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -28,9 +28,19 @@ import fr.free.nrw.commons.mwapi.LogEventResult; | |||
| import fr.free.nrw.commons.mwapi.MediaWikiApi; | ||||
| import timber.log.Timber; | ||||
| 
 | ||||
| import static android.content.Context.MODE_PRIVATE; | ||||
| import static fr.free.nrw.commons.contributions.Contribution.STATE_COMPLETED; | ||||
| import static fr.free.nrw.commons.contributions.Contribution.Table.COLUMN_FILENAME; | ||||
| import static fr.free.nrw.commons.contributions.ContributionsContentProvider.BASE_URI; | ||||
| 
 | ||||
| public class ContributionsSyncAdapter extends AbstractThreadedSyncAdapter { | ||||
| 
 | ||||
|     private static final String[] existsQuery = {COLUMN_FILENAME}; | ||||
|     private static final String existsSelection = COLUMN_FILENAME + " = ?"; | ||||
|     private static final ContentValues[] EMPTY = {}; | ||||
|     private static int COMMIT_THRESHOLD = 10; | ||||
| 
 | ||||
|     @SuppressWarnings("WeakerAccess") | ||||
|     @Inject MediaWikiApi mwApi; | ||||
| 
 | ||||
|     public ContributionsSyncAdapter(Context context, boolean autoInitialize) { | ||||
|  | @ -44,19 +54,16 @@ public class ContributionsSyncAdapter extends AbstractThreadedSyncAdapter { | |||
|         return limit; // FIXME: Parameterize! | ||||
|     } | ||||
| 
 | ||||
|     private static final String[] existsQuery = {Contribution.Table.COLUMN_FILENAME}; | ||||
|     private static final String existsSelection = Contribution.Table.COLUMN_FILENAME + " = ?"; | ||||
| 
 | ||||
|     private boolean fileExists(ContentProviderClient client, String filename) { | ||||
|         Cursor cursor = null; | ||||
|         try { | ||||
|             cursor = client.query(ContributionsContentProvider.BASE_URI, | ||||
|             cursor = client.query(BASE_URI, | ||||
|                     existsQuery, | ||||
|                     existsSelection, | ||||
|                     new String[]{filename}, | ||||
|                     "" | ||||
|             ); | ||||
|             return cursor.getCount() != 0; | ||||
|             return cursor != null && cursor.getCount() != 0; | ||||
|         } catch (RemoteException e) { | ||||
|             throw new RuntimeException(e); | ||||
|         } finally { | ||||
|  | @ -67,12 +74,12 @@ public class ContributionsSyncAdapter extends AbstractThreadedSyncAdapter { | |||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onPerformSync(Account account, Bundle bundle, String s, ContentProviderClient contentProviderClient, SyncResult syncResult) { | ||||
|     public void onPerformSync(Account account, Bundle bundle, String authority, | ||||
|                               ContentProviderClient contentProviderClient, SyncResult syncResult) { | ||||
|         ((CommonsApplication) getContext().getApplicationContext()).injector().inject(this); | ||||
| 
 | ||||
|         // This code is fraught with possibilities of race conditions, but lalalalala I can't hear you! | ||||
|         String user = account.name; | ||||
|         SharedPreferences prefs = getContext().getSharedPreferences("prefs", Context.MODE_PRIVATE); | ||||
|         SharedPreferences prefs = getContext().getSharedPreferences("prefs", MODE_PRIVATE); | ||||
|         String lastModified = prefs.getString("lastSyncTimestamp", ""); | ||||
|         Date curTime = new Date(); | ||||
|         LogEventResult result; | ||||
|  | @ -106,13 +113,15 @@ public class ContributionsSyncAdapter extends AbstractThreadedSyncAdapter { | |||
|                 } | ||||
|                 String thumbUrl = Utils.makeThumbBaseUrl(filename); | ||||
|                 Date dateUpdated = image.getDateUpdated(); | ||||
|                 Contribution contrib = new Contribution(null, thumbUrl, filename, "", -1, dateUpdated, dateUpdated, user, "", ""); | ||||
|                 contrib.setState(Contribution.STATE_COMPLETED); | ||||
|                 Contribution contrib = new Contribution(null, thumbUrl, filename, | ||||
|                         "", -1, dateUpdated, dateUpdated, user, | ||||
|                         "", ""); | ||||
|                 contrib.setState(STATE_COMPLETED); | ||||
|                 imageValues.add(contrib.toContentValues()); | ||||
| 
 | ||||
|                 if (imageValues.size() % COMMIT_THRESHOLD == 0) { | ||||
|                     try { | ||||
|                         contentProviderClient.bulkInsert(ContributionsContentProvider.BASE_URI, imageValues.toArray(new ContentValues[]{})); | ||||
|                         contentProviderClient.bulkInsert(BASE_URI, imageValues.toArray(EMPTY)); | ||||
|                     } catch (RemoteException e) { | ||||
|                         throw new RuntimeException(e); | ||||
|                     } | ||||
|  | @ -122,7 +131,7 @@ public class ContributionsSyncAdapter extends AbstractThreadedSyncAdapter { | |||
| 
 | ||||
|             if (imageValues.size() != 0) { | ||||
|                 try { | ||||
|                     contentProviderClient.bulkInsert(ContributionsContentProvider.BASE_URI, imageValues.toArray(new ContentValues[]{})); | ||||
|                     contentProviderClient.bulkInsert(BASE_URI, imageValues.toArray(EMPTY)); | ||||
|                 } catch (RemoteException e) { | ||||
|                     throw new RuntimeException(e); | ||||
|                 } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Paul Hawke
						Paul Hawke