add: logout button on drawer menu

This commit is contained in:
hyb1996
2017-12-31 17:56:35 +08:00
parent 002a11149e
commit 5ed6e2bea8
21 changed files with 839 additions and 607 deletions

View File

@@ -95,11 +95,6 @@
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
</intent-filter>
</activity>
<activity
android:name="com.stardust.autojs.core.image.ScreenCaptureRequestActivity"
android:excludeFromRecents="true"
android:taskAffinity="com.stardust.autojs.runtime.api.image.ScreenCaptureRequestActivity"
android:theme="@style/AppTheme.Transparent"/>
<activity
android:name=".ui.error.IssueReporterActivity"

View File

@@ -66,6 +66,10 @@ public class NodeBB {
}
public void invalidateConfig() {
mConfig = null;
}
public static String getErrorMessage(Throwable e, Context context, String defaultMsg) {
if (!(e instanceof HttpException)) {
return defaultMsg;
@@ -75,7 +79,7 @@ public class NodeBB {
if (body == null)
return defaultMsg;
try {
String errorMessage = getErrorMessage(context, e, body.string());
String errorMessage = getErrorMessage(context, httpException, body.string());
return errorMessage == null ? defaultMsg : errorMessage;
} catch (IOException e1) {
e1.printStackTrace();
@@ -83,7 +87,7 @@ public class NodeBB {
}
}
private static String getErrorMessage(Context context, Throwable error, String errorBody) {
private static String getErrorMessage(Context context, HttpException error, String errorBody) {
if (errorBody == null)
return null;
if (errorBody.contains("invalid-login-credentials")) {
@@ -99,6 +103,9 @@ public class NodeBB {
if (errorBody.contains("email-taken")) {
return context.getString(R.string.nodebb_error_email_taken);
}
if (error.code() == 403) {
return context.getString(R.string.nodebb_error_forbidden);
}
Log.d(LOG_TAG, "unknown error: " + errorBody, error);
return null;
}

View File

@@ -1,13 +1,18 @@
package com.stardust.scriptdroid.network;
import android.util.Log;
import com.stardust.scriptdroid.network.api.ConfigApi;
import com.jakewharton.retrofit2.adapter.rxjava2.HttpException;
import com.stardust.scriptdroid.network.api.UserApi;
import com.stardust.scriptdroid.network.entity.user.User;
import com.stardust.util.Objects;
import org.greenrobot.eventbus.EventBus;
import java.util.Collections;
import io.reactivex.Observable;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.subjects.PublishSubject;
import okhttp3.ResponseBody;
import retrofit2.Retrofit;
@@ -17,8 +22,22 @@ import retrofit2.Retrofit;
public class UserService {
public static class LoginStateChange {
private final boolean mOnline;
public LoginStateChange(boolean online) {
mOnline = online;
}
public boolean isOnline() {
return mOnline;
}
}
private static final UserService sInstance = new UserService();
private final Retrofit mRetrofit;
private volatile User mUser;
UserService() {
mRetrofit = NodeBB.getInstance().getRetrofit();
@@ -31,14 +50,20 @@ public class UserService {
public Observable<ResponseBody> login(String userName, final String password) {
return NodeBB.getInstance()
.getConfig()
.flatMap(config -> {
return mRetrofit.create(UserApi.class)
.login(Collections.singletonMap("x-csrf-token", config.getCsrfToken()),
userName, password);
});
.flatMap(config ->
mRetrofit.create(UserApi.class)
.login(Collections.singletonMap("x-csrf-token", config.getCsrfToken()),
userName, password)
.doOnError(error -> {
if (error instanceof HttpException && ((HttpException) error).code() == 403) {
NodeBB.getInstance().invalidateConfig();
}
}))
.doOnComplete(this::refreshOnlineStatus);
}
public Observable<ResponseBody> register(String email, String userName, String password) {
return NodeBB.getInstance()
.getConfig()
@@ -46,4 +71,55 @@ public class UserService {
.register(Collections.singletonMap("x-csrf-token", config.getCsrfToken()),
email, userName, password, password));
}
public boolean isOnline() {
return mUser != null;
}
private void setUser(User user) {
User old = mUser;
mUser = user;
if (!Objects.equals(old, mUser)) {
if (user == null) {
NodeBB.getInstance().invalidateConfig();
}
EventBus.getDefault().post(new LoginStateChange(user != null));
}
}
public Observable<Boolean> refreshOnlineStatus() {
PublishSubject<Boolean> online = PublishSubject.create();
mRetrofit.create(UserApi.class)
.me()
.subscribeOn(Schedulers.io())
.subscribe(user -> {
setUser(user);
online.onNext(true);
online.onComplete();
}, error -> {
setUser(null);
online.onNext(false);
online.onComplete();
});
return online;
}
public Observable<ResponseBody> logout() {
return NodeBB.getInstance()
.getConfig()
.flatMap(config ->
mRetrofit.create(UserApi.class)
.logout(Collections.singletonMap("x-csrf-token", config.getCsrfToken()))
)
.doOnError(Throwable::printStackTrace)
.doOnComplete(this::refreshOnlineStatus);
}
public Observable<User> me() {
return NodeBB.getInstance().getRetrofit()
.create(UserApi.class)
.me()
.doOnNext(this::setUser)
.doOnError(error -> setUser(null));
}
}

View File

@@ -31,4 +31,6 @@ public interface UserApi {
@Field("username") String userName, @Field("password") String password, @Field("password-confirm") String repeatPassword);
@POST("/logout")
Observable<ResponseBody> logout(@HeaderMap Map<String, String> csrfToken);
}

View File

@@ -1,6 +1,7 @@
package com.stardust.scriptdroid.ui.main.drawer;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.network.UserService;
import com.stardust.scriptdroid.ui.main.community.CommunityFragment;
import org.greenrobot.eventbus.EventBus;
@@ -9,46 +10,105 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
/**
* Created by Stardust on 2017/12/10.
*/
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 List<DrawerMenuItem> mDrawerMenuItems = new ArrayList<>(Arrays.asList(
new DrawerMenuGroup(R.string.text_community),
new DrawerMenuItem(R.drawable.community_list, R.string.text_community_category, this::showCategories),
new DrawerMenuItem(R.drawable.community_inbox, R.string.text_community_unread, this::showUnread),
mUnreadItem,
new DrawerMenuItem(R.drawable.community_time, R.string.text_community_recent, this::showRecent),
new DrawerMenuItem(R.drawable.community_fire, R.string.text_community_popular, this::showPopular),
new DrawerMenuItem(R.drawable.community_tags, R.string.text_community_tags, this::showTags)
new DrawerMenuItem(R.drawable.community_tags, R.string.text_community_tags, this::showTags),
mLogoutItem
));
private boolean mShown = false;
public List<DrawerMenuItem> getItems() {
return mDrawerMenuItems;
}
public void showCommunityMenu(DrawerMenuAdapter adapter) {
mShown = true;
List<DrawerMenuItem> items = adapter.getDrawerMenuItems();
if (items.get(0) == mDrawerMenuItems.get(0)) {
refreshUserStatus(adapter);
return;
}
items.addAll(0, mDrawerMenuItems);
adapter.notifyItemRangeInserted(0, mDrawerMenuItems.size());
adapter.notifyItemChanged(mDrawerMenuItems.size());
refreshUserStatus(adapter);
}
private void refreshUserStatus(DrawerMenuAdapter adapter) {
UserService.getInstance().refreshOnlineStatus()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(online -> setUserOnlineStatus(adapter, online));
}
public void setUserOnlineStatus(DrawerMenuAdapter adapter, boolean online) {
if (online) {
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);
}
}
private void addItem(DrawerMenuAdapter adapter, int title, DrawerMenuItem itemToAdd) {
List<DrawerMenuItem> items = adapter.getDrawerMenuItems();
for (int i = 0; i < items.size(); i++) {
DrawerMenuItem item = items.get(i);
if (item.getTitle() == title) {
if (i >= items.size() || items.get(i + 1) != itemToAdd) {
items.add(i + 1, itemToAdd);
adapter.notifyItemInserted(i + 1);
}
break;
}
}
}
private void removeItem(DrawerMenuAdapter adapter, int title) {
List<DrawerMenuItem> items = adapter.getDrawerMenuItems();
for (int i = 0; i < items.size(); i++) {
DrawerMenuItem item = items.get(i);
if (item.getTitle() == title) {
items.remove(i);
adapter.notifyItemRemoved(i);
break;
}
}
}
public void hideCommunityMenu(DrawerMenuAdapter adapter) {
List<DrawerMenuItem> items = adapter.getDrawerMenuItems();
mShown = false;
if (items.isEmpty() || items.get(0) != mDrawerMenuItems.get(0)) {
return;
}
items.subList(0, mDrawerMenuItems.size()).clear();
adapter.notifyItemChanged(mDrawerMenuItems.size());
adapter.notifyItemRangeRemoved(0, mDrawerMenuItems.size());
for (int i = 1; i < items.size(); i++) {
DrawerMenuItem item = items.get(i);
if (item instanceof DrawerMenuGroup) {
items.subList(0, i).clear();
adapter.notifyItemRangeRemoved(0, i);
adapter.notifyItemChanged(0);
break;
}
}
}
private void showCategories(DrawerMenuItemViewHolder holder) {
@@ -76,4 +136,14 @@ public class CommunityDrawerMenu {
}
private void logout(DrawerMenuItemViewHolder holder) {
UserService.getInstance().logout()
.subscribeOn(Schedulers.io())
.subscribe();
EventBus.getDefault().post(new CommunityFragment.LoadUrl("/"));
}
public boolean isShown() {
return mShown;
}
}

View File

@@ -22,6 +22,7 @@ import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.Pref;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.network.GlideApp;
import com.stardust.scriptdroid.network.UserService;
import com.stardust.scriptdroid.pluginclient.DevPluginClient;
import com.stardust.scriptdroid.ui.floating.CircularMenu;
import com.stardust.scriptdroid.ui.floating.FloatyWindowManger;
@@ -52,6 +53,7 @@ import org.androidannotations.annotations.EFragment;
import org.androidannotations.annotations.ViewById;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.ArrayList;
import java.util.Arrays;
@@ -147,8 +149,7 @@ public class DrawerFragment extends android.support.v4.app.Fragment {
@Click(R.id.avatar)
void loginOrShowUserInfo() {
NodeBB.getInstance().getRetrofit()
.create(UserApi.class)
UserService.getInstance()
.me()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
@@ -368,6 +369,13 @@ public class DrawerFragment extends android.support.v4.app.Fragment {
mDrawerMenu.scrollToPosition(0);
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onLoginStateChange(UserService.LoginStateChange change) {
syncUserInfo();
if (mCommunityDrawerMenu.isShown()) {
mCommunityDrawerMenu.setUserOnlineStatus(mDrawerMenuAdapter, change.isOnline());
}
}
@Override
public void onDestroy() {

View File

@@ -6,8 +6,8 @@ package com.stardust.scriptdroid.ui.main.drawer;
public class DrawerMenuGroup extends DrawerMenuItem {
public DrawerMenuGroup(int title) {
super(0, title, null);
}
}

View File

@@ -77,4 +77,19 @@ public class DrawerMenuItem {
if (mAction != null)
mAction.onClick(holder);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DrawerMenuItem that = (DrawerMenuItem) o;
return mTitle == that.mTitle;
}
@Override
public int hashCode() {
return mTitle;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 B

View File

@@ -336,4 +336,6 @@
<string name="nodebb_error_change_password_error_length">密码太短</string>
<string name="nodebb_error_email_taken">邮箱已被占用</string>
<string name="nodebb_error_change_password_error_match">两次输入的密码不一致</string>
<string name="text_logout">退出登录</string>
<string name="nodebb_error_forbidden">操作失败,请稍后重试</string>
</resources>