Added option in the action bar menu to view archived notifications (#2422)

* changed layout and implemented archived notificaitons feature

* set different texts for toolbar,menu option and no notification text in archived

* modified the startup intent for NotificationsActivity

* disabled swipe on archived

* commit

* fixed navigation drawer on notification activity

* handled on back pressed

* updated strings.xml

* removed TODO

* some minor changes

* set progress bar visibility

* some code quality changes

* commit

* some code quality changes

* removing unused import statements
This commit is contained in:
Shubham Pinjwani 2019-02-10 16:10:08 +05:30 committed by Vivek Maskara
parent cb3a570090
commit a9629c6f99
10 changed files with 186 additions and 80 deletions

View file

@ -292,7 +292,7 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag
final View notification = notificationsMenuItem.getActionView();
notificationCount = notification.findViewById(R.id.notification_count_badge);
notification.setOnClickListener(view -> {
NotificationActivity.startYourself(MainActivity.this);
NotificationActivity.startYourself(MainActivity.this, "unread");
});
this.menu = menu;
updateMenuItem();
@ -302,7 +302,7 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag
@SuppressLint("CheckResult")
private void setNotificationCount() {
Observable.fromCallable(() -> notificationController.getNotifications())
Observable.fromCallable(() -> notificationController.getNotifications(false))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::initNotificationViews,
@ -344,7 +344,7 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag
switch (item.getItemId()) {
case R.id.notifications:
// Starts notification activity on click to notification icon
NotificationActivity.startYourself(this);
NotificationActivity.startYourself(this, "unread");
return true;
case R.id.list_sheet:
if (contributionsActivityPagerAdapter.getItem(1) != null) {

View file

@ -273,6 +273,7 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
}
@Override
@Nullable
public String appendEdit(String editToken, String processedPageContent, String filename, String summary) throws IOException {
@ -557,16 +558,22 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
@Override
@NonNull
public List<Notification> getNotifications() {
public List<Notification> getNotifications(boolean archived) {
CustomApiResult notificationNode = null;
String notfilter;
try {
if (archived) {
notfilter = "read";
}else {
notfilter = "!read";
}
notificationNode = api.action("query")
.param("notprop", "list")
.param("format", "xml")
.param("meta", "notifications")
.param("notformat", "model")
.param("notwikis", "wikidatawiki|commonswiki|enwiki")
.param("notfilter","!read")
.param("notfilter", notfilter)
.get()
.getNode("/api/query/notifications/list");
} catch (IOException e) {

View file

@ -81,7 +81,7 @@ public interface MediaWikiApi {
Observable<String> allCategories(String filter, int searchCatsLimit);
@NonNull
List<Notification> getNotifications() throws IOException;
List<Notification> getNotifications(boolean archived) throws IOException;
@NonNull
boolean markNotificationAsRead(Notification notification) throws IOException;

View file

@ -5,15 +5,19 @@ import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.constraint.ConstraintLayout;
import android.support.design.widget.Snackbar;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.support.v7.widget.Toolbar;
import com.pedrogomez.renderers.RVRendererAdapter;
@ -47,7 +51,9 @@ public class NotificationActivity extends NavigationBaseActivity {
@BindView(R.id.container)
RelativeLayout relativeLayout;
@BindView(R.id.no_notification_background)
ConstraintLayout no_notification;
RelativeLayout no_notification;
@BindView(R.id.toolbar)
Toolbar toolbar;
/* @BindView(R.id.swipe_bg)
TextView swipe_bg;*/
@Inject
@ -57,6 +63,8 @@ public class NotificationActivity extends NavigationBaseActivity {
private NotificationWorkerFragment mNotificationWorkerFragment;
private RVRendererAdapter<Notification> adapter;
private List<Notification> notificationList;
MenuItem notificationmenuitem;
TextView nonotificationtext;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -67,6 +75,8 @@ public class NotificationActivity extends NavigationBaseActivity {
.findFragmentByTag(TAG_NOTIFICATION_WORKER_FRAGMENT);
initListView();
initDrawer();
nonotificationtext = (TextView)this.findViewById(R.id.no_notification_text);
setPageTitle();
}
@SuppressLint("CheckResult")
@ -84,6 +94,7 @@ public class NotificationActivity extends NavigationBaseActivity {
snackbar.show();
if (notificationList.size()==0){
setEmptyView();
relativeLayout.setVisibility(View.GONE);
no_notification.setVisibility(View.VISIBLE);
}
@ -108,27 +119,34 @@ public class NotificationActivity extends NavigationBaseActivity {
recyclerView.setLayoutManager(new LinearLayoutManager(this));
DividerItemDecoration itemDecor = new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL);
recyclerView.addItemDecoration(itemDecor);
refresh();
}
private void refresh() {
if (!NetworkUtils.isInternetConnectionEstablished(this)) {
progressBar.setVisibility(View.GONE);
Snackbar.make(relativeLayout, R.string.no_internet, Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.retry, view -> refresh()).show();
if (getIntent().getStringExtra("title").equals("read")) {
refresh(true);
} else {
progressBar.setVisibility(View.VISIBLE);
addNotifications();
refresh(false);
}
}
private void refresh(boolean archived) {
if (!NetworkUtils.isInternetConnectionEstablished(this)) {
progressBar.setVisibility(View.GONE);
Snackbar.make(relativeLayout, R.string.no_internet, Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.retry, view -> refresh(archived)).show();
} else {
addNotifications(archived);
}
progressBar.setVisibility(View.VISIBLE);
no_notification.setVisibility(View.GONE);
relativeLayout.setVisibility(View.VISIBLE);
}
@SuppressLint("CheckResult")
private void addNotifications() {
private void addNotifications(boolean archived) {
Timber.d("Add notifications");
if (mNotificationWorkerFragment == null) {
Observable.fromCallable(() -> {
progressBar.setVisibility(View.VISIBLE);
return controller.getNotifications();
return controller.getNotifications(archived);
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
@ -137,10 +155,12 @@ public class NotificationActivity extends NavigationBaseActivity {
Timber.d("Number of notifications is %d", notificationList.size());
this.notificationList = notificationList;
if (notificationList.size()==0){
setEmptyView();
relativeLayout.setVisibility(View.GONE);
no_notification.setVisibility(View.VISIBLE);
} else {
setAdapter(notificationList);
} if (notificationmenuitem != null) {
}
progressBar.setVisibility(View.GONE);
}, throwable -> {
@ -154,6 +174,31 @@ public class NotificationActivity extends NavigationBaseActivity {
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_notifications, menu);
notificationmenuitem = menu.findItem(R.id.archived);
setMenuItemTitle();
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.archived:
if (item.getTitle().equals(getString(R.string.menu_option_archived))) {
NotificationActivity.startYourself(NotificationActivity.this, "read");
}else if (item.getTitle().equals(getString(R.string.menu_option_unread))) {
onBackPressed();
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void handleUrl(String url) {
if (url == null || url.equals("")) {
return;
@ -167,9 +212,18 @@ public class NotificationActivity extends NavigationBaseActivity {
/*progressBar.setVisibility(View.GONE);
recyclerView.setVisibility(View.GONE);*/
relativeLayout.setVisibility(View.GONE);
setEmptyView();
no_notification.setVisibility(View.VISIBLE);
return;
}
boolean isarchivedvisible;
if (getIntent().getStringExtra("title").equals("read")) {
isarchivedvisible = true;
} else {
isarchivedvisible = false;
}
notificationAdapterFactory = new NotificationAdapterFactory(new NotificationRenderer.NotificationClicked() {
@Override
public void notificationClicked(Notification notification) {
@ -182,16 +236,45 @@ public class NotificationActivity extends NavigationBaseActivity {
Timber.d("Notification to mark as read %s", notification.notificationId);
removeNotification(notification);
}
});
}, isarchivedvisible);
adapter = notificationAdapterFactory.create(notificationList);
relativeLayout.setVisibility(View.VISIBLE);
no_notification.setVisibility(View.GONE);
recyclerView.setAdapter(adapter);
}
public static void startYourself(Context context) {
public static void startYourself(Context context, String title) {
Intent intent = new Intent(context, NotificationActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra("title", title);
context.startActivity(intent);
}
private void setPageTitle() {
if (getSupportActionBar() != null) {
if (getIntent().getStringExtra("title").equals("read")) {
getSupportActionBar().setTitle(R.string.archived_notifications);
} else {
getSupportActionBar().setTitle(R.string.notifications);
}
}
}
private void setEmptyView() {
if (getIntent().getStringExtra("title").equals("read")) {
nonotificationtext.setText(R.string.no_archived_notification);
}else {
nonotificationtext.setText(R.string.no_notification);
}
}
private void setMenuItemTitle() {
if (getIntent().getStringExtra("title").equals("read")) {
notificationmenuitem.setTitle(R.string.menu_option_unread);
}else {
notificationmenuitem.setTitle(R.string.menu_option_archived);
}
}
}

View file

@ -15,14 +15,16 @@ import java.util.List;
class NotificationAdapterFactory {
private NotificationRenderer.NotificationClicked listener;
private boolean isarchivedvisible = false;
NotificationAdapterFactory(@NonNull NotificationRenderer.NotificationClicked listener) {
NotificationAdapterFactory(@NonNull NotificationRenderer.NotificationClicked listener, boolean isarchivedvisible) {
this.listener = listener;
this.isarchivedvisible = isarchivedvisible;
}
public RVRendererAdapter<Notification> create(List<Notification> notifications) {
RendererBuilder<Notification> builder = new RendererBuilder<Notification>()
.bind(Notification.class, new NotificationRenderer(listener));
.bind(Notification.class, new NotificationRenderer(listener, isarchivedvisible));
ListAdapteeCollection<Notification> collection = new ListAdapteeCollection<>(
notifications != null ? notifications : Collections.<Notification>emptyList());
return new RVRendererAdapter<>(builder, collection);

View file

@ -25,13 +25,13 @@ public class NotificationController {
this.sessionManager = sessionManager;
}
public List<Notification> getNotifications() throws IOException {
public List<Notification> getNotifications(boolean archived) throws IOException {
if (mediaWikiApi.validateLogin()) {
return mediaWikiApi.getNotifications();
return mediaWikiApi.getNotifications(archived);
} else {
Boolean authTokenValidated = sessionManager.revalidateAuthToken();
if (authTokenValidated != null && authTokenValidated) {
return mediaWikiApi.getNotifications();
return mediaWikiApi.getNotifications(archived);
}
}
return new ArrayList<>();

View file

@ -35,10 +35,12 @@ public class NotificationRenderer extends Renderer<Notification> {
LinearLayout bottomLayout;
private NotificationClicked listener;
private boolean isarchivedvisible = false;
NotificationRenderer(NotificationClicked listener) {
NotificationRenderer(NotificationClicked listener, boolean isarchivedvisible) {
this.listener = listener;
this.isarchivedvisible = isarchivedvisible;
}
@OnClick(R.id.bottom)
void onBottomLayoutClicked(){
@ -59,7 +61,11 @@ public class NotificationRenderer extends Renderer<Notification> {
protected View inflate(LayoutInflater layoutInflater, ViewGroup viewGroup) {
View inflatedView = layoutInflater.inflate(R.layout.item_notification, viewGroup, false);
ButterKnife.bind(this, inflatedView);
if (isarchivedvisible) {
swipeLayout.setSwipeEnabled(false);
}else {
swipeLayout.setSwipeEnabled(true);
}
swipeLayout.addDrag(SwipeLayout.DragEdge.Top, bottomLayout);
swipeLayout.addRevealListener(R.id.bottom_wrapper_child1, (child, edge, fraction, distance) -> {
View star = child.findViewById(R.id.star);

View file

@ -7,7 +7,6 @@
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -17,59 +16,53 @@
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_height="wrap_content" />
<android.support.v7.widget.RecyclerView
android:id="@+id/listView"
<RelativeLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/toolbar"
/>
android:layout_below="@id/toolbar">
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_height="wrap_content" />
<android.support.v7.widget.RecyclerView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/no_notification_background"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/toolbar">
<ImageView
android:id="@+id/imageView"
android:layout_width="110dp"
android:layout_height="160dp"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
app:srcCompat="@drawable/ic_notifications_off_black_24dp" />
<TextView
android:id="@+id/no_notification_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/imageView"
android:layout_centerHorizontal="true"
android:text="@string/no_notification"
android:textSize="20sp" />
</RelativeLayout>
</RelativeLayout>
<android.support.constraint.ConstraintLayout
android:id="@+id/no_notification_background"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="118dp"
android:layout_height="172dp"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toTopOf="@+id/textView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.501"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.763"
app:srcCompat="@drawable/ic_notifications_off_black_24dp" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="188dp"
android:text="@string/no_notification"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</android.support.constraint.ConstraintLayout>
<android.support.design.widget.NavigationView
android:id="@+id/navigation_view"
android:layout_width="wrap_content"

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/archived"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:icon="@drawable/ic_more_vert_white_24dp"
android:title="@string/menu_option_archived" />
</menu>

View file

@ -378,6 +378,7 @@
<string name="contributions_fragment">Contributions</string>
<string name="nearby_fragment">Nearby</string>
<string name="notifications">Notifications</string>
<string name="archived_notifications">Notifications(archived)</string>
<string name="display_nearby_notification">Display nearby notification</string>
<string name="display_nearby_notification_summary">Tap here to see the nearest place that needs pictures</string>
<string name="no_close_nearby">No nearby places found close to you</string>
@ -462,7 +463,11 @@ Upload your first media by touching the camera or gallery icon above.</string>
<string name="no_image_uploaded">No images uploaded</string>
<string name="no_notification">You have no unread Notification</string>
<string name="no_archived_notification">You have no archived notification</string>
<string name="share_logs_using">Share logs using</string>
<string name="menu_option_archived">View archived</string>
<string name="menu_option_unread">View unread</string>
<string name="error_occurred_in_picking_images">Error occurred while picking images</string>
<string name="image_chooser_title">Choose Images to upload</string>