Skip to content

Commit 1b62ac4

Browse files
vanshikaaroramaskaravivek
authored andcommitted
Code to retrive unknown notification and UI (commons-app#2340)
* request change, changed notification icon * Completed task 1 of the work * commit changes * commit changes * updated notification class * before notification id * gradle reverted * Minor changes to mark notifications as read * commit changes * delete on swipe * notification count * sipe to delete * changes * worked on changes requested * commit changes * Fix notification count * reviewed changes * round icon, swipe with icon * Fix pending NPE issues with notifications * final commit * graddle changes * removed changes for testing
1 parent 9451b00 commit 1b62ac4

22 files changed

+381
-195
lines changed

app/build.gradle

+3
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ dependencies {
8888
implementation "com.android.support:customtabs:$SUPPORT_LIB_VERSION"
8989
implementation "com.android.support:cardview-v7:$SUPPORT_LIB_VERSION"
9090
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
91+
//swipe_layout
92+
implementation 'com.daimajia.swipelayout:library:1.2.0@aar'
93+
implementation 'com.nineoldandroids:library:2.4.0'
9194
}
9295

9396
android {

app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java

+1-13
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
import android.widget.Toast;
3232

3333
import java.util.ArrayList;
34-
import java.util.concurrent.CountDownLatch;
3534

3635
import javax.inject.Inject;
3736
import javax.inject.Named;
@@ -56,7 +55,6 @@
5655
import fr.free.nrw.commons.nearby.NearbyNotificationCardView;
5756
import fr.free.nrw.commons.nearby.Place;
5857
import fr.free.nrw.commons.notification.NotificationController;
59-
import fr.free.nrw.commons.notification.UnreadNotificationsCheckAsync;
6058
import fr.free.nrw.commons.settings.Prefs;
6159
import fr.free.nrw.commons.upload.UploadService;
6260
import fr.free.nrw.commons.utils.ConfigUtils;
@@ -87,8 +85,7 @@ public class ContributionsFragment
8785
@Inject @Named("default_preferences") BasicKvStore defaultKvStore;
8886
@Inject ContributionDao contributionDao;
8987
@Inject MediaWikiApi mediaWikiApi;
90-
@Inject NotificationController notificationController;
91-
@Inject NearbyController nearbyController;
88+
@Inject NearbyController nearbyController;
9289

9390
private ArrayList<DataSetObserver> observersWaitingForLoad = new ArrayList<>();
9491
private UploadService uploadService;
@@ -213,7 +210,6 @@ public void onAttach(Context context) {
213210
if (((MainActivity)getActivity()).isAuthCookieAcquired && !isFragmentAttachedBefore) {
214211
onAuthCookieAcquired(((MainActivity)getActivity()).uploadServiceIntent);
215212
isFragmentAttachedBefore = true;
216-
new UnreadNotificationsCheckAsync((MainActivity) getActivity(), notificationController).execute();
217213

218214
}
219215
}
@@ -478,14 +474,6 @@ public void betaSetUploadCount(int betaUploadCount) {
478474
displayUploadCount(betaUploadCount);
479475
}
480476

481-
/**
482-
* Updates notification indicator on toolbar to indicate there are unread notifications
483-
* @param isThereUnreadNotifications true if user checked notifications before last notification date
484-
*/
485-
public void updateNotificationsNotification(boolean isThereUnreadNotifications) {
486-
((MainActivity)getActivity()).updateNotificationIcon(isThereUnreadNotifications);
487-
}
488-
489477
@Override
490478
public void onPause() {
491479
super.onPause();

app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.java

+44-35
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package fr.free.nrw.commons.contributions;
22

3+
import android.annotation.SuppressLint;
34
import android.app.AlertDialog;
45
import android.content.Intent;
56
import android.content.pm.PackageManager;
@@ -8,14 +9,14 @@
89
import android.support.v4.app.Fragment;
910
import android.support.v4.app.FragmentManager;
1011
import android.support.v4.app.FragmentPagerAdapter;
11-
import android.support.v4.content.ContextCompat;
1212
import android.support.v4.view.ViewPager;
1313
import android.view.LayoutInflater;
1414
import android.view.Menu;
1515
import android.view.MenuInflater;
1616
import android.view.MenuItem;
1717
import android.view.View;
1818
import android.widget.ImageView;
19+
import android.widget.TextView;
1920

2021
import com.esafirm.imagepicker.features.ImagePicker;
2122
import com.esafirm.imagepicker.model.Image;
@@ -35,10 +36,15 @@
3536
import fr.free.nrw.commons.location.LocationServiceManager;
3637
import fr.free.nrw.commons.nearby.NearbyFragment;
3738
import fr.free.nrw.commons.nearby.NearbyNotificationCardView;
39+
import fr.free.nrw.commons.notification.Notification;
3840
import fr.free.nrw.commons.notification.NotificationActivity;
41+
import fr.free.nrw.commons.notification.NotificationController;
3942
import fr.free.nrw.commons.upload.UploadService;
4043
import fr.free.nrw.commons.utils.ImageUtils;
4144
import fr.free.nrw.commons.utils.IntentUtils;
45+
import io.reactivex.Observable;
46+
import io.reactivex.android.schedulers.AndroidSchedulers;
47+
import io.reactivex.schedulers.Schedulers;
4248
import timber.log.Timber;
4349

4450
import static android.content.ContentResolver.requestSync;
@@ -58,6 +64,8 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag
5864
@Inject
5965
@Named("default_preferences")
6066
public BasicKvStore defaultKvStore;
67+
@Inject
68+
NotificationController notificationController;
6169

6270

6371
public Intent uploadServiceIntent;
@@ -69,10 +77,12 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag
6977

7078
public boolean isContributionsFragmentVisible = true; // False means nearby fragment is visible
7179
private Menu menu;
72-
private boolean isThereUnreadNotifications = false;
7380

7481
private boolean onOrientationChanged = false;
7582

83+
private MenuItem notificationsMenuItem;
84+
private TextView notificationCount;
85+
7686
public void onCreate(Bundle savedInstanceState) {
7787
super.onCreate(savedInstanceState);
7888
setContentView(R.layout.activity_contributions);
@@ -82,6 +92,7 @@ public void onCreate(Bundle savedInstanceState) {
8292
initDrawer();
8393
setTitle(getString(R.string.navigation_item_home)); // Should I create a new string variable with another name instead?
8494

95+
8596
if (savedInstanceState != null ) {
8697
onOrientationChanged = true; // Will be used in nearby fragment to determine significant update of map
8798

@@ -126,13 +137,11 @@ private void addTabsAndFragments() {
126137
tabLayout.getTabAt(1).setCustomView(nearbyTabLinearLayout);
127138

128139
nearbyInfo.setOnClickListener(view ->
129-
new AlertDialog.Builder(MainActivity.this)
130-
.setTitle(R.string.title_activity_nearby)
131-
.setMessage(R.string.showcase_view_whole_nearby_activity)
132-
.setCancelable(true)
133-
.setPositiveButton(android.R.string.ok, (dialog, id) -> dialog.cancel())
134-
.create()
135-
.show()
140+
new AlertDialog.Builder(MainActivity.this).setTitle(R.string.title_activity_nearby).setMessage(R.string.showcase_view_whole_nearby_activity)
141+
.setCancelable(true)
142+
.setPositiveButton(android.R.string.ok, (dialog, id) -> dialog.cancel())
143+
.create()
144+
.show()
136145
);
137146

138147
if (uploadServiceIntent != null) {
@@ -278,20 +287,35 @@ public boolean onCreateOptionsMenu(Menu menu) {
278287
MenuInflater inflater = getMenuInflater();
279288
inflater.inflate(R.menu.contribution_activity_notification_menu, menu);
280289

281-
if (!isThereUnreadNotifications) {
282-
// TODO: used vectors are not compatible with API 19 and below, change them
283-
menu.findItem(R.id.notifications).setIcon(ContextCompat.getDrawable(this, R.drawable.ic_notification_white_clip_art));
284-
} else {
285-
menu.findItem(R.id.notifications).setIcon(ContextCompat.getDrawable(this, R.drawable.ic_notification_white_clip_art_dot));
286-
}
287-
290+
notificationsMenuItem = menu.findItem(R.id.notifications);
291+
final View notification = notificationsMenuItem.getActionView();
292+
notificationCount = notification.findViewById(R.id.notification_count_badge);
293+
notification.setOnClickListener(view -> NotificationActivity.startYourself(MainActivity.this));
288294
this.menu = menu;
289-
290295
updateMenuItem();
291-
296+
setNotificationCount();
292297
return true;
293298
}
294299

300+
@SuppressLint("CheckResult")
301+
private void setNotificationCount() {
302+
Observable.fromCallable(() -> notificationController.getNotifications())
303+
.subscribeOn(Schedulers.io())
304+
.observeOn(AndroidSchedulers.mainThread())
305+
.subscribe(this::initNotificationViews,
306+
throwable -> Timber.e(throwable, "Error occurred while loading notifications"));
307+
}
308+
309+
private void initNotificationViews(List<Notification> notificationList) {
310+
Timber.d("Number of notifications is %d", notificationList.size());
311+
if (notificationList.isEmpty()) {
312+
notificationCount.setVisibility(View.GONE);
313+
} else {
314+
notificationCount.setVisibility(View.VISIBLE);
315+
notificationCount.setText(String.valueOf(notificationList.size()));
316+
}
317+
}
318+
295319
/**
296320
* Responsible with displaying required menu items according to displayed fragment.
297321
* Notifications icon when contributions list is visible, list sheet icon when nearby is visible
@@ -319,7 +343,7 @@ public boolean onOptionsItemSelected(MenuItem item) {
319343
// Starts notification activity on click to notification icon
320344
NotificationActivity.startYourself(this);
321345
return true;
322-
case R.id.list_sheet:
346+
case R.id.list_sheet:NotificationActivity.startYourself(this);
323347
if (contributionsActivityPagerAdapter.getItem(1) != null) {
324348
((NearbyFragment)contributionsActivityPagerAdapter.getItem(1)).listOptionMenuIteClicked();
325349
}
@@ -335,21 +359,6 @@ private boolean deviceHasCamera() {
335359
pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT);
336360
}
337361

338-
/**
339-
* Update notification icon if there is an unread notification
340-
* @param isThereUnreadNotifications true if user didn't visit notifications activity since
341-
* latest notification came to account
342-
*/
343-
public void updateNotificationIcon(boolean isThereUnreadNotifications) {
344-
if (!isThereUnreadNotifications) {
345-
this.isThereUnreadNotifications = false;
346-
menu.findItem(R.id.notifications).setIcon(ContextCompat.getDrawable(this, R.drawable.ic_notification_white_clip_art));
347-
} else {
348-
this.isThereUnreadNotifications = true;
349-
menu.findItem(R.id.notifications).setIcon(ContextCompat.getDrawable(this, R.drawable.ic_notification_white_clip_art_dot));
350-
}
351-
}
352-
353362
public class ContributionsActivityPagerAdapter extends FragmentPagerAdapter {
354363
FragmentManager fragmentManager;
355364
private boolean isContributionsListFragment = true; // to know what to put in first tab, Contributions of Media Details
@@ -471,7 +480,7 @@ public void onRequestPermissionsResult(int requestCode,
471480
if (!isContributionsFragmentVisible) {
472481
viewPager.setCurrentItem(CONTRIBUTIONS_TAB_POSITION);
473482

474-
// TODO: If contrib fragment is visible and location permission is not given, display permission request button
483+
// TODO: If contrib fragment is visible and location permission is not given, display permission request button
475484
} else {
476485

477486
}

app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java

-11
Original file line numberDiff line numberDiff line change
@@ -164,17 +164,6 @@ public JsonKvStore providesDirectNearbyUploadKvStore(Context context, Gson gson)
164164
return new JsonKvStore(context, "direct_nearby_upload_prefs", gson);
165165
}
166166

167-
/**
168-
* Is used to determine when user is viewed notifications activity last
169-
* @param context
170-
* @return date of lastReadNotificationDate
171-
*/
172-
@Provides
173-
@Named("last_read_notification_date")
174-
public BasicKvStore providesLastReadNotificationDateKvStore(Context context) {
175-
return new BasicKvStore(context, "last_read_notification_date");
176-
}
177-
178167
@Provides
179168
public UploadController providesUploadController(SessionManager sessionManager,
180169
@Named("default_preferences") BasicKvStore kvStore,

app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java

+19-2
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import fr.free.nrw.commons.notification.NotificationUtils;
5555
import fr.free.nrw.commons.utils.ConfigUtils;
5656
import fr.free.nrw.commons.utils.DateUtils;
57+
import fr.free.nrw.commons.utils.StringUtils;
5758
import fr.free.nrw.commons.utils.ViewUtil;
5859
import in.yuvi.http.fluent.Http;
5960
import io.reactivex.Observable;
@@ -82,7 +83,7 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
8283
private Gson gson;
8384
private final OkHttpClient okHttpClient;
8485
private final String WIKIMEDIA_CAMPAIGNS_BASE_URL =
85-
"https://raw.githubusercontent.com/commons-app/campaigns/master/campaigns.json";
86+
"https://raw.githubusercontent.com/commons-app/campaigns/master/campaigns.json";
8687

8788
private final String ERROR_CODE_BAD_TOKEN = "badtoken";
8889

@@ -587,6 +588,7 @@ public List<Notification> getNotifications() {
587588
.param("meta", "notifications")
588589
.param("notformat", "model")
589590
.param("notwikis", "wikidatawiki|commonswiki|enwiki")
591+
.param("notfilter","!read")
590592
.get()
591593
.getNode("/api/query/notifications/list");
592594
} catch (IOException e) {
@@ -599,11 +601,26 @@ public List<Notification> getNotifications() {
599601
|| notificationNode.getDocument().getChildNodes().getLength() == 0) {
600602
return new ArrayList<>();
601603
}
602-
603604
NodeList childNodes = notificationNode.getDocument().getChildNodes();
604605
return NotificationUtils.getNotificationsFromList(context, childNodes);
605606
}
606607

608+
@Override
609+
public boolean markNotificationAsRead(Notification notification) throws IOException {
610+
Timber.d("Trying to mark notification as read: %s", notification.toString());
611+
String result = api.action("echomarkread")
612+
.param("token", getEditToken())
613+
.param("list", notification.notificationId)
614+
.post()
615+
.getString("/api/query/echomarkread/@result");
616+
617+
if (StringUtils.isNullOrWhiteSpace(result)) {
618+
return false;
619+
}
620+
621+
return result.equals("success");
622+
}
623+
607624
/**
608625
* The method takes categoryName as input and returns a List of Subcategories
609626
* It uses the generator query API to get the subcategories in a category, 500 at a time.

app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java

+3
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ public interface MediaWikiApi {
8484
@NonNull
8585
List<Notification> getNotifications() throws IOException;
8686

87+
@NonNull
88+
boolean markNotificationAsRead(Notification notification) throws IOException;
89+
8790
@NonNull
8891
Observable<String> searchTitles(String title, int searchCatsLimit);
8992

app/src/main/java/fr/free/nrw/commons/notification/Notification.java

+17-1
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,30 @@ public class Notification {
1212
public String link;
1313
public String iconUrl;
1414
public String dateWithYear;
15+
public String notificationId;
1516

16-
public Notification(NotificationType notificationType, String notificationText, String date, String description, String link, String iconUrl, String dateWithYear) {
17+
public Notification(NotificationType notificationType, String notificationText, String date, String description, String link, String iconUrl, String dateWithYear, String notificationId) {
1718
this.notificationType = notificationType;
1819
this.notificationText = notificationText;
1920
this.date = date;
2021
this.description = description;
2122
this.link = link;
2223
this.iconUrl = iconUrl;
2324
this.dateWithYear = dateWithYear;
25+
this.notificationId=notificationId;
26+
}
27+
28+
@Override
29+
public String toString() {
30+
return "Notification" +
31+
"notificationType='" + notificationType + '\'' +
32+
", notificationText='" + notificationText + '\'' +
33+
", date='" + date + '\'' +
34+
", description='" + description + '\'' +
35+
", link='" + link + '\'' +
36+
", iconUrl='" + iconUrl + '\'' +
37+
", dateWithYear=" + dateWithYear +
38+
", notificationId='" + notificationId + '\'' +
39+
'}';
2440
}
2541
}

0 commit comments

Comments
 (0)