Skip to content

Commit 86878fb

Browse files
ujjwalagrawal17neslihanturan
authored andcommitted
Add feature to Browse commons via app (#1716)
* Search activity, image search fragment added * Removed explore icon xml * Updated Javadocs for search Activity and Navigation Base Activity * SearchImageItem class updated * Javadocs added for search activity * removed redundant code and added javadocs for search image modules * Javadocs added for updateImageList method * Rename featuredImage to explore * Fixed null query issue * changed cisibility to gone in case of successful Fetch * Consolidate the networking libraries - drop volley in favor of OkHttp * Extracted a few networking related items into a new Dagger module and finished the process of mocking the main component for tests. * Refactoring to extract GpsCategoryModel and ensure single-responsibility-principle is maintained in CategoryApi. * fixed featured image back bug * Localisation updates from https://translatewiki.net. * Javadocs added * Add option to set image as wallpaper (#1535) * Add option to set image as wallpaper * Added java docs * Toast message on setting the wallpaper successfully * Localisation updates from https://translatewiki.net. * SearchHistory Fragment added * Search History Item added * Content Provider, RecentSearchesDao added * Database version changed to 7 and added methods for find, save ,.. * Delete icon deleted * Reverted changes in gradle files * Reverted changes in gradle files 2 * Optimized Improts * reverted refractor for container name * Refactored packagename, changed name to query in POJO class. * Updated lastUsed to lastSearched * Javadocs updated * Check if user has been in search page for 5 seconds if yes then save it to history * If else indentation updated * added import in test * edittext replaced with Searchview * RxSearchview added * Added support for API 21+ * Snackbar removed on success * Improved code * Pagination added * Removed unnecessary toast * Comment added in method * Support for landscape mode added * Fixed screen rotation issue on Explore and Search activity * Clear focus added * Delete all function added in Content Provider and called from fragment * Scrollbar Recyclerview added * Share Icon changed to 32 dp and back button added in explore, search activity. * Removed unnecessary code * Wrote and run tests for Recent Searches (creating db, migrating from versions, deletion, finding,.. * Category Search Fragment added * Adapter factory added * Renderer added * Improvements * Viewpager adapter added * Updated XML * Improvements in category card design * tabs colors changed * renamed images to media * Java docs improved * Javadoc added for setTabs * JavaDoc for ViewPagerAdapter added * Refreshed listview after delete * Added mediaContainer * Fixed ghost issue in image search fragment * Ghost issue for categories fixed * Removed Calling API call onback press * Category Details activity added * Menu added in category details activity * back button added * back button bugs * Improvements in category images fragment * JavaDoc added for some methods * trimming added, Tab layout hided, recent searches refreshed * SubCategory list fragment added, API added to extract subCategory Details * API params updated to get more precise results * Javadocs added for MWAPI method * Pagination removed * Fix API for fetching images inside category * Parent category API added * Fix #1704 * Fix #1704 corrected * Fix #1702 * Fix #1702 and #1704 * added try catch statements * Optimimzed imports * loops replaced with Functions * Javadocs for various methods added * Fix java docs for Dao * Javadocs for various methods added * Fix java docs for Dao * More javadocs added for explore Feature * Javadocs added * Javadocs added * Improvements in indentation (#1739)
1 parent 2171b68 commit 86878fb

File tree

70 files changed

+3030
-78
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+3030
-78
lines changed

app/src/main/AndroidManifest.xml

+18
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,17 @@
9797
android:label="@string/title_activity_featured_images"
9898
android:parentActivityName=".contributions.ContributionsActivity" />
9999

100+
<activity
101+
android:name=".category.CategoryDetailsActivity"
102+
android:label="@string/title_activity_featured_images"
103+
android:parentActivityName=".contributions.ContributionsActivity" />
104+
105+
<activity
106+
android:name=".explore.SearchActivity"
107+
android:label="@string/title_activity_search"
108+
android:parentActivityName=".contributions.ContributionsActivity"
109+
/>
110+
100111
<service android:name=".upload.UploadService" />
101112

102113
<service
@@ -165,6 +176,13 @@
165176
android:label="@string/provider_categories"
166177
android:syncable="false" />
167178

179+
<provider
180+
android:name=".explore.recentsearches.RecentSearchesContentProvider"
181+
android:authorities="fr.free.nrw.commons.explore.recentsearches.contentprovider"
182+
android:exported="false"
183+
android:label="@string/provider_searches"
184+
android:syncable="false" />
185+
168186
<receiver android:name=".widget.PicOfDayAppWidget">
169187
<intent-filter>
170188
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />

app/src/main/java/fr/free/nrw/commons/Media.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@
33
import android.net.Uri;
44
import android.os.Parcel;
55
import android.os.Parcelable;
6+
import android.support.annotation.NonNull;
67
import android.support.annotation.Nullable;
78

89
import java.util.ArrayList;
10+
import java.util.Collection;
911
import java.util.Date;
1012
import java.util.HashMap;
13+
import java.util.Iterator;
1114
import java.util.List;
1215
import java.util.Map;
16+
import java.util.Set;
1317
import java.util.regex.Matcher;
1418
import java.util.regex.Pattern;
1519

@@ -356,12 +360,8 @@ public void setCategories(List<String> categories) {
356360
* @param descriptions Media descriptions
357361
*/
358362
void setDescriptions(Map<String, String> descriptions) {
359-
for (String key : this.descriptions.keySet()) {
360-
this.descriptions.remove(key);
361-
}
362-
for (String key : descriptions.keySet()) {
363-
this.descriptions.put(key, descriptions.get(key));
364-
}
363+
this.descriptions.clear();
364+
this.descriptions.putAll(descriptions);
365365
}
366366

367367
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
package fr.free.nrw.commons.category;
2+
3+
import android.content.Context;
4+
import android.content.Intent;
5+
import android.database.DataSetObserver;
6+
import android.os.Bundle;
7+
import android.support.design.widget.TabLayout;
8+
import android.support.v4.app.Fragment;
9+
import android.support.v4.app.FragmentManager;
10+
import android.support.v4.view.ViewPager;
11+
import android.view.Menu;
12+
import android.view.MenuInflater;
13+
import android.view.MenuItem;
14+
import android.view.View;
15+
import android.widget.AdapterView;
16+
import android.widget.FrameLayout;
17+
import android.widget.Toast;
18+
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
22+
import butterknife.BindView;
23+
import butterknife.ButterKnife;
24+
import fr.free.nrw.commons.Media;
25+
import fr.free.nrw.commons.PageTitle;
26+
import fr.free.nrw.commons.R;
27+
import fr.free.nrw.commons.explore.ViewPagerAdapter;
28+
import fr.free.nrw.commons.media.MediaDetailPagerFragment;
29+
import fr.free.nrw.commons.theme.NavigationBaseActivity;
30+
31+
import static android.widget.Toast.LENGTH_SHORT;
32+
33+
/**
34+
* This activity displays details of a particular category
35+
* Its generic and simply takes the name of category name in its start intent to load all images, subcategories in
36+
* a particular category on wikimedia commons.
37+
*/
38+
39+
public class CategoryDetailsActivity extends NavigationBaseActivity
40+
implements MediaDetailPagerFragment.MediaDetailProvider,
41+
AdapterView.OnItemClickListener{
42+
43+
44+
private FragmentManager supportFragmentManager;
45+
private CategoryImagesListFragment categoryImagesListFragment;
46+
private MediaDetailPagerFragment mediaDetails;
47+
private String categoryName;
48+
@BindView(R.id.mediaContainer) FrameLayout mediaContainer;
49+
@BindView(R.id.tabLayout) TabLayout tabLayout;
50+
@BindView(R.id.viewPager) ViewPager viewPager;
51+
52+
ViewPagerAdapter viewPagerAdapter;
53+
54+
@Override
55+
protected void onCreate(Bundle savedInstanceState) {
56+
super.onCreate(savedInstanceState);
57+
setContentView(R.layout.activity_category_details);
58+
ButterKnife.bind(this);
59+
supportFragmentManager = getSupportFragmentManager();
60+
viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
61+
viewPager.setAdapter(viewPagerAdapter);
62+
viewPager.setOffscreenPageLimit(2);
63+
tabLayout.setupWithViewPager(viewPager);
64+
setTabs();
65+
setPageTitle();
66+
initDrawer();
67+
forceInitBackButton();
68+
}
69+
70+
/**
71+
* This activity contains 3 tabs and a viewpager. This method is used to set the titles of tab,
72+
* Set the fragments according to the tab selected in the viewPager.
73+
*/
74+
private void setTabs() {
75+
List<Fragment> fragmentList = new ArrayList<>();
76+
List<String> titleList = new ArrayList<>();
77+
categoryImagesListFragment = new CategoryImagesListFragment();
78+
SubCategoryListFragment subCategoryListFragment = new SubCategoryListFragment();
79+
SubCategoryListFragment parentCategoryListFragment = new SubCategoryListFragment();
80+
categoryName = getIntent().getStringExtra("categoryName");
81+
if (getIntent() != null && categoryName != null) {
82+
Bundle arguments = new Bundle();
83+
arguments.putString("categoryName", categoryName);
84+
arguments.putBoolean("isParentCategory", false);
85+
categoryImagesListFragment.setArguments(arguments);
86+
subCategoryListFragment.setArguments(arguments);
87+
Bundle parentCategoryArguments = new Bundle();
88+
parentCategoryArguments.putString("categoryName", categoryName);
89+
parentCategoryArguments.putBoolean("isParentCategory", true);
90+
parentCategoryListFragment.setArguments(parentCategoryArguments);
91+
}
92+
fragmentList.add(categoryImagesListFragment);
93+
titleList.add("MEDIA");
94+
fragmentList.add(subCategoryListFragment);
95+
titleList.add("SUBCATEGORIES");
96+
fragmentList.add(parentCategoryListFragment);
97+
titleList.add("PARENT CATEGORIES");
98+
viewPagerAdapter.setTabData(fragmentList, titleList);
99+
viewPagerAdapter.notifyDataSetChanged();
100+
101+
}
102+
103+
/**
104+
* Gets the passed categoryName from the intents and displays it as the page title
105+
*/
106+
private void setPageTitle() {
107+
if (getIntent() != null && getIntent().getStringExtra("categoryName") != null) {
108+
setTitle(getIntent().getStringExtra("categoryName"));
109+
}
110+
}
111+
112+
/**
113+
* This method is called onClick of media inside category details (CategoryImageListFragment).
114+
*/
115+
@Override
116+
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
117+
tabLayout.setVisibility(View.GONE);
118+
viewPager.setVisibility(View.GONE);
119+
mediaContainer.setVisibility(View.VISIBLE);
120+
if (mediaDetails == null || !mediaDetails.isVisible()) {
121+
// set isFeaturedImage true for featured images, to include author field on media detail
122+
mediaDetails = new MediaDetailPagerFragment(false, true);
123+
FragmentManager supportFragmentManager = getSupportFragmentManager();
124+
supportFragmentManager
125+
.beginTransaction()
126+
.replace(R.id.mediaContainer, mediaDetails)
127+
.addToBackStack(null)
128+
.commit();
129+
supportFragmentManager.executePendingTransactions();
130+
}
131+
mediaDetails.showImage(i);
132+
forceInitBackButton();
133+
}
134+
135+
136+
/**
137+
* Consumers should be simply using this method to use this activity.
138+
* @param context A Context of the application package implementing this class.
139+
* @param categoryName Name of the category for displaying its details
140+
*/
141+
public static void startYourself(Context context, String categoryName) {
142+
Intent intent = new Intent(context, CategoryDetailsActivity.class);
143+
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
144+
intent.putExtra("categoryName", categoryName);
145+
context.startActivity(intent);
146+
}
147+
148+
/**
149+
* This method is called mediaDetailPagerFragment. It returns the Media Object at that Index
150+
* @param i It is the index of which media object is to be returned which is same as
151+
* current index of viewPager.
152+
* @return Media Object
153+
*/
154+
@Override
155+
public Media getMediaAtPosition(int i) {
156+
if (categoryImagesListFragment.getAdapter() == null) {
157+
// not yet ready to return data
158+
return null;
159+
} else {
160+
return (Media) categoryImagesListFragment.getAdapter().getItem(i);
161+
}
162+
}
163+
164+
/**
165+
* This method is called on from getCount of MediaDetailPagerFragment
166+
* The viewpager will contain same number of media items as that of media elements in adapter.
167+
* @return Total Media count in the adapter
168+
*/
169+
@Override
170+
public int getTotalMediaCount() {
171+
if (categoryImagesListFragment.getAdapter() == null) {
172+
return 0;
173+
}
174+
return categoryImagesListFragment.getAdapter().getCount();
175+
}
176+
177+
/**
178+
* This method is never called but it was in MediaDetailProvider Interface
179+
* so it needs to be overrided.
180+
*/
181+
@Override
182+
public void notifyDatasetChanged() {
183+
184+
}
185+
186+
/**
187+
* This method is never called but it was in MediaDetailProvider Interface
188+
* so it needs to be overrided.
189+
*/
190+
@Override
191+
public void registerDataSetObserver(DataSetObserver observer) {
192+
}
193+
194+
/**
195+
* This method is never called but it was in MediaDetailProvider Interface
196+
* so it needs to be overrided.
197+
*/
198+
@Override
199+
public void unregisterDataSetObserver(DataSetObserver observer) {
200+
201+
}
202+
203+
/**
204+
* This method inflates the menu in the toolbar
205+
*/
206+
@Override
207+
public boolean onCreateOptionsMenu(Menu menu) {
208+
MenuInflater inflater = getMenuInflater();
209+
inflater.inflate(R.menu.fragment_category_detail, menu);
210+
return super.onCreateOptionsMenu(menu);
211+
}
212+
213+
/**
214+
* This method handles the logic on ItemSelect in toolbar menu
215+
* Currently only 1 choice is available to open category details page in browser
216+
*/
217+
@Override
218+
public boolean onOptionsItemSelected(MenuItem item) {
219+
220+
// Handle item selection
221+
switch (item.getItemId()) {
222+
case R.id.menu_browser_current_category:
223+
Intent viewIntent = new Intent();
224+
viewIntent.setAction(Intent.ACTION_VIEW);
225+
viewIntent.setData(new PageTitle(categoryName).getCanonicalUri());
226+
//check if web browser available
227+
if (viewIntent.resolveActivity(this.getPackageManager()) != null) {
228+
startActivity(viewIntent);
229+
} else {
230+
Toast toast = Toast.makeText(this, getString(R.string.no_web_browser), LENGTH_SHORT);
231+
toast.show();
232+
}
233+
return true;
234+
default:
235+
return super.onOptionsItemSelected(item);
236+
}
237+
}
238+
239+
/**
240+
* This method is called on backPressed of anyFragment in the activity.
241+
* If condition is called when mediaDetailFragment is opened.
242+
*/
243+
@Override
244+
public void onBackPressed() {
245+
if (supportFragmentManager.getBackStackEntryCount() == 1){
246+
// back to search so show search toolbar and hide navigation toolbar
247+
tabLayout.setVisibility(View.VISIBLE);
248+
viewPager.setVisibility(View.VISIBLE);
249+
mediaContainer.setVisibility(View.GONE);
250+
}
251+
super.onBackPressed();
252+
}
253+
}

app/src/main/java/fr/free/nrw/commons/category/CategoryImageUtils.java

+20-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import java.text.ParseException;
99
import java.text.SimpleDateFormat;
1010
import java.util.ArrayList;
11+
import java.util.Collections;
1112
import java.util.Date;
1213
import java.util.List;
1314

@@ -27,12 +28,30 @@ public static List<Media> getMediaList(NodeList childNodes) {
2728
List<Media> categoryImages = new ArrayList<>();
2829
for (int i = 0; i < childNodes.getLength(); i++) {
2930
Node node = childNodes.item(i);
30-
categoryImages.add(getMediaFromPage(node));
31+
if (getMediaFromPage(node).getFilename().substring(0,5).equals("File:")){
32+
categoryImages.add(getMediaFromPage(node));
33+
}
3134
}
3235

3336
return categoryImages;
3437
}
3538

39+
/**
40+
* The method iterates over the child nodes to return a list of Subcategory name
41+
* sorted alphabetically
42+
* @param childNodes
43+
* @return
44+
*/
45+
public static List<String> getSubCategoryList(NodeList childNodes) {
46+
List<String> subCategories = new ArrayList<>();
47+
for (int i = 0; i < childNodes.getLength(); i++) {
48+
Node node = childNodes.item(i);
49+
subCategories.add(getMediaFromPage(node).getFilename());
50+
}
51+
Collections.sort(subCategories);
52+
return subCategories;
53+
}
54+
3655
/**
3756
* Creates a new Media object from the XML response as received by the API
3857
* @param node

0 commit comments

Comments
 (0)