完善登陆UI数据管理

0515
panqihua 4 years ago
parent d56e41699c
commit 8ce7134a04
  1. 30
      app/src/main/java/com/community/pocket/data/login/LoginDataSource.java
  2. 56
      app/src/main/java/com/community/pocket/data/login/LoginRepository.java
  3. 35
      app/src/main/java/com/community/pocket/data/login/LoginRequest.java
  4. 58
      app/src/main/java/com/community/pocket/data/login/Result.java
  5. 26
      app/src/main/java/com/community/pocket/data/model/Token.java
  6. 30
      app/src/main/java/com/community/pocket/ui/login/LoginActivity.java
  7. 11
      app/src/main/java/com/community/pocket/ui/login/LoginResponse.java
  8. 32
      app/src/main/java/com/community/pocket/ui/login/LoginResult.java
  9. 34
      app/src/main/java/com/community/pocket/ui/login/LoginViewModel.java
  10. 28
      app/src/main/java/com/community/pocket/ui/login/LoginViewModelFactory.java
  11. 32
      app/src/main/java/com/community/pocket/ui/main/ui/share/Response.java
  12. 1
      app/src/main/res/values-en-rUS/strings.xml
  13. 1
      app/src/main/res/values-zh-rCN/strings.xml
  14. 1
      app/src/main/res/values/strings.xml

@ -1,30 +0,0 @@
package com.community.pocket.data.login;
import com.community.pocket.data.model.LoggedInUser;
import java.io.IOException;
/**
* Class that handles authentication w/ login credentials and retrieves user information.
* 该类处理身份验证w/登录凭据并检索用户信息
*/
public class LoginDataSource {
public Result<LoggedInUser> login(String username, String password) {
try {
// TODO: handle loggedInUser authentication
LoggedInUser fakeUser =
new LoggedInUser(
java.util.UUID.randomUUID().toString(),
"Jane Doe");
return new Result.Success<>(fakeUser);
} catch (Exception e) {
return new Result.Error<>(new IOException("Error logging in", e), LoggedInUser.class);
}
}
void logout() {
// TODO: revoke authentication
}
}

@ -1,56 +0,0 @@
package com.community.pocket.data.login;
import com.community.pocket.data.model.LoggedInUser;
/**
* Class that requests authentication and user information from the remote data source and
* maintains an in-memory cache of login status and user credentials information.
* 该类请求来自远程数据源的身份验证和用户信息
* 在内存中保存登录状态和用户凭证信息
*/
public class LoginRepository {
private static volatile LoginRepository instance;
private LoginDataSource dataSource;
// If user credentials will be cached in local storage, it is recommended it be encrypted
// @see https://developer.android.com/training/articles/keystore
private LoggedInUser user = null;
// private constructor : singleton access
private LoginRepository(LoginDataSource dataSource) {
this.dataSource = dataSource;
}
public static LoginRepository getInstance(LoginDataSource dataSource) {
if (instance == null) {
instance = new LoginRepository(dataSource);
}
return instance;
}
public boolean isLoggedIn() {
return user != null;
}
public void logout() {
user = null;
dataSource.logout();
}
private void setLoggedInUser(LoggedInUser user) {
this.user = user;
// If user credentials will be cached in local storage, it is recommended it be encrypted
// @see https://developer.android.com/training/articles/keystore
}
public Result<LoggedInUser> login(String username, String password) {
// handle login
Result<LoggedInUser> result = dataSource.login(username, password);
if (result instanceof Result.Success) {
setLoggedInUser(((Result.Success<LoggedInUser>) result).getData());
}
return result;
}
}

@ -0,0 +1,35 @@
package com.community.pocket.data.login;
import com.community.pocket.R;
import com.community.pocket.data.model.Token;
import com.community.pocket.ui.login.LoginResponse;
/**
* 登陆请求接口
* TODO 完善逻辑
*/
public class LoginRequest {
private static volatile LoginRequest instance;
private LoginRequest() {
}
public static LoginRequest getInstance() {
if (instance == null) {
instance = new LoginRequest();
}
return instance;
}
public LoginResponse login(String username, String password) {
Token token = new Token();
token.setTime(System.currentTimeMillis());
token.setToken("123");
LoginResponse loginResponse = new LoginResponse();
loginResponse.setSuccess(R.string.login_ok, username);
loginResponse.setBody(token);
return loginResponse;
}
}

@ -1,58 +0,0 @@
package com.community.pocket.data.login;
import org.jetbrains.annotations.NotNull;
/**
* A generic class that holds a result success w/ data or an error exception.
* 一个泛型类它持有一个结果成功w/数据或一个错误异常
*/
public class Result<T> {
// hide the private constructor to limit subclass types (Success, Error)
private Result() {
}
@NotNull
@Override
public String toString() {
if (this instanceof Result.Success) {
Result.Success success = (Result.Success) this;
return "Success[data=" + success.getData().toString() + "]";
} else if (this instanceof Result.Error) {
Result.Error error = (Result.Error) this;
return "Error[exception=" + error.getError().toString() + "]";
}
return "";
}
// Success sub-class
public final static class Success<T> extends Result<T> {
private T data;
Success(T data) {
this.data = data;
}
public T getData() {
return this.data;
}
}
// Error sub-class
final static class Error<T> extends Result<T> {
private Exception error;
private Class<T> c;
Error(Exception error, Class<T> c) {
this.error = error;
this.c = c;
}
Exception getError() {
return this.error;
}
public Class<T> getC() {
return c;
}
}
}

@ -0,0 +1,26 @@
package com.community.pocket.data.model;
/**
* 登陆令牌
*/
public class Token {
private String token;
private long time;
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
}

@ -14,7 +14,6 @@ import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.StringRes;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
@ -59,7 +58,7 @@ public class LoginActivity extends BaseActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
loginViewModel = new ViewModelProvider(this, new LoginViewModelFactory()).get(LoginViewModel.class);
loginViewModel = new ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory()).get(LoginViewModel.class);
//监听数据校验状态
loginViewModel.getLoginFormState().observe(this, new Observer<LoginFormState>() {
@ -79,18 +78,19 @@ public class LoginActivity extends BaseActivity {
});
//监听登陆请求结果
loginViewModel.getLoginResult().observe(this, new Observer<LoginResult>() {
loginViewModel.getLoginResult().observe(this, new Observer<LoginResponse>() {
@Override
public void onChanged(@Nullable LoginResult loginResult) {
if (loginResult == null) {
public void onChanged(@Nullable LoginResponse loginResponse) {
if (loginResponse == null) {
return;
}
loadingProgressBar.setVisibility(View.GONE);
if (loginResult.getError() != null) {
showLoginFailed(loginResult.getError());
if (loginResponse.getError() != null) {
Toast.makeText(getApplicationContext(), loginResponse.fail(getApplicationContext()), Toast.LENGTH_SHORT).show();
}
if (loginResult.getSuccess() != null) {
updateUiWithUser(loginResult.getSuccess());
if (loginResponse.getSuccess() != null) {
Toast.makeText(getApplicationContext(), loginResponse.ok(getApplicationContext()), Toast.LENGTH_SHORT).show();
}
setResult(Activity.RESULT_OK);
@ -136,16 +136,4 @@ public class LoginActivity extends BaseActivity {
startActivity(new Intent(this, ResetPwdActivity.class));
}
//登陆成功信息
private void updateUiWithUser(LoggedInUserView model) {
String welcome = getString(R.string.welcome) + model.getDisplayName();
// TODO : initiate successful logged in experience
Toast.makeText(getApplicationContext(), welcome, Toast.LENGTH_LONG).show();
}
//登陆错误信息
private void showLoginFailed(@StringRes Integer errorString) {
Toast.makeText(getApplicationContext(), errorString, Toast.LENGTH_SHORT).show();
}
}

@ -0,0 +1,11 @@
package com.community.pocket.ui.login;
import com.community.pocket.data.model.Token;
import com.community.pocket.ui.main.ui.share.Response;
/**
* 登陆响应结果
*/
public class LoginResponse extends Response<Token> {
}

@ -1,32 +0,0 @@
package com.community.pocket.ui.login;
import androidx.annotation.Nullable;
/**
* Authentication result : success (user details) or error message.
* 验证结果:成功(用户详细信息)或错误消息
*/
class LoginResult {
@Nullable
private LoggedInUserView success;
@Nullable
private Integer error;
LoginResult(@Nullable Integer error) {
this.error = error;
}
LoginResult(@Nullable LoggedInUserView success) {
this.success = success;
}
@Nullable
LoggedInUserView getSuccess() {
return success;
}
@Nullable
Integer getError() {
return error;
}
}

@ -2,49 +2,34 @@ package com.community.pocket.ui.login;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import com.community.pocket.R;
import com.community.pocket.data.login.LoginRepository;
import com.community.pocket.data.login.Result;
import com.community.pocket.data.model.LoggedInUser;
import com.community.pocket.data.login.LoginRequest;
import com.community.pocket.ui.main.ui.share.BaseViewModel;
import com.community.pocket.util.ValidUtil;
/**
* 管理 登陆UI 相关数据
*/
public class LoginViewModel extends ViewModel {
public class LoginViewModel extends BaseViewModel<LoginRequest> {
//登陆表单校验信息
private MutableLiveData<LoginFormState> loginFormState = new MutableLiveData<>();
//登陆结果
private MutableLiveData<LoginResult> loginResult = new MutableLiveData<>();
//登陆请求数据源
private LoginRepository loginRepository;
LoginViewModel(LoginRepository loginRepository) {
this.loginRepository = loginRepository;
}
private MutableLiveData<LoginResponse> loginResult = new MutableLiveData<>();
LiveData<LoginFormState> getLoginFormState() {
return loginFormState;
}
LiveData<LoginResult> getLoginResult() {
LiveData<LoginResponse> getLoginResult() {
return loginResult;
}
//登陆
public void login(String username, String password) {
// can be launched in a separate asynchronous job
Result<LoggedInUser> result = loginRepository.login(username, password);
if (result instanceof Result.Success) {
LoggedInUser data = ((Result.Success<LoggedInUser>) result).getData();
loginResult.setValue(new LoginResult(new LoggedInUserView(data.getDisplayName())));
} else {
loginResult.setValue(new LoginResult(R.string.login_failed));
}
LoginResponse response = getRequest().login(username, password);
loginResult.setValue(response);
}
//登陆表单数据变化触发数据校验
@ -57,4 +42,9 @@ public class LoginViewModel extends ViewModel {
loginFormState.setValue(new LoginFormState(true));
}
}
@Override
protected LoginRequest getRequest() {
return LoginRequest.getInstance();
}
}

@ -1,28 +0,0 @@
package com.community.pocket.ui.login;
import androidx.annotation.NonNull;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import com.community.pocket.data.login.LoginDataSource;
import com.community.pocket.data.login.LoginRepository;
/**
* ViewModel provider factory to instantiate LoginViewModel.
* Required given LoginViewModel has a non-empty constructor
* ViewModel提供程序工厂来实例化LoginViewModel
* 给定的LoginViewModel有一个非空的构造函数
*/
public class LoginViewModelFactory implements ViewModelProvider.Factory {
@NonNull
@Override
@SuppressWarnings("unchecked")
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
if (modelClass.isAssignableFrom(LoginViewModel.class)) {
return (T) new LoginViewModel(LoginRepository.getInstance(new LoginDataSource()));
} else {
throw new IllegalArgumentException("Unknown ViewModel class");
}
}
}

@ -1,5 +1,7 @@
package com.community.pocket.ui.main.ui.share;
import android.content.Context;
import androidx.annotation.Nullable;
/**
@ -14,6 +16,8 @@ public abstract class Response<T> {
//失败描述
@Nullable
private Integer error;
private Object[] args;
//响应体
private T body;
@ -22,8 +26,9 @@ public abstract class Response<T> {
return success;
}
public void setSuccess(@Nullable Integer success) {
public void setSuccess(@Nullable Integer success, Object... args) {
this.success = success;
this.args = args;
}
@Nullable
@ -31,8 +36,9 @@ public abstract class Response<T> {
return error;
}
public void setError(@Nullable Integer error) {
public void setError(@Nullable Integer error, Object... args) {
this.error = error;
this.args = args;
}
public T getBody() {
@ -42,4 +48,26 @@ public abstract class Response<T> {
public void setBody(T body) {
this.body = body;
}
public String ok(Context context) {
if (success != null) {
return context.getString(success, args);
}
return null;
}
public String fail(Context context) {
if (error != null) {
return context.getString(error, args);
}
return null;
}
public Object[] getArgs() {
return args;
}
public void setArgs(Object[] args) {
this.args = args;
}
}

@ -151,4 +151,5 @@
<string name="load_visitor_my_fail">load my visitor fail</string>
<string name="load_visitor_reservation_ok">load reservation success</string>
<string name="load_visitor_reservation_fail">load reservation fail</string>
<string name="login_ok">Welcome the %1s to log in this system</string>
</resources>

@ -151,4 +151,5 @@
<string name="load_visitor_my_fail">加载我的访客失败</string>
<string name="load_visitor_reservation_ok">加载我的预约成功</string>
<string name="load_visitor_reservation_fail">加载我的预约失败</string>
<string name="login_ok">欢迎用户%1s登陆口袋社区</string>
</resources>

@ -152,6 +152,7 @@
<string name="load_visitor_my_fail">load my visitor fail</string>
<string name="load_visitor_reservation_ok">load reservation success</string>
<string name="load_visitor_reservation_fail">load reservation fail</string>
<string name="login_ok">Welcome the %1s to log in this system</string>
<!-- Strings used for fragments for navigation -->
<!-- Strings used for fragments for navigation -->

Loading…
Cancel
Save