+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..ff2bd08
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000..457e5a0
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1,7 @@
+/build
+.idea
+gradlew
+gradlew.bat
+.DS_Store
+*.iml
+.gradle
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 0000000..4bc71cd
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,75 @@
+plugins {
+ id 'com.android.application'
+ id 'kotlin-android'
+ id 'kotlin-android-extensions'
+ id 'kotlin-kapt'
+}
+
+
+static def releaseTime() {
+ return "" + new Date().format("yyyyMMddHHmm", TimeZone.getTimeZone("Asia/Shanghai"))
+}
+
+android {
+ compileSdk 32
+ defaultConfig {
+ applicationId "com.cmx.hydrology"
+ minSdk 21
+ targetSdk 29
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ android.applicationVariants.all { variant ->
+ variant.outputs.all {
+ outputFileName = "hydrology" + versionName + "_" + versionCode + "_" + releaseTime() + ".apk"
+ }
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+ buildFeatures {
+ viewBinding true
+ }
+}
+
+
+dependencies {
+ implementation(fileTree("libs"))
+ implementation 'androidx.work:work-runtime:2.7.1'
+ implementation 'androidx.appcompat:appcompat:1.3.0'
+ implementation 'com.google.android.material:material:1.4.0'
+ implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
+ implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1'
+ implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
+ implementation 'androidx.navigation:navigation-fragment:2.3.5'
+ implementation 'androidx.navigation:navigation-ui:2.3.5'
+ implementation 'androidx.annotation:annotation:1.2.0'
+ testImplementation 'junit:junit:4.13.2'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.3'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
+ implementation 'com.google.code.gson:gson:2.6.2'
+ implementation 'com.squareup.retrofit2:retrofit:2.4.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
+ implementation 'com.github.GrenderG:Toasty:1.5.2'
+ implementation 'com.squareup.okhttp3:logging-interceptor:3.8.1'
+ implementation 'com.github.lsxiao.Apollo:core:1.0.2'
+ implementation 'com.github.lsxiao.Apollo:ipc:1.0.2'
+ kapt "com.github.lsxiao.Apollo:processor:1.0.2"
+ //Apollo的编译时注解处理器
+ annotationProcessor "com.github.lsxiao.Apollo:processor:1.0.2"
+ implementation "io.reactivex.rxjava2:rxjava:2.2.4"
+ implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
+ implementation 'com.github.nanchen2251:CompressHelper:1.0.5'
+
+ implementation 'com.scwang.wave:MultiWaveHeader:1.0.0-andx'
+}
\ No newline at end of file
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..d78ea24
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/cmx/hydrology/activity/BaseActivity.java b/app/src/main/java/com/cmx/hydrology/activity/BaseActivity.java
new file mode 100644
index 0000000..b5dc572
--- /dev/null
+++ b/app/src/main/java/com/cmx/hydrology/activity/BaseActivity.java
@@ -0,0 +1,75 @@
+package com.cmx.hydrology.activity;
+
+import android.os.Bundle;
+import android.webkit.WebResourceError;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+import androidx.appcompat.app.AppCompatActivity;
+
+import com.cmx.hydrology.view.BaseLoadingDialog;
+import com.lsxiao.apollo.core.Apollo;
+import com.lsxiao.apollo.core.contract.ApolloBinder;
+
+public class BaseActivity extends AppCompatActivity {
+
+ private static final String TAG = "BaseActivity";
+ private BaseLoadingDialog mBaseLoadingDialog;
+ private ApolloBinder mApolloBinder;
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mBaseLoadingDialog = new BaseLoadingDialog(this);
+ mApolloBinder = Apollo.bind(this);
+ }
+
+
+ public void showDialog() {
+ if (!mBaseLoadingDialog.isShowing()) {
+ mBaseLoadingDialog.show();
+ }
+ }
+
+
+ public void disDialog() {
+ if (mBaseLoadingDialog.isShowing()) {
+ mBaseLoadingDialog.dismiss();
+ }
+ }
+
+ public void setWeb(WebView mWebView) {
+ mWebView.setWebViewClient(new WebViewClient() {
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView view, String url) {
+ //使用WebView加载显示url
+ view.loadUrl(url);
+ //返回true
+ return true;
+ }
+
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ disDialog();
+ }
+
+ @Override
+ public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
+ disDialog();
+ }
+ }
+
+ );
+ }
+
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (mApolloBinder != null) {
+ mApolloBinder.unbind();
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/cmx/hydrology/activity/LoginActivity.java b/app/src/main/java/com/cmx/hydrology/activity/LoginActivity.java
new file mode 100644
index 0000000..491e689
--- /dev/null
+++ b/app/src/main/java/com/cmx/hydrology/activity/LoginActivity.java
@@ -0,0 +1,92 @@
+package com.cmx.hydrology.activity;
+
+import android.content.Intent;
+import android.os.Build;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.View;
+
+import androidx.annotation.RequiresApi;
+
+import com.cmx.hydrology.databinding.ActivityLoginBinding;
+import com.cmx.hydrology.model.LoginBean;
+import com.cmx.hydrology.model.LoginRes;
+import com.cmx.hydrology.retrofit.RetrofitAPIManager;
+import com.cmx.hydrology.utils.MyUtils;
+import com.cmx.hydrology.utils.SpUtils;
+
+import es.dmoral.toasty.Toasty;
+import retrofit2.Call;
+import retrofit2.Callback;
+import retrofit2.Response;
+
+public class LoginActivity extends BaseActivity {
+
+ private ActivityLoginBinding binding;
+
+ @RequiresApi(api = Build.VERSION_CODES.M)
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ binding = ActivityLoginBinding.inflate(getLayoutInflater());
+ setContentView(binding.getRoot());
+ MyUtils.setFullscreen(this, true, true);
+ binding.btnLogin.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Intent intent = new Intent(LoginActivity.this, MainActivity.class);
+ startActivity(intent);
+ finish();
+ // if (TextUtils.isEmpty(binding.edtUsername.getText().toString().trim())) {
+ // Toasty.info(LoginActivity.this, "请输入用户名").show();
+ // return;
+ // }
+ // if (TextUtils.isEmpty(binding.edtPassword.getText().toString().trim())) {
+ // Toasty.info(LoginActivity.this, "请输入密码").show();
+ // return;
+ // }
+ // toLogin();
+ }
+ });
+ }
+
+
+ /**
+ * 登录
+ */
+ private void toLogin() {
+ showDialog();
+ LoginBean LoginBean = new LoginBean();
+ LoginBean.setUsername(binding.edtUsername.getText().toString().trim());
+ LoginBean.setPassword(binding.edtPassword.getText().toString().trim());
+ Call call = RetrofitAPIManager.provideClientApi().login(LoginBean);
+ call.enqueue(new Callback() {
+ @Override
+ public void onResponse(Call call, Response response) {
+ disDialog();
+ if (response.isSuccessful() && response.body().getCode() == 0) {
+ SpUtils.putString(LoginActivity.this, "token", response.body().getAccess_token());
+ SpUtils.putString(LoginActivity.this, "admin", response.body().getIs_admin());
+ Intent intent = new Intent(LoginActivity.this, MainActivity.class);
+ startActivity(intent);
+ finish();
+ } else {
+ Toasty.error(LoginActivity.this, response.body().getMessage()).show();
+ }
+ }
+
+ @Override
+ public void onFailure(Call call, Throwable t) {
+ disDialog();
+ Toasty.info(LoginActivity.this, "登录失败").show();
+ }
+ });
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ binding = null;
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/cmx/hydrology/activity/MainActivity.java b/app/src/main/java/com/cmx/hydrology/activity/MainActivity.java
new file mode 100644
index 0000000..b0e1190
--- /dev/null
+++ b/app/src/main/java/com/cmx/hydrology/activity/MainActivity.java
@@ -0,0 +1,114 @@
+package com.cmx.hydrology.activity;
+
+import android.content.Intent;
+import android.os.Build;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+
+import androidx.annotation.RequiresApi;
+import androidx.navigation.NavController;
+import androidx.navigation.Navigation;
+import androidx.navigation.ui.NavigationUI;
+
+import com.cmx.hydrology.R;
+import com.cmx.hydrology.constant.Events;
+import com.cmx.hydrology.databinding.ActivityMainBinding;
+import com.google.android.material.bottomnavigation.BottomNavigationView;
+import com.lsxiao.apollo.core.Apollo;
+import com.lsxiao.apollo.core.annotations.Receive;
+
+public class MainActivity extends BaseActivity {
+
+ private ActivityMainBinding binding;
+ private BottomNavigationView navView;
+ private NavController navController;
+
+
+ @RequiresApi(api = Build.VERSION_CODES.M)
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ binding = ActivityMainBinding.inflate(getLayoutInflater());
+ setContentView(binding.getRoot());
+ navView = findViewById(R.id.nav_view);
+ navController = Navigation.findNavController(this, R.id.nav_host_fragment_activity_main);
+ NavigationUI.setupWithNavController(binding.navView, navController);
+ }
+
+
+ /**
+ * 显示tabbar
+ */
+ @Receive(Events.JS_OPEN_TABBAR_SHOW)
+ public void showTab() {
+ binding.navView.setVisibility(View.VISIBLE);
+ }
+
+ /**
+ * 隐藏tabbar
+ */
+ @Receive(Events.JS_OPEN_TABBAR_HIDE)
+ public void hideTab() {
+ binding.navView.setVisibility(View.GONE);
+ }
+
+
+ /**
+ * 打开新的web
+ */
+ @Receive(Events.JS_OPEN_OPEN_WEB)
+ public void openWeb(String url) {
+ Intent intent = new Intent(this, WebActivity.class);
+ intent.putExtra("url", url);
+ startActivity(intent);
+ }
+
+
+ /**
+ * 选择tab
+ */
+ @Receive(Events.JS_OPEN_TAB)
+ public void ckTab(String mode) {
+ Apollo.emit(Events.JS_OPEN_CLOSE_WEB);
+ switch (mode) {
+ case "1":
+ Menu menu = navView.getMenu();
+ MenuItem menuItem = menu.getItem(0); // 将index替换为您想要点击的项目的索引
+ menuItem.setChecked(true);
+ navController.navigate(R.id.navigation_home);
+ break;
+ case "2":
+ Menu menu2 = navView.getMenu();
+ MenuItem menuItem2 = menu2.getItem(1); // 将index替换为您想要点击的项目的索引
+ menuItem2.setChecked(true);
+ navController.navigate(R.id.navigation_msg);
+ break;
+ case "3":
+ Menu menu3 = navView.getMenu();
+ MenuItem menuItem3 = menu3.getItem(2); // 将index替换为您想要点击的项目的索引
+ menuItem3.setChecked(true);
+ navController.navigate(R.id.navigation_map);
+ break;
+ case "4":
+ Menu menu4 = navView.getMenu();
+ MenuItem menuItem4 = menu4.getItem(3); // 将index替换为您想要点击的项目的索引
+ menuItem4.setChecked(true);
+ navController.navigate(R.id.navigation_my);
+ break;
+ }
+ }
+
+
+ /**
+ * 退出登录
+ */
+ @Receive(Events.JS_OPEN_LOGOUT)
+ public void exit() {
+ Apollo.emit(Events.JS_OPEN_CLOSE_WEB);
+ finish();
+ Intent intent = new Intent(this, LoginActivity.class);
+ startActivity(intent);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/cmx/hydrology/activity/MyApplication.java b/app/src/main/java/com/cmx/hydrology/activity/MyApplication.java
new file mode 100644
index 0000000..47a522f
--- /dev/null
+++ b/app/src/main/java/com/cmx/hydrology/activity/MyApplication.java
@@ -0,0 +1,40 @@
+package com.cmx.hydrology.activity;
+
+import android.app.Application;
+import android.content.Context;
+
+import com.lsxiao.apollo.core.Apollo;
+
+import io.reactivex.android.schedulers.AndroidSchedulers;
+
+public class MyApplication extends Application {
+ private static MyApplication mInstance;
+
+ private static String mToken;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mInstance = this;
+ Apollo.init(AndroidSchedulers.mainThread(), this);
+ }
+
+
+ @Override
+ protected void attachBaseContext(Context base) {
+ super.attachBaseContext(base);
+ }
+
+
+ public static MyApplication getmInstance() {
+ return mInstance;
+ }
+
+ public static String getmToken() {
+ return mToken;
+ }
+
+ public static void setmToken(String mToken) {
+ MyApplication.mToken = mToken;
+ }
+}
diff --git a/app/src/main/java/com/cmx/hydrology/activity/WebActivity.java b/app/src/main/java/com/cmx/hydrology/activity/WebActivity.java
new file mode 100644
index 0000000..c16255a
--- /dev/null
+++ b/app/src/main/java/com/cmx/hydrology/activity/WebActivity.java
@@ -0,0 +1,179 @@
+package com.cmx.hydrology.activity;
+
+import android.app.Activity;
+import android.content.ClipData;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Environment;
+import android.provider.MediaStore;
+import android.util.Log;
+import android.webkit.ValueCallback;
+import android.webkit.WebChromeClient;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+
+import androidx.annotation.Nullable;
+
+import com.cmx.hydrology.databinding.ActivityWebBinding;
+import com.cmx.hydrology.utils.AndroidtoJs;
+import com.cmx.hydrology.utils.L;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+
+public class WebActivity extends BaseActivity {
+
+ private WebView mWebView;
+ private ActivityWebBinding binding;
+ private String url;
+ public static final int REQUEST_CODE_LIVENESS = 209;
+ public static final int TRUST_LEVEL = 50;
+ private ValueCallback mUploadMessage;
+ private String mCameraPhotoPath = null;
+ private long size = 0;
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ binding = ActivityWebBinding.inflate(getLayoutInflater());
+ setContentView(binding.getRoot());
+ url = getIntent().getStringExtra("url");
+ // MyUtils.setFullscreen(this, true, true);//影响键盘 模式 页面遮挡
+ // MyUtils.setAndroidNativeLightStatusBar(this, true);//影响键盘 模式 页面遮挡
+ mWebView = binding.wvRegister;
+ WebSettings webSettings = mWebView.getSettings();
+ webSettings.setJavaScriptEnabled(true);
+ webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
+ webSettings.setDomStorageEnabled(true);
+ mWebView.addJavascriptInterface(new AndroidtoJs(), "AndroidtoJs");
+ mWebView.loadUrl(url);
+ showDialog();
+ setWeb(mWebView);
+ mWebView.setWebChromeClient(new PQChromeClient());
+ }
+
+
+ // @Receive(Events.JS_OPEN_CLOSE_WEB)
+ // public void fin() {
+ // finish();
+ // }
+
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (requestCode == 101 && mUploadMessage != null) {
+ try {
+ String file_path = mCameraPhotoPath.replace("file:", "");
+ File file = new File(file_path);
+ size = file.length();
+ if (!(data != null || size > 0)) {
+ mUploadMessage.onReceiveValue(null);
+ mUploadMessage = null;
+ return;
+ }
+ if (data != null || mCameraPhotoPath != null) {
+ Integer count = 1;
+ ClipData images = null;
+ try {
+ images = data.getClipData();
+ } catch (Exception e) {
+ Log.e("Error11!", e.getLocalizedMessage());
+ }
+ if (images == null && data != null && data.getDataString() != null) {
+ count = data.getDataString().length();
+ } else if (images != null) {
+ count = images.getItemCount();
+ }
+ Uri[] results = new Uri[count];
+ // Check that the response is a good one
+ if (resultCode == Activity.RESULT_OK) {
+ if (size != 0) {
+ // If there is not data, then we may have taken a photo
+ if (mCameraPhotoPath != null) {
+ results = new Uri[]{Uri.parse(mCameraPhotoPath)};
+ }
+ } else if (data.getClipData() == null) {
+ results = new Uri[]{Uri.parse(data.getDataString())};
+ } else {
+ for (int i = 0; i < images.getItemCount(); i++) {
+ results[i] = images.getItemAt(i).getUri();
+ }
+ }
+ }
+ mUploadMessage.onReceiveValue(results);
+ mUploadMessage = null;
+ }
+ } catch (Exception e) {
+ Log.e("Error22!", "Error while opening image file" + e.getLocalizedMessage());
+ }
+ }
+ }
+
+ public class PQChromeClient extends WebChromeClient {
+ // For Android 5.0+
+ public boolean onShowFileChooser(WebView view, ValueCallback filePath, WebChromeClient.FileChooserParams fileChooserParams) {
+ L.e("点击》》", "11");
+ // Double check that we don't have any existing callbacks
+ if (mUploadMessage != null) {
+ L.e("点击》》", "22");
+ mUploadMessage.onReceiveValue(null);
+ }
+ mUploadMessage = filePath;
+ Log.e("FileCooserParams => ", filePath.toString());
+ Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+ if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
+ // Create the File where the photo should go
+ File photoFile = null;
+ try {
+ photoFile = createImageFile();
+ takePictureIntent.putExtra("PhotoPath", mCameraPhotoPath);
+ } catch (IOException ex) {
+ // Error occurred while creating the File
+ Log.e("test", "Unable to create Image File", ex);
+ }
+ // Continue only if the File was successfully created
+ if (photoFile != null) {
+ mCameraPhotoPath = "file:" + photoFile.getAbsolutePath();
+ takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
+ } else {
+ takePictureIntent = null;
+ }
+ }
+
+ Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
+ contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
+ contentSelectionIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
+ contentSelectionIntent.setType("image/*");
+ Intent[] intentArray;
+ if (takePictureIntent != null) {
+ intentArray = new Intent[]{takePictureIntent};
+ } else {
+ intentArray = new Intent[2];
+ }
+ Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
+ chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
+ chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser");
+ chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
+ startActivityForResult(Intent.createChooser(chooserIntent, "Select images"), 101);
+ return true;
+ }
+ }
+
+ private File createImageFile() throws IOException {
+ // Create an image file name
+ String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
+ String imageFileName = "JPEG_" + timeStamp + "_";
+ File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
+ File imageFile = File.createTempFile(imageFileName, /* prefix */
+ ".jpg", /* suffix */
+ storageDir /* directory */);
+ return imageFile;
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/cmx/hydrology/constant/Events.kt b/app/src/main/java/com/cmx/hydrology/constant/Events.kt
new file mode 100644
index 0000000..c14c8f5
--- /dev/null
+++ b/app/src/main/java/com/cmx/hydrology/constant/Events.kt
@@ -0,0 +1,42 @@
+package com.cmx.hydrology.constant
+
+
+/**
+ * @author LIJIE
+ */
+interface Events {
+ companion object {
+ const val WEB_SERVER_URL = "http://8.222.137.126:80"
+ const val SERVER_URL = "http://192.168.110.174:8000"
+
+ /**
+ * tabbar显示
+ */
+ const val JS_OPEN_TABBAR_SHOW = "js_open_tabbar_show"
+
+ /**
+ * tabbar隐藏
+ */
+ const val JS_OPEN_TABBAR_HIDE = "js_open_tabbat_hide"
+
+ /**
+ * 打开一个新web界面
+ */
+ const val JS_OPEN_OPEN_WEB = "js_open_open_web"
+
+ /**
+ * 关闭web界面
+ */
+ const val JS_OPEN_CLOSE_WEB = "js_open_close_web"
+
+ /**
+ * 退出登录
+ */
+ const val JS_OPEN_LOGOUT = "js_open_logout"
+
+ /**
+ * 切换tab
+ */
+ const val JS_OPEN_TAB = "js_open_tab"
+ }
+}
diff --git a/app/src/main/java/com/cmx/hydrology/model/LoginBean.java b/app/src/main/java/com/cmx/hydrology/model/LoginBean.java
new file mode 100644
index 0000000..e70d15d
--- /dev/null
+++ b/app/src/main/java/com/cmx/hydrology/model/LoginBean.java
@@ -0,0 +1,22 @@
+package com.cmx.hydrology.model;
+
+public class LoginBean {
+ String username;
+ String password;
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+}
diff --git a/app/src/main/java/com/cmx/hydrology/model/LoginRes.java b/app/src/main/java/com/cmx/hydrology/model/LoginRes.java
new file mode 100644
index 0000000..b83f261
--- /dev/null
+++ b/app/src/main/java/com/cmx/hydrology/model/LoginRes.java
@@ -0,0 +1,51 @@
+package com.cmx.hydrology.model;
+
+
+public class LoginRes {
+
+
+ /**
+ * code : 0
+ * message : 登录成功
+ * access_token : 1914936f8c87fddd11836ebebb65317bb7f57506
+ * is_admin : 1
+ */
+
+
+ private int code;
+ private String message;
+ private String access_token;
+ private String is_admin;
+
+ public int getCode() {
+ return code;
+ }
+
+ public void setCode(int code) {
+ this.code = code;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public String getAccess_token() {
+ return access_token;
+ }
+
+ public void setAccess_token(String access_token) {
+ this.access_token = access_token;
+ }
+
+ public String getIs_admin() {
+ return is_admin;
+ }
+
+ public void setIs_admin(String is_admin) {
+ this.is_admin = is_admin;
+ }
+}
diff --git a/app/src/main/java/com/cmx/hydrology/retrofit/ApiRequtest.java b/app/src/main/java/com/cmx/hydrology/retrofit/ApiRequtest.java
new file mode 100644
index 0000000..a88dd2d
--- /dev/null
+++ b/app/src/main/java/com/cmx/hydrology/retrofit/ApiRequtest.java
@@ -0,0 +1,47 @@
+package com.cmx.hydrology.retrofit;
+
+import com.google.gson.reflect.TypeToken;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.IOException;
+
+import okhttp3.ResponseBody;
+import retrofit2.Call;
+import retrofit2.Callback;
+
+
+public class ApiRequtest {
+ private static final String TAG = ApiRequtest.class.getSimpleName();
+
+ private TypeToken mResultType;
+
+ public ApiRequtest (Call call, TypeToken resultType, final ApiResponse.Listener> listener, final ApiResponse.ErrorListener errorListener){
+ mResultType = resultType;
+ call.enqueue(new Callback() {
+ @Override
+ public void onResponse(Call call, retrofit2.Response response) {
+ try {
+ ResponseBody responseBody = response.body();
+ if(responseBody != null){
+ String jsonString = response.body().string();
+ final ApiResult result = new ApiResult<>(new JSONObject(jsonString), mResultType);
+ listener.onResponse(result);
+ }
+
+ }catch (IOException e){
+ }catch (JSONException e) {
+ }
+ }
+
+ @Override
+ public void onFailure(Call call, Throwable t) {
+ errorListener.onErrorResponse(t);
+ }
+ });
+ }
+
+
+
+}
diff --git a/app/src/main/java/com/cmx/hydrology/retrofit/ApiResponse.java b/app/src/main/java/com/cmx/hydrology/retrofit/ApiResponse.java
new file mode 100644
index 0000000..14f7f53
--- /dev/null
+++ b/app/src/main/java/com/cmx/hydrology/retrofit/ApiResponse.java
@@ -0,0 +1,19 @@
+package com.cmx.hydrology.retrofit;
+
+public class ApiResponse {
+
+ /**
+ * network request error response
+ */
+ public interface ErrorListener {
+ void onErrorResponse(Throwable requestError);
+ }
+
+ /**
+ * network request success response result
+ * @param data result
+ */
+ public interface Listener {
+ void onResponse(T result);
+ }
+}
diff --git a/app/src/main/java/com/cmx/hydrology/retrofit/ApiResult.java b/app/src/main/java/com/cmx/hydrology/retrofit/ApiResult.java
new file mode 100644
index 0000000..35c1b55
--- /dev/null
+++ b/app/src/main/java/com/cmx/hydrology/retrofit/ApiResult.java
@@ -0,0 +1,104 @@
+package com.cmx.hydrology.retrofit;
+
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+
+import org.json.JSONObject;
+
+
+/**
+ *
+ */
+public class ApiResult {
+
+ private final static String TAG = ApiResult.class.getSimpleName();
+
+ public static final int OK = 0;
+
+ public Boolean success = true;
+ private Integer code = OK;
+ private String msg="";
+ private T result;
+ private String msgJson;
+ private static Gson gson = new Gson();
+
+
+ public ApiResult() {
+ super();
+ // TODO Auto-generated constructor stub
+ }
+
+ public ApiResult(JSONObject jsonObject, TypeToken typeToken) {
+ super();
+ try{
+ if (jsonObject.has("errcode")){
+ code = jsonObject.getInt("errcode");
+ if (code != OK) {
+ if (jsonObject.has("errmsg")) {
+ msg = jsonObject.getString("errmsg");
+ }
+
+ success = false;
+
+ }
+ }else{
+
+ }
+
+ if (code == OK){
+ try {
+ result = gson.fromJson(jsonObject.toString(), typeToken.getType());
+ }catch (Exception ex){
+
+ }
+
+ }
+ }catch (Exception e) {
+ // TODO: handle exception
+ }
+
+ }
+ private T testDefault(String msg){
+ Gson gson = new Gson();
+ result = gson.fromJson(msg,new TypeToken(){}.getType());
+ return result;
+ }
+ private T test(String msg, TypeToken typeToken){
+ Gson gson = new Gson();
+ result = gson.fromJson(msg,typeToken.getType());
+ return result;
+ }
+
+ public Integer getCode() {
+ return code;
+ }
+ public void setCode(Integer code) {
+ this.code = code;
+ }
+ public String getMsg() {
+ return msg;
+ }
+ public void setMsg(String msg) {
+ this.msg = msg;
+ }
+
+ public T getResult() {
+ return result;
+ }
+
+ public void setResult(T result) {
+ this.result = result;
+ }
+
+ public Boolean getSuccess() {
+ return success;
+ }
+
+ public void setSuccess(Boolean success) {
+ this.success = success;
+ }
+
+ public String getMsgJson() {
+ return msgJson;
+ }
+}
diff --git a/app/src/main/java/com/cmx/hydrology/retrofit/ApiService.java b/app/src/main/java/com/cmx/hydrology/retrofit/ApiService.java
new file mode 100644
index 0000000..46a8f62
--- /dev/null
+++ b/app/src/main/java/com/cmx/hydrology/retrofit/ApiService.java
@@ -0,0 +1,22 @@
+package com.cmx.hydrology.retrofit;
+
+import com.cmx.hydrology.model.LoginBean;
+import com.cmx.hydrology.model.LoginRes;
+
+import retrofit2.Call;
+import retrofit2.http.Body;
+import retrofit2.http.POST;
+
+/**
+ * Created by
+ */
+public interface ApiService {
+ /**
+ * 登录
+ *
+ * @param body
+ * @return
+ */
+ @POST("/login")
+ Call login(@Body LoginBean body);
+}
diff --git a/app/src/main/java/com/cmx/hydrology/retrofit/RetrofitAPIManager.java b/app/src/main/java/com/cmx/hydrology/retrofit/RetrofitAPIManager.java
new file mode 100644
index 0000000..c9f3e89
--- /dev/null
+++ b/app/src/main/java/com/cmx/hydrology/retrofit/RetrofitAPIManager.java
@@ -0,0 +1,71 @@
+package com.cmx.hydrology.retrofit;
+
+
+import static com.cmx.hydrology.constant.Events.SERVER_URL;
+
+import android.util.Log;
+
+import com.cmx.hydrology.activity.MyApplication;
+import com.cmx.hydrology.utils.SpUtils;
+import com.google.gson.reflect.TypeToken;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.concurrent.TimeUnit;
+
+import okhttp3.Interceptor;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import okhttp3.ResponseBody;
+import okhttp3.logging.HttpLoggingInterceptor;
+import retrofit2.Call;
+import retrofit2.Retrofit;
+import retrofit2.converter.gson.GsonConverterFactory;
+
+/**
+ * Created by TTLock on 2018/9/5.
+ */
+
+
+public class RetrofitAPIManager {
+
+
+ public static ApiService provideClientApi() {
+ Retrofit retrofit = new Retrofit.Builder().client(genericClient()).baseUrl(SERVER_URL).addConverterFactory(GsonConverterFactory.create()).build();
+ return retrofit.create(ApiService.class);
+ }
+
+ public static OkHttpClient genericClient() {
+ HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
+ @Override
+ public void log(String message) {
+ // try {
+ // String text = URLDecoder.decode(message, "utf-8");
+ // Log.e("OKHttp-----", text);
+ // } catch (UnsupportedEncodingException e) {
+ // e.printStackTrace();
+ Log.e("OKHttp-----", message);
+ // }
+ }
+ });
+ interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
+ OkHttpClient httpClient = new OkHttpClient.Builder().connectTimeout(35, TimeUnit.SECONDS).readTimeout(35, TimeUnit.SECONDS).writeTimeout(35, TimeUnit.SECONDS).addInterceptor(interceptor).addInterceptor(new Interceptor() {
+ @Override
+ public Response intercept(Chain chain) throws IOException {
+ Request original = chain.request();
+ Request.Builder requestBuilder = original.newBuilder().header("token", SpUtils.getString(MyApplication.getmInstance(), "token"));
+ Request request = requestBuilder.build();
+ return chain.proceed(request);
+ }
+ }).build();
+
+ return httpClient;
+ }
+
+ public static ApiRequtest enqueue(Call call, TypeToken resultType, ApiResponse.Listener> listener, ApiResponse.ErrorListener errorListener) {
+ ApiRequtest request = new ApiRequtest<>(call, resultType, listener, errorListener);
+ return request;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/cmx/hydrology/retrofit/onRequestResponse.java b/app/src/main/java/com/cmx/hydrology/retrofit/onRequestResponse.java
new file mode 100644
index 0000000..686672a
--- /dev/null
+++ b/app/src/main/java/com/cmx/hydrology/retrofit/onRequestResponse.java
@@ -0,0 +1,9 @@
+package com.cmx.hydrology.retrofit;
+
+/**
+ * Created by Administrator on 2018/1/17 0017.
+ */
+
+public interface onRequestResponse {
+ void onResult(boolean success);
+}
diff --git a/app/src/main/java/com/cmx/hydrology/retrofit/onServerRequestCallBack.java b/app/src/main/java/com/cmx/hydrology/retrofit/onServerRequestCallBack.java
new file mode 100644
index 0000000..cce0ed1
--- /dev/null
+++ b/app/src/main/java/com/cmx/hydrology/retrofit/onServerRequestCallBack.java
@@ -0,0 +1,9 @@
+package com.cmx.hydrology.retrofit;
+
+/**
+ * Created by Administrator on 2018/1/17 0017.
+ */
+
+public interface onServerRequestCallBack {
+ void onResult(int resultCode);
+}
diff --git a/app/src/main/java/com/cmx/hydrology/ui/HomeFragment.java b/app/src/main/java/com/cmx/hydrology/ui/HomeFragment.java
new file mode 100644
index 0000000..e4a1332
--- /dev/null
+++ b/app/src/main/java/com/cmx/hydrology/ui/HomeFragment.java
@@ -0,0 +1,226 @@
+package com.cmx.hydrology.ui;
+
+
+import android.app.Activity;
+import android.content.ClipData;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Environment;
+import android.provider.MediaStore;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.ValueCallback;
+import android.webkit.WebChromeClient;
+import android.webkit.WebResourceError;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+
+import com.cmx.hydrology.databinding.FragmentHomeBinding;
+import com.cmx.hydrology.utils.AndroidtoJs;
+import com.cmx.hydrology.utils.MyUtils;
+import com.cmx.hydrology.view.BaseLoadingDialog;
+import com.lsxiao.apollo.core.Apollo;
+import com.lsxiao.apollo.core.contract.ApolloBinder;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class HomeFragment extends Fragment {
+
+ private FragmentHomeBinding binding;
+ private BaseLoadingDialog mBaseLoadingDialog;
+ private WebView mWebView;
+ private ApolloBinder mApolloBinder;
+ private ValueCallback mUploadMessage;
+ private String mCameraPhotoPath = null;
+ private long size = 0;
+ private static final int INPUT_FILE_REQUEST_CODE = 1;
+
+
+ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ binding = FragmentHomeBinding.inflate(inflater, container, false);
+ mBaseLoadingDialog = new BaseLoadingDialog(getActivity());
+ View root = binding.getRoot();
+ MyUtils.setFullscreen(requireActivity(), false, false);
+ MyUtils.setAndroidNativeLightStatusBar(requireActivity(), true);
+ mWebView = binding.wvHome;
+ mApolloBinder = Apollo.bind(this);
+ WebSettings webSettings = mWebView.getSettings();
+ webSettings.setJavaScriptEnabled(true);
+ webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
+ webSettings.setDomStorageEnabled(true);
+ webSettings.setAllowFileAccess(true);//文件访问
+ webSettings.setAllowFileAccessFromFileURLs(true);
+ mWebView.addJavascriptInterface(new AndroidtoJs(), "AndroidtoJs");
+ mWebView.loadUrl("https://cmx.bskies.cc:8000/cmx-hydrology-h5/#/home");
+ showDialog();
+ mWebView.setWebChromeClient(new PQChromeClient());
+ mWebView.setWebViewClient(new WebViewClient() {
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView view, String url) {
+ //使用WebView加载显示url
+ view.loadUrl(url);
+ //返回true
+ return true;
+ }
+
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ disDialog();
+ }
+
+ @Override
+ public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
+ disDialog();
+ }
+ }
+
+ );
+ return root;
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ binding = null;
+ if (mApolloBinder != null) {
+ mApolloBinder.unbind();
+ }
+ }
+
+ public void showDialog() {
+ mBaseLoadingDialog = new BaseLoadingDialog(getActivity());
+ if (!mBaseLoadingDialog.isShowing()) {
+ mBaseLoadingDialog.show();
+ }
+ }
+
+ public void disDialog() {
+ if (mBaseLoadingDialog.isShowing()) {
+ mBaseLoadingDialog.dismiss();
+ }
+ }
+
+
+ public class PQChromeClient extends WebChromeClient {
+ // For Android 5.0+
+ public boolean onShowFileChooser(WebView view, ValueCallback filePath, WebChromeClient.FileChooserParams fileChooserParams) {
+ // Double check that we don't have any existing callbacks
+ if (mUploadMessage != null) {
+ mUploadMessage.onReceiveValue(null);
+ }
+ mUploadMessage = filePath;
+ Log.e("FileCooserParams => ", filePath.toString());
+ Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+ if (takePictureIntent.resolveActivity(getActivity().getPackageManager()) != null) {
+ // Create the File where the photo should go
+ File photoFile = null;
+ try {
+ photoFile = createImageFile();
+ takePictureIntent.putExtra("PhotoPath", mCameraPhotoPath);
+ } catch (IOException ex) {
+ // Error occurred while creating the File
+ Log.e("test", "Unable to create Image File", ex);
+ }
+
+ // Continue only if the File was successfully created
+ if (photoFile != null) {
+ mCameraPhotoPath = "file:" + photoFile.getAbsolutePath();
+ takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
+ } else {
+ takePictureIntent = null;
+ }
+ }
+
+ Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
+ contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
+ contentSelectionIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
+ contentSelectionIntent.setType("image/*");
+ Intent[] intentArray;
+ if (takePictureIntent != null) {
+ intentArray = new Intent[]{takePictureIntent};
+ } else {
+ intentArray = new Intent[2];
+ }
+ Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
+ chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
+ chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser");
+ chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
+ startActivityForResult(Intent.createChooser(chooserIntent, "Select images"), 1);
+ return true;
+ }
+ }
+
+
+ private File createImageFile() throws IOException {
+ // Create an image file name
+ String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
+ String imageFileName = "JPEG_" + timeStamp + "_";
+ File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
+ File imageFile = File.createTempFile(imageFileName, /* prefix */
+ ".jpg", /* suffix */
+ storageDir /* directory */);
+ return imageFile;
+ }
+
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode != INPUT_FILE_REQUEST_CODE || mUploadMessage == null) {
+ super.onActivityResult(requestCode, resultCode, data);
+ return;
+ }
+ try {
+ String file_path = mCameraPhotoPath.replace("file:", "");
+ File file = new File(file_path);
+ size = file.length();
+ if (data != null || mCameraPhotoPath != null) {
+ Integer count = 1;
+ ClipData images = null;
+ try {
+ images = data.getClipData();
+ } catch (Exception e) {
+ Log.e("Error!", e.getLocalizedMessage());
+ }
+
+ if (images == null && data != null && data.getDataString() != null) {
+ count = data.getDataString().length();
+ } else if (images != null) {
+ count = images.getItemCount();
+ }
+ Uri[] results = new Uri[count];
+ // Check that the response is a good one
+ if (resultCode == Activity.RESULT_OK) {
+ if (size != 0) {
+ // If there is not data, then we may have taken a photo
+ if (mCameraPhotoPath != null) {
+ results = new Uri[]{Uri.parse(mCameraPhotoPath)};
+ }
+ } else if (data.getClipData() == null) {
+ results = new Uri[]{Uri.parse(data.getDataString())};
+ } else {
+
+ for (int i = 0; i < images.getItemCount(); i++) {
+ results[i] = images.getItemAt(i).getUri();
+ }
+ }
+ }
+ mUploadMessage.onReceiveValue(results);
+ mUploadMessage = null;
+ }
+ } catch (Exception e) {
+ Log.e("Error!", "Error while opening image file" + e.getLocalizedMessage());
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/cmx/hydrology/ui/MapFragment.java b/app/src/main/java/com/cmx/hydrology/ui/MapFragment.java
new file mode 100644
index 0000000..b1d7858
--- /dev/null
+++ b/app/src/main/java/com/cmx/hydrology/ui/MapFragment.java
@@ -0,0 +1,93 @@
+package com.cmx.hydrology.ui;
+
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.WebResourceError;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+
+import com.cmx.hydrology.databinding.FragmentMapBinding;
+import com.cmx.hydrology.utils.AndroidtoJs;
+import com.cmx.hydrology.utils.MyUtils;
+import com.cmx.hydrology.view.BaseLoadingDialog;
+import com.lsxiao.apollo.core.Apollo;
+import com.lsxiao.apollo.core.contract.ApolloBinder;
+
+public class MapFragment extends Fragment {
+
+ private FragmentMapBinding binding;
+ private BaseLoadingDialog mBaseLoadingDialog;
+ private WebView mWebView;
+ private ApolloBinder mApolloBinder;
+
+ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ binding = FragmentMapBinding.inflate(inflater, container, false);
+ mBaseLoadingDialog = new BaseLoadingDialog(getActivity());
+ View root = binding.getRoot();
+ mApolloBinder = Apollo.bind(this);
+ MyUtils.setFullscreen(requireActivity(), false, false);
+ MyUtils.setAndroidNativeLightStatusBar(requireActivity(), true);
+ mWebView = binding.wvMine;
+ WebSettings webSettings = mWebView.getSettings();
+ webSettings.setJavaScriptEnabled(true);
+ webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
+ webSettings.setDomStorageEnabled(true);
+ mWebView.addJavascriptInterface(new AndroidtoJs(), "AndroidtoJs");
+ // mWebView.loadUrl(SERVER_URL + "/nigeria/?lang=English#/my");
+ // showDialog();
+ mWebView.setWebViewClient(new WebViewClient() {
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView view, String url) {
+ //使用WebView加载显示url
+ view.loadUrl(url);
+ //返回true
+ return true;
+ }
+
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ disDialog();
+ }
+
+ @Override
+ public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
+ disDialog();
+ }
+ }
+
+ );
+ return root;
+ }
+
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ binding = null;
+ if (mApolloBinder != null) {
+ mApolloBinder.unbind();
+ }
+ }
+
+ public void showDialog() {
+ mBaseLoadingDialog = new BaseLoadingDialog(getActivity());
+ if (!mBaseLoadingDialog.isShowing()) {
+ mBaseLoadingDialog.show();
+ }
+ }
+
+
+ public void disDialog() {
+ if (mBaseLoadingDialog.isShowing()) {
+ mBaseLoadingDialog.dismiss();
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/cmx/hydrology/ui/MsgFragment.java b/app/src/main/java/com/cmx/hydrology/ui/MsgFragment.java
new file mode 100644
index 0000000..f1778cb
--- /dev/null
+++ b/app/src/main/java/com/cmx/hydrology/ui/MsgFragment.java
@@ -0,0 +1,232 @@
+package com.cmx.hydrology.ui;
+
+
+import android.app.Activity;
+import android.content.ClipData;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Environment;
+import android.provider.MediaStore;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.ValueCallback;
+import android.webkit.WebChromeClient;
+import android.webkit.WebResourceError;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+
+import com.cmx.hydrology.databinding.FragmentMsgBinding;
+import com.cmx.hydrology.utils.AndroidtoJs;
+import com.cmx.hydrology.utils.MyUtils;
+import com.cmx.hydrology.view.BaseLoadingDialog;
+import com.lsxiao.apollo.core.Apollo;
+import com.lsxiao.apollo.core.contract.ApolloBinder;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class MsgFragment extends Fragment {
+
+ private FragmentMsgBinding binding;
+ private BaseLoadingDialog mBaseLoadingDialog;
+ private WebView mWebView;
+ private ApolloBinder mApolloBinder;
+ private ValueCallback mUploadMessage;
+ private String mCameraPhotoPath = null;
+ private long size = 0;
+ private static final int INPUT_FILE_REQUEST_CODE = 1;
+
+
+ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ binding = FragmentMsgBinding.inflate(inflater, container, false);
+ mBaseLoadingDialog = new BaseLoadingDialog(getActivity());
+ View root = binding.getRoot();
+ MyUtils.setFullscreen(requireActivity(), false, false);
+ MyUtils.setAndroidNativeLightStatusBar(requireActivity(), true);
+ mWebView = binding.wvLoan;
+ mApolloBinder = Apollo.bind(this);
+ WebSettings webSettings = mWebView.getSettings();
+ webSettings.setJavaScriptEnabled(true);
+ webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
+ webSettings.setDomStorageEnabled(true);
+ webSettings.setAllowFileAccess(true);//文件访问
+ webSettings.setAllowFileAccessFromFileURLs(true);
+ mWebView.addJavascriptInterface(new AndroidtoJs(), "AndroidtoJs");
+ // mWebView.loadUrl(SERVER_URL + "/nigeria/?lang=English#/loans");
+ // showDialog();
+ mWebView.setWebChromeClient(new PQChromeClient());
+ mWebView.setWebViewClient(new WebViewClient() {
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView view, String url) {
+ //使用WebView加载显示url
+ view.loadUrl(url);
+ //返回true
+ return true;
+ }
+
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ disDialog();
+ }
+
+ @Override
+ public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
+ disDialog();
+ }
+ }
+
+ );
+ return root;
+ }
+
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ binding = null;
+ if (mApolloBinder != null) {
+ mApolloBinder.unbind();
+ }
+ }
+
+
+ public void showDialog() {
+ mBaseLoadingDialog = new BaseLoadingDialog(getActivity());
+ if (!mBaseLoadingDialog.isShowing()) {
+ mBaseLoadingDialog.show();
+ }
+ }
+
+
+ public void disDialog() {
+ if (mBaseLoadingDialog.isShowing()) {
+ mBaseLoadingDialog.dismiss();
+ }
+ }
+
+
+ public class PQChromeClient extends WebChromeClient {
+ // For Android 5.0+
+ public boolean onShowFileChooser(WebView view, ValueCallback filePath, WebChromeClient.FileChooserParams fileChooserParams) {
+ // Double check that we don't have any existing callbacks
+ if (mUploadMessage != null) {
+ mUploadMessage.onReceiveValue(null);
+ }
+ mUploadMessage = filePath;
+ Log.e("FileCooserParams => ", filePath.toString());
+ Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+ if (takePictureIntent.resolveActivity(getActivity().getPackageManager()) != null) {
+ // Create the File where the photo should go
+ File photoFile = null;
+ try {
+ photoFile = createImageFile();
+ takePictureIntent.putExtra("PhotoPath", mCameraPhotoPath);
+ } catch (IOException ex) {
+ // Error occurred while creating the File
+ Log.e("test", "Unable to create Image File", ex);
+ }
+
+ // Continue only if the File was successfully created
+ if (photoFile != null) {
+ mCameraPhotoPath = "file:" + photoFile.getAbsolutePath();
+ takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
+ } else {
+ takePictureIntent = null;
+ }
+ }
+
+ Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
+ contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
+ contentSelectionIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
+ contentSelectionIntent.setType("image/*");
+
+ Intent[] intentArray;
+ if (takePictureIntent != null) {
+ intentArray = new Intent[]{takePictureIntent};
+ } else {
+ intentArray = new Intent[2];
+ }
+ Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
+ chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
+ chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser");
+ chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
+ startActivityForResult(Intent.createChooser(chooserIntent, "Select images"), 1);
+
+ return true;
+ }
+ }
+
+
+ private File createImageFile() throws IOException {
+ // Create an image file name
+ String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
+ String imageFileName = "JPEG_" + timeStamp + "_";
+ File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
+ File imageFile = File.createTempFile(imageFileName, /* prefix */
+ ".jpg", /* suffix */
+ storageDir /* directory */);
+ return imageFile;
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode != INPUT_FILE_REQUEST_CODE || mUploadMessage == null) {
+ super.onActivityResult(requestCode, resultCode, data);
+ return;
+ }
+ try {
+ String file_path = mCameraPhotoPath.replace("file:", "");
+ File file = new File(file_path);
+ size = file.length();
+
+ } catch (Exception e) {
+ Log.e("Error!", "Error while opening image file" + e.getLocalizedMessage());
+ }
+
+ if (data != null || mCameraPhotoPath != null) {
+ Integer count = 1;
+ ClipData images = null;
+ try {
+ images = data.getClipData();
+ } catch (Exception e) {
+ Log.e("Error!", e.getLocalizedMessage());
+ }
+
+ if (images == null && data != null && data.getDataString() != null) {
+ count = data.getDataString().length();
+ } else if (images != null) {
+ count = images.getItemCount();
+ }
+ Uri[] results = new Uri[count];
+ // Check that the response is a good one
+ if (resultCode == Activity.RESULT_OK) {
+ if (size != 0) {
+ // If there is not data, then we may have taken a photo
+ if (mCameraPhotoPath != null) {
+ results = new Uri[]{Uri.parse(mCameraPhotoPath)};
+ }
+ } else if (data.getClipData() == null) {
+ results = new Uri[]{Uri.parse(data.getDataString())};
+ } else {
+
+ for (int i = 0; i < images.getItemCount(); i++) {
+ results[i] = images.getItemAt(i).getUri();
+ }
+ }
+ }
+ mUploadMessage.onReceiveValue(results);
+ mUploadMessage = null;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/cmx/hydrology/ui/MyFragment.java b/app/src/main/java/com/cmx/hydrology/ui/MyFragment.java
new file mode 100644
index 0000000..47d1890
--- /dev/null
+++ b/app/src/main/java/com/cmx/hydrology/ui/MyFragment.java
@@ -0,0 +1,93 @@
+package com.cmx.hydrology.ui;
+
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.WebResourceError;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+
+import com.cmx.hydrology.databinding.FragmentMyBinding;
+import com.cmx.hydrology.utils.AndroidtoJs;
+import com.cmx.hydrology.utils.MyUtils;
+import com.cmx.hydrology.view.BaseLoadingDialog;
+import com.lsxiao.apollo.core.Apollo;
+import com.lsxiao.apollo.core.contract.ApolloBinder;
+
+public class MyFragment extends Fragment {
+
+ private FragmentMyBinding binding;
+ private BaseLoadingDialog mBaseLoadingDialog;
+ private WebView mWebView;
+ private ApolloBinder mApolloBinder;
+
+ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ binding = FragmentMyBinding.inflate(inflater, container, false);
+ mBaseLoadingDialog = new BaseLoadingDialog(getActivity());
+ View root = binding.getRoot();
+ mApolloBinder = Apollo.bind(this);
+ MyUtils.setFullscreen(requireActivity(), false, false);
+ MyUtils.setAndroidNativeLightStatusBar(requireActivity(), true);
+ mWebView = binding.wvMine;
+ WebSettings webSettings = mWebView.getSettings();
+ webSettings.setJavaScriptEnabled(true);
+ webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
+ webSettings.setDomStorageEnabled(true);
+ mWebView.addJavascriptInterface(new AndroidtoJs(), "AndroidtoJs");
+ // mWebView.loadUrl(SERVER_URL + "/nigeria/?lang=English#/my");
+ // showDialog();
+ mWebView.setWebViewClient(new WebViewClient() {
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView view, String url) {
+ //使用WebView加载显示url
+ view.loadUrl(url);
+ //返回true
+ return true;
+ }
+
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ disDialog();
+ }
+
+ @Override
+ public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
+ disDialog();
+ }
+ }
+
+ );
+ return root;
+ }
+
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ binding = null;
+ if (mApolloBinder != null) {
+ mApolloBinder.unbind();
+ }
+ }
+
+ public void showDialog() {
+ mBaseLoadingDialog = new BaseLoadingDialog(getActivity());
+ if (!mBaseLoadingDialog.isShowing()) {
+ mBaseLoadingDialog.show();
+ }
+ }
+
+
+ public void disDialog() {
+ if (mBaseLoadingDialog.isShowing()) {
+ mBaseLoadingDialog.dismiss();
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/cmx/hydrology/utils/AndroidtoJs.java b/app/src/main/java/com/cmx/hydrology/utils/AndroidtoJs.java
new file mode 100644
index 0000000..1b824d6
--- /dev/null
+++ b/app/src/main/java/com/cmx/hydrology/utils/AndroidtoJs.java
@@ -0,0 +1,89 @@
+package com.cmx.hydrology.utils;
+
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.util.Log;
+import android.webkit.JavascriptInterface;
+
+import com.cmx.hydrology.activity.MyApplication;
+import com.cmx.hydrology.constant.Events;
+import com.lsxiao.apollo.core.Apollo;
+
+public class AndroidtoJs {
+ private static final String TAG = "cmx_AndroidtoJs";
+
+ // 定义JS需要调用的方法
+ // 被JS调用的方法必须加入@JavascriptInterface注解
+ @JavascriptInterface
+ public String getAppToken() {
+ L.e("JS--", "getAppToken()");
+ return SpUtils.getString(MyApplication.getmInstance(), "token");
+ }
+
+ /**
+ * 用户角色类型
+ *
+ * @return
+ */
+ @JavascriptInterface
+ public String getUser() {
+ L.e("JS--", "getUser()");
+ return SpUtils.getString(MyApplication.getmInstance(), "admin");
+ }
+
+
+ @JavascriptInterface
+ public String getAppVersion() {
+ L.e("JS--", "getAppVersion()");
+ String versionname;//版本号
+ try {
+ PackageManager pm = MyApplication.getmInstance().getApplicationContext().getPackageManager();
+ PackageInfo pi = pm.getPackageInfo(MyApplication.getmInstance().getApplicationContext().getPackageName(), 0);
+ versionname = "V" + pi.versionName;
+ } catch (PackageManager.NameNotFoundException e) {
+ versionname = "未知";
+ }
+ Log.e(TAG, "getAppVersion=" + versionname);
+ return versionname;
+ }
+
+ @JavascriptInterface
+ public void existApp() {
+ L.e("JS--", "existApp()");
+ Apollo.emit(Events.JS_OPEN_LOGOUT);
+ }
+
+ @JavascriptInterface
+ public void showTab() {//tabbar显示
+ L.e("JS--", "showTab()");
+ Apollo.emit(Events.JS_OPEN_TABBAR_SHOW);
+ }
+
+ @JavascriptInterface
+ public void hideTab() {//tabbar隐藏
+ L.e("JS--", "hideTab()");
+ Apollo.emit(Events.JS_OPEN_TABBAR_HIDE);
+ }
+
+
+ @JavascriptInterface
+ public void openWeb(String url) {//打开一个新的web界面
+ L.e("JS--", "openWeb()" + url);
+ Apollo.emit(Events.JS_OPEN_OPEN_WEB, url);
+ }
+
+
+ @JavascriptInterface
+ public void closeWeb() {//关闭那个新的web界面
+ L.e("JS--", "closeWeb()");
+ Apollo.emit(Events.JS_OPEN_CLOSE_WEB);
+ }
+
+
+ @JavascriptInterface
+ public void checkTab(String mode) {//关闭注册/忘记密码
+ L.e("JS--", "checkTab()");
+ Apollo.emit(Events.JS_OPEN_TAB, mode);
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/cmx/hydrology/utils/L.java b/app/src/main/java/com/cmx/hydrology/utils/L.java
new file mode 100644
index 0000000..ce2125d
--- /dev/null
+++ b/app/src/main/java/com/cmx/hydrology/utils/L.java
@@ -0,0 +1,92 @@
+package com.cmx.hydrology.utils;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.os.Build;
+import android.provider.MediaStore;
+import android.util.Base64;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+
+public class L {
+ private L() {
+ throw new UnsupportedOperationException("cannot be instantiated");
+ }
+
+ public static boolean isDebug = true;
+ private static String TAG = "LjTestLog";
+
+ public static String getTAG() {
+ return TAG;
+ }
+
+ public static void setTAG(String TAG) {
+ L.TAG = TAG;
+ }
+
+ public static void setDebugMode(boolean debug) {
+ isDebug = debug;
+ }
+
+ public static void i(String msg) {
+ if (isDebug)
+ Log.i(TAG, msg);
+ }
+
+ public static void d(String msg) {
+ if (isDebug)
+ Log.d(TAG, msg);
+ }
+
+ public static void e(String msg) {
+ if (isDebug)
+ Log.e(TAG, msg);
+ }
+
+ public static void v(String msg) {
+ if (isDebug)
+ Log.v(TAG, msg);
+ }
+
+ public static void i(String tag, String msg) {
+ if (isDebug)
+ Log.i(tag, msg);
+ }
+
+ public static void d(String tag, String msg) {
+ if (isDebug)
+ Log.d(tag, msg);
+ }
+
+ public static void e(String tag, String msg) {
+ if (isDebug)
+ Log.e(tag, msg);
+ }
+
+ public static void v(String tag, String msg) {
+ if (isDebug)
+ Log.v(tag, msg);
+
+ }
+
+
+}
+
+
+
diff --git a/app/src/main/java/com/cmx/hydrology/utils/MyUtils.java b/app/src/main/java/com/cmx/hydrology/utils/MyUtils.java
new file mode 100644
index 0000000..0195b5c
--- /dev/null
+++ b/app/src/main/java/com/cmx/hydrology/utils/MyUtils.java
@@ -0,0 +1,220 @@
+package com.cmx.hydrology.utils;
+
+import android.app.Activity;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.graphics.Color;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Environment;
+import android.os.StatFs;
+import android.provider.MediaStore;
+import android.util.Log;
+import android.view.View;
+import android.view.WindowManager;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Locale;
+
+public class MyUtils {
+ private static final String TAG = "cmx_" + MyUtils.class.getSimpleName();
+ public static void setNavigationStatusColor(Activity activity, int color) {
+ activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+ activity.getWindow().setNavigationBarColor(color);
+ activity.getWindow().setStatusBarColor(color);
+ }
+
+ public static void setFullscreen(Activity activity, boolean isShowStatusBar, boolean isShowNavigationBar) {
+ int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+
+ if (!isShowStatusBar) {
+ uiOptions |= View.SYSTEM_UI_FLAG_FULLSCREEN;
+ }
+ if (!isShowNavigationBar) {
+ uiOptions |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+ }
+ activity.getWindow().getDecorView().setSystemUiVisibility(uiOptions);
+ setNavigationStatusColor(activity, Color.TRANSPARENT);
+ }
+
+ public static void setAndroidNativeLightStatusBar(Activity activity, boolean dark) {
+ View decor = activity.getWindow().getDecorView();
+ if (dark) {
+ decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+ } else {
+ decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
+ }
+ }
+
+
+ private static String getVersionName(Activity activity) throws Exception {
+ PackageManager packageManager = activity.getPackageManager();
+ // getPackageName()是你当前类的包名,0代表是获取版本信息
+ PackageInfo packInfo = packageManager.getPackageInfo(activity.getPackageName(), 0);
+ String version = packInfo.versionName;
+ return version;
+ }
+
+ public static void getDeviceInfo(Activity activity) throws Exception {
+ String model = android.os.Build.MODEL;
+ String carrier = android.os.Build.MANUFACTURER;
+ String version = getVersionName(activity);
+ String lang = getSystemLanguage();
+ String brand = getPhoneBrand();
+ String releaseVersion = getVersionRelease();
+ int sdkVersion = getSdkVersion();
+ Log.e(TAG, "model=" + model + ", carrier=" + carrier + ", version=" + version + ", lang=" + lang + ", brand=" + brand + ", releaseVersion=" + releaseVersion + ",sdk version=" + sdkVersion);
+ }
+
+ public static String getSystemLanguage() {
+ return Locale.getDefault().getLanguage();
+ }
+
+ public static Locale[] getSystemLanguageList() {
+ return Locale.getAvailableLocales();
+ }
+
+ public static String getPhoneBrand() {
+ return Build.BRAND;
+ }
+
+ public static String getVersionRelease() {
+ return Build.VERSION.RELEASE;
+ }
+
+ public static int getSdkVersion() {
+ return Build.VERSION.SDK_INT;
+ }
+
+
+ public static String getSerialNum() {
+ String serial = "unknown";
+ try {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {//9.0+
+ serial = Build.getSerial();
+ } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {//8.0+
+ serial = Build.SERIAL;
+ } else {//8.0-
+ Class> c = Class.forName("android.os.SystemProperties");
+ Method get = c.getMethod("get", String.class);
+ serial = (String) get.invoke(c, "ro.serialno");
+ }
+ } catch (Exception e) {
+ Log.e("序列号》》", e.toString());
+ e.printStackTrace();
+ }
+
+ Log.e("序列号》》", serial);
+ return serial;
+ }
+
+ public static File createTempImageFile(Context context) {
+ File destFolder = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
+ destFolder.mkdirs();
+ String dateTimeString = System.currentTimeMillis() + "";
+ File imageFile = null;
+ try {
+ imageFile = File.createTempFile(dateTimeString + "-", ".jpg", destFolder);
+ } catch (IOException e) {
+ Log.e("文件失败>>>", e.toString());
+ throw new RuntimeException(e);
+ }
+
+
+ return imageFile;
+ }
+
+
+ public static String getTotalRam() {
+ String path = "/proc/meminfo";
+ String ramMemorySize = null;
+ int totalRam = 0;
+ try {
+ FileReader fileReader = new FileReader(path);
+ BufferedReader br = new BufferedReader(fileReader, 4096);
+ ramMemorySize = br.readLine().split("\\s+")[1];
+ br.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ if (ramMemorySize != null) {
+ totalRam = (int) Math.ceil((Float.valueOf(Float.parseFloat(ramMemorySize) / (1024 * 1024)).doubleValue()));
+ }
+
+ return totalRam + "";
+ }
+
+ public static String getTotalRom() {
+ File dataDir = Environment.getDataDirectory();
+ StatFs stat = new StatFs(dataDir.getPath());
+ long blockSize = stat.getBlockSizeLong();
+ long totalBlocks = stat.getBlockCountLong();
+ long size = totalBlocks * blockSize;
+ long GB = 1024 * 1024 * 1024;
+ final long[] deviceRomMemoryMap = {2 * GB, 4 * GB, 8 * GB, 16 * GB, 32 * GB, 64 * GB, 128 * GB, 256 * GB, 512 * GB, 1024 * GB, 2048 * GB};
+ String[] displayRomSize = {"2GB", "4GB", "8GB", "16GB", "32GB", "64GB", "128GB", "256GB", "512GB", "1024GB", "2048GB"};
+ int i;
+ for (i = 0; i < deviceRomMemoryMap.length; i++) {
+ if (size <= deviceRomMemoryMap[i]) {
+ break;
+ }
+ if (i == deviceRomMemoryMap.length) {
+ i--;
+ }
+ }
+ return displayRomSize[i].replace("GB", "");
+ }
+
+ /**
+ * sha256加密
+ *
+ * @param str 要加密的字符串
+ * @return 加密后的字符串
+ */
+ public static String getSha256Str(String str) {
+ MessageDigest messageDigest;
+ String encodeStr = "";
+ try {
+ messageDigest = MessageDigest.getInstance("SHA-256");
+ messageDigest.update(str.getBytes(StandardCharsets.UTF_8));
+ encodeStr = byte2Hex(messageDigest.digest());
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ }
+ return encodeStr;
+ }
+
+
+ /**
+ * sha256加密 将byte转为16进制
+ *
+ * @param bytes 字节码
+ * @return 加密后的字符串
+ */
+ private static String byte2Hex(byte[] bytes) {
+ StringBuilder stringBuilder = new StringBuilder();
+ String temp;
+ for (byte aByte : bytes) {
+ temp = Integer.toHexString(aByte & 0xFF);
+ if (temp.length() == 1) {
+ //1得到一位的进行补0操作
+ stringBuilder.append("0");
+ }
+ stringBuilder.append(temp);
+ }
+ return stringBuilder.toString();
+ }
+
+
+}
diff --git a/app/src/main/java/com/cmx/hydrology/utils/SpUtils.java b/app/src/main/java/com/cmx/hydrology/utils/SpUtils.java
new file mode 100644
index 0000000..7b35754
--- /dev/null
+++ b/app/src/main/java/com/cmx/hydrology/utils/SpUtils.java
@@ -0,0 +1,24 @@
+package com.cmx.hydrology.utils;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.view.WindowManager;
+
+public class SpUtils {
+ private static final String SP_NAME = "SP_USER_DATA";
+
+
+ public static void putString(Context context, String key, String val) {
+ SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = sp.edit();
+ editor.putString(key, val);
+ editor.commit();
+ }
+
+ public static String getString(Context context, String key) {
+ SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
+ return sp.getString(key, "");
+ }
+
+}
diff --git a/app/src/main/java/com/cmx/hydrology/utils/StaticFinalData.java b/app/src/main/java/com/cmx/hydrology/utils/StaticFinalData.java
new file mode 100644
index 0000000..24c3d60
--- /dev/null
+++ b/app/src/main/java/com/cmx/hydrology/utils/StaticFinalData.java
@@ -0,0 +1,8 @@
+package com.cmx.hydrology.utils;
+
+public class StaticFinalData {
+ public static final String LOGOUT = "LOGOUT";
+ public static final String UPLOAD_FACE = "UPLOAD_FACE";
+ public static final String UPLOAD_FACE_OVER = "UPLOAD_FACE_OVER";
+ public static final String CHANGE_TAB = "CHANGE_TAB";
+}
diff --git a/app/src/main/java/com/cmx/hydrology/view/BaseLoadingDialog.java b/app/src/main/java/com/cmx/hydrology/view/BaseLoadingDialog.java
new file mode 100644
index 0000000..bec4084
--- /dev/null
+++ b/app/src/main/java/com/cmx/hydrology/view/BaseLoadingDialog.java
@@ -0,0 +1,37 @@
+package com.cmx.hydrology.view;
+
+import android.animation.ObjectAnimator;
+import android.app.Dialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.animation.LinearInterpolator;
+import android.widget.ImageView;
+
+import com.cmx.hydrology.R;
+
+
+public class BaseLoadingDialog extends Dialog {
+
+ private ImageView load;
+
+ public BaseLoadingDialog(Context context) {
+ super(context, R.style.CustomDialog);
+ }
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.dialog_confirm);
+ load = findViewById(R.id.iv_load);
+ ObjectAnimator animator = ObjectAnimator.ofFloat(load, "rotationY", 0, 360);
+ animator.setDuration(3000);
+ animator.setInterpolator(new LinearInterpolator());
+ animator.setRepeatCount(-1);
+ animator.start();
+ setCancelable(true);
+ setCanceledOnTouchOutside(true);
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_checkbox.xml b/app/src/main/res/drawable/bg_checkbox.xml
new file mode 100644
index 0000000..a8b409b
--- /dev/null
+++ b/app/src/main/res/drawable/bg_checkbox.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/curse_sharp.xml b/app/src/main/res/drawable/curse_sharp.xml
new file mode 100644
index 0000000..18a3fc4
--- /dev/null
+++ b/app/src/main/res/drawable/curse_sharp.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/dialog_custom_bg.xml b/app/src/main/res/drawable/dialog_custom_bg.xml
new file mode 100644
index 0000000..2fa8cfd
--- /dev/null
+++ b/app/src/main/res/drawable/dialog_custom_bg.xml
@@ -0,0 +1,5 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/edittext_active_sharp.xml b/app/src/main/res/drawable/edittext_active_sharp.xml
new file mode 100644
index 0000000..0dbb556
--- /dev/null
+++ b/app/src/main/res/drawable/edittext_active_sharp.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/edittext_normal_sharp.xml b/app/src/main/res/drawable/edittext_normal_sharp.xml
new file mode 100644
index 0000000..caeba65
--- /dev/null
+++ b/app/src/main/res/drawable/edittext_normal_sharp.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_dashboard_black_24dp.xml b/app/src/main/res/drawable/ic_dashboard_black_24dp.xml
new file mode 100644
index 0000000..46fc8de
--- /dev/null
+++ b/app/src/main/res/drawable/ic_dashboard_black_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_home_black_24dp.xml b/app/src/main/res/drawable/ic_home_black_24dp.xml
new file mode 100644
index 0000000..f8bb0b5
--- /dev/null
+++ b/app/src/main/res/drawable/ic_home_black_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_login_bg.xml b/app/src/main/res/drawable/ic_login_bg.xml
new file mode 100644
index 0000000..3eaf50a
--- /dev/null
+++ b/app/src/main/res/drawable/ic_login_bg.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_notifications_black_24dp.xml b/app/src/main/res/drawable/ic_notifications_black_24dp.xml
new file mode 100644
index 0000000..78b75c3
--- /dev/null
+++ b/app/src/main/res/drawable/ic_notifications_black_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/round_btn_sharp.xml b/app/src/main/res/drawable/round_btn_sharp.xml
new file mode 100644
index 0000000..eea6eb0
--- /dev/null
+++ b/app/src/main/res/drawable/round_btn_sharp.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/round_btn_sharp_empty.xml b/app/src/main/res/drawable/round_btn_sharp_empty.xml
new file mode 100644
index 0000000..67c9f80
--- /dev/null
+++ b/app/src/main/res/drawable/round_btn_sharp_empty.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/selector_edit_text.xml b/app/src/main/res/drawable/selector_edit_text.xml
new file mode 100644
index 0000000..9916b19
--- /dev/null
+++ b/app/src/main/res/drawable/selector_edit_text.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/selector_round_btn_sharp.xml b/app/src/main/res/drawable/selector_round_btn_sharp.xml
new file mode 100644
index 0000000..25a6d0c
--- /dev/null
+++ b/app/src/main/res/drawable/selector_round_btn_sharp.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/actionbar_custom.xml b/app/src/main/res/layout/actionbar_custom.xml
new file mode 100644
index 0000000..cb78f9e
--- /dev/null
+++ b/app/src/main/res/layout/actionbar_custom.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_agreement.xml b/app/src/main/res/layout/activity_agreement.xml
new file mode 100644
index 0000000..ade2878
--- /dev/null
+++ b/app/src/main/res/layout/activity_agreement.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml
new file mode 100644
index 0000000..0ad315b
--- /dev/null
+++ b/app/src/main/res/layout/activity_login.xml
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..3b8a463
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_register.xml b/app/src/main/res/layout/activity_register.xml
new file mode 100644
index 0000000..57cbe1c
--- /dev/null
+++ b/app/src/main/res/layout/activity_register.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_register_success.xml b/app/src/main/res/layout/activity_register_success.xml
new file mode 100644
index 0000000..5804ff9
--- /dev/null
+++ b/app/src/main/res/layout/activity_register_success.xml
@@ -0,0 +1,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_web.xml b/app/src/main/res/layout/activity_web.xml
new file mode 100644
index 0000000..a9a0cc6
--- /dev/null
+++ b/app/src/main/res/layout/activity_web.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_confirm.xml b/app/src/main/res/layout/dialog_confirm.xml
new file mode 100644
index 0000000..272a48a
--- /dev/null
+++ b/app/src/main/res/layout/dialog_confirm.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml
new file mode 100644
index 0000000..555e981
--- /dev/null
+++ b/app/src/main/res/layout/fragment_home.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_map.xml b/app/src/main/res/layout/fragment_map.xml
new file mode 100644
index 0000000..49d590d
--- /dev/null
+++ b/app/src/main/res/layout/fragment_map.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_msg.xml b/app/src/main/res/layout/fragment_msg.xml
new file mode 100644
index 0000000..f5d5416
--- /dev/null
+++ b/app/src/main/res/layout/fragment_msg.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_my.xml b/app/src/main/res/layout/fragment_my.xml
new file mode 100644
index 0000000..49d590d
--- /dev/null
+++ b/app/src/main/res/layout/fragment_my.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/bottom_nav_menu.xml b/app/src/main/res/menu/bottom_nav_menu.xml
new file mode 100644
index 0000000..9bf6d71
--- /dev/null
+++ b/app/src/main/res/menu/bottom_nav_menu.xml
@@ -0,0 +1,23 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/icon_logo.png b/app/src/main/res/mipmap-hdpi/icon_logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..fc65e44c9e516bd8d2641acefa48519a1b607233
GIT binary patch
literal 6923
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
F{|BtaD{cS)
literal 0
HcmV?d00001
diff --git a/app/src/main/res/mipmap-hdpi/icon_title_back.png b/app/src/main/res/mipmap-hdpi/icon_title_back.png
new file mode 100644
index 0000000000000000000000000000000000000000..e186f74409cafaf4f94d60bd48c512e7e0b908d1
GIT binary patch
literal 3169
zcmc&%_gfR$8jct-AZ0*Mz7NnyyzvlYk0Ckz^H=64XU-O(;gu6#}Ayf*~R$#1N1g
zKon^!pcJKwyL6-%5fKy#O{5Cq3XAt-_g}crbAOnb=b3rW_r2%++L?&sb~e(IDv}rs
zMw&vlasbaJ(S;KS_xzIuX&8)@4#f&}y6QHQ>Xp)aSU%)YJ!t~}AMHV}_cJu_m*U=`
z(lQ?~KNdbDeD>@7DcGy_UC)ZbJF!>oIZoZ=p}pzUzE97;-#G7e9{Cg*428V3l<0kO
z3xid&!=T2hkZ~A>b@>1s0t+_aCUKpp-@EW#Yz#}m;oP%ajS$%6l9i$b29?w`80?iZ
zhgA1JkR*h_w-u5ve!{`w+#U9}A#EO0eW)O#k4_P+1R6%nG2BumL0uXnr2r#LTf>+Z)<
z$ZqqG`eYk2T|$r?7L)fwKNk~q>_ymN)py|nA}FgEj=WI
zUM?4fOyjkZthh^FeOr^+O&J+q=aqm41G+A_k>Jr6NX1b^gq*}I_}uUBmr~#F@bT6TiX|wr?Rl~cyTle
zxugXY*DKY;0B%clSHnwi-5bY{J5{|i*0$G8?u7kfM#Rxt4I93d`pF3Qc~)}$a5VD4
zWr5-4%Q_vZ3t0#{RP&^!CVklSHeUQdW1JXj;#?aT
zjE>_A&pC)Vg#le;9;alH_R5+PY&LW0GS-lXzkoS0b~gKjq3$HuTx}y9&br1~5Cpj_
zC#zRk0NcxTF!{(Vv0<-BkUayo3%*!}eJOIskK6CU9;%LO&&YT-tb{!k6O0?#a_x--
z$=N-=)&o~$p%{zT!v@iBzuH;G1|TCY06A=)`}37LyxbxFm{X
zPq?ldFEusQv9hvq>d~bpVzj>Lr0cdl;VbKLQXAg)9M1;HWV<`-Bs%`(uk6*;)v3X}
z6+=x?B2LvS=!P?A9hJq@8<*NY-w!w~fNgsON8dYBsmrF)3=pQbe)LFrq@hd`h~4Pd
z0WfYHm?D$JTywKb6w&@WQ5`Em@NN-|$|my(Ag*e}fh~OD$)C0{EV%eY{+Z00O3ZXplJz^lNXX_NuT%7T4%Skb7X@>S!fSxkT?*0PDhlKE!-pyOl&}`
zlX=1S|H%qDePz@kcM`_G$&fhuGY@;G1Gd~5Q`Da#fOAg=MNz+IsQRwNDj*wZGI~Oy
zZa{vsB>!hEGyT70W0!noFTXcUFM;nM6idsSQGF{6-F-iVn<$1y%={Bhe4oECEGFxd
z?$U0-Gv&`8Ag9|rYJE3=a
z(~jAvIMm&)NRug#5D%D_XYV@9b7~s!zTz-k)%0WEz13!;w`c5GP5Txyt17osI5PI_
zjL5B4~XO(6gh0g~I4-?ZgPjJt_f0MFDK`U6j2JFQl6-NrJ_?m>ppx~Oa(
zBF(g?WmIb4U~)GhBJ6D$9TL9yZeYv&MXkbu?~^`+&dQ+Nm!Acu8he{=9&y}c0zk$9
zMDPcN$?=m%lqUvMg$0mMsdad@SWo+!qocG4QwCZ!{QbrXpLbJmyB;RX
zdeb@Y$=WDi?VC)JJbL}XjG$77$=_~pq!XC<4BB+s)DXwE=X4yY`Af0~&&smRNF4RP
zc8J#&7)%*Q$ldzWhq^V$JDuiUkIOb40E_)M^B=|{RO%zM=V=Vp)-Q;Pdnyge+DZDyP-bHoMv^Ggu
zSr1H#JH~(YD&y=0@cQwmB_0M8wFkkwNmv2%E`v5Iuy5ZMEmC=XXDB@MOSi8k=^}+nMwzeISWgjgk;jJcO1a`WIo$rJCiyAgtPOhAZ
zgjGM}YZ$QSqgpA>F<6qxHVM>3?6gf8nLm!~XncGZFJ6yA8^fo`a`ZK-n_WO0(sb5I
z0ZSAs=NeGtm9^9gG<=n|ZA7Kc7HCj83;Sb`J$La9*5(lX{xo@_y2h=4+5bgLY4%-k
zBxz2R+kkD(N%XEy!?51yYtj#6A><)w@_}MFT1Om5SzYZ9RwVhRg#jmXY0?hlI`2YX_
literal 0
HcmV?d00001
diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml
new file mode 100644
index 0000000..a8dfd3d
--- /dev/null
+++ b/app/src/main/res/navigation/mobile_navigation.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml
new file mode 100644
index 0000000..14d7e91
--- /dev/null
+++ b/app/src/main/res/navigation/nav_graph.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-land/dimens.xml b/app/src/main/res/values-land/dimens.xml
new file mode 100644
index 0000000..75f68a4
--- /dev/null
+++ b/app/src/main/res/values-land/dimens.xml
@@ -0,0 +1,4 @@
+
+ 48dp
+ 48dp
+
\ No newline at end of file
diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml
new file mode 100644
index 0000000..ed0a78c
--- /dev/null
+++ b/app/src/main/res/values-night/themes.xml
@@ -0,0 +1,16 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-w1240dp/dimens.xml b/app/src/main/res/values-w1240dp/dimens.xml
new file mode 100644
index 0000000..c1b372b
--- /dev/null
+++ b/app/src/main/res/values-w1240dp/dimens.xml
@@ -0,0 +1,4 @@
+
+ 200dp
+ 200dp
+
\ No newline at end of file
diff --git a/app/src/main/res/values-w600dp/dimens.xml b/app/src/main/res/values-w600dp/dimens.xml
new file mode 100644
index 0000000..75f68a4
--- /dev/null
+++ b/app/src/main/res/values-w600dp/dimens.xml
@@ -0,0 +1,4 @@
+
+ 48dp
+ 48dp
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..9bb8f85
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,14 @@
+
+
+ #FFBB86FC
+ #FF6200EE
+ #FF3700B3
+ #FF03DAC5
+ #FF018786
+ #FF000000
+ #FFFFFFFF
+ #2FDF98
+ #2FDF98
+ #11D183
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..31a9d11
--- /dev/null
+++ b/app/src/main/res/values/dimens.xml
@@ -0,0 +1,6 @@
+
+
+ 16dp
+ 16dp
+ 16dp
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..9b47fa8
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,55 @@
+
+ 水文监测
+ Home
+ Loan
+ Mine
+ Login
+ Email
+ Password
+ Sign in or register
+ Sign in
+ "Welcome !"
+ Not a valid username
+ Password must be >5 characters
+ "Login failed"
+ RegisterResultActivity
+
+ First Fragment
+ Second Fragment
+ Next
+ Previous
+
+ Hello first fragment
+ Hello second fragment. Arg: %1$s
+ Sign in
+ Password
+ Username
+ 我已阅读并同意《非洲金融用户协议》
+ Sign up
+
+ Please enter the user name
+ Please enter the password
+ 请阅读并同意协议
+
+ Terms & Conditions \n
+By downloading or using the app, these terms will automatically apply to you – you should make sure therefore that you read them carefully before using the app. You’re not allowed to copy or modify the app, any part of the app, or our trademarks in any way. You’re not allowed to attempt to extract the source code of the app, and you also shouldn’t try to translate the app into other languages or make derivative versions. The app itself, and all the trademarks, copyright, database rights, and other intellectual property rights related to it, still belong to Fintech.\n
+Fintech is committed to ensuring that the app is as useful and efficient as possible. For that reason, we reserve the right to make changes to the app or to charge for its services, at any time and for any reason. We will never charge you for the app or its services without making it very clear to you exactly what you’re paying for.\n
+The InstaCredit app stores and processes personal data that you have provided to us, to provide our Service. It’s your responsibility to keep your phone and access to the app secure. We therefore recommend that you do not jailbreak or root your phone, which is the process of removing software restrictions and limitations imposed by the official operating system of your device. It could make your phone vulnerable to malware/viruses/malicious programs, compromise your phone’s security features and it could mean that the InstaCredit app won’t work properly or at all.\n
+The app does use third-party services that declare their Terms and Conditions.
+Link to Terms and Conditions of third-party service providers used by the app
+• Google Play Services
+You should be aware that there are certain things that Fintech will not take responsibility for. Certain functions of the app will require the app to have an active internet connection. The connection can be Wi-Fi or provided by your mobile network provider, but Fintech cannot take responsibility for the app not working at full functionality if you don’t have access to Wi-Fi, and you don’t have any of your data allowance left.\n
+If you’re using the app outside of an area with Wi-Fi, you should remember that the terms of the agreement with your mobile network provider will still apply. As a result, you may be charged by your mobile provider for the cost of data for the duration of the connection while accessing the app, or other third-party charges. In using the app, you’re accepting responsibility for any such charges, including roaming data charges if you use the app outside of your home territory (i.e. region or country) without turning off data roaming. If you are not the bill payer for the device on which you’re using the app, please be aware that we assume that you have received permission from the bill payer for using the app.\n
+Along the same lines, Fintech cannot always take responsibility for the way you use the app i.e. You need to make sure that your device stays charged – if it runs out of battery and you can’t turn it on to avail the Service, Fintech cannot accept responsibility.\n
+With respect to Fintech’s responsibility for your use of the app, when you’re using the app, it’s important to bear in mind that although we endeavor to ensure that it is updated and correct at all times, we do rely on third parties to provide information to us so that we can make it available to you. Fintech accepts no liability for any loss, direct or indirect, you experience as a result of relying wholly on this functionality of the app.\n
+At some point, we may wish to update the app. The app is currently available on Android – the requirements for the system(and for any additional systems we decide to extend the availability of the app to) may change, and you’ll need to download the updates if you want to keep using the app. Fintech does not promise that it will always update the app so that it is relevant to you and/or works with the Android version that you have installed on your device. However, you promise to always accept updates to the application when offered to you, We may also wish to stop providing the app, and may terminate use of it at any time without giving notice of termination to you. Unless we tell you otherwise, upon any termination, (a) the rights and licenses granted to you in these terms will end; (b) you must stop using the app, and (if needed) delete it from your device.\n
+Changes to This Terms and Conditions\n
+We may update our Terms and Conditions from time to time. Thus, you are advised to review this page periodically for any changes. We will notify you of any changes by posting the new Terms and Conditions on this page.
+These terms and conditions are effective as of 2023-06-17\n
+Contact Us\n
+If you have any questions or suggestions about our Terms and Conditions, do not hesitate to contact us at eric.xia@cusper.io.
+This Terms and Conditions page was generated by App Privacy Policy Generator
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..bbe2262
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
new file mode 100644
index 0000000..cc4e391
--- /dev/null
+++ b/app/src/main/res/values/themes.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/backup_rules.xml b/app/src/main/res/xml/backup_rules.xml
new file mode 100644
index 0000000..fa0f996
--- /dev/null
+++ b/app/src/main/res/xml/backup_rules.xml
@@ -0,0 +1,13 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 0000000..9ee9997
--- /dev/null
+++ b/app/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/file_paths.xml b/app/src/main/res/xml/file_paths.xml
new file mode 100644
index 0000000..9836f4a
--- /dev/null
+++ b/app/src/main/res/xml/file_paths.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..e7d3a98
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,15 @@
+buildscript {
+ ext.kotlin_version = '1.4.21'
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.31"
+ classpath 'com.android.tools.build:gradle:7.1.2'
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..f9e65bb
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,22 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app"s APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Enables namespacing of each library's R class so that its R class includes only the
+# resources declared in the library itself and none from the library's dependencies,
+# thereby reducing the size of the R class for that library
+android.nonTransitiveRClass=true
+android.enableJetifier=true
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000000000000000000000000000000000..e708b1c023ec8b20f512888fe07c5bd3ff77bb8f
GIT binary patch
literal 59203
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