diff --git a/app/build.gradle b/app/build.gradle index c09dee4..cdcdd83 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,12 +1,12 @@ apply plugin: 'com.android.application' - +apply plugin: 'multi-languages' android { compileSdkVersion 29 buildToolsVersion "29.0.3" defaultConfig { applicationId "com.community.pocket" - minSdkVersion 14 + minSdkVersion 15 targetSdkVersion 29 versionCode 1 versionName "1.0" @@ -26,12 +26,16 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'com.google.android.material:material:1.0.0' + implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'com.google.android.material:material:1.1.0' implementation 'androidx.annotation:annotation:1.1.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' - implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0' - testImplementation 'junit:junit:4.12' + implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' + testImplementation 'junit:junit:4.13' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + + implementation 'com.github.jokar:multi-languages:0.0.8' + implementation 'org.xutils:xutils:3.8.5' + implementation 'com.squareup.okhttp3:okhttp:4.4.1' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 431fdf5..b3cf93e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -8,7 +8,9 @@ android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" - android:theme="@style/AppTheme"> + android:theme="@style/AppTheme" + android:name=".util.InitApp" + android:fullBackupContent="@xml/backup_descriptor"> diff --git a/app/src/main/assets/config.properties b/app/src/main/assets/config.properties new file mode 100644 index 0000000..ae52e13 --- /dev/null +++ b/app/src/main/assets/config.properties @@ -0,0 +1,2 @@ +#登陆表单密码长度 +password.length=5 \ No newline at end of file diff --git a/app/src/main/java/com/community/pocket/data/LoginDataSource.java b/app/src/main/java/com/community/pocket/data/LoginDataSource.java index 98372e2..dc9f48a 100644 --- a/app/src/main/java/com/community/pocket/data/LoginDataSource.java +++ b/app/src/main/java/com/community/pocket/data/LoginDataSource.java @@ -6,6 +6,7 @@ import java.io.IOException; /** * Class that handles authentication w/ login credentials and retrieves user information. + * 该类处理身份验证w/登录凭据并检索用户信息。 */ public class LoginDataSource { @@ -19,11 +20,11 @@ public class LoginDataSource { "Jane Doe"); return new Result.Success<>(fakeUser); } catch (Exception e) { - return new Result.Error(new IOException("Error logging in", e)); + return new Result.Error<>(new IOException("Error logging in", e), LoggedInUser.class); } } - public void logout() { + void logout() { // TODO: revoke authentication } } diff --git a/app/src/main/java/com/community/pocket/data/LoginRepository.java b/app/src/main/java/com/community/pocket/data/LoginRepository.java index ff7c407..645265e 100644 --- a/app/src/main/java/com/community/pocket/data/LoginRepository.java +++ b/app/src/main/java/com/community/pocket/data/LoginRepository.java @@ -5,6 +5,8 @@ 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 { diff --git a/app/src/main/java/com/community/pocket/data/Result.java b/app/src/main/java/com/community/pocket/data/Result.java index 2248db2..3b40e5d 100644 --- a/app/src/main/java/com/community/pocket/data/Result.java +++ b/app/src/main/java/com/community/pocket/data/Result.java @@ -1,13 +1,17 @@ package com.community.pocket.data; +import org.jetbrains.annotations.NotNull; + /** * A generic class that holds a result success w/ data or an error exception. + * 一个泛型类,它持有一个结果成功w/数据或一个错误异常。 */ public class Result { // hide the private constructor to limit subclass types (Success, Error) private Result() { } + @NotNull @Override public String toString() { if (this instanceof Result.Success) { @@ -21,10 +25,10 @@ public class Result { } // Success sub-class - public final static class Success extends Result { + public final static class Success extends Result { private T data; - public Success(T data) { + Success(T data) { this.data = data; } @@ -34,15 +38,21 @@ public class Result { } // Error sub-class - public final static class Error extends Result { + final static class Error extends Result { private Exception error; + private Class c; - public Error(Exception error) { + Error(Exception error, Class c) { this.error = error; + this.c = c; } - public Exception getError() { + Exception getError() { return this.error; } + + public Class getC() { + return c; + } } } diff --git a/app/src/main/java/com/community/pocket/data/adapter/LocaleAdapter.java b/app/src/main/java/com/community/pocket/data/adapter/LocaleAdapter.java new file mode 100644 index 0000000..88e524a --- /dev/null +++ b/app/src/main/java/com/community/pocket/data/adapter/LocaleAdapter.java @@ -0,0 +1,58 @@ +package com.community.pocket.data.adapter; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.TextView; + +import com.community.pocket.util.LocaleType; + +import org.xutils.view.annotation.ViewInject; +import org.xutils.x; + +public class LocaleAdapter extends BaseAdapter { + private LayoutInflater inflater; + + public LocaleAdapter(LayoutInflater inflater) { + this.inflater = inflater; + } + + @Override + public int getCount() { + return LocaleType.values().length; + } + + @Override + public Object getItem(int position) { + return LocaleType.getLocale(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + ViewHolder viewHolder; + if (convertView == null) { + convertView = inflater.inflate(android.R.layout.simple_list_item_1, null); + viewHolder = new ViewHolder(); + //ViewHolder注解 + x.view().inject(viewHolder, convertView); + convertView.setTag(viewHolder); + } else { + viewHolder = (ViewHolder) convertView.getTag(); + } + viewHolder.childName.setText(convertView.getResources().getText(LocaleType.getLocale(position).getResId())); + return convertView; + } + + private class ViewHolder { + @ViewInject(android.R.id.text1)//加载item的控件 + TextView childName; + } + + +} diff --git a/app/src/main/java/com/community/pocket/data/model/LoggedInUser.java b/app/src/main/java/com/community/pocket/data/model/LoggedInUser.java index 2959cc0..f7885c3 100644 --- a/app/src/main/java/com/community/pocket/data/model/LoggedInUser.java +++ b/app/src/main/java/com/community/pocket/data/model/LoggedInUser.java @@ -2,6 +2,7 @@ package com.community.pocket.data.model; /** * Data class that captures user information for logged in users retrieved from LoginRepository + * 从LoginRepository检索的已登录用户捕获用户信息的数据类 */ public class LoggedInUser { diff --git a/app/src/main/java/com/community/pocket/ui/BaseActivity.java b/app/src/main/java/com/community/pocket/ui/BaseActivity.java new file mode 100644 index 0000000..2829f62 --- /dev/null +++ b/app/src/main/java/com/community/pocket/ui/BaseActivity.java @@ -0,0 +1,22 @@ +package com.community.pocket.ui; + +import android.content.Context; +import android.os.Bundle; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import org.xutils.x; + +public abstract class BaseActivity extends AppCompatActivity { + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(newBase); + } + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + x.view().inject(this);//加载布局,控件 + } +} diff --git a/app/src/main/java/com/community/pocket/ui/MainActivity.java b/app/src/main/java/com/community/pocket/ui/MainActivity.java new file mode 100644 index 0000000..86f39ad --- /dev/null +++ b/app/src/main/java/com/community/pocket/ui/MainActivity.java @@ -0,0 +1,8 @@ +package com.community.pocket.ui; + +import android.annotation.SuppressLint; + +@SuppressLint("Registered") +public class MainActivity extends BaseActivity { + +} diff --git a/app/src/main/java/com/community/pocket/ui/login/LoggedInUserView.java b/app/src/main/java/com/community/pocket/ui/login/LoggedInUserView.java index 6bd1b89..4ddc57a 100644 --- a/app/src/main/java/com/community/pocket/ui/login/LoggedInUserView.java +++ b/app/src/main/java/com/community/pocket/ui/login/LoggedInUserView.java @@ -2,6 +2,7 @@ package com.community.pocket.ui.login; /** * Class exposing authenticated user details to the UI. + * 类向UI公开已验证的用户详细信息。 */ class LoggedInUserView { private String displayName; diff --git a/app/src/main/java/com/community/pocket/ui/login/LoginActivity.java b/app/src/main/java/com/community/pocket/ui/login/LoginActivity.java index 3e346a9..54c7dfb 100644 --- a/app/src/main/java/com/community/pocket/ui/login/LoginActivity.java +++ b/app/src/main/java/com/community/pocket/ui/login/LoginActivity.java @@ -1,47 +1,76 @@ package com.community.pocket.ui.login; import android.app.Activity; - -import androidx.lifecycle.Observer; -import androidx.lifecycle.ViewModelProviders; - +import android.content.Context; +import android.content.Intent; import android.os.Bundle; - -import androidx.annotation.Nullable; -import androidx.annotation.StringRes; -import androidx.appcompat.app.AppCompatActivity; - import android.text.Editable; import android.text.TextWatcher; import android.view.KeyEvent; +import android.view.LayoutInflater; import android.view.View; import android.view.inputmethod.EditorInfo; +import android.widget.AdapterView; import android.widget.Button; import android.widget.EditText; import android.widget.ProgressBar; +import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProvider; + import com.community.pocket.R; -import com.community.pocket.ui.login.LoginViewModel; -import com.community.pocket.ui.login.LoginViewModelFactory; +import com.community.pocket.data.adapter.LocaleAdapter; +import com.community.pocket.ui.BaseActivity; +import com.community.pocket.util.LocalManageUtil; +import com.community.pocket.util.LocaleType; +import com.community.pocket.util.PropertiesUtil; +import com.community.pocket.util.SPUtil; + +import org.xutils.view.annotation.ContentView; +import org.xutils.view.annotation.ViewInject; + +/** + * 登陆 + */ -public class LoginActivity extends AppCompatActivity { +@ContentView(R.layout.activity_login) +public class LoginActivity extends BaseActivity { private LoginViewModel loginViewModel; + //选择语言 + @ViewInject(R.id.selectLang) + private Spinner spinner; + + //用户名 + @ViewInject(R.id.username) + private EditText usernameEditText; + + //密码 + @ViewInject(R.id.password) + private EditText passwordEditText; + + //登录按钮 + @ViewInject(R.id.login) + private Button loginButton; + + //进度条 + @ViewInject(R.id.loading) + private ProgressBar loadingProgressBar; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.activity_login); - loginViewModel = ViewModelProviders.of(this, new LoginViewModelFactory()) - .get(LoginViewModel.class); +// setContentView(R.layout.activity_login); - final EditText usernameEditText = findViewById(R.id.username); - final EditText passwordEditText = findViewById(R.id.password); - final Button loginButton = findViewById(R.id.login); - final ProgressBar loadingProgressBar = findViewById(R.id.loading); + loginViewModel = new ViewModelProvider(this, new LoginViewModelFactory()).get(LoginViewModel.class); + //监听数据校验状态 loginViewModel.getLoginFormState().observe(this, new Observer() { @Override public void onChanged(@Nullable LoginFormState loginFormState) { @@ -53,11 +82,12 @@ public class LoginActivity extends AppCompatActivity { usernameEditText.setError(getString(loginFormState.getUsernameError())); } if (loginFormState.getPasswordError() != null) { - passwordEditText.setError(getString(loginFormState.getPasswordError())); + passwordEditText.setError(getString(loginFormState.getPasswordError(), PropertiesUtil.getIntValue("password.length"))); } } }); + //监听登陆请求结果 loginViewModel.getLoginResult().observe(this, new Observer() { @Override public void onChanged(@Nullable LoginResult loginResult) { @@ -74,10 +104,31 @@ public class LoginActivity extends AppCompatActivity { setResult(Activity.RESULT_OK); //Complete and destroy login activity once successful - finish(); +// finish(); } }); + + //加载语言选项 + spinner.setAdapter(new LocaleAdapter(LayoutInflater.from(this))); + spinner.setSelection(SPUtil.getInstance(getBaseContext()).getSelectLanguage()); + //选择语言事件 + spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + if (SPUtil.getInstance(getBaseContext()).getSelectLanguage() != position) { + LocaleType locale = LocaleType.getLocale(position); + selectLanguage(locale); + } + } + + @Override + public void onNothingSelected(AdapterView parent) { + + } + }); + +// 监听用户密码文本输入框内容改变 TextWatcher afterTextChangedListener = new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { @@ -95,23 +146,31 @@ public class LoginActivity extends AppCompatActivity { passwordEditText.getText().toString()); } }; + + //添加监听器到组件 usernameEditText.addTextChangedListener(afterTextChangedListener); passwordEditText.addTextChangedListener(afterTextChangedListener); + + //监听密码软键盘输入 passwordEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + //点击完成执行登陆操作 if (actionId == EditorInfo.IME_ACTION_DONE) { loginViewModel.login(usernameEditText.getText().toString(), passwordEditText.getText().toString()); } + //默认不执行任何操作 return false; } }); + //登录按钮触发登录请求操作 loginButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { + //显示登录请求处理进度 loadingProgressBar.setVisibility(View.VISIBLE); loginViewModel.login(usernameEditText.getText().toString(), passwordEditText.getText().toString()); @@ -119,13 +178,36 @@ public class LoginActivity extends AppCompatActivity { }); } + //登陆成功信息 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(); } + + /** + * 选择语言 + * + * @param locale 语言 + */ + private void selectLanguage(LocaleType locale) { + LocalManageUtil.saveSelectLanguage(this, locale.getType()); + reStart(this); + } + + /** + * 重启 + * + * @param context 应用上下文 + */ + public static void reStart(Context context) { + Intent intent = new Intent(context, LoginActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } } diff --git a/app/src/main/java/com/community/pocket/ui/login/LoginFormState.java b/app/src/main/java/com/community/pocket/ui/login/LoginFormState.java index 881825b..7b05e14 100644 --- a/app/src/main/java/com/community/pocket/ui/login/LoginFormState.java +++ b/app/src/main/java/com/community/pocket/ui/login/LoginFormState.java @@ -4,6 +4,7 @@ import androidx.annotation.Nullable; /** * Data validation state of the login form. + * 登陆表单的数据校验 */ class LoginFormState { @Nullable diff --git a/app/src/main/java/com/community/pocket/ui/login/LoginResult.java b/app/src/main/java/com/community/pocket/ui/login/LoginResult.java index 165f735..225fbb0 100644 --- a/app/src/main/java/com/community/pocket/ui/login/LoginResult.java +++ b/app/src/main/java/com/community/pocket/ui/login/LoginResult.java @@ -4,6 +4,7 @@ import androidx.annotation.Nullable; /** * Authentication result : success (user details) or error message. + * 验证结果:成功(用户详细信息)或错误消息。 */ class LoginResult { @Nullable diff --git a/app/src/main/java/com/community/pocket/ui/login/LoginViewModel.java b/app/src/main/java/com/community/pocket/ui/login/LoginViewModel.java index 440be8d..1964afc 100644 --- a/app/src/main/java/com/community/pocket/ui/login/LoginViewModel.java +++ b/app/src/main/java/com/community/pocket/ui/login/LoginViewModel.java @@ -1,20 +1,26 @@ package com.community.pocket.ui.login; +import android.util.Patterns; + import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModel; -import android.util.Patterns; - +import com.community.pocket.R; import com.community.pocket.data.LoginRepository; import com.community.pocket.data.Result; import com.community.pocket.data.model.LoggedInUser; -import com.community.pocket.R; +/** + * 登陆表单数据 + */ public class LoginViewModel extends ViewModel { + //登陆表单校验信息 private MutableLiveData loginFormState = new MutableLiveData<>(); + //登陆结果 private MutableLiveData loginResult = new MutableLiveData<>(); + //登陆请求数据源 private LoginRepository loginRepository; LoginViewModel(LoginRepository loginRepository) { @@ -29,6 +35,7 @@ public class LoginViewModel extends ViewModel { return loginResult; } + //登陆 public void login(String username, String password) { // can be launched in a separate asynchronous job Result result = loginRepository.login(username, password); @@ -41,7 +48,8 @@ public class LoginViewModel extends ViewModel { } } - public void loginDataChanged(String username, String password) { + //登陆表单数据变化触发数据校验 + void loginDataChanged(String username, String password) { if (!isUserNameValid(username)) { loginFormState.setValue(new LoginFormState(R.string.invalid_username, null)); } else if (!isPasswordValid(password)) { @@ -52,6 +60,7 @@ public class LoginViewModel extends ViewModel { } // A placeholder username validation check + //用户名校验 private boolean isUserNameValid(String username) { if (username == null) { return false; @@ -64,6 +73,7 @@ public class LoginViewModel extends ViewModel { } // A placeholder password validation check + //密码校验 private boolean isPasswordValid(String password) { return password != null && password.trim().length() > 5; } diff --git a/app/src/main/java/com/community/pocket/ui/login/LoginViewModelFactory.java b/app/src/main/java/com/community/pocket/ui/login/LoginViewModelFactory.java index 929365c..0f68c5f 100644 --- a/app/src/main/java/com/community/pocket/ui/login/LoginViewModelFactory.java +++ b/app/src/main/java/com/community/pocket/ui/login/LoginViewModelFactory.java @@ -1,8 +1,8 @@ package com.community.pocket.ui.login; +import androidx.annotation.NonNull; import androidx.lifecycle.ViewModel; import androidx.lifecycle.ViewModelProvider; -import androidx.annotation.NonNull; import com.community.pocket.data.LoginDataSource; import com.community.pocket.data.LoginRepository; @@ -10,6 +10,8 @@ import com.community.pocket.data.LoginRepository; /** * ViewModel provider factory to instantiate LoginViewModel. * Required given LoginViewModel has a non-empty constructor + * ViewModel提供程序工厂来实例化LoginViewModel。 + * 给定的LoginViewModel有一个非空的构造函数 */ public class LoginViewModelFactory implements ViewModelProvider.Factory { diff --git a/app/src/main/java/com/community/pocket/util/InitApp.java b/app/src/main/java/com/community/pocket/util/InitApp.java new file mode 100644 index 0000000..0d117ed --- /dev/null +++ b/app/src/main/java/com/community/pocket/util/InitApp.java @@ -0,0 +1,50 @@ +package com.community.pocket.util; + +import android.app.Application; +import android.content.Context; +import android.content.res.Configuration; + +import com.github.jokar.multilanguages.library.LanguageLocalListener; +import com.github.jokar.multilanguages.library.MultiLanguage; + +import org.jetbrains.annotations.NotNull; +import org.xutils.x; + +import java.util.Locale; + +/** + * 应用启动初始化 + */ +public class InitApp extends Application { + @Override + public void onCreate() { + super.onCreate(); + //框架初始化 + x.Ext.init(this); + + MultiLanguage.init(new LanguageLocalListener() { + @Override + public Locale getSetLanguageLocale(Context context) { + //返回自己本地保存选择的语言设置 + return LocalManageUtil.getSetLanguageLocale(context); + } + }); + MultiLanguage.setApplicationLanguage(this); + } + + @Override + protected void attachBaseContext(Context base) { + //第一次进入app时保存系统选择语言(为了选择随系统语言时使用,如果不保存,切换语言后就拿不到了) + LocalManageUtil.saveSystemCurrentLanguage(base); + super.attachBaseContext(MultiLanguage.setLocal(base)); + } + + @Override + public void onConfigurationChanged(@NotNull Configuration newConfig) { + super.onConfigurationChanged(newConfig); + //用户在系统设置页面切换语言时保存系统选择语言(为了选择随系统语言时使用,如果不保存,切换语言后就拿不到了) + LocalManageUtil.saveSystemCurrentLanguage(getApplicationContext(), newConfig); + MultiLanguage.onConfigurationChanged(getApplicationContext()); + } + +} diff --git a/app/src/main/java/com/community/pocket/util/LocalManageUtil.java b/app/src/main/java/com/community/pocket/util/LocalManageUtil.java new file mode 100644 index 0000000..fe1e9cf --- /dev/null +++ b/app/src/main/java/com/community/pocket/util/LocalManageUtil.java @@ -0,0 +1,65 @@ +package com.community.pocket.util; + +import android.content.Context; +import android.content.res.Configuration; + +import com.github.jokar.multilanguages.library.MultiLanguage; + +import java.util.Locale; + +//界面语言管理工具类 +public class LocalManageUtil { + private static final String TAG = "LocalManageUtil"; + + /** + * 获取系统的locale + * + * @return Locale对象 + */ + private static Locale getSystemLocale(Context context) { + return SPUtil.getInstance(context).getSystemCurrentLocal(); + } + + public static String getSelectLanguage(Context context) { + int type = SPUtil.getInstance(context).getSelectLanguage(); + return context.getString(LocaleType.getLocale(type).getResId()); + } + + /** + * 获取选择的语言设置 + * + * @param context 应用上下文 + */ + static Locale getSetLanguageLocale(Context context) { + + int type = SPUtil.getInstance(context).getSelectLanguage(); + if (type == 0) { + return getSystemLocale(context); + } else { + return LocaleType.getLocale(type).getLocale(); + } + } + + + static void saveSystemCurrentLanguage(Context context) { + SPUtil.getInstance(context).setSystemCurrentLocal(MultiLanguage.getSystemLocal(context)); + } + + /** + * 保存系统语言 + * + * @param context 应用上下文 + * @param newConfig 刷新系统配置 + */ + static void saveSystemCurrentLanguage(Context context, Configuration newConfig) { + + SPUtil.getInstance(context).setSystemCurrentLocal(MultiLanguage.getSystemLocal(newConfig)); + } + + public static void saveSelectLanguage(Context context, int select) { + SPUtil.getInstance(context).saveLanguage(select); + MultiLanguage.setApplicationLanguage(context); + } + + +} diff --git a/app/src/main/java/com/community/pocket/util/LocaleType.java b/app/src/main/java/com/community/pocket/util/LocaleType.java new file mode 100644 index 0000000..a8ae033 --- /dev/null +++ b/app/src/main/java/com/community/pocket/util/LocaleType.java @@ -0,0 +1,46 @@ +package com.community.pocket.util; + +import com.community.pocket.R; + +import java.util.Locale; + +//语言类型 +public enum LocaleType { + auto(Locale.ENGLISH, 0, R.string.language_auto), + chs(Locale.CHINA, 1, R.string.language_chs), + en(Locale.ENGLISH, 2, R.string.language_en); + + //语言 + private Locale locale; + //类型值 + private int type; + //选项名对应的资源id + private int resId; + + public Locale getLocale() { + return locale; + } + + public int getType() { + return type; + } + + public int getResId() { + return resId; + } + + LocaleType(Locale locale, int type, int resId) { + this.locale = locale; + this.type = type; + this.resId = resId; + } + + public static LocaleType getLocale(int type) { + for (LocaleType t : LocaleType.values()) { + if (t.type == type) { + return t; + } + } + return LocaleType.auto; + } +} diff --git a/app/src/main/java/com/community/pocket/util/PropertiesUtil.java b/app/src/main/java/com/community/pocket/util/PropertiesUtil.java new file mode 100644 index 0000000..2af346d --- /dev/null +++ b/app/src/main/java/com/community/pocket/util/PropertiesUtil.java @@ -0,0 +1,48 @@ +package com.community.pocket.util; + +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +//读取配置文件工具类 +public class PropertiesUtil { + + private static Properties properties; + + private final static Map values = new HashMap<>(); + + // 文件路径 + private static final String filePath = "/assets/config.properties"; + + static { + properties = new Properties(); + try { + InputStream is = PropertiesUtil.class.getResourceAsStream(filePath); + properties.load(is); + } catch (Exception e) { + e.printStackTrace(); + } + } + + //获取字符串配置 + private static String getValue(String key) { + if (values.containsKey(key)) { + return values.get(key); + } else { + String value = properties.getProperty(key); + values.put(key, value); + return value; + } + } + + // 获取整数配置 + public static int getIntValue(String key) { + String value = getValue(key); + if (value.matches("\\d+")) { + return Integer.parseInt(value); + } else { + throw new RuntimeException("值转换异常!无法把" + key + "=" + value + "转化成整数"); + } + } +} diff --git a/app/src/main/java/com/community/pocket/util/SPUtil.java b/app/src/main/java/com/community/pocket/util/SPUtil.java new file mode 100644 index 0000000..6313c57 --- /dev/null +++ b/app/src/main/java/com/community/pocket/util/SPUtil.java @@ -0,0 +1,56 @@ +package com.community.pocket.util; + +import android.content.Context; +import android.content.SharedPreferences; + +import java.util.Locale; + +/** + * 界面语言配置读写 + */ +public class SPUtil { + + private final String SP_NAME = "language_setting"; + private final String TAG_LANGUAGE = "language_select"; + private static volatile SPUtil instance; + + private final SharedPreferences mSharedPreferences; + + private Locale systemCurrentLocal = Locale.ENGLISH; + + + private SPUtil(Context context) { + mSharedPreferences = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); + } + + + void saveLanguage(int select) { + SharedPreferences.Editor edit = mSharedPreferences.edit(); + edit.putInt(TAG_LANGUAGE, select); + edit.apply(); + } + + public int getSelectLanguage() { + return mSharedPreferences.getInt(TAG_LANGUAGE, 0); + } + + + Locale getSystemCurrentLocal() { + return systemCurrentLocal; + } + + void setSystemCurrentLocal(Locale local) { + systemCurrentLocal = local; + } + + public static SPUtil getInstance(Context context) { + if (instance == null) { + synchronized (SPUtil.class) { + if (instance == null) { + instance = new SPUtil(context); + } + } + } + return instance; + } +} diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index ee0ad0a..7ab34d9 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -24,7 +24,8 @@ android:selectAllOnFocus="true" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toTopOf="parent" + android:autofillHints="@string/AUTOFILL_HINT_USERNAME" /> + app:layout_constraintTop_toBottomOf="@+id/username" + android:autofillHints="@string/AUTOFILL_HINT_PASSWORD" />