mirror of
				https://github.com/commons-app/apps-android-commons.git
				synced 2025-10-30 22:34:02 +01:00 
			
		
		
		
	Wmhack2018 (#1536)
* Add new activity to manifest * Create review activity layout base * Add a new menu item to drawer for peer review * Add a top menu with randomizer icon to review activity * Add strings for review button * Add activity to ActivityBuilderModule for injection * Add a new drawer item to start review acitivty * Create base of the Review Activity * Add fragment pager * Add new fragment for injection * Create a fragment pager layout * Wikimedia hackathon 2018 (#1533) * First draft of fn to get random recent image * Use log entries for requests to beta, try to connect refresh button FIXME: runs http request on main thread, breaks * Tweak button connection * Add ReviewController class * Fix fragments * Wmhack2018 (#1534) * tiny fixes * Load pictures into activities * Re-use same class for all review fragments (#1537) And try to add pager indicator * [WIP] category check * [WIP] add on-click actions to ReviewActivity * [WIP] add SendThankTask * Make it beautiful * Use standalone category extraction code in MediaDataExtractor * Add categories to category review page
This commit is contained in:
		
							parent
							
								
									1520fc01f7
								
							
						
					
					
						commit
						01cb9ccd70
					
				
					 28 changed files with 1086 additions and 45 deletions
				
			
		|  | @ -24,6 +24,7 @@ import javax.xml.parsers.ParserConfigurationException; | |||
| import fr.free.nrw.commons.location.LatLng; | ||||
| import fr.free.nrw.commons.mwapi.MediaResult; | ||||
| import fr.free.nrw.commons.mwapi.MediaWikiApi; | ||||
| import fr.free.nrw.commons.utils.MediaDataExtractorUtil; | ||||
| import timber.log.Timber; | ||||
| 
 | ||||
| /** | ||||
|  | @ -71,28 +72,13 @@ public class MediaDataExtractor { | |||
|         MediaResult result = mediaWikiApi.fetchMediaByFilename(filename); | ||||
| 
 | ||||
|         // In-page category links are extracted from source, as XML doesn't cover [[links]] | ||||
|         extractCategories(result.getWikiSource()); | ||||
|         categories = MediaDataExtractorUtil.extractCategories(result.getWikiSource()); | ||||
| 
 | ||||
|         // Description template info is extracted from preprocessor XML | ||||
|         processWikiParseTree(result.getParseTreeXmlSource(), licenseList); | ||||
|         fetched = true; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * We could fetch all category links from API, but we actually only want the ones | ||||
|      * directly in the page source so they're editable. In the future this may change. | ||||
|      * | ||||
|      * @param source wikitext source code | ||||
|      */ | ||||
|     private void extractCategories(String source) { | ||||
|         Pattern regex = Pattern.compile("\\[\\[\\s*Category\\s*:([^]]*)\\s*\\]\\]", Pattern.CASE_INSENSITIVE); | ||||
|         Matcher matcher = regex.matcher(source); | ||||
|         while (matcher.find()) { | ||||
|             String cat = matcher.group(1).trim(); | ||||
|             categories.add(cat); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private void processWikiParseTree(String source, LicenseList licenseList) throws IOException { | ||||
|         Document doc; | ||||
|         try { | ||||
|  |  | |||
|  | @ -54,7 +54,7 @@ public class DeleteTask extends AsyncTask<Void, Integer, Boolean> { | |||
|         notificationBuilder = new NotificationCompat.Builder(context); | ||||
|         Toast toast = new Toast(context); | ||||
|         toast.setGravity(Gravity.CENTER,0,0); | ||||
|         toast = Toast.makeText(context,"Trying to nominate "+media.getDisplayTitle()+ " for deletion",Toast.LENGTH_SHORT); | ||||
|         toast = Toast.makeText(context,"Trying to nominate "+media.getDisplayTitle()+ " for deletion", Toast.LENGTH_SHORT); | ||||
|         toast.show(); | ||||
|     } | ||||
| 
 | ||||
|  | @ -64,7 +64,7 @@ public class DeleteTask extends AsyncTask<Void, Integer, Boolean> { | |||
| 
 | ||||
|         String editToken; | ||||
|         String authCookie; | ||||
|         String summary = "Nominating " + media.getFilename() +" for deletion."; | ||||
|         String summary = context.getString(R.string.nominating_file_for_deletion, media.getFilename()); | ||||
| 
 | ||||
|         authCookie = sessionManager.getAuthCookie(); | ||||
|         mwApi.setAuthCookie(authCookie); | ||||
|  | @ -97,19 +97,19 @@ public class DeleteTask extends AsyncTask<Void, Integer, Boolean> { | |||
|             publishProgress(1); | ||||
| 
 | ||||
|             mwApi.prependEdit(editToken,fileDeleteString+"\n", | ||||
|                     media.getFilename(),summary); | ||||
|                     media.getFilename(), summary); | ||||
|             publishProgress(2); | ||||
| 
 | ||||
|             mwApi.edit(editToken,subpageString+"\n", | ||||
|                     "Commons:Deletion_requests/"+media.getFilename(),summary); | ||||
|                     "Commons:Deletion_requests/"+media.getFilename(), summary); | ||||
|             publishProgress(3); | ||||
| 
 | ||||
|             mwApi.appendEdit(editToken,logPageString+"\n", | ||||
|                     "Commons:Deletion_requests/"+date,summary); | ||||
|                     "Commons:Deletion_requests/"+date, summary); | ||||
|             publishProgress(4); | ||||
| 
 | ||||
|             mwApi.appendEdit(editToken,userPageString+"\n", | ||||
|                     "User_Talk:"+sessionManager.getCurrentAccount().name,summary); | ||||
|                     "User_Talk:"+sessionManager.getCurrentAccount().name, summary); | ||||
|             publishProgress(5); | ||||
|         } | ||||
|         catch (Exception e) { | ||||
|  | @ -123,29 +123,21 @@ public class DeleteTask extends AsyncTask<Void, Integer, Boolean> { | |||
|     protected void onProgressUpdate (Integer... values){ | ||||
|         super.onProgressUpdate(values); | ||||
| 
 | ||||
|         int[] messages = new int[]{ | ||||
|                 R.string.getting_edit_token, | ||||
|                 R.string.nominate_for_deletion_edit_file_page, | ||||
|                 R.string.nominate_for_deletion_create_deletion_request, | ||||
|                 R.string.nominate_for_deletion_edit_deletion_request_log, | ||||
|                 R.string.nominate_for_deletion_notify_user, | ||||
|                 R.string.nominate_for_deletion_done | ||||
|         }; | ||||
| 
 | ||||
|         String message = ""; | ||||
|         switch (values[0]){ | ||||
|             case 0: | ||||
|                 message = "Getting token"; | ||||
|                 break; | ||||
|             case 1: | ||||
|                 message = "Adding delete message to file"; | ||||
|                 break; | ||||
|             case 2: | ||||
|                 message = "Creating Delete requests sub-page"; | ||||
|                 break; | ||||
|             case 3: | ||||
|                 message = "Adding file to Delete requests log"; | ||||
|                 break; | ||||
|             case 4: | ||||
|                 message = "Notifying User on Talk page"; | ||||
|                 break; | ||||
|             case 5: | ||||
|                 message = "Done"; | ||||
|                 break; | ||||
|         if (0 < values[0] && values[0] < messages.length) { | ||||
|             message = context.getString(messages[values[0]]); | ||||
|         } | ||||
| 
 | ||||
|         notificationBuilder.setContentTitle("Nominating "+media.getDisplayTitle()+" for deletion") | ||||
|         notificationBuilder.setContentTitle(context.getString(R.string.nominating_file_for_deletion, media.getFilename())) | ||||
|                 .setStyle(new NotificationCompat.BigTextStyle() | ||||
|                         .bigText(message)) | ||||
|                 .setSmallIcon(R.drawable.ic_launcher) | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ import fr.free.nrw.commons.contributions.ContributionsActivity; | |||
| import fr.free.nrw.commons.category.CategoryImagesActivity; | ||||
| import fr.free.nrw.commons.nearby.NearbyActivity; | ||||
| import fr.free.nrw.commons.notification.NotificationActivity; | ||||
| import fr.free.nrw.commons.review.ReviewActivity; | ||||
| import fr.free.nrw.commons.settings.SettingsActivity; | ||||
| import fr.free.nrw.commons.upload.MultipleShareActivity; | ||||
| import fr.free.nrw.commons.upload.ShareActivity; | ||||
|  | @ -50,4 +51,7 @@ public abstract class ActivityBuilderModule { | |||
| 
 | ||||
|     @ContributesAndroidInjector | ||||
|     abstract CategoryImagesActivity bindFeaturedImagesActivity(); | ||||
| 
 | ||||
|     @ContributesAndroidInjector | ||||
|     abstract ReviewActivity bindReviewActivity(); | ||||
| } | ||||
|  |  | |||
|  | @ -9,11 +9,11 @@ import dagger.android.support.AndroidSupportInjectionModule; | |||
| import fr.free.nrw.commons.CommonsApplication; | ||||
| import fr.free.nrw.commons.MediaWikiImageView; | ||||
| import fr.free.nrw.commons.auth.LoginActivity; | ||||
| import fr.free.nrw.commons.contributions.Contribution; | ||||
| import fr.free.nrw.commons.contributions.ContributionsActivity; | ||||
| import fr.free.nrw.commons.contributions.ContributionsSyncAdapter; | ||||
| import fr.free.nrw.commons.delete.DeleteTask; | ||||
| import fr.free.nrw.commons.modifications.ModificationsSyncAdapter; | ||||
| import fr.free.nrw.commons.review.CheckCategoryTask; | ||||
| import fr.free.nrw.commons.review.SendThankTask; | ||||
| import fr.free.nrw.commons.settings.SettingsFragment; | ||||
| import fr.free.nrw.commons.nearby.PlaceRenderer; | ||||
| 
 | ||||
|  | @ -40,6 +40,10 @@ public interface CommonsApplicationComponent extends AndroidInjector<Application | |||
| 
 | ||||
|     void inject(DeleteTask deleteTask); | ||||
| 
 | ||||
|     void inject(CheckCategoryTask checkCategoryTask); | ||||
| 
 | ||||
|     void inject(SendThankTask sendThankTask); | ||||
| 
 | ||||
|     void inject(SettingsFragment fragment); | ||||
| 
 | ||||
|     @Override | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ import fr.free.nrw.commons.media.MediaDetailPagerFragment; | |||
| import fr.free.nrw.commons.nearby.NearbyListFragment; | ||||
| import fr.free.nrw.commons.nearby.NearbyMapFragment; | ||||
| import fr.free.nrw.commons.nearby.NoPermissionsFragment; | ||||
| import fr.free.nrw.commons.review.ReviewImageFragment; | ||||
| import fr.free.nrw.commons.settings.SettingsFragment; | ||||
| import fr.free.nrw.commons.upload.MultipleUploadListFragment; | ||||
| import fr.free.nrw.commons.upload.SingleUploadFragment; | ||||
|  | @ -51,4 +52,7 @@ public abstract class FragmentBuilderModule { | |||
|     @ContributesAndroidInjector | ||||
|     abstract CategoryImagesListFragment bindFeaturedImagesListFragment(); | ||||
| 
 | ||||
|     @ContributesAndroidInjector | ||||
|     abstract ReviewImageFragment bindReviewOutOfContextFragment(); | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -46,7 +46,12 @@ import fr.free.nrw.commons.delete.DeleteTask; | |||
| import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; | ||||
| import fr.free.nrw.commons.location.LatLng; | ||||
| import fr.free.nrw.commons.mwapi.MediaWikiApi; | ||||
| import fr.free.nrw.commons.review.CheckCategoryTask; | ||||
| import fr.free.nrw.commons.review.SendThankTask; | ||||
| import fr.free.nrw.commons.ui.widget.CompatTextView; | ||||
| import io.reactivex.Observable; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.schedulers.Schedulers; | ||||
| import timber.log.Timber; | ||||
| 
 | ||||
| import static android.view.View.GONE; | ||||
|  | @ -357,6 +362,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { | |||
|         alert.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { | ||||
|             public void onClick(DialogInterface dialog, int whichButton) { | ||||
|                 String reason = input.getText().toString(); | ||||
| 
 | ||||
|                 DeleteTask deleteTask = new DeleteTask(getActivity(), media, reason); | ||||
|                 deleteTask.execute(); | ||||
|                 enableDeleteButton(false); | ||||
|  |  | |||
|  | @ -0,0 +1,32 @@ | |||
| package fr.free.nrw.commons.media; | ||||
| 
 | ||||
| import org.w3c.dom.Element; | ||||
| import org.w3c.dom.NodeList; | ||||
| 
 | ||||
| import javax.annotation.Nullable; | ||||
| 
 | ||||
| public class RecentChangesImageUtils { | ||||
| 
 | ||||
|     private static final String[] imageExtensions = new String[] | ||||
|             {".jpg", ".jpeg", ".png"}; | ||||
| 
 | ||||
|     @Nullable | ||||
|     public static String findImageInRecentChanges(NodeList childNodes) { | ||||
|         String imageTitle; | ||||
|         for (int i = 0; i < childNodes.getLength(); i++) { | ||||
|             Element e = (Element)childNodes.item(i); | ||||
|             if (e.getAttribute("type").equals("log") && !e.getAttribute("old_revid").equals("0")) { | ||||
|                 // For log entries, we only want ones where old_revid is zero, indicating a new file | ||||
|                 continue; | ||||
|             } | ||||
|             imageTitle = e.getAttribute("title"); | ||||
| 
 | ||||
|             for (String imageExtension : imageExtensions) { | ||||
|                 if (imageTitle.toLowerCase().endsWith(imageExtension)) { | ||||
|                     return imageTitle; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
| } | ||||
|  | @ -38,12 +38,14 @@ import java.util.Date; | |||
| import java.util.List; | ||||
| import java.util.Locale; | ||||
| import java.util.concurrent.Callable; | ||||
| import java.util.Random; | ||||
| 
 | ||||
| import fr.free.nrw.commons.BuildConfig; | ||||
| import fr.free.nrw.commons.Media; | ||||
| import fr.free.nrw.commons.PageTitle; | ||||
| import fr.free.nrw.commons.category.CategoryImageUtils; | ||||
| import fr.free.nrw.commons.category.QueryContinue; | ||||
| import fr.free.nrw.commons.media.RecentChangesImageUtils; | ||||
| import fr.free.nrw.commons.notification.Notification; | ||||
| import fr.free.nrw.commons.notification.NotificationUtils; | ||||
| import in.yuvi.http.fluent.Http; | ||||
|  | @ -60,6 +62,14 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi { | |||
|     private String wikiMediaToolforgeUrl = "https://tools.wmflabs.org/"; | ||||
| 
 | ||||
|     private static final String THUMB_SIZE = "640"; | ||||
|     // Give up if no random recent image found after 5 tries | ||||
|     private static final int MAX_RANDOM_TRIES = 5; | ||||
|     // Random image request is for some time in the past 30 days | ||||
|     private static final int RANDOM_SECONDS = 60 * 60 * 24 * 30; | ||||
|     // Assuming MW always gives me UTC | ||||
|     private static final SimpleDateFormat isoFormat = | ||||
|             new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH); | ||||
|     private static final String FILE_NAMESPACE = "6"; | ||||
|     private AbstractHttpClient httpClient; | ||||
|     private MWApi api; | ||||
|     private Context context; | ||||
|  | @ -223,6 +233,19 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi { | |||
|                 .getString("/api/query/pages/page/@_idx")) != -1; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean thank(String editToken, String revision) throws IOException { | ||||
|         ApiResult res = api.action("thank") | ||||
|                 .param("rev", revision) | ||||
|                 .param("token", editToken) | ||||
|                 .param("source", getUserAgent()) | ||||
|                 .post(); | ||||
|         String r = res.getString("/api/result/@success"); | ||||
|         // Does this correctly check the success/failure? | ||||
|         // The docs https://www.mediawiki.org/wiki/Extension:Thanks seems unclear about that. | ||||
|         return r.equals("success"); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     @Nullable | ||||
|     public String edit(String editToken, String processedPageContent, String filename, String summary) throws IOException { | ||||
|  | @ -435,6 +458,20 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi { | |||
|                 .getString("/api/query/pages/page/revisions/rev"); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     @Nullable | ||||
|     public String firstRevisionOfFile(String filename) throws IOException { | ||||
|         String res = api.action("query") | ||||
|                 .param("prop", "revisions") | ||||
|                 .param("rvprop", "timestamp|ids") | ||||
|                 .param("titles", filename) | ||||
|                 .param("rvdir", "newer") | ||||
|                 .param("rvlimit", "1") | ||||
|                 .get() | ||||
|                 .getString("/api/query/pages/page/revisions/rev/@revid"); | ||||
|         return res; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     @NonNull | ||||
|     public List<Notification> getNotifications() { | ||||
|  | @ -616,11 +653,59 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi { | |||
|     } | ||||
| 
 | ||||
|     private Date parseMWDate(String mwDate) { | ||||
|         SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH); // Assuming MW always gives me UTC | ||||
|         try { | ||||
|             return isoFormat.parse(mwDate); | ||||
|         } catch (ParseException e) { | ||||
|             throw new RuntimeException(e); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private String formatMWDate(Date date) { | ||||
|         return isoFormat.format(date); | ||||
|     } | ||||
| 
 | ||||
|     public Media getRecentRandomImage() throws IOException { | ||||
|         Media media = null; | ||||
|         int tries = 0; | ||||
|         Random r = new Random(); | ||||
| 
 | ||||
|         while (media == null && tries < MAX_RANDOM_TRIES) { | ||||
|             Date now = new Date(); | ||||
|             Date startDate = new Date(now.getTime() - r.nextInt(RANDOM_SECONDS) * 1000L); | ||||
|             ApiResult apiResult = null; | ||||
|             try { | ||||
|                 MWApi.RequestBuilder requestBuilder = api.action("query") | ||||
|                         .param("list", "recentchanges") | ||||
|                         .param("rcstart", formatMWDate(startDate)) | ||||
|                         .param("rcnamespace", FILE_NAMESPACE) | ||||
|                         .param("rcprop", "title|ids") | ||||
|                         .param("rctype", "new|log") | ||||
|                         .param("rctoponly", "1"); | ||||
| 
 | ||||
|                 apiResult = requestBuilder.get(); | ||||
|             } catch (IOException e) { | ||||
|                 Timber.e("Failed to obtain recent random", e); | ||||
|             } | ||||
|             if (apiResult != null) { | ||||
|                 ApiResult recentChangesNode = apiResult.getNode("/api/query/recentchanges"); | ||||
|                 if (recentChangesNode != null | ||||
|                         && recentChangesNode.getDocument() != null | ||||
|                         && recentChangesNode.getDocument().getChildNodes() != null | ||||
|                         && recentChangesNode.getDocument().getChildNodes().getLength() > 0) { | ||||
|                     NodeList childNodes = recentChangesNode.getDocument().getChildNodes(); | ||||
|                     String imageTitle = RecentChangesImageUtils.findImageInRecentChanges(childNodes); | ||||
|                     if (imageTitle != null) { | ||||
|                         boolean deletionStatus = pageExists("Commons:Deletion_requests/" + imageTitle); | ||||
|                         if (!deletionStatus) { | ||||
|                             // strip File: prefix | ||||
|                             imageTitle = imageTitle.replace("File:", ""); | ||||
|                             media = new Media(imageTitle); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             tries++; | ||||
|         } | ||||
|         return media; | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -75,7 +75,14 @@ public interface MediaWikiApi { | |||
|     @NonNull | ||||
|     Single<Integer> getUploadCount(String userName); | ||||
| 
 | ||||
|     boolean thank(String editToken, String revision) throws IOException; | ||||
| 
 | ||||
|     String firstRevisionOfFile(String filename) throws IOException; | ||||
| 
 | ||||
|     interface ProgressListener { | ||||
|         void onProgress(long transferred, long total); | ||||
|     } | ||||
| 
 | ||||
|     @Nullable | ||||
|     Media getRecentRandomImage() throws IOException; | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,130 @@ | |||
| package fr.free.nrw.commons.review; | ||||
| 
 | ||||
| import android.app.NotificationManager; | ||||
| import android.content.Context; | ||||
| import android.os.AsyncTask; | ||||
| import android.support.v4.app.NotificationCompat; | ||||
| import android.view.Gravity; | ||||
| import android.widget.Toast; | ||||
| 
 | ||||
| import javax.inject.Inject; | ||||
| 
 | ||||
| import fr.free.nrw.commons.Media; | ||||
| import fr.free.nrw.commons.R; | ||||
| import fr.free.nrw.commons.auth.SessionManager; | ||||
| import fr.free.nrw.commons.di.ApplicationlessInjection; | ||||
| import fr.free.nrw.commons.mwapi.MediaWikiApi; | ||||
| import timber.log.Timber; | ||||
| 
 | ||||
| import static android.support.v4.app.NotificationCompat.DEFAULT_ALL; | ||||
| import static android.support.v4.app.NotificationCompat.PRIORITY_HIGH; | ||||
| 
 | ||||
| // Example code: | ||||
| // CheckCategoryTask deleteTask = new CheckCategoryTask(getActivity(), media); | ||||
| 
 | ||||
| public class CheckCategoryTask extends AsyncTask<Void, Integer, Boolean> { | ||||
| 
 | ||||
|     @Inject | ||||
|     MediaWikiApi mwApi; | ||||
|     @Inject | ||||
|     SessionManager sessionManager; | ||||
| 
 | ||||
|     public static final int NOTIFICATION_CHECK_CATEGORY = 0x101; | ||||
| 
 | ||||
|     private NotificationManager notificationManager; | ||||
|     private NotificationCompat.Builder notificationBuilder; | ||||
|     private Context context; | ||||
|     private Media media; | ||||
| 
 | ||||
|     public CheckCategoryTask(Context context, Media media){ | ||||
|         this.context = context; | ||||
|         this.media = media; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onPreExecute(){ | ||||
|         ApplicationlessInjection | ||||
|                 .getInstance(context.getApplicationContext()) | ||||
|                 .getCommonsApplicationComponent() | ||||
|                 .inject(this); | ||||
| 
 | ||||
|         notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); | ||||
|         notificationBuilder = new NotificationCompat.Builder(context); | ||||
|         Toast toast = new Toast(context); | ||||
|         toast.setGravity(Gravity.CENTER,0,0); | ||||
|         toast = Toast.makeText(context, context.getString(R.string.check_category_toast, media.getDisplayTitle()), Toast.LENGTH_SHORT); | ||||
|         toast.show(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected Boolean doInBackground(Void ...voids) { | ||||
|         publishProgress(0); | ||||
| 
 | ||||
|         String editToken; | ||||
|         String authCookie; | ||||
|         String summary = context.getString(R.string.check_category_edit_summary); | ||||
| 
 | ||||
|         authCookie = sessionManager.getAuthCookie(); | ||||
|         mwApi.setAuthCookie(authCookie); | ||||
| 
 | ||||
|         try { | ||||
|             editToken = mwApi.getEditToken(); | ||||
|             if (editToken.equals("+\\")) { | ||||
|                 return false; | ||||
|             } | ||||
|             publishProgress(1); | ||||
| 
 | ||||
|             mwApi.appendEdit(editToken, "\n{{subst:chc}}\n", media.getFilename(), summary); | ||||
|             publishProgress(2); | ||||
|         } | ||||
|         catch (Exception e) { | ||||
|             Timber.d(e.getMessage()); | ||||
|             return false; | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onProgressUpdate (Integer... values){ | ||||
|         super.onProgressUpdate(values); | ||||
| 
 | ||||
|         int[] messages = new int[]{R.string.getting_edit_token, R.string.check_category_adding_template}; | ||||
|         String message = ""; | ||||
|         if (0 < values[0] && values[0] < messages.length) { | ||||
|             message = context.getString(messages[values[0]]); | ||||
|         } | ||||
| 
 | ||||
|         notificationBuilder.setContentTitle(context.getString(R.string.check_category_notification_title, media.getDisplayTitle())) | ||||
|                 .setStyle(new NotificationCompat.BigTextStyle() | ||||
|                         .bigText(message)) | ||||
|                 .setSmallIcon(R.drawable.ic_launcher) | ||||
|                 .setProgress(messages.length, values[0], false) | ||||
|                 .setOngoing(true); | ||||
|         notificationManager.notify(NOTIFICATION_CHECK_CATEGORY, notificationBuilder.build()); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onPostExecute(Boolean result) { | ||||
|         String message = ""; | ||||
|         String title = ""; | ||||
| 
 | ||||
|         if (result){ | ||||
|             title = context.getString(R.string.check_category_success_title); | ||||
|             message = context.getString(R.string.check_category_success_message, media.getDisplayTitle()); | ||||
|         } | ||||
|         else { | ||||
|             title = context.getString(R.string.check_category_failure_title); | ||||
|             message = context.getString(R.string.check_category_failure_message, media.getDisplayTitle()); | ||||
|         } | ||||
| 
 | ||||
|         notificationBuilder.setDefaults(DEFAULT_ALL) | ||||
|                 .setContentTitle(title) | ||||
|                 .setStyle(new NotificationCompat.BigTextStyle() | ||||
|                         .bigText(message)) | ||||
|                 .setSmallIcon(R.drawable.ic_launcher) | ||||
|                 .setProgress(0,0,false) | ||||
|                 .setOngoing(false) | ||||
|                 .setPriority(PRIORITY_HIGH); | ||||
|         notificationManager.notify(NOTIFICATION_CHECK_CATEGORY, notificationBuilder.build()); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										173
									
								
								app/src/main/java/fr/free/nrw/commons/review/ReviewActivity.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								app/src/main/java/fr/free/nrw/commons/review/ReviewActivity.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,173 @@ | |||
| package fr.free.nrw.commons.review; | ||||
| 
 | ||||
| import android.app.AlertDialog; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.os.Bundle; | ||||
| 
 | ||||
| import android.os.Handler; | ||||
| import android.support.design.widget.NavigationView; | ||||
| import android.support.v4.view.ViewPager; | ||||
| import android.support.v4.widget.DrawerLayout; | ||||
| import android.support.v7.widget.Toolbar; | ||||
| 
 | ||||
| import android.util.Log; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| import android.widget.EditText; | ||||
| 
 | ||||
| import com.viewpagerindicator.CirclePageIndicator; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| 
 | ||||
| import javax.inject.Inject; | ||||
| 
 | ||||
| import butterknife.BindView; | ||||
| import butterknife.ButterKnife; | ||||
| import fr.free.nrw.commons.Media; | ||||
| import fr.free.nrw.commons.R; | ||||
| import fr.free.nrw.commons.Utils; | ||||
| import fr.free.nrw.commons.auth.AuthenticatedActivity; | ||||
| import fr.free.nrw.commons.mwapi.MediaResult; | ||||
| import fr.free.nrw.commons.mwapi.MediaWikiApi; | ||||
| import fr.free.nrw.commons.utils.MediaDataExtractorUtil; | ||||
| import io.reactivex.Observable; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
| import io.reactivex.schedulers.Schedulers; | ||||
| 
 | ||||
| /** | ||||
|  * Created by root on 18.05.2018. | ||||
|  */ | ||||
| 
 | ||||
| public class ReviewActivity extends AuthenticatedActivity { | ||||
| 
 | ||||
|     @BindView(R.id.toolbar) | ||||
|     Toolbar toolbar; | ||||
|     @BindView(R.id.navigation_view) | ||||
|     NavigationView navigationView; | ||||
|     @BindView(R.id.drawer_layout) | ||||
|     DrawerLayout drawerLayout; | ||||
| 
 | ||||
|     @BindView(R.id.reviewPager) | ||||
|     ViewPager pager; | ||||
| 
 | ||||
|     @Inject MediaWikiApi mwApi; | ||||
| 
 | ||||
|     private ReviewPagerAdapter reviewPagerAdapter; | ||||
| 
 | ||||
|     //private ReviewCallback reviewCallback; | ||||
|     private ReviewController reviewController; | ||||
| 
 | ||||
|     @BindView(R.id.reviewPagerIndicator) | ||||
|     public CirclePageIndicator pagerIndicator; | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onAuthCookieAcquired(String authCookie) { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onAuthFailure() { | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_review); | ||||
|         ButterKnife.bind(this); | ||||
|         initDrawer(); | ||||
| 
 | ||||
|         reviewController = new ReviewController(); | ||||
| 
 | ||||
| 
 | ||||
|         reviewPagerAdapter = new ReviewPagerAdapter(getSupportFragmentManager()); | ||||
|         pager.setAdapter(reviewPagerAdapter); | ||||
|         reviewPagerAdapter.getItem(0); | ||||
|         pagerIndicator.setViewPager(pager); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean onCreateOptionsMenu(Menu menu) { | ||||
|         getMenuInflater().inflate(R.menu.review_randomizer_menu, menu); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         int id = item.getItemId(); | ||||
| 
 | ||||
|         if (id == R.id.action_review_randomizer) { | ||||
|             Observable.fromCallable(() -> { | ||||
|                 Media result = null; | ||||
|                 try { | ||||
|                     result = mwApi.getRecentRandomImage(); | ||||
| 
 | ||||
|                     //String thumBaseUrl = Utils.makeThumbBaseUrl(result.getFilename()); | ||||
|                     //reviewPagerAdapter.currentThumbBasedUrl = thumBaseUrl; | ||||
| 
 | ||||
|                     //Log.d("review", result.getWikiSource()); | ||||
| 
 | ||||
|                 } catch (IOException e) { | ||||
|                     Log.d("review", e.toString()); | ||||
|                 } | ||||
|                 return result; | ||||
|             }) | ||||
|                     .subscribeOn(Schedulers.io()) | ||||
|                     .observeOn(AndroidSchedulers.mainThread()) | ||||
|                     .subscribe(this::updateImage); | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
| 
 | ||||
|     private void updateImage(Media result) { | ||||
|         reviewController.onImageRefreshed(result.getFilename()); //file name is updated | ||||
|         reviewPagerAdapter.updateFilename(); | ||||
|         pager.setCurrentItem(0); | ||||
|         Observable.fromCallable(() -> { | ||||
|             MediaResult media = mwApi.fetchMediaByFilename("File:" + result.getFilename()); | ||||
|             return MediaDataExtractorUtil.extractCategories(media.getWikiSource()); | ||||
|         }) | ||||
|                 .subscribeOn(Schedulers.io()) | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|                 .subscribe(this::updateCategories); | ||||
|     } | ||||
| 
 | ||||
|     private void updateCategories(ArrayList<String> categories) { | ||||
|         reviewController.onCategoriesRefreshed(categories); | ||||
|         reviewPagerAdapter.updateCategories(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * References ReviewPagerAdapter to null before the activity is destroyed | ||||
|      */ | ||||
|     @Override | ||||
|     public void onDestroy() { | ||||
|         //adapter.setCallback(null); | ||||
|         super.onDestroy(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Consumers should be simply using this method to use this activity. | ||||
|      * @param context | ||||
|      * @param title Page title | ||||
|      */ | ||||
|     public static void startYourself(Context context, String title) { | ||||
|         Intent reviewActivity = new Intent(context, ReviewActivity.class); | ||||
|         context.startActivity(reviewActivity); | ||||
|     } | ||||
| 
 | ||||
|     interface ReviewCallback { | ||||
|         void onImageRefreshed(String itemTitle); | ||||
|         void onQuestionChanged(); | ||||
|         void onSurveyFinished(); | ||||
|         void onImproperImageReported(); | ||||
|         void onLicenceViolationReported(); | ||||
|         void onWrongCategoryReported(); | ||||
|         void onThankSent(); | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,52 @@ | |||
| package fr.free.nrw.commons.review; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| 
 | ||||
| /** | ||||
|  * Created by root on 19.05.2018. | ||||
|  */ | ||||
| 
 | ||||
| public class ReviewController implements ReviewActivity.ReviewCallback { | ||||
|     public static String fileName; | ||||
|     protected static ArrayList<String> categories; | ||||
| 
 | ||||
|     @Override | ||||
|     public void onImageRefreshed(String fileName) { | ||||
|         ReviewController.fileName = fileName; | ||||
|         ReviewController.categories = new ArrayList<>(); | ||||
|     } | ||||
| 
 | ||||
|     public void onCategoriesRefreshed(ArrayList<String> categories) { | ||||
|         ReviewController.categories = categories; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onQuestionChanged() { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onSurveyFinished() { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onImproperImageReported() { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onLicenceViolationReported() { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onWrongCategoryReported() { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onThankSent() { | ||||
| 
 | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,92 @@ | |||
| package fr.free.nrw.commons.review; | ||||
| 
 | ||||
| import android.app.AlertDialog; | ||||
| import android.os.Bundle; | ||||
| import android.text.TextUtils; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.EditText; | ||||
| import android.widget.TextView; | ||||
| 
 | ||||
| import com.facebook.drawee.view.SimpleDraweeView; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| 
 | ||||
| import fr.free.nrw.commons.R; | ||||
| import fr.free.nrw.commons.Utils; | ||||
| import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; | ||||
| 
 | ||||
| /** | ||||
|  * Created by root on 19.05.2018. | ||||
|  */ | ||||
| 
 | ||||
| public class ReviewImageFragment extends CommonsDaggerSupportFragment { | ||||
| 
 | ||||
|         public static final int SPAM = 0; | ||||
|         public static final int COPYRIGHT = 1; | ||||
|         public static final int CATEGORY = 2; | ||||
| 
 | ||||
|         private int position; | ||||
|         private String fileName; | ||||
|         private String catString; | ||||
|         private View catsView; | ||||
|         private SimpleDraweeView simpleDraweeView; | ||||
| 
 | ||||
|         public void update(int position, String fileName) { | ||||
|             this.position = position; | ||||
|             this.fileName = fileName; | ||||
| 
 | ||||
|             if (simpleDraweeView!=null) { | ||||
|                 simpleDraweeView.setImageURI(Utils.makeThumbBaseUrl(fileName)); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public void updateCategories(Iterable<String> categories) { | ||||
|             catString = TextUtils.join(", ", categories); | ||||
|             if (catsView != null) { | ||||
|                 ((TextView) catsView).setText(catString); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public void onCreate(Bundle savedInstanceState) { | ||||
|             super.onCreate(savedInstanceState); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public View onCreateView(LayoutInflater inflater, ViewGroup container, | ||||
|                                  Bundle savedInstanceState) { | ||||
|             position = getArguments().getInt("position"); | ||||
|             View layoutView = inflater.inflate(R.layout.fragment_review_image, container, | ||||
|                     false); | ||||
|             View textView = layoutView.findViewById(R.id.reviewQuestion); | ||||
|             catsView = layoutView.findViewById(R.id.reviewCategories); | ||||
|             String question; | ||||
|             switch(position) { | ||||
|                 case COPYRIGHT: | ||||
|                     question = getString(R.string.review_copyright); | ||||
|                     break; | ||||
|                 case CATEGORY: | ||||
|                     question = getString(R.string.review_category); | ||||
|                     catsView.setVisibility(View.VISIBLE); | ||||
|                     break; | ||||
|                 case SPAM: | ||||
|                     question = getString(R.string.review_spam); | ||||
|                     break; | ||||
|                 default: | ||||
|                     question = "How did we get here?"; | ||||
|             } | ||||
|             ((TextView) textView).setText(question); | ||||
|             simpleDraweeView = layoutView.findViewById(R.id.imageView); | ||||
| 
 | ||||
|             if (fileName != null) { | ||||
|                 simpleDraweeView.setImageURI(Utils.makeThumbBaseUrl(fileName)); | ||||
|             } | ||||
|             if (catString != null) { | ||||
|                 ((TextView) catsView).setText(catString); | ||||
|             } | ||||
|             return layoutView; | ||||
|         } | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,51 @@ | |||
| package fr.free.nrw.commons.review; | ||||
| 
 | ||||
| import android.os.Bundle; | ||||
| import android.support.v4.app.Fragment; | ||||
| import android.support.v4.app.FragmentManager; | ||||
| import android.support.v4.app.FragmentStatePagerAdapter; | ||||
| 
 | ||||
| /** | ||||
|  * Created by nes on 19.05.2018. | ||||
|  */ | ||||
| 
 | ||||
| public class ReviewPagerAdapter extends FragmentStatePagerAdapter { | ||||
|     private int currentPosition; | ||||
|     ReviewImageFragment[] reviewImageFragments; | ||||
| 
 | ||||
| 
 | ||||
|     public ReviewPagerAdapter(FragmentManager fm) { | ||||
|         super(fm); | ||||
|         reviewImageFragments = new ReviewImageFragment[] { | ||||
|             new ReviewImageFragment(), | ||||
|             new ReviewImageFragment(), | ||||
|             new ReviewImageFragment() | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int getCount() { | ||||
|         return 3; | ||||
|     } | ||||
| 
 | ||||
|     public void updateFilename() { | ||||
|         for (int i = 0; i < getCount(); i++) { | ||||
|             ReviewImageFragment fragment = reviewImageFragments[i]; | ||||
|             fragment.update(i, ReviewController.fileName); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void updateCategories() { | ||||
|         ReviewImageFragment categoryFragment = reviewImageFragments[ReviewImageFragment.CATEGORY]; | ||||
|         categoryFragment.updateCategories(ReviewController.categories); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public Fragment getItem(int position) { | ||||
|         Bundle bundle = new Bundle(); | ||||
|         bundle.putInt("position", position); | ||||
|         reviewImageFragments[position].setArguments(bundle); | ||||
|         return reviewImageFragments[position]; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										140
									
								
								app/src/main/java/fr/free/nrw/commons/review/SendThankTask.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								app/src/main/java/fr/free/nrw/commons/review/SendThankTask.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,140 @@ | |||
| package fr.free.nrw.commons.review; | ||||
| 
 | ||||
| import android.app.NotificationManager; | ||||
| import android.content.Context; | ||||
| import android.os.AsyncTask; | ||||
| import android.support.v4.app.NotificationCompat; | ||||
| import android.view.Gravity; | ||||
| import android.widget.Toast; | ||||
| 
 | ||||
| import javax.inject.Inject; | ||||
| 
 | ||||
| import fr.free.nrw.commons.Media; | ||||
| import fr.free.nrw.commons.R; | ||||
| import fr.free.nrw.commons.auth.SessionManager; | ||||
| import fr.free.nrw.commons.di.ApplicationlessInjection; | ||||
| import fr.free.nrw.commons.mwapi.MediaWikiApi; | ||||
| import timber.log.Timber; | ||||
| 
 | ||||
| import static android.support.v4.app.NotificationCompat.DEFAULT_ALL; | ||||
| import static android.support.v4.app.NotificationCompat.PRIORITY_HIGH; | ||||
| 
 | ||||
| // example code: | ||||
| // | ||||
| //                media = new Media("File:Iru.png"); | ||||
| //                        Observable.fromCallable(() -> mwApi.firstRevisionOfFile(media.getFilename())) | ||||
| //                        .subscribeOn(Schedulers.io()) | ||||
| //                        .observeOn(AndroidSchedulers.mainThread()) | ||||
| //                        .subscribe(revision -> { | ||||
| //                        SendThankTask task = new SendThankTask(getActivity(), media, revision); | ||||
| //                        task.execute(); | ||||
| //                        }); | ||||
| 
 | ||||
| public class SendThankTask extends AsyncTask<Void, Integer, Boolean> { | ||||
| 
 | ||||
|     @Inject | ||||
|     MediaWikiApi mwApi; | ||||
|     @Inject | ||||
|     SessionManager sessionManager; | ||||
| 
 | ||||
|     public static final int NOTIFICATION_SEND_THANK = 0x102; | ||||
| 
 | ||||
|     private NotificationManager notificationManager; | ||||
|     private NotificationCompat.Builder notificationBuilder; | ||||
|     private Context context; | ||||
|     private Media media; | ||||
|     private String revision; | ||||
| 
 | ||||
|     public SendThankTask(Context context, Media media, String revision){ | ||||
|         this.context = context; | ||||
|         this.media = media; | ||||
|         this.revision = revision; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onPreExecute(){ | ||||
|         ApplicationlessInjection | ||||
|                 .getInstance(context.getApplicationContext()) | ||||
|                 .getCommonsApplicationComponent() | ||||
|                 .inject(this); | ||||
| 
 | ||||
|         notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); | ||||
|         notificationBuilder = new NotificationCompat.Builder(context); | ||||
|         Toast toast = new Toast(context); | ||||
|         toast.setGravity(Gravity.CENTER,0,0); | ||||
|         toast = Toast.makeText(context, context.getString(R.string.send_thank_toast, media.getDisplayTitle()), Toast.LENGTH_SHORT); | ||||
|         toast.show(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected Boolean doInBackground(Void ...voids) { | ||||
|         publishProgress(0); | ||||
| 
 | ||||
|         String editToken; | ||||
|         String authCookie; | ||||
| 
 | ||||
|         authCookie = sessionManager.getAuthCookie(); | ||||
|         mwApi.setAuthCookie(authCookie); | ||||
| 
 | ||||
|         try { | ||||
|             editToken = mwApi.getEditToken(); | ||||
|             if (editToken.equals("+\\")) { | ||||
|                 return false; | ||||
|             } | ||||
|             publishProgress(1); | ||||
| 
 | ||||
|             mwApi.thank(editToken, revision); | ||||
| 
 | ||||
|             publishProgress(2); | ||||
|         } | ||||
|         catch (Exception e) { | ||||
|             Timber.d(e.getMessage()); | ||||
|             return false; | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onProgressUpdate (Integer... values){ | ||||
|         super.onProgressUpdate(values); | ||||
| 
 | ||||
|         int[] messages = new int[]{R.string.getting_edit_token, R.string.send_thank_send}; | ||||
|         String message = ""; | ||||
|         if (0 < values[0] && values[0] < messages.length) { | ||||
|             message = context.getString(messages[values[0]]); | ||||
|         } | ||||
| 
 | ||||
|         notificationBuilder.setContentTitle(context.getString(R.string.send_thank_notification_title)) | ||||
|                 .setStyle(new NotificationCompat.BigTextStyle() | ||||
|                         .bigText(message)) | ||||
|                 .setSmallIcon(R.drawable.ic_launcher) | ||||
|                 .setProgress(messages.length, values[0], false) | ||||
|                 .setOngoing(true); | ||||
|         notificationManager.notify(NOTIFICATION_SEND_THANK, notificationBuilder.build()); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onPostExecute(Boolean result) { | ||||
|         String message = ""; | ||||
|         String title = ""; | ||||
| 
 | ||||
|         if (result){ | ||||
|             title = context.getString(R.string.send_thank_success_title); | ||||
|             message = context.getString(R.string.send_thank_success_message, media.getDisplayTitle()); | ||||
|         } | ||||
|         else { | ||||
|             title = context.getString(R.string.send_thank_failure_title); | ||||
|             message = context.getString(R.string.send_thank_failure_message, media.getDisplayTitle()); | ||||
|         } | ||||
| 
 | ||||
|         notificationBuilder.setDefaults(DEFAULT_ALL) | ||||
|                 .setContentTitle(title) | ||||
|                 .setStyle(new NotificationCompat.BigTextStyle() | ||||
|                         .bigText(message)) | ||||
|                 .setSmallIcon(R.drawable.ic_launcher) | ||||
|                 .setProgress(0,0,false) | ||||
|                 .setOngoing(false) | ||||
|                 .setPriority(PRIORITY_HIGH); | ||||
|         notificationManager.notify(NOTIFICATION_SEND_THANK, notificationBuilder.build()); | ||||
|     } | ||||
| } | ||||
|  | @ -30,6 +30,7 @@ import fr.free.nrw.commons.contributions.ContributionsActivity; | |||
| import fr.free.nrw.commons.category.CategoryImagesActivity; | ||||
| import fr.free.nrw.commons.nearby.NearbyActivity; | ||||
| import fr.free.nrw.commons.notification.NotificationActivity; | ||||
| import fr.free.nrw.commons.review.ReviewActivity; | ||||
| import fr.free.nrw.commons.settings.SettingsActivity; | ||||
| import timber.log.Timber; | ||||
| 
 | ||||
|  | @ -160,6 +161,11 @@ public abstract class NavigationBaseActivity extends BaseActivity | |||
|                 drawerLayout.closeDrawer(navigationView); | ||||
|                 CategoryImagesActivity.startYourself(this, getString(R.string.title_activity_featured_images), FEATURED_IMAGES_CATEGORY); | ||||
|                 return true; | ||||
| 
 | ||||
|             case R.id.action_review: | ||||
|                 drawerLayout.closeDrawer(navigationView); | ||||
|                 ReviewActivity.startYourself(this, getString(R.string.title_activity_review)); | ||||
|                 return true; | ||||
|             default: | ||||
|                 Timber.e("Unknown option [%s] selected from the navigation menu", itemId); | ||||
|                 return false; | ||||
|  |  | |||
|  | @ -0,0 +1,28 @@ | |||
| package fr.free.nrw.commons.utils; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.regex.Matcher; | ||||
| import java.util.regex.Pattern; | ||||
| 
 | ||||
| public class MediaDataExtractorUtil { | ||||
| 
 | ||||
|     /** | ||||
|      * We could fetch all category links from API, but we actually only want the ones | ||||
|      * directly in the page source so they're editable. In the future this may change. | ||||
|      * | ||||
|      * @param source wikitext source code | ||||
|      */ | ||||
|     public static ArrayList<String> extractCategories(String source) { | ||||
|         ArrayList<String> categories = new ArrayList<>(); | ||||
|         Pattern regex = Pattern.compile("\\[\\[\\s*Category\\s*:([^]]*)\\s*\\]\\]", Pattern.CASE_INSENSITIVE); | ||||
|         Matcher matcher = regex.matcher(source); | ||||
|         while (matcher.find()) { | ||||
|             String cat = matcher.group(1).trim(); | ||||
|             categories.add(cat); | ||||
|         } | ||||
| 
 | ||||
|         return categories; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Elliott Eggleston
						Elliott Eggleston