feat(ui): show forum notification count on drawer menu

This commit is contained in:
hyb1996 2018-04-03 18:17:36 +08:00
parent aeae51bb74
commit c39ba26e1f
11 changed files with 290 additions and 18 deletions

View File

@ -2,12 +2,14 @@ package com.stardust.scriptdroid.network;
import com.jakewharton.retrofit2.adapter.rxjava2.HttpException;
import com.stardust.scriptdroid.network.api.UserApi;
import com.stardust.scriptdroid.network.entity.notification.Notification;
import com.stardust.scriptdroid.network.entity.notification.NotificationResponse;
import com.stardust.scriptdroid.network.entity.user.User;
import com.stardust.util.Objects;
import org.greenrobot.eventbus.EventBus;
import java.util.Collections;
import java.util.List;
import io.reactivex.Observable;
import io.reactivex.schedulers.Schedulers;
@ -21,7 +23,6 @@ import retrofit2.Retrofit;
public class UserService {
public static class LoginStateChange {
private final boolean mOnline;
@ -116,4 +117,13 @@ public class UserService {
.doOnNext(this::setUser)
.doOnError(error -> setUser(null));
}
public Observable<List<Notification>> getNotifications() {
return NodeBB.getInstance().getRetrofit()
.create(UserApi.class)
.getNotifitions()
.map(NotificationResponse::getNotifications);
}
}

View File

@ -1,5 +1,6 @@
package com.stardust.scriptdroid.network.api;
import com.stardust.scriptdroid.network.entity.notification.NotificationResponse;
import com.stardust.scriptdroid.network.entity.user.User;
import java.util.Map;
@ -33,4 +34,7 @@ public interface UserApi {
@POST("/logout")
Observable<ResponseBody> logout(@HeaderMap Map<String, String> csrfToken);
@GET("/api/notifications")
Observable<NotificationResponse> getNotifitions();
}

View File

@ -0,0 +1,134 @@
package com.stardust.scriptdroid.network.entity.notification;
import com.stardust.scriptdroid.network.entity.user.User;
public class Notification {
private boolean read;
private String mergeId;
private String importance;
private String nid;
private String type;
private String path;
private String readClass;
private String datetime;
private String from;
private String bodyShort;
private String datetimeISO;
private User user;
public void setRead(boolean read) {
this.read = read;
}
public boolean isRead() {
return read;
}
public void setMergeId(String mergeId) {
this.mergeId = mergeId;
}
public String getMergeId() {
return mergeId;
}
public void setImportance(String importance) {
this.importance = importance;
}
public String getImportance() {
return importance;
}
public void setNid(String nid) {
this.nid = nid;
}
public String getNid() {
return nid;
}
public void setType(String type) {
this.type = type;
}
public String getType() {
return type;
}
public void setPath(String path) {
this.path = path;
}
public String getPath() {
return path;
}
public void setReadClass(String readClass) {
this.readClass = readClass;
}
public String getReadClass() {
return readClass;
}
public void setDatetime(String datetime) {
this.datetime = datetime;
}
public String getDatetime() {
return datetime;
}
public void setFrom(String from) {
this.from = from;
}
public String getFrom() {
return from;
}
public void setBodyShort(String bodyShort) {
this.bodyShort = bodyShort;
}
public String getBodyShort() {
return bodyShort;
}
public void setDatetimeISO(String datetimeISO) {
this.datetimeISO = datetimeISO;
}
public String getDatetimeISO() {
return datetimeISO;
}
public void setUser(User user) {
this.user = user;
}
public User getUser() {
return user;
}
@Override
public String toString() {
return
"Notification{" +
"read = '" + read + '\'' +
",mergeId = '" + mergeId + '\'' +
",importance = '" + importance + '\'' +
",nid = '" + nid + '\'' +
",type = '" + type + '\'' +
",path = '" + path + '\'' +
",readClass = '" + readClass + '\'' +
",datetime = '" + datetime + '\'' +
",from = '" + from + '\'' +
",bodyShort = '" + bodyShort + '\'' +
",datetimeISO = '" + datetimeISO + '\'' +
",user = '" + user + '\'' +
"}";
}
}

View File

@ -0,0 +1,25 @@
package com.stardust.scriptdroid.network.entity.notification;
import java.util.List;
public class NotificationResponse {
private List<Notification> notifications;
public void setNotifications(List<Notification> notifications) {
this.notifications = notifications;
}
public List<Notification> getNotifications() {
return notifications;
}
@Override
public String toString() {
return
"NotificationResponse{" +
"notifications = '" + notifications + '\'' +
"}";
}
}

View File

@ -62,6 +62,10 @@ import java.util.Arrays;
@EActivity(R.layout.activity_main)
public class MainActivity extends BaseActivity implements OnActivityResultDelegate.DelegateHost, BackPressedHandler.HostActivity {
public static class DrawerOpenEvent {
static DrawerOpenEvent SINGLETON = new DrawerOpenEvent();
}
private static final String LOG_TAG = "MainActivity";
@ViewById(R.id.drawer_layout)
@ -100,6 +104,12 @@ public class MainActivity extends BaseActivity implements OnActivityResultDelega
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
registerBackPressHandlers();
ThemeColorManager.addViewBackground(findViewById(R.id.app_bar));
mDrawerLayout.addDrawerListener(new DrawerLayout.SimpleDrawerListener() {
@Override
public void onDrawerOpened(View drawerView) {
EventBus.getDefault().post(DrawerOpenEvent.SINGLETON);
}
});
}
private void showAnnunciationIfNeeded() {

View File

@ -2,6 +2,7 @@ package com.stardust.scriptdroid.ui.main.drawer;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.network.UserService;
import com.stardust.scriptdroid.network.entity.notification.Notification;
import com.stardust.scriptdroid.ui.main.community.CommunityFragment;
import org.greenrobot.eventbus.EventBus;
@ -10,7 +11,10 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
/**
@ -21,10 +25,11 @@ public class CommunityDrawerMenu {
private DrawerMenuItem mUnreadItem = new DrawerMenuItem(R.drawable.community_inbox, R.string.text_community_unread, this::showUnread);
private DrawerMenuItem mLogoutItem = new DrawerMenuItem(R.drawable.ic_exit_to_app_black_24dp, R.string.text_logout, this::logout);
private DrawerMenuItem mNotificationItem = new DrawerMenuItem(R.drawable.ic_ali_notification, R.string.text_notification, this::showNotifications);
private List<DrawerMenuItem> mDrawerMenuItems = new ArrayList<>(Arrays.asList(
new DrawerMenuGroup(R.string.text_community),
mNotificationItem,
new DrawerMenuItem(R.drawable.community_list, R.string.text_community_category, this::showCategories),
mUnreadItem,
new DrawerMenuItem(R.drawable.community_time, R.string.text_community_recent, this::showRecent),
@ -34,9 +39,11 @@ public class CommunityDrawerMenu {
));
private boolean mShown = false;
private DrawerMenuAdapter mMenuAdapter;
public void showCommunityMenu(DrawerMenuAdapter adapter) {
mMenuAdapter = adapter;
mShown = true;
List<DrawerMenuItem> items = adapter.getDrawerMenuItems();
if (items.get(0) == mDrawerMenuItems.get(0)) {
@ -49,21 +56,44 @@ public class CommunityDrawerMenu {
refreshUserStatus(adapter);
}
private void refreshUserStatus(DrawerMenuAdapter adapter) {
UserService.getInstance().refreshOnlineStatus()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(online -> setUserOnlineStatus(adapter, online));
.subscribe(online -> {
setUserOnlineStatus(adapter, online);
if (online) {
refreshNotificationCount(adapter);
}
});
}
public void refreshNotificationCount(DrawerMenuAdapter adapter) {
UserService.getInstance().getNotifications()
.flatMap(Observable::fromIterable)
.filter(n -> !n.isRead())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.count()
.subscribe(count -> setNotificationCount(adapter, count));
}
private void setNotificationCount(DrawerMenuAdapter adapter, long count) {
mNotificationItem.setNotificationCount((int) count);
adapter.notifyItemChanged(mNotificationItem);
}
public void setUserOnlineStatus(DrawerMenuAdapter adapter, boolean online) {
if (online) {
addItem(adapter, R.string.text_community, mNotificationItem);
addItem(adapter, R.string.text_community_category, mUnreadItem);
addItem(adapter, R.string.text_community_tags, mLogoutItem);
} else {
removeItem(adapter, R.string.text_community_unread);
removeItem(adapter, R.string.text_logout);
removeItem(adapter, R.string.text_notification);
}
}
@ -80,6 +110,7 @@ public class CommunityDrawerMenu {
break;
}
}
}
private void removeItem(DrawerMenuAdapter adapter, int title) {
@ -94,6 +125,7 @@ public class CommunityDrawerMenu {
}
}
public void hideCommunityMenu(DrawerMenuAdapter adapter) {
List<DrawerMenuItem> items = adapter.getDrawerMenuItems();
mShown = false;
@ -111,6 +143,11 @@ public class CommunityDrawerMenu {
}
}
private void showNotifications(DrawerMenuItemViewHolder holder) {
EventBus.getDefault().post(new CommunityFragment.LoadUrl("/notifications"));
setNotificationCount(mMenuAdapter, 0);
}
private void showCategories(DrawerMenuItemViewHolder holder) {
EventBus.getDefault().post(new CommunityFragment.LoadUrl("/categories"));
}

View File

@ -35,6 +35,7 @@ import com.stardust.scriptdroid.network.api.UserApi;
import com.stardust.scriptdroid.network.entity.user.User;
import com.stardust.scriptdroid.network.entity.VersionInfo;
import com.stardust.scriptdroid.tool.SimpleObserver;
import com.stardust.scriptdroid.ui.main.MainActivity;
import com.stardust.scriptdroid.ui.main.community.CommunityFragment;
import com.stardust.scriptdroid.ui.user.LoginActivity_;
import com.stardust.scriptdroid.ui.settings.SettingsActivity;
@ -403,6 +404,13 @@ public class DrawerFragment extends android.support.v4.app.Fragment {
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onDrawerOpen(MainActivity.DrawerOpenEvent event) {
if (mCommunityDrawerMenu.isShown()) {
mCommunityDrawerMenu.refreshNotificationCount(mDrawerMenuAdapter);
}
}
private void showStableModePromptIfNeeded() {
new NotAskAgainDialog.Builder(getContext(), "DrawerFragment.stable_mode")
.title(R.string.text_stable_mode)

View File

@ -18,6 +18,7 @@ public class DrawerMenuItem {
private Action mAction;
private boolean mSwitchChecked;
private boolean mOnProgress;
private int mNotificationCount;
public DrawerMenuItem(int icon, int title, Action action) {
mIcon = icon;
@ -36,6 +37,14 @@ public class DrawerMenuItem {
mSwitchEnabled = true;
}
public int getNotificationCount() {
return mNotificationCount;
}
public void setNotificationCount(int notificationCount) {
mNotificationCount = notificationCount;
}
public int getIcon() {
return mIcon;
}

View File

@ -37,6 +37,10 @@ public class DrawerMenuItemViewHolder extends BindableViewHolder<DrawerMenuItem>
@BindView(R.id.title)
TextView mTitle;
@BindView(R.id.notifications)
TextView mNotifications;
private boolean mAntiShake;
private long mLastClickMillis;
private DrawerMenuItem mDrawerMenuItem;
@ -62,6 +66,16 @@ public class DrawerMenuItemViewHolder extends BindableViewHolder<DrawerMenuItem>
mAntiShake = item.antiShake();
setSwitch(item);
setProgress(item.isProgress());
setNotifications(item.getNotificationCount());
}
private void setNotifications(int notificationCount) {
if (notificationCount == 0) {
mNotifications.setVisibility(View.GONE);
} else {
mNotifications.setVisibility(View.VISIBLE);
mNotifications.setText(String.valueOf(notificationCount));
}
}
private void setSwitch(DrawerMenuItem item) {

View File

@ -1,15 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="?selectableItemBackground"
android:orientation="horizontal">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="?selectableItemBackground"
android:orientation="horizontal">
<FrameLayout
android:id="@+id/icon_container"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_margin="16dp">
<ImageView
@ -28,23 +31,40 @@
</FrameLayout>
<TextView
android:id="@+id/title"
android:layout_width="0dp"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_centerVertical="true"
android:layout_toRightOf="@+id/icon_container"
android:gravity="center_vertical"
android:textColor="#484C4F"
android:textSize="14sp"
tools:text="@string/text_auto_operate_service"/>
<TextView
android:id="@+id/notifications"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="16dp"
android:background="@drawable/circle_red"
android:padding="4dp"
android:textColor="@android:color/white"
android:textSize="12sp"
android:visibility="gone"
tools:text="2"
tools:visibility="visible"/>
<com.stardust.scriptdroid.ui.widget.PrefSwitch
android:id="@+id/sw"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="16dp"
android:visibility="gone"/>
android:visibility="gone"
tools:visibility="visible"/>
</LinearLayout>
</RelativeLayout>

View File

@ -349,4 +349,5 @@
<string name="text_preview">预览</string>
<string name="text_size_current_value" formatted="true">字体大小: %d</string>
<string name="error_regex_find_prev">正则表达式不能向前查找</string>
<string name="text_notification">通知</string>
</resources>