Skip to content

Commit 3697eb5

Browse files
authored
Merge pull request #1089 from maskaravivek/notifications
Integrated Notifications API
2 parents 6604398 + d12e234 commit 3697eb5

26 files changed

+669
-8
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@
8787
android:label="@string/title_activity_nearby"
8888
android:parentActivityName=".contributions.ContributionsActivity" />
8989

90+
<activity
91+
android:name=".notification.NotificationActivity"
92+
android:label="@string/navigation_item_notification" />
93+
9094
<service android:name=".upload.UploadService" />
9195

9296
<service

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import fr.free.nrw.commons.auth.SignupActivity;
99
import fr.free.nrw.commons.contributions.ContributionsActivity;
1010
import fr.free.nrw.commons.nearby.NearbyActivity;
11+
import fr.free.nrw.commons.notification.NotificationActivity;
1112
import fr.free.nrw.commons.settings.SettingsActivity;
1213
import fr.free.nrw.commons.upload.MultipleShareActivity;
1314
import fr.free.nrw.commons.upload.ShareActivity;
@@ -43,4 +44,6 @@ public abstract class ActivityBuilderModule {
4344
@ContributesAndroidInjector
4445
abstract NearbyActivity bindNearbyActivity();
4546

47+
@ContributesAndroidInjector
48+
abstract NotificationActivity bindNotificationActivity();
4649
}

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
import javax.inject.Named;
1010
import javax.inject.Singleton;
1111

12-
import dagger.Binds;
1312
import dagger.Module;
1413
import dagger.Provides;
1514
import fr.free.nrw.commons.BuildConfig;
15+
import fr.free.nrw.commons.CommonsApplication;
1616
import fr.free.nrw.commons.auth.AccountUtil;
1717
import fr.free.nrw.commons.auth.SessionManager;
1818
import fr.free.nrw.commons.caching.CacheController;
@@ -31,7 +31,9 @@
3131
@SuppressWarnings({"WeakerAccess", "unused"})
3232
public class CommonsApplicationModule {
3333
public static final String CATEGORY_AUTHORITY = "fr.free.nrw.commons.categories.contentprovider";
34+
public static final long OK_HTTP_CACHE_SIZE = 10 * 1024 * 1024;
3435

36+
private CommonsApplication application;
3537
private Context applicationContext;
3638

3739
public CommonsApplicationModule(Context applicationContext) {
@@ -100,8 +102,8 @@ public SessionManager providesSessionManager(Context context,
100102

101103
@Provides
102104
@Singleton
103-
public MediaWikiApi provideMediaWikiApi() {
104-
return new ApacheHttpClientMediaWikiApi(BuildConfig.WIKIMEDIA_API_HOST);
105+
public MediaWikiApi provideMediaWikiApi(Context context) {
106+
return new ApacheHttpClientMediaWikiApi(context, BuildConfig.WIKIMEDIA_API_HOST);
105107
}
106108

107109
@Provides
@@ -133,4 +135,4 @@ public NearbyPlaces provideNearbyPlaces() {
133135
public LruCache<String, String> provideLruCache() {
134136
return new LruCache<>(1024);
135137
}
136-
}
138+
}

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

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package fr.free.nrw.commons.mwapi;
22

3+
import android.content.Context;
34
import android.os.Build;
45
import android.support.annotation.NonNull;
56
import android.support.annotation.Nullable;
@@ -21,6 +22,8 @@
2122
import org.apache.http.util.EntityUtils;
2223
import org.mediawiki.api.ApiResult;
2324
import org.mediawiki.api.MWApi;
25+
import org.w3c.dom.Node;
26+
import org.w3c.dom.NodeList;
2427

2528
import java.io.IOException;
2629
import java.io.InputStream;
@@ -36,11 +39,17 @@
3639

3740
import fr.free.nrw.commons.BuildConfig;
3841
import fr.free.nrw.commons.PageTitle;
42+
import fr.free.nrw.commons.notification.Notification;
3943
import in.yuvi.http.fluent.Http;
4044
import io.reactivex.Observable;
4145
import io.reactivex.Single;
4246
import timber.log.Timber;
4347

48+
import static fr.free.nrw.commons.notification.NotificationType.UNKNOWN;
49+
import static fr.free.nrw.commons.notification.NotificationUtils.getNotificationFromApiResult;
50+
import static fr.free.nrw.commons.notification.NotificationUtils.getNotificationType;
51+
import static fr.free.nrw.commons.notification.NotificationUtils.isCommonsNotification;
52+
4453
/**
4554
* @author Addshore
4655
*/
@@ -50,8 +59,10 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
5059
private static final String THUMB_SIZE = "640";
5160
private AbstractHttpClient httpClient;
5261
private MWApi api;
62+
private Context context;
5363

54-
public ApacheHttpClientMediaWikiApi(String apiURL) {
64+
public ApacheHttpClientMediaWikiApi(Context context, String apiURL) {
65+
this.context = context;
5566
BasicHttpParams params = new BasicHttpParams();
5667
SchemeRegistry schemeRegistry = new SchemeRegistry();
5768
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
@@ -353,6 +364,42 @@ public String revisionsByFilename(String filename) throws IOException {
353364
.getString("/api/query/pages/page/revisions/rev");
354365
}
355366

367+
@Override
368+
@NonNull
369+
public List<Notification> getNotifications() {
370+
ApiResult notificationNode = null;
371+
try {
372+
notificationNode = api.action("query")
373+
.param("notprop", "list")
374+
.param("format", "xml")
375+
.param("meta", "notifications")
376+
.param("notfilter", "!read")
377+
.get()
378+
.getNode("/api/query/notifications/list");
379+
} catch (IOException e) {
380+
Timber.e("Failed to obtain searchCategories", e);
381+
}
382+
383+
if (notificationNode == null) {
384+
return new ArrayList<>();
385+
}
386+
387+
List<Notification> notifications = new ArrayList<>();
388+
389+
NodeList childNodes = notificationNode.getDocument().getChildNodes();
390+
391+
for (int i = 0; i < childNodes.getLength(); i++) {
392+
Node node = childNodes.item(i);
393+
if (isCommonsNotification(node)
394+
&& !getNotificationType(node).equals(UNKNOWN)) {
395+
notifications.add(getNotificationFromApiResult(context, node));
396+
}
397+
}
398+
399+
return notifications;
400+
}
401+
402+
356403
@Override
357404
public boolean existingFile(String fileSha1) throws IOException {
358405
return api.action("query")

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55

66
import java.io.IOException;
77
import java.io.InputStream;
8+
import java.util.List;
89

10+
import fr.free.nrw.commons.notification.Notification;
911
import io.reactivex.Observable;
1012
import io.reactivex.Single;
1113

@@ -43,6 +45,9 @@ public interface MediaWikiApi {
4345
@NonNull
4446
Observable<String> allCategories(String filter, int searchCatsLimit);
4547

48+
@NonNull
49+
List<Notification> getNotifications() throws IOException;
50+
4651
@NonNull
4752
Observable<String> searchTitles(String title, int searchCatsLimit);
4853

@@ -51,6 +56,8 @@ public interface MediaWikiApi {
5156

5257
boolean existingFile(String fileSha1) throws IOException;
5358

59+
60+
5461
@NonNull
5562
LogEventResult logEvents(String user, String lastModified, String queryContinue, int limit) throws IOException;
5663

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package fr.free.nrw.commons.notification;
2+
3+
import android.support.annotation.Nullable;
4+
5+
public class MarkReadResponse {
6+
@SuppressWarnings("unused") @Nullable
7+
private String result;
8+
9+
public String result() {
10+
return result;
11+
}
12+
13+
public static class QueryMarkReadResponse {
14+
@SuppressWarnings("unused") @Nullable private MarkReadResponse echomarkread;
15+
}
16+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package fr.free.nrw.commons.notification;
2+
3+
/**
4+
* Created by root on 18.12.2017.
5+
*/
6+
7+
public class Notification {
8+
public NotificationType notificationType;
9+
public String notificationText;
10+
public String date;
11+
public String description;
12+
public String link;
13+
14+
public Notification(NotificationType notificationType, String notificationText, String date, String description, String link) {
15+
this.notificationType = notificationType;
16+
this.notificationText = notificationText;
17+
this.date = date;
18+
this.description = description;
19+
this.link = link;
20+
}
21+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package fr.free.nrw.commons.notification;
2+
3+
import android.annotation.SuppressLint;
4+
import android.content.Context;
5+
import android.content.Intent;
6+
import android.net.Uri;
7+
import android.os.Bundle;
8+
import android.support.v7.widget.LinearLayoutManager;
9+
import android.support.v7.widget.RecyclerView;
10+
11+
import com.pedrogomez.renderers.RVRendererAdapter;
12+
13+
import java.util.List;
14+
15+
import javax.inject.Inject;
16+
17+
import butterknife.BindView;
18+
import butterknife.ButterKnife;
19+
import fr.free.nrw.commons.R;
20+
import fr.free.nrw.commons.theme.NavigationBaseActivity;
21+
import io.reactivex.Observable;
22+
import io.reactivex.android.schedulers.AndroidSchedulers;
23+
import io.reactivex.schedulers.Schedulers;
24+
import timber.log.Timber;
25+
26+
/**
27+
* Created by root on 18.12.2017.
28+
*/
29+
30+
public class NotificationActivity extends NavigationBaseActivity {
31+
NotificationAdapterFactory notificationAdapterFactory;
32+
33+
@BindView(R.id.listView) RecyclerView recyclerView;
34+
35+
@Inject NotificationController controller;
36+
37+
38+
@Override
39+
protected void onCreate(Bundle savedInstanceState) {
40+
super.onCreate(savedInstanceState);
41+
setContentView(R.layout.activity_notification);
42+
ButterKnife.bind(this);
43+
initListView();
44+
initDrawer();
45+
}
46+
47+
private void initListView() {
48+
recyclerView = findViewById(R.id.listView);
49+
recyclerView.setLayoutManager(new LinearLayoutManager(this));
50+
addNotifications();
51+
}
52+
53+
@SuppressLint("CheckResult")
54+
private void addNotifications() {
55+
Timber.d("Add notifications");
56+
57+
Observable.fromCallable(() -> controller.getNotifications())
58+
.subscribeOn(Schedulers.io())
59+
.observeOn(AndroidSchedulers.mainThread())
60+
.subscribe(notificationList -> {
61+
Timber.d("Number of notifications is %d", notificationList.size());
62+
setAdapter(notificationList);
63+
}, throwable -> {
64+
Timber.e(throwable, "Error occurred while loading notifications");
65+
});
66+
}
67+
68+
private void handleUrl(String url) {
69+
if (url == null || url.equals("")) {
70+
return;
71+
}
72+
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
73+
}
74+
75+
private void setAdapter(List<Notification> notificationList) {
76+
notificationAdapterFactory = new NotificationAdapterFactory(notification -> {
77+
Timber.d("Notification clicked %s", notification.link);
78+
handleUrl(notification.link);
79+
});
80+
RVRendererAdapter<Notification> adapter = notificationAdapterFactory.create(notificationList);
81+
recyclerView.setAdapter(adapter);
82+
}
83+
84+
public static void startYourself(Context context) {
85+
Intent intent = new Intent(context, NotificationActivity.class);
86+
context.startActivity(intent);
87+
}
88+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package fr.free.nrw.commons.notification;
2+
3+
import android.support.annotation.NonNull;
4+
5+
import com.pedrogomez.renderers.ListAdapteeCollection;
6+
import com.pedrogomez.renderers.RVRendererAdapter;
7+
import com.pedrogomez.renderers.RendererBuilder;
8+
9+
import java.util.Collections;
10+
import java.util.List;
11+
12+
/**
13+
* Created by root on 19.12.2017.
14+
*/
15+
16+
class NotificationAdapterFactory {
17+
private NotificationRenderer.NotificationClicked listener;
18+
19+
NotificationAdapterFactory(@NonNull NotificationRenderer.NotificationClicked listener) {
20+
this.listener = listener;
21+
}
22+
23+
public RVRendererAdapter<Notification> create(List<Notification> notifications) {
24+
RendererBuilder<Notification> builder = new RendererBuilder<Notification>()
25+
.bind(Notification.class, new NotificationRenderer(listener));
26+
ListAdapteeCollection<Notification> collection = new ListAdapteeCollection<>(
27+
notifications != null ? notifications : Collections.<Notification>emptyList());
28+
return new RVRendererAdapter<>(builder, collection);
29+
}
30+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package fr.free.nrw.commons.notification;
2+
3+
import java.io.IOException;
4+
import java.util.ArrayList;
5+
import java.util.List;
6+
7+
import javax.inject.Inject;
8+
import javax.inject.Singleton;
9+
10+
import fr.free.nrw.commons.auth.SessionManager;
11+
import fr.free.nrw.commons.mwapi.MediaWikiApi;
12+
13+
/**
14+
* Created by root on 19.12.2017.
15+
*/
16+
@Singleton
17+
public class NotificationController {
18+
19+
private MediaWikiApi mediaWikiApi;
20+
private SessionManager sessionManager;
21+
22+
@Inject
23+
public NotificationController(MediaWikiApi mediaWikiApi, SessionManager sessionManager) {
24+
this.mediaWikiApi = mediaWikiApi;
25+
this.sessionManager = sessionManager;
26+
}
27+
28+
public List<Notification> getNotifications() throws IOException {
29+
if (mediaWikiApi.validateLogin()) {
30+
return mediaWikiApi.getNotifications();
31+
} else {
32+
Boolean authTokenValidated = sessionManager.revalidateAuthToken();
33+
if (authTokenValidated != null && authTokenValidated) {
34+
return mediaWikiApi.getNotifications();
35+
}
36+
}
37+
return new ArrayList<>();
38+
}
39+
}

0 commit comments

Comments
 (0)