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.jakewharton.retrofit2.adapter.rxjava2.HttpException;
import com.stardust.scriptdroid.network.api.UserApi; 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.scriptdroid.network.entity.user.User;
import com.stardust.util.Objects; import com.stardust.util.Objects;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
import java.util.Collections; import java.util.List;
import io.reactivex.Observable; import io.reactivex.Observable;
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers;
@@ -21,7 +23,6 @@ import retrofit2.Retrofit;
public class UserService { public class UserService {
public static class LoginStateChange { public static class LoginStateChange {
private final boolean mOnline; private final boolean mOnline;
@@ -116,4 +117,13 @@ public class UserService {
.doOnNext(this::setUser) .doOnNext(this::setUser)
.doOnError(error -> setUser(null)); .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; package com.stardust.scriptdroid.network.api;
import com.stardust.scriptdroid.network.entity.notification.NotificationResponse;
import com.stardust.scriptdroid.network.entity.user.User; import com.stardust.scriptdroid.network.entity.user.User;
import java.util.Map; import java.util.Map;
@@ -33,4 +34,7 @@ public interface UserApi {
@POST("/logout") @POST("/logout")
Observable<ResponseBody> logout(@HeaderMap Map<String, String> csrfToken); 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) @EActivity(R.layout.activity_main)
public class MainActivity extends BaseActivity implements OnActivityResultDelegate.DelegateHost, BackPressedHandler.HostActivity { 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"; private static final String LOG_TAG = "MainActivity";
@ViewById(R.id.drawer_layout) @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); View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
registerBackPressHandlers(); registerBackPressHandlers();
ThemeColorManager.addViewBackground(findViewById(R.id.app_bar)); 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() { 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.R;
import com.stardust.scriptdroid.network.UserService; import com.stardust.scriptdroid.network.UserService;
import com.stardust.scriptdroid.network.entity.notification.Notification;
import com.stardust.scriptdroid.ui.main.community.CommunityFragment; import com.stardust.scriptdroid.ui.main.community.CommunityFragment;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
@@ -10,7 +11,10 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers; 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 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 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( private List<DrawerMenuItem> mDrawerMenuItems = new ArrayList<>(Arrays.asList(
new DrawerMenuGroup(R.string.text_community), new DrawerMenuGroup(R.string.text_community),
mNotificationItem,
new DrawerMenuItem(R.drawable.community_list, R.string.text_community_category, this::showCategories), new DrawerMenuItem(R.drawable.community_list, R.string.text_community_category, this::showCategories),
mUnreadItem, mUnreadItem,
new DrawerMenuItem(R.drawable.community_time, R.string.text_community_recent, this::showRecent), 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 boolean mShown = false;
private DrawerMenuAdapter mMenuAdapter;
public void showCommunityMenu(DrawerMenuAdapter adapter) { public void showCommunityMenu(DrawerMenuAdapter adapter) {
mMenuAdapter = adapter;
mShown = true; mShown = true;
List<DrawerMenuItem> items = adapter.getDrawerMenuItems(); List<DrawerMenuItem> items = adapter.getDrawerMenuItems();
if (items.get(0) == mDrawerMenuItems.get(0)) { if (items.get(0) == mDrawerMenuItems.get(0)) {
@@ -49,21 +56,44 @@ public class CommunityDrawerMenu {
refreshUserStatus(adapter); refreshUserStatus(adapter);
} }
private void refreshUserStatus(DrawerMenuAdapter adapter) { private void refreshUserStatus(DrawerMenuAdapter adapter) {
UserService.getInstance().refreshOnlineStatus() UserService.getInstance().refreshOnlineStatus()
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .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) { public void setUserOnlineStatus(DrawerMenuAdapter adapter, boolean online) {
if (online) { if (online) {
addItem(adapter, R.string.text_community, mNotificationItem);
addItem(adapter, R.string.text_community_category, mUnreadItem); addItem(adapter, R.string.text_community_category, mUnreadItem);
addItem(adapter, R.string.text_community_tags, mLogoutItem); addItem(adapter, R.string.text_community_tags, mLogoutItem);
} else { } else {
removeItem(adapter, R.string.text_community_unread); removeItem(adapter, R.string.text_community_unread);
removeItem(adapter, R.string.text_logout); removeItem(adapter, R.string.text_logout);
removeItem(adapter, R.string.text_notification);
} }
} }
@@ -80,6 +110,7 @@ public class CommunityDrawerMenu {
break; break;
} }
} }
} }
private void removeItem(DrawerMenuAdapter adapter, int title) { private void removeItem(DrawerMenuAdapter adapter, int title) {
@@ -94,6 +125,7 @@ public class CommunityDrawerMenu {
} }
} }
public void hideCommunityMenu(DrawerMenuAdapter adapter) { public void hideCommunityMenu(DrawerMenuAdapter adapter) {
List<DrawerMenuItem> items = adapter.getDrawerMenuItems(); List<DrawerMenuItem> items = adapter.getDrawerMenuItems();
mShown = false; 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) { private void showCategories(DrawerMenuItemViewHolder holder) {
EventBus.getDefault().post(new CommunityFragment.LoadUrl("/categories")); 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.user.User;
import com.stardust.scriptdroid.network.entity.VersionInfo; import com.stardust.scriptdroid.network.entity.VersionInfo;
import com.stardust.scriptdroid.tool.SimpleObserver; 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.main.community.CommunityFragment;
import com.stardust.scriptdroid.ui.user.LoginActivity_; import com.stardust.scriptdroid.ui.user.LoginActivity_;
import com.stardust.scriptdroid.ui.settings.SettingsActivity; 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() { private void showStableModePromptIfNeeded() {
new NotAskAgainDialog.Builder(getContext(), "DrawerFragment.stable_mode") new NotAskAgainDialog.Builder(getContext(), "DrawerFragment.stable_mode")
.title(R.string.text_stable_mode) .title(R.string.text_stable_mode)

View File

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

View File

@@ -37,6 +37,10 @@ public class DrawerMenuItemViewHolder extends BindableViewHolder<DrawerMenuItem>
@BindView(R.id.title) @BindView(R.id.title)
TextView mTitle; TextView mTitle;
@BindView(R.id.notifications)
TextView mNotifications;
private boolean mAntiShake; private boolean mAntiShake;
private long mLastClickMillis; private long mLastClickMillis;
private DrawerMenuItem mDrawerMenuItem; private DrawerMenuItem mDrawerMenuItem;
@@ -62,6 +66,16 @@ public class DrawerMenuItemViewHolder extends BindableViewHolder<DrawerMenuItem>
mAntiShake = item.antiShake(); mAntiShake = item.antiShake();
setSwitch(item); setSwitch(item);
setProgress(item.isProgress()); 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) { private void setSwitch(DrawerMenuItem item) {

View File

@@ -1,15 +1,18 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="48dp" android:layout_height="48dp"
android:background="?selectableItemBackground" android:background="?selectableItemBackground"
android:orientation="horizontal"> android:orientation="horizontal">
<FrameLayout <FrameLayout
android:id="@+id/icon_container"
android:layout_width="16dp" android:layout_width="16dp"
android:layout_height="16dp" android:layout_height="16dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_margin="16dp"> android:layout_margin="16dp">
<ImageView <ImageView
@@ -28,23 +31,40 @@
</FrameLayout> </FrameLayout>
<TextView <TextView
android:id="@+id/title" android:id="@+id/title"
android:layout_width="0dp" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_weight="1" android:layout_centerVertical="true"
android:layout_toRightOf="@+id/icon_container"
android:gravity="center_vertical" android:gravity="center_vertical"
android:textColor="#484C4F" android:textColor="#484C4F"
android:textSize="14sp" android:textSize="14sp"
tools:text="@string/text_auto_operate_service"/> 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 <com.stardust.scriptdroid.ui.widget.PrefSwitch
android:id="@+id/sw" android:id="@+id/sw"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="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: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_preview">预览</string>
<string name="text_size_current_value" formatted="true">字体大小: %d</string> <string name="text_size_current_value" formatted="true">字体大小: %d</string>
<string name="error_regex_find_prev">正则表达式不能向前查找</string> <string name="error_regex_find_prev">正则表达式不能向前查找</string>
<string name="text_notification">通知</string>
</resources> </resources>