Skip to content

Integrated Notifications API #1089

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@
android:label="@string/title_activity_nearby"
android:parentActivityName=".contributions.ContributionsActivity" />

<activity
android:name=".notification.NotificationActivity"
android:label="@string/navigation_item_notification" />

<service android:name=".upload.UploadService" />

<service
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import fr.free.nrw.commons.auth.SignupActivity;
import fr.free.nrw.commons.contributions.ContributionsActivity;
import fr.free.nrw.commons.nearby.NearbyActivity;
import fr.free.nrw.commons.notification.NotificationActivity;
import fr.free.nrw.commons.settings.SettingsActivity;
import fr.free.nrw.commons.upload.MultipleShareActivity;
import fr.free.nrw.commons.upload.ShareActivity;
Expand Down Expand Up @@ -43,4 +44,6 @@ public abstract class ActivityBuilderModule {
@ContributesAndroidInjector
abstract NearbyActivity bindNearbyActivity();

@ContributesAndroidInjector
abstract NotificationActivity bindNotificationActivity();
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
import javax.inject.Named;
import javax.inject.Singleton;

import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import fr.free.nrw.commons.BuildConfig;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.auth.AccountUtil;
import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.caching.CacheController;
Expand All @@ -31,7 +31,9 @@
@SuppressWarnings({"WeakerAccess", "unused"})
public class CommonsApplicationModule {
public static final String CATEGORY_AUTHORITY = "fr.free.nrw.commons.categories.contentprovider";
public static final long OK_HTTP_CACHE_SIZE = 10 * 1024 * 1024;

private CommonsApplication application;
private Context applicationContext;

public CommonsApplicationModule(Context applicationContext) {
Expand Down Expand Up @@ -100,8 +102,8 @@ public SessionManager providesSessionManager(Context context,

@Provides
@Singleton
public MediaWikiApi provideMediaWikiApi() {
return new ApacheHttpClientMediaWikiApi(BuildConfig.WIKIMEDIA_API_HOST);
public MediaWikiApi provideMediaWikiApi(Context context) {
return new ApacheHttpClientMediaWikiApi(context, BuildConfig.WIKIMEDIA_API_HOST);
}

@Provides
Expand Down Expand Up @@ -133,4 +135,4 @@ public NearbyPlaces provideNearbyPlaces() {
public LruCache<String, String> provideLruCache() {
return new LruCache<>(1024);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package fr.free.nrw.commons.mwapi;

import android.content.Context;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
Expand All @@ -21,6 +22,8 @@
import org.apache.http.util.EntityUtils;
import org.mediawiki.api.ApiResult;
import org.mediawiki.api.MWApi;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.io.IOException;
import java.io.InputStream;
Expand All @@ -36,11 +39,17 @@

import fr.free.nrw.commons.BuildConfig;
import fr.free.nrw.commons.PageTitle;
import fr.free.nrw.commons.notification.Notification;
import in.yuvi.http.fluent.Http;
import io.reactivex.Observable;
import io.reactivex.Single;
import timber.log.Timber;

import static fr.free.nrw.commons.notification.NotificationType.UNKNOWN;
import static fr.free.nrw.commons.notification.NotificationUtils.getNotificationFromApiResult;
import static fr.free.nrw.commons.notification.NotificationUtils.getNotificationType;
import static fr.free.nrw.commons.notification.NotificationUtils.isCommonsNotification;

/**
* @author Addshore
*/
Expand All @@ -50,8 +59,10 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
private static final String THUMB_SIZE = "640";
private AbstractHttpClient httpClient;
private MWApi api;
private Context context;

public ApacheHttpClientMediaWikiApi(String apiURL) {
public ApacheHttpClientMediaWikiApi(Context context, String apiURL) {
this.context = context;
BasicHttpParams params = new BasicHttpParams();
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
Expand Down Expand Up @@ -353,6 +364,42 @@ public String revisionsByFilename(String filename) throws IOException {
.getString("/api/query/pages/page/revisions/rev");
}

@Override
@NonNull
public List<Notification> getNotifications() {
ApiResult notificationNode = null;
try {
notificationNode = api.action("query")
.param("notprop", "list")
.param("format", "xml")
.param("meta", "notifications")
.param("notfilter", "!read")
.get()
.getNode("/api/query/notifications/list");
} catch (IOException e) {
Timber.e("Failed to obtain searchCategories", e);
}

if (notificationNode == null) {
return new ArrayList<>();
}

List<Notification> notifications = new ArrayList<>();

NodeList childNodes = notificationNode.getDocument().getChildNodes();

for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
if (isCommonsNotification(node)
&& !getNotificationType(node).equals(UNKNOWN)) {
notifications.add(getNotificationFromApiResult(context, node));
}
}

return notifications;
}


@Override
public boolean existingFile(String fileSha1) throws IOException {
return api.action("query")
Expand Down
7 changes: 7 additions & 0 deletions app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import fr.free.nrw.commons.notification.Notification;
import io.reactivex.Observable;
import io.reactivex.Single;

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

@NonNull
List<Notification> getNotifications() throws IOException;

@NonNull
Observable<String> searchTitles(String title, int searchCatsLimit);

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

boolean existingFile(String fileSha1) throws IOException;



@NonNull
LogEventResult logEvents(String user, String lastModified, String queryContinue, int limit) throws IOException;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package fr.free.nrw.commons.notification;

import android.support.annotation.Nullable;

public class MarkReadResponse {
@SuppressWarnings("unused") @Nullable
private String result;

public String result() {
return result;
}

public static class QueryMarkReadResponse {
@SuppressWarnings("unused") @Nullable private MarkReadResponse echomarkread;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package fr.free.nrw.commons.notification;

/**
* Created by root on 18.12.2017.
*/

public class Notification {
public NotificationType notificationType;
public String notificationText;
public String date;
public String description;
public String link;

public Notification(NotificationType notificationType, String notificationText, String date, String description, String link) {
this.notificationType = notificationType;
this.notificationText = notificationText;
this.date = date;
this.description = description;
this.link = link;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package fr.free.nrw.commons.notification;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;

import com.pedrogomez.renderers.RVRendererAdapter;

import java.util.List;

import javax.inject.Inject;

import butterknife.BindView;
import butterknife.ButterKnife;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.theme.NavigationBaseActivity;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import timber.log.Timber;

/**
* Created by root on 18.12.2017.
*/

public class NotificationActivity extends NavigationBaseActivity {
NotificationAdapterFactory notificationAdapterFactory;

@BindView(R.id.listView) RecyclerView recyclerView;

@Inject NotificationController controller;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_notification);
ButterKnife.bind(this);
initListView();
initDrawer();
}

private void initListView() {
recyclerView = findViewById(R.id.listView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
addNotifications();
}

@SuppressLint("CheckResult")
private void addNotifications() {
Timber.d("Add notifications");

Observable.fromCallable(() -> controller.getNotifications())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(notificationList -> {
Timber.d("Number of notifications is %d", notificationList.size());
setAdapter(notificationList);
}, throwable -> {
Timber.e(throwable, "Error occurred while loading notifications");
});
}

private void handleUrl(String url) {
if (url == null || url.equals("")) {
return;
}
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
}

private void setAdapter(List<Notification> notificationList) {
notificationAdapterFactory = new NotificationAdapterFactory(notification -> {
Timber.d("Notification clicked %s", notification.link);
handleUrl(notification.link);
});
RVRendererAdapter<Notification> adapter = notificationAdapterFactory.create(notificationList);
recyclerView.setAdapter(adapter);
}

public static void startYourself(Context context) {
Intent intent = new Intent(context, NotificationActivity.class);
context.startActivity(intent);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package fr.free.nrw.commons.notification;

import android.support.annotation.NonNull;

import com.pedrogomez.renderers.ListAdapteeCollection;
import com.pedrogomez.renderers.RVRendererAdapter;
import com.pedrogomez.renderers.RendererBuilder;

import java.util.Collections;
import java.util.List;

/**
* Created by root on 19.12.2017.
*/

class NotificationAdapterFactory {
private NotificationRenderer.NotificationClicked listener;

NotificationAdapterFactory(@NonNull NotificationRenderer.NotificationClicked listener) {
this.listener = listener;
}

public RVRendererAdapter<Notification> create(List<Notification> notifications) {
RendererBuilder<Notification> builder = new RendererBuilder<Notification>()
.bind(Notification.class, new NotificationRenderer(listener));
ListAdapteeCollection<Notification> collection = new ListAdapteeCollection<>(
notifications != null ? notifications : Collections.<Notification>emptyList());
return new RVRendererAdapter<>(builder, collection);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package fr.free.nrw.commons.notification;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.inject.Inject;
import javax.inject.Singleton;

import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.mwapi.MediaWikiApi;

/**
* Created by root on 19.12.2017.
*/
@Singleton
public class NotificationController {

private MediaWikiApi mediaWikiApi;
private SessionManager sessionManager;

@Inject
public NotificationController(MediaWikiApi mediaWikiApi, SessionManager sessionManager) {
this.mediaWikiApi = mediaWikiApi;
this.sessionManager = sessionManager;
}

public List<Notification> getNotifications() throws IOException {
if (mediaWikiApi.validateLogin()) {
return mediaWikiApi.getNotifications();
} else {
Boolean authTokenValidated = sessionManager.revalidateAuthToken();
if (authTokenValidated != null && authTokenValidated) {
return mediaWikiApi.getNotifications();
}
}
return new ArrayList<>();
}
}
Loading