From 2eb6e4732e35c5cfa656075ab7e3d75cc6b7ffbc Mon Sep 17 00:00:00 2001 From: kerwincui <164770707@qq.com> Date: Sat, 19 Jun 2021 17:16:47 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90Android=E7=AB=AF=E5=BC=80?= =?UTF-8?q?=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/build.gradle | 4 + android/app/src/main/assets/tips.json | 10 +- .../src/main/java/com/kerwin/wumei/MyApp.java | 19 +- .../wumei/activity/AddDeviceActivity.java | 90 ++-- .../kerwin/wumei/activity/LoginActivity.java | 1 + .../kerwin/wumei/activity/MainActivity.java | 116 +++-- .../kerwin/wumei/activity/SplashActivity.java | 19 +- .../adapter/entity/EspTouchViewModel.java | 3 +- .../kerwin/wumei/adapter/entity/NewInfo.java | 16 - .../wumei/core/http/api/ApiService.java | 2 +- .../java/com/kerwin/wumei/entity/Dept.java | 121 +++++ .../com/kerwin/wumei/entity/DictData.java | 65 +++ .../com/kerwin/wumei/entity/IotCategory.java | 39 ++ .../com/kerwin/wumei/entity/IotDevice.java | 126 ++++++ .../com/kerwin/wumei/entity/IotDeviceSet.java | 282 ++++++++++++ .../kerwin/wumei/entity/IotDeviceStatus.java | 234 ++++++++++ .../com/kerwin/wumei/entity/IotGroup.java | 63 +++ .../java/com/kerwin/wumei/entity/Roles.java | 119 +++++ .../java/com/kerwin/wumei/entity/User.java | 162 +++++++ .../kerwin/wumei/entity/bo/CaptureImage.java | 33 ++ .../kerwin/wumei/entity/vo/IotDeviceVo.java | 222 ++++++++++ .../kerwin/wumei/fragment/AboutFragment.java | 41 +- .../wumei/fragment/FeedbackFragment.java | 10 + .../kerwin/wumei/fragment/LoginFragment.java | 190 ++++---- .../wumei/fragment/MessageFragment.java | 31 +- .../wumei/fragment/SettingsFragment.java | 50 ++- .../fragment/device/AddDeviceFragment.java | 180 +++++++- .../fragment/device/AddDeviceTwoFragment.java | 10 + .../fragment/device/DeviceDetailFragment.java | 78 ++++ .../fragment/device/DeviceEditFragment.java | 238 ++++++++++ .../wumei/fragment/device/DeviceFragment.java | 264 +++++++++-- .../fragment/device/DeviceSetFragment.java | 268 +++++++++++ .../fragment/device/DeviceStatusFragment.java | 307 +++++++++++++ .../FragmentStateViewPager2Adapter.java | 10 + .../wumei/fragment/device/GroupFragment.java | 10 + .../wumei/fragment/device/SceneFragment.java | 147 +++++- .../fragment/device/ShareDeviceFragment.java | 10 + .../fragment/device/SimpleTabFragment.java | 418 ++++++++++++------ .../wumei/fragment/news/HomePageFragment.java | 122 +++++ .../wumei/fragment/news/NewsFragment.java | 10 + .../fragment/profile/AccountFragment.java | 133 ++++++ .../fragment/profile/ProfileFragment.java | 96 +++- .../http/callback/NoTipRequestCallBack.java | 55 +++ .../http/callback/TipRequestCallBack.java | 60 +++ .../interceptor/CustomLoggingInterceptor.java | 100 +++++ .../http/request/CaptchaImageApiResult.java | 61 +++ .../wumei/http/request/CustomApiResult.java | 97 ++++ .../wumei/http/request/CustomGetRequest.java | 53 +++ .../wumei/http/request/ListApiResult.java | 52 +++ .../wumei/http/request/NoDataApiResult.java | 36 ++ .../wumei/http/request/TokenApiResult.java | 48 ++ .../wumei/http/request/UserInfoApiResult.java | 48 ++ .../subscriber/NoTipRequestSubscriber.java | 58 +++ .../http/subscriber/TipRequestSubscriber.java | 63 +++ .../kerwin/wumei/utils/DemoDataProvider.java | 2 +- .../com/kerwin/wumei/utils/DialogUtils.java | 42 ++ .../wumei/utils/HProgressDialogUtils.java | 105 +++++ .../com/kerwin/wumei/utils/RouterUtils.java | 50 +++ .../kerwin/wumei/utils/SettingSPUtils.java | 65 +++ .../com/kerwin/wumei/utils/SettingUtils.java | 103 ++++- .../com/kerwin/wumei/utils/TokenUtils.java | 8 +- .../wumei/utils/sdkinit/XUpdateInit.java | 18 +- .../kerwin/wumei/widget/GuideTipsDialog.java | 1 + .../app/src/main/res/drawable-hdpi/alarm.png | Bin 0 -> 5665 bytes .../src/main/res/drawable-hdpi/category.png | Bin 6520 -> 5129 bytes .../app/src/main/res/drawable-hdpi/image.png | Bin 0 -> 4571 bytes .../src/main/res/drawable-hdpi/light_on.png | Bin 0 -> 5541 bytes .../app/src/main/res/drawable-hdpi/lock.png | Bin 0 -> 3370 bytes .../app/src/main/res/drawable-hdpi/logo.png | Bin 3329 -> 2911 bytes .../app/src/main/res/drawable-hdpi/radar.png | Bin 0 -> 7200 bytes .../src/main/res/drawable-hdpi/radar_bg.png | Bin 0 -> 9148 bytes .../app/src/main/res/drawable-hdpi/relay.png | Bin 0 -> 2705 bytes .../app/src/main/res/drawable-hdpi/set.png | Bin 0 -> 17516 bytes .../src/main/res/drawable-hdpi/switch_c.png | Bin 0 -> 7244 bytes .../app/src/main/res/drawable-hdpi/title.png | Bin 0 -> 2734 bytes .../app/src/main/res/drawable-hdpi/update.png | Bin 0 -> 6028 bytes .../app/src/main/res/drawable-hdpi/user.png | Bin 0 -> 21499 bytes .../app/src/main/res/drawable-hdpi/wifi_0.png | Bin 0 -> 6302 bytes .../app/src/main/res/drawable-hdpi/wifi_1.png | Bin 0 -> 6360 bytes .../app/src/main/res/drawable-hdpi/wifi_2.png | Bin 0 -> 6438 bytes .../app/src/main/res/drawable-hdpi/wifi_3.png | Bin 0 -> 6562 bytes .../app/src/main/res/drawable-hdpi/wifi_4.png | Bin 0 -> 6585 bytes .../src/main/res/drawable/ic_default_head.xml | 2 +- .../adapter_device_card_view_list_item.xml | 248 +++++++---- .../src/main/res/layout/dialog_guide_tips.xml | 6 +- .../src/main/res/layout/fragment_about.xml | 55 ++- .../src/main/res/layout/fragment_account.xml | 194 ++++++++ .../main/res/layout/fragment_add_device.xml | 177 ++++++-- .../res/layout/fragment_add_device_two.xml | 10 + .../src/main/res/layout/fragment_device.xml | 10 + .../res/layout/fragment_device_detail.xml | 41 ++ .../main/res/layout/fragment_device_edit.xml | 224 ++++++++++ .../main/res/layout/fragment_device_set.xml | 337 ++++++++++++++ .../res/layout/fragment_device_status.xml | 389 ++++++++++++++++ .../src/main/res/layout/fragment_group.xml | 11 +- .../main/res/layout/fragment_home_page.xml | 53 +++ .../src/main/res/layout/fragment_login.xml | 122 ++--- .../src/main/res/layout/fragment_message.xml | 18 +- .../src/main/res/layout/fragment_profile.xml | 74 ++-- .../src/main/res/layout/fragment_scene.xml | 240 +++++++++- .../main/res/layout/fragment_share_device.xml | 11 +- .../main/res/layout/fragment_simple_tab.xml | 14 - android/app/src/main/res/menu/menu_drawer.xml | 16 +- .../main/res/menu/menu_navigation_bottom.xml | 8 +- android/app/src/main/res/values/dimens.xml | 30 +- android/app/src/main/res/values/strings.xml | 22 +- android/app/src/main/res/values/styles.xml | 8 +- .../app/src/main/res/values/styles_widget.xml | 30 ++ android/app/x-library.gradle | 2 +- 109 files changed, 7018 insertions(+), 828 deletions(-) create mode 100644 android/app/src/main/java/com/kerwin/wumei/entity/Dept.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/entity/DictData.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/entity/IotCategory.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/entity/IotDevice.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/entity/IotDeviceSet.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/entity/IotDeviceStatus.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/entity/IotGroup.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/entity/Roles.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/entity/User.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/entity/bo/CaptureImage.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/entity/vo/IotDeviceVo.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/fragment/device/DeviceDetailFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/fragment/device/DeviceEditFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/fragment/device/DeviceSetFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/fragment/device/DeviceStatusFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/fragment/news/HomePageFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/fragment/profile/AccountFragment.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/http/callback/NoTipRequestCallBack.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/http/callback/TipRequestCallBack.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/http/interceptor/CustomLoggingInterceptor.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/http/request/CaptchaImageApiResult.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/http/request/CustomApiResult.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/http/request/CustomGetRequest.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/http/request/ListApiResult.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/http/request/NoDataApiResult.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/http/request/TokenApiResult.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/http/request/UserInfoApiResult.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/http/subscriber/NoTipRequestSubscriber.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/http/subscriber/TipRequestSubscriber.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/utils/DialogUtils.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/utils/HProgressDialogUtils.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/utils/RouterUtils.java create mode 100644 android/app/src/main/java/com/kerwin/wumei/utils/SettingSPUtils.java create mode 100644 android/app/src/main/res/drawable-hdpi/alarm.png create mode 100644 android/app/src/main/res/drawable-hdpi/image.png create mode 100644 android/app/src/main/res/drawable-hdpi/light_on.png create mode 100644 android/app/src/main/res/drawable-hdpi/lock.png create mode 100644 android/app/src/main/res/drawable-hdpi/radar.png create mode 100644 android/app/src/main/res/drawable-hdpi/radar_bg.png create mode 100644 android/app/src/main/res/drawable-hdpi/relay.png create mode 100644 android/app/src/main/res/drawable-hdpi/set.png create mode 100644 android/app/src/main/res/drawable-hdpi/switch_c.png create mode 100644 android/app/src/main/res/drawable-hdpi/title.png create mode 100644 android/app/src/main/res/drawable-hdpi/update.png create mode 100644 android/app/src/main/res/drawable-hdpi/user.png create mode 100644 android/app/src/main/res/drawable-hdpi/wifi_0.png create mode 100644 android/app/src/main/res/drawable-hdpi/wifi_1.png create mode 100644 android/app/src/main/res/drawable-hdpi/wifi_2.png create mode 100644 android/app/src/main/res/drawable-hdpi/wifi_3.png create mode 100644 android/app/src/main/res/drawable-hdpi/wifi_4.png create mode 100644 android/app/src/main/res/layout/fragment_account.xml create mode 100644 android/app/src/main/res/layout/fragment_device_detail.xml create mode 100644 android/app/src/main/res/layout/fragment_device_edit.xml create mode 100644 android/app/src/main/res/layout/fragment_device_set.xml create mode 100644 android/app/src/main/res/layout/fragment_device_status.xml create mode 100644 android/app/src/main/res/layout/fragment_home_page.xml diff --git a/android/app/build.gradle b/android/app/build.gradle index 603984ae..4653cf2e 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -122,6 +122,10 @@ dependencies { //美团多渠道打包 implementation 'com.meituan.android.walle:library:1.1.6' + + //rxutil2 + implementation deps.rxbinding + implementation 'com.github.xuexiangjys:rxutil2:1.2.0' } //自动添加X-Library依赖 apply from: 'x-library.gradle' diff --git a/android/app/src/main/assets/tips.json b/android/app/src/main/assets/tips.json index 969a4c43..a85c1806 100644 --- a/android/app/src/main/assets/tips.json +++ b/android/app/src/main/assets/tips.json @@ -3,19 +3,15 @@ "Data": [ { "title": "微信公众号", - "content": "获取更多资讯内容,欢迎微信搜索公众号:「我的Android开源之旅」" + "content": "获取更多资讯内容,欢迎微信搜索公众号:「我的Android开源之旅」" }, { "title": "关于作者", - "content": "点击关注作者,了解最新动态!
Github
\n知乎
\n掘金
简书
\n思否
\n哔哩哔哩
\n今日头条" - }, - { - "title": "赞助作者", - "content": "你的打赏是我维护的动力,点击此处支持我吧!" + "content": "点击关注作者,了解最新动态!
Gitee
" }, { "title": "QQ交流群", - "content": "XUI开源交流1号群
XUI开源交流2号群
AndroidGitHub开源交流群
XUpdate官方交流群" + "content": "物美智能交流群
" } ] } diff --git a/android/app/src/main/java/com/kerwin/wumei/MyApp.java b/android/app/src/main/java/com/kerwin/wumei/MyApp.java index 6cbf244e..4da8dfcd 100644 --- a/android/app/src/main/java/com/kerwin/wumei/MyApp.java +++ b/android/app/src/main/java/com/kerwin/wumei/MyApp.java @@ -14,14 +14,15 @@ import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.Observer; import androidx.multidex.MultiDex; -import com.kerwin.wumei.BuildConfig; +import com.kerwin.wumei.http.interceptor.CustomLoggingInterceptor; +import com.kerwin.wumei.utils.SettingSPUtils; import com.kerwin.wumei.utils.sdkinit.ANRWatchDogInit; import com.kerwin.wumei.utils.sdkinit.UMengInit; import com.kerwin.wumei.utils.sdkinit.XBasicLibInit; import com.kerwin.wumei.utils.sdkinit.XUpdateInit; +import com.xuexiang.xhttp2.XHttpSDK; -import java.util.HashMap; -import java.util.Map; +import static com.kerwin.wumei.utils.SettingUtils.getServeUrl; /** * @author xuexiang @@ -60,7 +61,7 @@ public class MyApp extends Application { public void onCreate() { super.onCreate(); initLibs(); - + initHttp(); app = this; mBroadcastData = new MutableLiveData<>(); IntentFilter filter = new IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION); @@ -102,6 +103,16 @@ public class MyApp extends Application { ANRWatchDogInit.init(); } + private void initHttp() { + XHttpSDK.init(this); //初始化网络请求框架,必须首先执行 + XHttpSDK.setSuccessCode(200); + XHttpSDK.debug(); //需要调试的时候执行 + XHttpSDK.debug(new CustomLoggingInterceptor()); //设置自定义的日志打印拦截器 + XHttpSDK.setBaseUrl(getServeUrl()); //设置网络请求的基础地址 +// XHttpSDK.addInterceptor(new CustomDynamicInterceptor()); //设置动态参数添加拦截器 +// XHttpSDK.addInterceptor(new CustomExpiredInterceptor()); //请求失效校验拦截器 + } + /** * @return 当前app是否是调试开发模式 diff --git a/android/app/src/main/java/com/kerwin/wumei/activity/AddDeviceActivity.java b/android/app/src/main/java/com/kerwin/wumei/activity/AddDeviceActivity.java index 9b89c562..c4ec7fdd 100644 --- a/android/app/src/main/java/com/kerwin/wumei/activity/AddDeviceActivity.java +++ b/android/app/src/main/java/com/kerwin/wumei/activity/AddDeviceActivity.java @@ -14,6 +14,7 @@ import android.net.wifi.WifiManager; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; +import android.os.Handler; import android.text.Spannable; import android.text.SpannableString; import android.text.SpannableStringBuilder; @@ -35,9 +36,11 @@ import com.kerwin.wumei.R; import com.kerwin.wumei.adapter.entity.EspTouchViewModel; import com.kerwin.wumei.core.BaseActivity; import com.kerwin.wumei.fragment.LoginFragment; +import com.kerwin.wumei.fragment.device.AddDeviceFragment; import com.kerwin.wumei.utils.NetUtils; import com.xuexiang.xui.utils.KeyboardUtils; import com.xuexiang.xui.utils.StatusBarUtils; +import com.xuexiang.xui.widget.progress.CircleProgressView; import com.xuexiang.xutil.display.Colors; import java.lang.ref.WeakReference; @@ -68,6 +71,10 @@ public class AddDeviceActivity extends BaseActivity { return mViewModel; } + private AddDeviceFragment addDeviceFragment; + private IEsptouchTask mEsptouchTask; + + public void executeEsptouch() { EspTouchViewModel viewModel = mViewModel; // byte[] ssid = viewModel.ssidBytes == null ? ByteUtil.getBytesByString(viewModel.ssid): viewModel.ssidBytes; @@ -77,7 +84,8 @@ public class AddDeviceActivity extends BaseActivity { byte[] password = pwdStr == null ? null : ByteUtil.getBytesByString(pwdStr.toString()); byte[] bssid = TouchNetUtil.parseBssid2bytes(viewModel.bssid); byte[] broadcast = {(byte) (mViewModel.packageModeGroup.getCheckedRadioButtonId() == R.id.packageBroadcast? 1 : 0)}; - byte[] deviceCount = "1".getBytes(); + int count = mViewModel.xsbDeviceCount.getSelectedNumber(); + byte[] deviceCount = String.valueOf(count).getBytes(); if (mTask != null) { mTask.cancelEsptouch(); } @@ -259,12 +267,19 @@ public class AddDeviceActivity extends BaseActivity { super.onRequestPermissionsResult(requestCode, permissions, grantResults); } - public static class EsptouchAsyncTask4 extends AsyncTask> { + /** + * 中断配网任务 + */ + public void interruptEspTouchTask(){ + if (mEsptouchTask != null) { + mEsptouchTask.interrupt(); + } + } + + public class EsptouchAsyncTask4 extends AsyncTask> { private WeakReference mActivity; private final Object mLock = new Object(); - private ProgressDialog mProgressDialog; - private AlertDialog mResultDialog; - private IEsptouchTask mEsptouchTask; + EsptouchAsyncTask4(AddDeviceActivity activity) { mActivity = new WeakReference<>(activity); @@ -272,12 +287,6 @@ public class AddDeviceActivity extends BaseActivity { public void cancelEsptouch() { cancel(true); - if (mProgressDialog != null) { - mProgressDialog.dismiss(); - } - if (mResultDialog != null) { - mResultDialog.dismiss(); - } if (mEsptouchTask != null) { mEsptouchTask.interrupt(); } @@ -285,26 +294,8 @@ public class AddDeviceActivity extends BaseActivity { @Override protected void onPreExecute() { - Activity activity = mActivity.get(); - mProgressDialog = new ProgressDialog(activity); - mProgressDialog.setMessage(activity.getString(R.string.esptouch1_configuring_message)); - mProgressDialog.setCanceledOnTouchOutside(false); - mProgressDialog.setOnCancelListener(dialog -> { - synchronized (mLock) { - if (mEsptouchTask != null) { - mEsptouchTask.interrupt(); - } - } - }); - mProgressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, activity.getText(android.R.string.cancel), - (dialog, which) -> { - synchronized (mLock) { - if (mEsptouchTask != null) { - mEsptouchTask.interrupt(); - } - } - }); - mProgressDialog.show(); + addDeviceFragment = (AddDeviceFragment) getSupportFragmentManager().getFragments().get(0); + addDeviceFragment.beginCounter(); } @Override @@ -341,13 +332,9 @@ public class AddDeviceActivity extends BaseActivity { protected void onPostExecute(List result) { AddDeviceActivity activity = mActivity.get(); activity.mTask = null; - mProgressDialog.dismiss(); if (result == null) { - mResultDialog = new AlertDialog.Builder(activity) - .setMessage(R.string.esptouch1_configure_result_failed_port) - .setPositiveButton(android.R.string.ok, null) - .show(); - mResultDialog.setCanceledOnTouchOutside(false); + addDeviceFragment.showMessage("建立 EspTouch 任务失败, 端口可能被其他程序占用",false); + addDeviceFragment.endCounter(); return; } @@ -356,31 +343,20 @@ public class AddDeviceActivity extends BaseActivity { if (firstResult.isCancelled()) { return; } - // the task received some results including cancelled while - // executing before receiving enough results if (!firstResult.isSuc()) { - mResultDialog = new AlertDialog.Builder(activity) - .setMessage(R.string.esptouch1_configure_result_failed) - .setPositiveButton(android.R.string.ok, null) - .show(); - mResultDialog.setCanceledOnTouchOutside(false); + addDeviceFragment.showMessage("配网失败",false); + addDeviceFragment.endCounter(); return; } - ArrayList resultMsgList = new ArrayList<>(result.size()); + String message=""; for (IEsptouchResult touchResult : result) { - String message = activity.getString(R.string.esptouch1_configure_result_success_item, - touchResult.getBssid(), touchResult.getInetAddress().getHostAddress()); - resultMsgList.add(message); + message += "BSSID: "+touchResult.getBssid()+", 地址: "+touchResult.getInetAddress().getHostAddress()+"\n"; } - CharSequence[] items = new CharSequence[resultMsgList.size()]; - mResultDialog = new AlertDialog.Builder(activity) - .setTitle(R.string.esptouch1_configure_result_success) - .setItems(resultMsgList.toArray(items), null) - .setPositiveButton(android.R.string.ok, null) - .show(); - mResultDialog.setCanceledOnTouchOutside(false); + + addDeviceFragment.endCounter(); + addDeviceFragment.showMessage("完成配网\n"+message,true); } } @@ -391,6 +367,8 @@ public class AddDeviceActivity extends BaseActivity { super.onCreate(savedInstanceState); mWifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE); mViewModel = new EspTouchViewModel(); + + } @Override @@ -407,4 +385,6 @@ public class AddDeviceActivity extends BaseActivity { public boolean onKeyDown(int keyCode, KeyEvent event) { return KeyboardUtils.onDisableBackKeyDown(keyCode) && super.onKeyDown(keyCode, event); } + + } diff --git a/android/app/src/main/java/com/kerwin/wumei/activity/LoginActivity.java b/android/app/src/main/java/com/kerwin/wumei/activity/LoginActivity.java index bab79c1c..88d8c584 100644 --- a/android/app/src/main/java/com/kerwin/wumei/activity/LoginActivity.java +++ b/android/app/src/main/java/com/kerwin/wumei/activity/LoginActivity.java @@ -6,6 +6,7 @@ import android.view.KeyEvent; import com.kerwin.wumei.core.BaseActivity; import com.kerwin.wumei.fragment.LoginFragment; +import com.kerwin.wumei.fragment.device.DeviceDetailFragment; import com.xuexiang.xui.utils.KeyboardUtils; import com.xuexiang.xui.utils.StatusBarUtils; import com.xuexiang.xutil.display.Colors; diff --git a/android/app/src/main/java/com/kerwin/wumei/activity/MainActivity.java b/android/app/src/main/java/com/kerwin/wumei/activity/MainActivity.java index 9c05b48f..6f8bc317 100644 --- a/android/app/src/main/java/com/kerwin/wumei/activity/MainActivity.java +++ b/android/app/src/main/java/com/kerwin/wumei/activity/MainActivity.java @@ -51,6 +51,12 @@ import androidx.core.location.LocationManagerCompat; import androidx.drawerlayout.widget.DrawerLayout; import androidx.viewpager.widget.ViewPager; +import com.kerwin.wumei.entity.User; +import com.kerwin.wumei.fragment.profile.AccountFragment; +import com.kerwin.wumei.http.callback.TipRequestCallBack; +import com.kerwin.wumei.http.request.UserInfoApiResult; +import com.kerwin.wumei.utils.sdkinit.XUpdateInit; + import com.espressif.iot.esptouch.EsptouchTask; import com.espressif.iot.esptouch.IEsptouchResult; import com.espressif.iot.esptouch.IEsptouchTask; @@ -70,6 +76,7 @@ import com.kerwin.wumei.fragment.device.AddDeviceFragment; import com.kerwin.wumei.fragment.device.GroupFragment; import com.kerwin.wumei.fragment.device.SceneFragment; import com.kerwin.wumei.fragment.device.ShareDeviceFragment; +import com.kerwin.wumei.fragment.news.HomePageFragment; import com.kerwin.wumei.fragment.news.NewsFragment; import com.kerwin.wumei.fragment.profile.ProfileFragment; import com.kerwin.wumei.fragment.device.DeviceFragment; @@ -78,6 +85,9 @@ import com.kerwin.wumei.utils.Utils; import com.kerwin.wumei.utils.XToastUtils; import com.kerwin.wumei.widget.GuideTipsDialog; import com.xuexiang.xaop.annotation.SingleClick; +import com.xuexiang.xhttp2.XHttp; +import com.xuexiang.xhttp2.callback.CallBackProxy; +import com.xuexiang.xhttp2.exception.ApiException; import com.xuexiang.xpage.core.PageOption; import com.xuexiang.xpage.enums.CoreAnim; import com.xuexiang.xui.adapter.FragmentAdapter; @@ -99,6 +109,10 @@ import java.util.List; import butterknife.BindView; +import static com.kerwin.wumei.utils.TokenUtils.clearToken; +import static com.kerwin.wumei.utils.TokenUtils.getToken; +import static com.kerwin.wumei.utils.TokenUtils.hasToken; + public class MainActivity extends BaseActivity implements View.OnClickListener, ViewPager.OnPageChangeListener, BottomNavigationView.OnNavigationItemSelectedListener, ClickUtils.OnClick2ExitListener, Toolbar.OnMenuItemClickListener { @BindView(R.id.toolbar) @@ -129,6 +143,7 @@ public class MainActivity extends BaseActivity implements View.OnClickListener, protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initViews(); +// initData(); initListeners(); } @@ -148,14 +163,20 @@ public class MainActivity extends BaseActivity implements View.OnClickListener, BaseFragment[] fragments = new BaseFragment[]{ new DeviceFragment(), new SceneFragment(), - new NewsFragment(), + new HomePageFragment(), new ProfileFragment(), }; FragmentAdapter adapter = new FragmentAdapter<>(getSupportFragmentManager(), fragments); viewPager.setOffscreenPageLimit(mTitles.length - 1); viewPager.setAdapter(adapter); + //显示提示 +// GuideTipsDialog.showTips(this); + } + + private void initData() { GuideTipsDialog.showTips(this); + XUpdateInit.checkUpdate(this, false); } /** @@ -183,10 +204,11 @@ public class MainActivity extends BaseActivity implements View.OnClickListener, } } - // TODO: 2019-10-09 初始化数据 + // 绑定数据 ivAvatar.setImageResource(R.drawable.ic_default_head); - tvAvatar.setText("15208747707"); - tvSign.setText("物美点亮智慧生活..."); + tvAvatar.setText("匿名用户"); + tvSign.setText("物美智能点亮智慧生活..."); + getUserInfo(tvAvatar,tvSign ); navHeader.setOnClickListener(this); } @@ -197,34 +219,31 @@ public class MainActivity extends BaseActivity implements View.OnClickListener, //侧边栏点击事件 navView.setNavigationItemSelectedListener(menuItem -> { - switch (menuItem.getItemId()) { - case R.id.nav_add_device: - PageOption.to(AddDeviceFragment.class) //跳转的fragment - .setAnim(CoreAnim.slide) //页面转场动画 - .setRequestCode(100) //请求码,用于返回结果 - .setAddToBackStack(true) //是否加入堆栈 - .setNewActivity(true,AddDeviceActivity.class) //是否使用新的Activity打开 - .open(this); //打开页面进行跳转 - break; - case R.id.nav_settings: - openNewPage(SettingsFragment.class); - break; - case R.id.nav_about: - openNewPage(AboutFragment.class); - break; - case R.id.nav_message: - openNewPage(MessageFragment.class); - break; - case R.id.nav_share_device: - openNewPage(ShareDeviceFragment.class); - break; - case R.id.nav_group: - openNewPage(GroupFragment.class); - break; - default: - XToastUtils.toast("点击了:" + menuItem.getTitle()); - break; - } + + switch (menuItem.getItemId()) { + case R.id.nav_add_device: + PageOption.to(AddDeviceFragment.class) //跳转的fragment + .setAnim(CoreAnim.slide) //页面转场动画 + .setRequestCode(100) //请求码,用于返回结果 + .setAddToBackStack(true) //是否加入堆栈 + .setNewActivity(true, AddDeviceActivity.class) //是否使用新的Activity打开 + .open(this); //打开页面进行跳转 + break; + case R.id.nav_about: + openNewPage(AboutFragment.class); + break; + case R.id.nav_serve_config: + drawerLayout.closeDrawers(); + toolbar.setTitle(menuItem.getTitle()); + viewPager.setCurrentItem(1, false); + break; + case R.id.nav_message: + openNewPage(MessageFragment.class); + break; + default: + XToastUtils.toast("点击了:" + menuItem.getTitle()); + break; + } return true; }); @@ -258,7 +277,7 @@ public class MainActivity extends BaseActivity implements View.OnClickListener, public void onClick(View v) { switch (v.getId()) { case R.id.nav_header: - XToastUtils.toast("功能完善中..."); + openNewPage(AccountFragment.class); break; default: break; @@ -325,5 +344,36 @@ public class MainActivity extends BaseActivity implements View.OnClickListener, XUtil.exitApp(); } + /** + * HTTP获取用户信息 + */ + private void getUserInfo(TextView avatar,TextView sign){ + if(!hasToken()) return; + XHttp.get("/prod-api/getInfo") + .headers("Authorization","Bearer "+getToken()) + .execute(new CallBackProxy, User>(new TipRequestCallBack() { + @Override + public void onSuccess(User user) throws Throwable { + Log.d("user:",user.getNickName()); + if(user.getNickName()!=null && user.getNickName().length()!=0) + { + avatar.setText(user.getNickName()); + }else{ + avatar.setText(user.getUserName()); + } + sign.setText("物美智能开源项目(wumei-smart)"); + } + @Override + public void onError(ApiException e) { + if(e.getCode()==401){ + XToastUtils.info("匿名登录状态,功能受限"); + clearToken(); + }else{ + XToastUtils.error(e.getMessage()); + } + } + }){}); + } + } diff --git a/android/app/src/main/java/com/kerwin/wumei/activity/SplashActivity.java b/android/app/src/main/java/com/kerwin/wumei/activity/SplashActivity.java index 9f9328e5..4a789743 100644 --- a/android/app/src/main/java/com/kerwin/wumei/activity/SplashActivity.java +++ b/android/app/src/main/java/com/kerwin/wumei/activity/SplashActivity.java @@ -38,15 +38,16 @@ public class SplashActivity extends BaseSplashActivity implements CancelAdapt { */ @Override protected void onSplashFinished() { - if (SettingUtils.isAgreePrivacy()) { - loginOrGoMainPage(); - } else { - Utils.showPrivacyDialog(this, (dialog, which) -> { - dialog.dismiss(); - SettingUtils.setIsAgreePrivacy(true); - loginOrGoMainPage(); - }); - } + loginOrGoMainPage(); +// if (SettingUtils.isAgreePrivacy()) { +// loginOrGoMainPage(); +// } else { +// Utils.showPrivacyDialog(this, (dialog, which) -> { +// dialog.dismiss(); +// SettingUtils.setIsAgreePrivacy(true); +// loginOrGoMainPage(); +// }); +// } } private void loginOrGoMainPage() { diff --git a/android/app/src/main/java/com/kerwin/wumei/adapter/entity/EspTouchViewModel.java b/android/app/src/main/java/com/kerwin/wumei/adapter/entity/EspTouchViewModel.java index fb4a2429..074708fe 100644 --- a/android/app/src/main/java/com/kerwin/wumei/adapter/entity/EspTouchViewModel.java +++ b/android/app/src/main/java/com/kerwin/wumei/adapter/entity/EspTouchViewModel.java @@ -5,12 +5,13 @@ import android.widget.EditText; import android.widget.RadioGroup; import android.widget.TextView; +import com.xuexiang.xui.widget.picker.XSeekBar; import com.xuexiang.xui.widget.spinner.materialspinner.MaterialSpinner; public class EspTouchViewModel { public MaterialSpinner ssidSpinner; public EditText apPasswordEdit; - public EditText deviceCountEdit; + public XSeekBar xsbDeviceCount; public RadioGroup packageModeGroup; public TextView messageView; public Button confirmBtn; diff --git a/android/app/src/main/java/com/kerwin/wumei/adapter/entity/NewInfo.java b/android/app/src/main/java/com/kerwin/wumei/adapter/entity/NewInfo.java index 165ed133..14bdd448 100644 --- a/android/app/src/main/java/com/kerwin/wumei/adapter/entity/NewInfo.java +++ b/android/app/src/main/java/com/kerwin/wumei/adapter/entity/NewInfo.java @@ -1,19 +1,3 @@ -/* - * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ package com.kerwin.wumei.adapter.entity; diff --git a/android/app/src/main/java/com/kerwin/wumei/core/http/api/ApiService.java b/android/app/src/main/java/com/kerwin/wumei/core/http/api/ApiService.java index efda7d0a..b1dcf95c 100644 --- a/android/app/src/main/java/com/kerwin/wumei/core/http/api/ApiService.java +++ b/android/app/src/main/java/com/kerwin/wumei/core/http/api/ApiService.java @@ -39,7 +39,7 @@ public class ApiService { /** * 获得小贴士 */ - @GET("/xuexiangjys/Resource/raw/master/jsonapi/tips.json") + @GET("http://wumei.live/tips.json") Observable>> getTips(); } diff --git a/android/app/src/main/java/com/kerwin/wumei/entity/Dept.java b/android/app/src/main/java/com/kerwin/wumei/entity/Dept.java new file mode 100644 index 00000000..90e651b5 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/entity/Dept.java @@ -0,0 +1,121 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ + +package com.kerwin.wumei.entity; + +import java.util.List; + +public class Dept { + private String remark; + + private int deptId; + + private int parentId; + + private String ancestors; + + private String deptName; + + private String orderNum; + + private String leader; + + private String phone; + + private String email; + + private String status; + + private String delFlag; + + private String parentName; + + private List children ; + + public void setRemark(String remark){ + this.remark = remark; + } + public String getRemark(){ + return this.remark; + } + public void setDeptId(int deptId){ + this.deptId = deptId; + } + public int getDeptId(){ + return this.deptId; + } + public void setParentId(int parentId){ + this.parentId = parentId; + } + public int getParentId(){ + return this.parentId; + } + public void setAncestors(String ancestors){ + this.ancestors = ancestors; + } + public String getAncestors(){ + return this.ancestors; + } + public void setDeptName(String deptName){ + this.deptName = deptName; + } + public String getDeptName(){ + return this.deptName; + } + public void setOrderNum(String orderNum){ + this.orderNum = orderNum; + } + public String getOrderNum(){ + return this.orderNum; + } + public void setLeader(String leader){ + this.leader = leader; + } + public String getLeader(){ + return this.leader; + } + public void setPhone(String phone){ + this.phone = phone; + } + public String getPhone(){ + return this.phone; + } + public void setEmail(String email){ + this.email = email; + } + public String getEmail(){ + return this.email; + } + public void setStatus(String status){ + this.status = status; + } + public String getStatus(){ + return this.status; + } + public void setDelFlag(String delFlag){ + this.delFlag = delFlag; + } + public String getDelFlag(){ + return this.delFlag; + } + public void setParentName(String parentName){ + this.parentName = parentName; + } + public String getParentName(){ + return this.parentName; + } + public void setChildren(List children){ + this.children = children; + } + public List getChildren(){ + return this.children; + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/entity/DictData.java b/android/app/src/main/java/com/kerwin/wumei/entity/DictData.java new file mode 100644 index 00000000..c35b0f65 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/entity/DictData.java @@ -0,0 +1,65 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ + +package com.kerwin.wumei.entity; + +public class DictData { + + /** 字典标签 */ + private String dictLabel; + + /** 字典键值 */ + private Integer dictValue; + + /** 字典编码 */ + private Long dictCode; + + /** 字典类型 */ + private String dictType; + + + public Long getDictCode() + { + return dictCode; + } + public void setDictCode(Long dictCode) + { + this.dictCode = dictCode; + } + + public String getDictLabel() + { + return dictLabel; + } + public void setDictLabel(String dictLabel) + { + this.dictLabel = dictLabel; + } + + public Integer getDictValue() + { + return dictValue; + } + public void setDictValue(Integer dictValue) + { + this.dictValue = dictValue; + } + + public String getDictType() + { + return dictType; + } + public void setDictType(String dictType) + { + this.dictType = dictType; + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/entity/IotCategory.java b/android/app/src/main/java/com/kerwin/wumei/entity/IotCategory.java new file mode 100644 index 00000000..1bee7422 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/entity/IotCategory.java @@ -0,0 +1,39 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ + +package com.kerwin.wumei.entity; + +public class IotCategory { + /** 序号 */ + private Long categoryId; + + /** 分类名称 */ + private String categoryName; + + public void setCategoryId(Long categoryId) + { + this.categoryId = categoryId; + } + public Long getCategoryId() + { + return categoryId; + } + + public void setCategoryName(String categoryName) + { + this.categoryName = categoryName; + } + public String getCategoryName() + { + return categoryName; + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/entity/IotDevice.java b/android/app/src/main/java/com/kerwin/wumei/entity/IotDevice.java new file mode 100644 index 00000000..a6d4634b --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/entity/IotDevice.java @@ -0,0 +1,126 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ + +package com.kerwin.wumei.entity; + +import java.math.BigDecimal; +import java.util.Date; + +public class IotDevice { + /** 序号 */ + private Long deviceId; + + /** 编号 */ + private String deviceNum; + + /** 分类 */ + private String categoryName; + + /** 名称 */ + private String deviceName; + + /** 固件版本 */ + private String firmwareVersion; + + /** 用户 */ + private String ownerId; + + /** 备注 */ + private String remark; + + /** 设备温度 */ + private String deviceTemp; + + /** 创建时间 */ + private String createTime; + + public void setDeviceId(Long deviceId) + { + this.deviceId = deviceId; + } + + public Long getDeviceId() + { + return deviceId; + } + public void setDeviceNum(String deviceNum) + { + this.deviceNum = deviceNum; + } + + public String getDeviceNum() + { + return deviceNum; + } + public void setCategoryId(String categoryId) + { + this.categoryName = categoryName; + } + + public String getCategoryName() + { + return categoryName; + } + public void setDeviceName(String deviceName) + { + this.deviceName = deviceName; + } + + public String getDeviceName() + { + return deviceName; + } + public void setFirmwareVersion(String firmwareVersion) + { + this.firmwareVersion = firmwareVersion; + } + + public String getFirmwareVersion() + { + return firmwareVersion; + } + public void setOwnerId(String ownerId) + { + this.ownerId = ownerId; + } + + public String getOwnerId() + { + return ownerId; + } + + public void setRemark(String remark) + { + this.remark = remark; + } + public String getRemark() + { + return remark; + } + + public void setDeviceTemp(String deviceTemperature) + { + this.deviceTemp = deviceTemperature; + } + public String getDeviceTemp() + { + return deviceTemp; + } + + public void setCreateTime(String createTime) + { + this.createTime = createTime; + } + public String getCreateTime() + { + return createTime; + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/entity/IotDeviceSet.java b/android/app/src/main/java/com/kerwin/wumei/entity/IotDeviceSet.java new file mode 100644 index 00000000..6b2247cc --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/entity/IotDeviceSet.java @@ -0,0 +1,282 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ + +package com.kerwin.wumei.entity; + +public class IotDeviceSet { + /** 序号 */ + private Long deviceSetId; + + /** 设备 */ + private Long deviceId; + + /** 设备编号 */ + private String deviceNum; + + /** 报警 */ + private Integer isAlarm; + + /** 雷达感应 */ + private Integer isRadar; + + /** 托管 */ + private Integer isHost; + + /** 重启 */ + private Integer isReset; + + /** 打开AP */ + private Integer isAp; + + /** 是否离线使用 */ + private Integer isWifiOffline; + + /** 是否使用证书 */ + private Integer isOpenCertifi; + + /** 智能配网 */ + private Integer isSmartConfig; + + /** 射频遥控 */ + private Integer isRfControl; + + /** 遥控配对 */ + private Integer isRfLearn; + + /** 遥控清码 */ + private Integer isRfClear; + + /** 按键一 */ + private Integer rfOneFunc; + + /** 按键二 */ + private Integer rfTwoFunc; + + /** 按键三 */ + private Integer rfThreeFunc; + + /** 按键四 */ + private Integer rfFourFunc; + + /** 用户 */ + private String ownerId; + + /** 配网地址 */ + private String networkAddress; + + /** 配网IP */ + private String networkIp; + + /** 雷达感应间隔 */ + private Integer radarInterval; + + public void setDeviceSetId(Long deviceSetId) + { + this.deviceSetId = deviceSetId; + } + + public Long getDeviceSetId() + { + return deviceSetId; + } + public void setDeviceId(Long deviceId) + { + this.deviceId = deviceId; + } + + public Long getDeviceId() + { + return deviceId; + } + public void setDeviceNum(String deviceNum) + { + this.deviceNum = deviceNum; + } + + public String getDeviceNum() + { + return deviceNum; + } + public void setIsAlarm(Integer isAlarm) + { + this.isAlarm = isAlarm; + } + + public Integer getIsAlarm() + { + return isAlarm; + } + public void setIsRadar(Integer isRadar) + { + this.isRadar = isRadar; + } + + public Integer getIsRadar() + { + return isRadar; + } + public void setIsHost(Integer isHost) + { + this.isHost = isHost; + } + + public Integer getIsHost() + { + return isHost; + } + public void setIsReset(Integer isReset) + { + this.isReset = isReset; + } + + public Integer getIsReset() + { + return isReset; + } + + public void setIsAp(Integer isAp) + { + this.isAp = isAp; + } + public Integer getIsAp() + { + return isAp; + } + + public void setIsWifiOffline(Integer isWifiOffline) + { + this.isWifiOffline = isWifiOffline; + } + public Integer getIsWifiOffline() + { + return isWifiOffline; + } + + public void setIsOpenCertifi(Integer isOpenCertifi) + { + this.isOpenCertifi = isOpenCertifi; + } + public Integer getIsOpenCertifi() + { + return isOpenCertifi; + } + + public void setIsSmartConfig(Integer isSmartConfig) + { + this.isSmartConfig = isSmartConfig; + } + + public Integer getIsSmartConfig() + { + return isSmartConfig; + } + public void setIsRfControl(Integer isRfControl) + { + this.isRfControl = isRfControl; + } + + public Integer getIsRfControl() + { + return isRfControl; + } + public void setIsRfLearn(Integer isRfLearn) + { + this.isRfLearn = isRfLearn; + } + + public Integer getIsRfLearn() + { + return isRfLearn; + } + public void setIsRfClear(Integer isRfClear) + { + this.isRfClear = isRfClear; + } + + public Integer getIsRfClear() + { + return isRfClear; + } + public void setRfOneFunc(Integer rfOneFunc) + { + this.rfOneFunc = rfOneFunc; + } + + public Integer getRfOneFunc() + { + return rfOneFunc; + } + public void setRfTwoFunc(Integer rfTwoFunc) + { + this.rfTwoFunc = rfTwoFunc; + } + + public Integer getRfTwoFunc() + { + return rfTwoFunc; + } + public void setRfThreeFunc(Integer rfThreeFunc) + { + this.rfThreeFunc = rfThreeFunc; + } + + public Integer getRfThreeFunc() + { + return rfThreeFunc; + } + public void setRfFourFunc(Integer rfFourFunc) + { + this.rfFourFunc = rfFourFunc; + } + + public Integer getRfFourFunc() + { + return rfFourFunc; + } + public void setOwnerId(String ownerId) + { + this.ownerId = ownerId; + } + + public String getOwnerId() + { + return ownerId; + } + public void setNetworkAddress(String networkAddress) + { + this.networkAddress = networkAddress; + } + + public String getNetworkAddress() + { + return networkAddress; + } + public void setNetworkIp(String networkIp) + { + this.networkIp = networkIp; + } + + public String getNetworkIp() + { + return networkIp; + } + + public void setRadarInterval(Integer radarInterval) + { + this.radarInterval = radarInterval; + } + + public Integer getRadarInterval() + { + return radarInterval; + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/entity/IotDeviceStatus.java b/android/app/src/main/java/com/kerwin/wumei/entity/IotDeviceStatus.java new file mode 100644 index 00000000..cdd70040 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/entity/IotDeviceStatus.java @@ -0,0 +1,234 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ + +package com.kerwin.wumei.entity; + +import java.math.BigDecimal; + +public class IotDeviceStatus { + /** 序号 */ + private Long deviceStatusId; + + /** 设备 */ + private Long deviceId; + + /** 设备编号 */ + private String deviceNum; + + /** 继电器 */ + private Integer relayStatus; + + /** 灯状态 */ + private Integer lightStatus; + + /** 在线 */ + private Integer isOnline; + + /** 设备温度 */ + private BigDecimal deviceTemperature; + + /** 设备湿度 */ + private Integer rssi; + + /** 空气温度 */ + private BigDecimal airTemperature; + + /** 空气湿度 */ + private BigDecimal airHumidity; + + /** 触发源 */ + private Integer triggerSource; + + /** 彩灯亮度 */ + private Integer brightness; + + /** 渐变间隔 */ + private Integer lightInterval; + + /** 彩灯模式 */ + private Integer lightMode; + + /** 灯渐变时间 */ + private Integer fadeTime; + + /** 红灯 */ + private Integer red; + + /** 绿灯 */ + private Integer green; + + /** 蓝灯 */ + private Integer blue; + + public void setDeviceStatusId(Long deviceStatusId) + { + this.deviceStatusId = deviceStatusId; + } + + public Long getDeviceStatusId() + { + return deviceStatusId; + } + public void setDeviceId(Long deviceId) + { + this.deviceId = deviceId; + } + + public Long getDeviceId() + { + return deviceId; + } + public void setDeviceNum(String deviceNum) + { + this.deviceNum = deviceNum; + } + + public String getDeviceNum() + { + return deviceNum; + } + public void setRelayStatus(Integer relayStatus) + { + this.relayStatus = relayStatus; + } + + public Integer getRelayStatus() + { + return relayStatus; + } + public void setLightStatus(Integer lightStatus) + { + this.lightStatus = lightStatus; + } + + public Integer getLightStatus() + { + return lightStatus; + } + public void setIsOnline(Integer isOnline) + { + this.isOnline = isOnline; + } + + public Integer getIsOnline() + { + return isOnline; + } + public void setDeviceTemperature(BigDecimal deviceTemperature) + { + this.deviceTemperature = deviceTemperature; + } + + public BigDecimal getDeviceTemperature() + { + return deviceTemperature; + } + public void setRssi(Integer rssi) + { + this.rssi = rssi; + } + + public Integer getRssi() + { + return rssi; + } + public void setAirTemperature(BigDecimal airTemperature) + { + this.airTemperature = airTemperature; + } + + public BigDecimal getAirTemperature() + { + return airTemperature; + } + public void setAirHumidity(BigDecimal airHumidity) + { + this.airHumidity = airHumidity; + } + + public BigDecimal getAirHumidity() + { + return airHumidity; + } + public void setTriggerSource(Integer triggerSource) + { + this.triggerSource = triggerSource; + } + + public Integer getTriggerSource() + { + return triggerSource; + } + public void setBrightness(Integer brightness) + { + this.brightness = brightness; + } + + public Integer getBrightness() + { + return brightness; + } + public void setLightInterval(Integer lightInterval) + { + this.lightInterval = lightInterval; + } + + public Integer getLightInterval() + { + return lightInterval; + } + public void setLightMode(Integer lightMode) + { + this.lightMode = lightMode; + } + + public Integer getLightMode() + { + return lightMode; + } + public void setRed(Integer red) + { + this.red = red; + } + + public Integer getRed() + { + return red; + } + public void setGreen(Integer green) + { + this.green = green; + } + + public Integer getGreen() + { + return green; + } + public void setBlue(Integer blue) + { + this.blue = blue; + } + + public Integer getBlue() + { + return blue; + } + + public void setFadeTime(Integer fadeTime) + { + this.fadeTime = fadeTime; + } + public Integer getFadeTime() + { + return fadeTime; + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/entity/IotGroup.java b/android/app/src/main/java/com/kerwin/wumei/entity/IotGroup.java new file mode 100644 index 00000000..b15b9e4c --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/entity/IotGroup.java @@ -0,0 +1,63 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ + +package com.kerwin.wumei.entity; + +public class IotGroup { + /** 设备分组 */ + private Long groupId; + + /** 用户 */ + private Long userId; + + /** 分组名称 */ + private String groupName; + + /** 排序 */ + private Integer groupOrder; + + public void setGroupId(Long groupId) + { + this.groupId = groupId; + } + + public Long getGroupId() + { + return groupId; + } + public void setUserId(Long userId) + { + this.userId = userId; + } + + public Long getUserId() + { + return userId; + } + public void setGroupName(String groupName) + { + this.groupName = groupName; + } + + public String getGroupName() + { + return groupName; + } + public void setGroupOrder(Integer groupOrder) + { + this.groupOrder = groupOrder; + } + + public Integer getGroupOrder() + { + return groupOrder; + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/entity/Roles.java b/android/app/src/main/java/com/kerwin/wumei/entity/Roles.java new file mode 100644 index 00000000..c089b1da --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/entity/Roles.java @@ -0,0 +1,119 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ + +package com.kerwin.wumei.entity; + +public class Roles { + private String remark; + + private int roleId; + + private String roleName; + + private String roleKey; + + private String roleSort; + + private String dataScope; + + private boolean menuCheckStrictly; + + private boolean deptCheckStrictly; + + private String status; + + private boolean flag; + + private String menuIds; + + private String deptIds; + + private boolean admin; + + public void setRemark(String remark){ + this.remark = remark; + } + public String getRemark(){ + return this.remark; + } + public void setRoleId(int roleId){ + this.roleId = roleId; + } + public int getRoleId(){ + return this.roleId; + } + public void setRoleName(String roleName){ + this.roleName = roleName; + } + public String getRoleName(){ + return this.roleName; + } + public void setRoleKey(String roleKey){ + this.roleKey = roleKey; + } + public String getRoleKey(){ + return this.roleKey; + } + public void setRoleSort(String roleSort){ + this.roleSort = roleSort; + } + public String getRoleSort(){ + return this.roleSort; + } + public void setDataScope(String dataScope){ + this.dataScope = dataScope; + } + public String getDataScope(){ + return this.dataScope; + } + public void setMenuCheckStrictly(boolean menuCheckStrictly){ + this.menuCheckStrictly = menuCheckStrictly; + } + public boolean getMenuCheckStrictly(){ + return this.menuCheckStrictly; + } + public void setDeptCheckStrictly(boolean deptCheckStrictly){ + this.deptCheckStrictly = deptCheckStrictly; + } + public boolean getDeptCheckStrictly(){ + return this.deptCheckStrictly; + } + public void setStatus(String status){ + this.status = status; + } + public String getStatus(){ + return this.status; + } + public void setFlag(boolean flag){ + this.flag = flag; + } + public boolean getFlag(){ + return this.flag; + } + public void setMenuIds(String menuIds){ + this.menuIds = menuIds; + } + public String getMenuIds(){ + return this.menuIds; + } + public void setDeptIds(String deptIds){ + this.deptIds = deptIds; + } + public String getDeptIds(){ + return this.deptIds; + } + public void setAdmin(boolean admin){ + this.admin = admin; + } + public boolean getAdmin(){ + return this.admin; + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/entity/User.java b/android/app/src/main/java/com/kerwin/wumei/entity/User.java new file mode 100644 index 00000000..86a4f78d --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/entity/User.java @@ -0,0 +1,162 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ + +package com.kerwin.wumei.entity; + +import java.util.List; + +public class User { + + private String remark; + + private int userId; + + private int deptId; + + private String userName; + + private String nickName; + + private String email; + + private String phonenumber; + + private String sex; + + private String avatar; + + private String status; + + private String loginIp; + + private String loginDate; + + private Dept dept; + + private List roles ; + + private String roleIds; + + private String postIds; + + private boolean admin; + + private String createTime; + + public void setRemark(String remark){ + this.remark = remark; + } + public String getRemark(){ + return this.remark; + } + public void setUserId(int userId){ + this.userId = userId; + } + public int getUserId(){ + return this.userId; + } + public void setDeptId(int deptId){ + this.deptId = deptId; + } + public int getDeptId(){ + return this.deptId; + } + public void setUserName(String userName){ + this.userName = userName; + } + public String getUserName(){ + return this.userName; + } + public void setNickName(String nickName){ + this.nickName = nickName; + } + public String getNickName(){ + return this.nickName; + } + public void setEmail(String email){ + this.email = email; + } + public String getEmail(){ + return this.email; + } + public void setPhonenumber(String phonenumber){ + this.phonenumber = phonenumber; + } + public String getPhonenumber(){ + return this.phonenumber; + } + public void setSex(String sex){ + this.sex = sex; + } + public String getSex(){ + return this.sex; + } + public void setAvatar(String avatar){ + this.avatar = avatar; + } + public String getAvatar(){ + return this.avatar; + } + public void setStatus(String status){ + this.status = status; + } + public String getStatus(){ + return this.status; + } + public void setLoginIp(String loginIp){ + this.loginIp = loginIp; + } + public String getLoginIp(){ + return this.loginIp; + } + public void setLoginDate(String loginDate){ + this.loginDate = loginDate; + } + public String getLoginDate(){ + return this.loginDate; + } + public void setDept(Dept dept){ + this.dept = dept; + } + public Dept getDept(){ + return this.dept; + } + public void setRoles(List roles){ + this.roles = roles; + } + public List getRoles(){ + return this.roles; + } + public void setRoleIds(String roleIds){ + this.roleIds = roleIds; + } + public String getRoleIds(){ + return this.roleIds; + } + public void setPostIds(String postIds){ + this.postIds = postIds; + } + public String getPostIds(){ + return this.postIds; + } + public void setAdmin(boolean admin){ + this.admin = admin; + } + public boolean getAdmin(){ + return this.admin; + } + public void setCreateTime(String createTime){ + this.createTime = createTime; + } + public String getCreateTime(){ + return this.createTime; + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/entity/bo/CaptureImage.java b/android/app/src/main/java/com/kerwin/wumei/entity/bo/CaptureImage.java new file mode 100644 index 00000000..a26fa2cc --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/entity/bo/CaptureImage.java @@ -0,0 +1,33 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ + +package com.kerwin.wumei.entity.bo; + +public class CaptureImage { + private String uuid; + + private String img; + + public String getUuid() { + return uuid; + } + public void setUuid(String uuid) { + this.uuid = uuid ; + } + + public String getImg() { + return img; + } + public void setImg(String img) { + this.img = img ; + } + +} \ No newline at end of file diff --git a/android/app/src/main/java/com/kerwin/wumei/entity/vo/IotDeviceVo.java b/android/app/src/main/java/com/kerwin/wumei/entity/vo/IotDeviceVo.java new file mode 100644 index 00000000..0bb945ac --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/entity/vo/IotDeviceVo.java @@ -0,0 +1,222 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ + +package com.kerwin.wumei.entity.vo; + +import java.math.BigDecimal; + +public class IotDeviceVo { + private Long deviceId; + + /** 编号 */ + private String deviceNum; + + /** 分类 */ + private Long categoryId; + + /** 分类名称 */ + private String categoryName; + + /** 名称 */ + private String deviceName; + + /** 固件版本 */ + private String firmwareVersion; + + /** 用户 */ + private String ownerId; + + private String nickName; + + /** 删除标志(0代表存在 2代表删除) */ + private String delFlag; + + /** 报警 */ + private Integer isAlarm; + + /** 雷达感应 */ + private Integer isRadar; + + /** 射频遥控 */ + private Integer isRfControl; + + /** 配网地址 */ + private String networkAddress; + + /** 配网IP */ + private String networkIp; + + /** 继电器 */ + private Integer relayStatus; + + /** 灯状态 */ + private Integer lightStatus; + + /** 在线 */ + private Integer isOnline; + + /** 设备温度 */ + private BigDecimal deviceTemperature; + + /** 设备湿度 */ + private Integer rssi; + + + + public void setDeviceId(Long deviceId) + { + this.deviceId = deviceId; + } + public Long getDeviceId() + { + return deviceId; + } + public void setDeviceNum(String deviceNum) + { + this.deviceNum = deviceNum; + } + public String getDeviceNum() + { + return deviceNum; + } + public void setCategoryId(Long categoryId) + { + this.categoryId = categoryId; + } + public Long getCategoryId() + { + return categoryId; + } + public void setCategoryName(String categoryName) + { + this.categoryName = categoryName; + } + public String getCategoryName() + { + return categoryName; + } + public void setDeviceName(String deviceName) + { + this.deviceName = deviceName; + } + public String getDeviceName() + { + return deviceName; + } + public void setFirmwareVersion(String firmwareVersion) { this.firmwareVersion = firmwareVersion; } + public String getFirmwareVersion() + { + return firmwareVersion; + } + public void setOwnerId(String ownerId) + { + this.ownerId = ownerId; + } + public String getOwnerId() + { + return ownerId; + } + public void setNickName(String nickName) + { + this.nickName = nickName; + } + public String getNickName() + { + return nickName; + } + public void setDelFlag(String delFlag) + { + this.delFlag = delFlag; + } + public String getDelFlag() + { + return delFlag; + } + + public void setIsAlarm(Integer isAlarm) + { + this.isAlarm = isAlarm; + } + public Integer getIsAlarm() + { + return isAlarm; + } + public void setIsRadar(Integer isRadar) + { + this.isRadar = isRadar; + } + public Integer getIsRadar() + { + return isRadar; + } + public void setIsRfControl(Integer isRfControl) + { + this.isRfControl = isRfControl; + } + public Integer getIsRfControl() + { + return isRfControl; + } + public void setNetworkAddress(String networkAddress) + { + this.networkAddress = networkAddress; + } + public String getNetworkAddress() + { + return networkAddress; + } + public void setNetworkIp(String networkIp) + { + this.networkIp = networkIp; + } + public String getNetworkIp() + { + return networkIp; + } + + public void setRelayStatus(Integer relayStatus) + { + this.relayStatus = relayStatus; + } + public Integer getRelayStatus() + { + return relayStatus; + } + public void setLightStatus(Integer lightStatus) + { + this.lightStatus = lightStatus; + } + public Integer getLightStatus() + { + return lightStatus; + } + public void setIsOnline(Integer isOnline) + { + this.isOnline = isOnline; + } + public Integer getIsOnline() + { + return isOnline; + } + public void setDeviceTemperature(BigDecimal deviceTemperature) { this.deviceTemperature = deviceTemperature; } + public BigDecimal getDeviceTemperature() + { + return deviceTemperature; + } + public void setRssi(Integer rssi) + { + this.rssi = rssi; + } + public Integer getRssi() + { + return rssi; + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/AboutFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/AboutFragment.java index 0ea94321..6e327927 100644 --- a/android/app/src/main/java/com/kerwin/wumei/fragment/AboutFragment.java +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/AboutFragment.java @@ -1,19 +1,13 @@ -/* - * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ package com.kerwin.wumei.fragment; @@ -24,6 +18,7 @@ import com.kerwin.wumei.core.webview.AgentWebActivity; import com.kerwin.wumei.R; import com.kerwin.wumei.utils.XToastUtils; import com.xuexiang.xpage.annotation.Page; +import com.xuexiang.xui.widget.actionbar.TitleBar; import com.xuexiang.xui.widget.grouplist.XUIGroupListView; import com.xuexiang.xutil.app.AppUtils; @@ -36,6 +31,8 @@ import butterknife.BindView; @Page(name = "关于") public class AboutFragment extends BaseFragment { + @BindView(R.id.titlebar_min) + TitleBar titleBarMin; @BindView(R.id.tv_version) TextView mVersionTextView; @@ -43,6 +40,13 @@ public class AboutFragment extends BaseFragment { XUIGroupListView mAboutGroupListView; @BindView(R.id.tv_copyright) TextView mCopyrightTextView; + @BindView(R.id.tv_autho) + TextView tvAutho; + + @Override + protected TitleBar initTitle() { + return null; + } @Override protected int getLayoutId() { @@ -51,12 +55,15 @@ public class AboutFragment extends BaseFragment { @Override protected void initViews() { + titleBarMin.setLeftClickListener(v -> popToBack()); + mVersionTextView.setText(String.format("版本号:%s", AppUtils.getAppVersionName())); + tvAutho.setText("Author:kerwinci Website:www.wumei.live"); XUIGroupListView.newSection(getContext()) .addItemView(mAboutGroupListView.createItemView(getResources().getString(R.string.about_item_homepage)), v -> AgentWebActivity.goWeb(getContext(), getString(R.string.url_project_github))) .addItemView(mAboutGroupListView.createItemView(getResources().getString(R.string.about_item_author_github)), v -> AgentWebActivity.goWeb(getContext(), getString(R.string.url_author_github))) - .addItemView(mAboutGroupListView.createItemView("版本"), v -> XToastUtils.toast("版本升级")) + .addItemView(mAboutGroupListView.createItemView(getResources().getString(R.string.about_item_add_qq_group)), v -> AgentWebActivity.goWeb(getContext(), getString(R.string.url_add_qq_group))) .addTo(mAboutGroupListView); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy", Locale.CHINA); diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/FeedbackFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/FeedbackFragment.java index fec81e94..2ff25e34 100644 --- a/android/app/src/main/java/com/kerwin/wumei/fragment/FeedbackFragment.java +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/FeedbackFragment.java @@ -1,3 +1,13 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ package com.kerwin.wumei.fragment; import android.widget.TextView; diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/LoginFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/LoginFragment.java index 683c09f9..fbe3606c 100644 --- a/android/app/src/main/java/com/kerwin/wumei/fragment/LoginFragment.java +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/LoginFragment.java @@ -1,37 +1,47 @@ -/* - * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ package com.kerwin.wumei.fragment; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.Color; +import android.util.Base64; +import android.util.Log; import android.view.View; +import android.widget.ImageView; +import com.kerwin.wumei.activity.LoginActivity; import com.kerwin.wumei.activity.MainActivity; import com.kerwin.wumei.core.BaseFragment; import com.kerwin.wumei.R; -import com.kerwin.wumei.utils.RandomUtils; +import com.kerwin.wumei.entity.IotGroup; +import com.kerwin.wumei.entity.bo.CaptureImage; +import com.kerwin.wumei.entity.User; +import com.kerwin.wumei.http.callback.TipRequestCallBack; +import com.kerwin.wumei.http.request.CaptchaImageApiResult; +import com.kerwin.wumei.http.request.ListApiResult; +import com.kerwin.wumei.http.request.TokenApiResult; +import com.kerwin.wumei.http.request.UserInfoApiResult; +import com.kerwin.wumei.utils.MMKVUtils; import com.kerwin.wumei.utils.SettingUtils; import com.kerwin.wumei.utils.TokenUtils; import com.kerwin.wumei.utils.Utils; import com.kerwin.wumei.utils.XToastUtils; import com.xuexiang.xaop.annotation.SingleClick; +import com.xuexiang.xhttp2.XHttp; +import com.xuexiang.xhttp2.callback.CallBackProxy; +import com.xuexiang.xhttp2.exception.ApiException; import com.xuexiang.xpage.annotation.Page; import com.xuexiang.xpage.enums.CoreAnim; -import com.xuexiang.xui.utils.CountDownButtonHelper; import com.xuexiang.xui.utils.ResUtils; import com.xuexiang.xui.utils.ThemeUtils; import com.xuexiang.xui.widget.actionbar.TitleBar; @@ -39,9 +49,15 @@ import com.xuexiang.xui.widget.button.roundbutton.RoundButton; import com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText; import com.xuexiang.xutil.app.ActivityUtils; +import java.util.List; + import butterknife.BindView; import butterknife.OnClick; +import static com.kerwin.wumei.utils.TokenUtils.clearToken; +import static com.kerwin.wumei.utils.TokenUtils.getToken; +import static com.kerwin.wumei.utils.TokenUtils.hasToken; + /** * 登录页面 @@ -54,12 +70,17 @@ public class LoginFragment extends BaseFragment { @BindView(R.id.et_phone_number) MaterialEditText etPhoneNumber; + @BindView(R.id.et_password) + MaterialEditText etPassword; @BindView(R.id.et_verify_code) MaterialEditText etVerifyCode; - @BindView(R.id.btn_get_verify_code) - RoundButton btnGetVerifyCode; + @BindView(R.id.iv_code) + ImageView imgVertifyCode; + @BindView(R.id.btn_clear) + RoundButton btnClear; - private CountDownButtonHelper mCountDownHelper; + private String uuid=""; + private String token=""; @Override protected int getLayoutId() { @@ -77,6 +98,7 @@ public class LoginFragment extends BaseFragment { titleBar.addAction(new TitleBar.TextAction(R.string.title_jump_login) { @Override public void performAction(View view) { + clearToken(); onLoginSuccess(); } }); @@ -85,87 +107,103 @@ public class LoginFragment extends BaseFragment { @Override protected void initViews() { - mCountDownHelper = new CountDownButtonHelper(btnGetVerifyCode, 60); - //隐私政策弹窗 - if (!SettingUtils.isAgreePrivacy()) { - Utils.showPrivacyDialog(getContext(), (dialog, which) -> { - dialog.dismiss(); - SettingUtils.setIsAgreePrivacy(true); - }); - } +// if (!SettingUtils.isAgreePrivacy()) { +// Utils.showPrivacyDialog(getContext(), (dialog, which) -> { +// dialog.dismiss(); +// SettingUtils.setIsAgreePrivacy(true); +// }); +// } + getCatpureImage(); + getLocalAccount(); } @SingleClick - @OnClick({R.id.btn_get_verify_code, R.id.btn_login, R.id.tv_other_login, R.id.tv_forget_password, R.id.tv_user_protocol, R.id.tv_privacy_protocol}) + @OnClick({ R.id.btn_login,R.id.iv_code,R.id.btn_clear}) public void onViewClicked(View view) { switch (view.getId()) { - case R.id.btn_get_verify_code: - if (etPhoneNumber.validate()) { - getVerifyCode(etPhoneNumber.getEditValue()); - } + case R.id.btn_clear: + SettingUtils.clearPassword(); + etPassword.clear(); + break; + case R.id.iv_code: + getCatpureImage(); break; case R.id.btn_login: if (etPhoneNumber.validate()) { if (etVerifyCode.validate()) { - loginByVerifyCode(etPhoneNumber.getEditValue(), etVerifyCode.getEditValue()); + loginByVerifyCode(etPhoneNumber.getEditValue(), etPassword.getEditValue(), etVerifyCode.getEditValue()); } } break; - case R.id.tv_other_login: - XToastUtils.info("其他登录方式"); - break; - case R.id.tv_forget_password: - XToastUtils.info("忘记密码"); - break; - case R.id.tv_user_protocol: - XToastUtils.info("用户协议"); - break; - case R.id.tv_privacy_protocol: - XToastUtils.info("隐私政策"); - break; default: break; } } - /** - * 获取验证码 - */ - private void getVerifyCode(String phoneNumber) { - // TODO: 2020/8/29 这里只是界面演示而已 - XToastUtils.warning("只是演示,验证码请随便输"); - mCountDownHelper.start(); - } - - /** - * 根据验证码登录 - * - * @param phoneNumber 手机号 - * @param verifyCode 验证码 - */ - private void loginByVerifyCode(String phoneNumber, String verifyCode) { - // TODO: 2020/8/29 这里只是界面演示而已 - onLoginSuccess(); + @Override + public void onDestroyView() { + super.onDestroyView(); } /** * 登录成功的处理 */ private void onLoginSuccess() { - String token = RandomUtils.getRandomNumbersAndLetters(16); - if (TokenUtils.handleLoginSuccess(token)) { - popToBack(); - ActivityUtils.startActivity(MainActivity.class); - } + TokenUtils.handleLoginSuccess(token); + popToBack(); + ActivityUtils.startActivity(MainActivity.class); } - @Override - public void onDestroyView() { - if (mCountDownHelper != null) { - mCountDownHelper.recycle(); - } - super.onDestroyView(); + /** + * 获取本地存储的账号 + */ + private void getLocalAccount(){ + etPhoneNumber.setText(SettingUtils.getUserName()); + etPassword.setText(SettingUtils.getPassword()); } + + /** + * HTTP获取验证码 + */ + private void getCatpureImage(){ + XHttp.get("/prod-api/captchaImage") + .execute(new CallBackProxy, CaptureImage>(new TipRequestCallBack() { + @Override + public void onSuccess(CaptureImage image) throws Throwable { + uuid=image.getUuid(); + byte[] decode = Base64.decode(image.getImg(), Base64.DEFAULT); + Bitmap bitmap = BitmapFactory.decodeByteArray(decode, 0, decode.length); + imgVertifyCode.setImageBitmap(bitmap); + } + }){}); + } + + /** + * HTTP登录 + * + * @param phoneNumber 手机号 + * @param verifyCode 验证码 + */ + private void loginByVerifyCode(String phoneNumber,String password, String verifyCode) { + XHttp.post("/prod-api/login") + .upJson("{\"username\":\""+phoneNumber+"\",\"password\":\""+password+"\",\"code\":\""+verifyCode+"\",\"uuid\":\""+uuid+"\"}") + .execute(new CallBackProxy, String>(new TipRequestCallBack() { + @Override + public void onSuccess(String tokenResult) throws Throwable { + SettingUtils.setAccount(etPhoneNumber.getEditValue(),etPassword.getEditValue()); + token=tokenResult; + onLoginSuccess(); + } + @Override + public void onError(ApiException e) { + clearToken(); + } + }){}); + } + + + + } diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/MessageFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/MessageFragment.java index d5fecd09..7ea2744b 100644 --- a/android/app/src/main/java/com/kerwin/wumei/fragment/MessageFragment.java +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/MessageFragment.java @@ -1,3 +1,13 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ package com.kerwin.wumei.fragment; import android.view.View; @@ -6,6 +16,7 @@ import android.widget.TextView; import com.kerwin.wumei.R; import com.kerwin.wumei.core.BaseFragment; import com.kerwin.wumei.core.webview.AgentWebActivity; +import com.kerwin.wumei.utils.XToastUtils; import com.xuexiang.xaop.annotation.SingleClick; import com.xuexiang.xpage.annotation.Page; import com.xuexiang.xui.widget.actionbar.TitleBar; @@ -21,6 +32,8 @@ import butterknife.BindView; @Page(name = "消息") public class MessageFragment extends BaseFragment { + @BindView(R.id.titlebar_min) + TitleBar titleBarMin; @Override protected int getLayoutId() { @@ -29,26 +42,12 @@ public class MessageFragment extends BaseFragment { @Override protected TitleBar initTitle() { - com.xuexiang.xui.widget.actionbar.TitleBar titleBar = super.initTitle(); - titleBar.setCenterClickListener(new View.OnClickListener() { - @SingleClick - @Override - public void onClick(View view) { - - } - }); - titleBar.addAction(new com.xuexiang.xui.widget.actionbar.TitleBar.TextAction("菜单") { - @SingleClick - @Override - public void performAction(View view) { - - } - }); - return titleBar; + return null; } @Override protected void initViews() { + titleBarMin.setLeftClickListener(v -> popToBack()); } } diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/SettingsFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/SettingsFragment.java index 0e3ccd6c..661bdede 100644 --- a/android/app/src/main/java/com/kerwin/wumei/fragment/SettingsFragment.java +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/SettingsFragment.java @@ -1,27 +1,27 @@ -/* - * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ package com.kerwin.wumei.fragment; import com.kerwin.wumei.core.BaseFragment; import com.kerwin.wumei.R; +import com.kerwin.wumei.http.callback.TipRequestCallBack; +import com.kerwin.wumei.http.request.NoDataApiResult; +import com.kerwin.wumei.http.request.TokenApiResult; import com.kerwin.wumei.utils.TokenUtils; import com.kerwin.wumei.utils.XToastUtils; import com.xuexiang.xaop.annotation.SingleClick; +import com.xuexiang.xhttp2.XHttp; +import com.xuexiang.xhttp2.callback.CallBackProxy; +import com.xuexiang.xhttp2.exception.ApiException; import com.xuexiang.xpage.annotation.Page; import com.xuexiang.xui.widget.dialog.DialogLoader; import com.xuexiang.xui.widget.textview.supertextview.SuperTextView; @@ -64,6 +64,23 @@ public class SettingsFragment extends BaseFragment implements SuperTextView.OnSu menuLogout.setOnSuperTextViewClickListener(this); } + /** + * HTTP退出登录 + */ + private void logout(){ + XHttp.post("/prod-api/logout") + .execute(new CallBackProxy, String>(new TipRequestCallBack() { + @Override + public void onSuccess(String tokenResult) throws Throwable { + XToastUtils.success("登出成功" ); + } + @Override + public void onError(ApiException e) { + + } + }){}); + } + @SingleClick @Override public void onClick(SuperTextView superTextView) { @@ -83,6 +100,7 @@ public class SettingsFragment extends BaseFragment implements SuperTextView.OnSu getString(R.string.lab_logout_confirm), getString(R.string.lab_yes), (dialog, which) -> { + logout(); dialog.dismiss(); XUtil.getActivityLifecycleHelper().exit(); TokenUtils.handleLogoutSuccess(); diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/device/AddDeviceFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/device/AddDeviceFragment.java index 8c9af48d..e02cc600 100644 --- a/android/app/src/main/java/com/kerwin/wumei/fragment/device/AddDeviceFragment.java +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/device/AddDeviceFragment.java @@ -1,34 +1,45 @@ +/***************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + *****************************************************************************/ package com.kerwin.wumei.fragment.device; import android.Manifest; +import android.graphics.Color; import android.os.Build; +import android.os.Handler; import android.text.method.HideReturnsTransformationMethod; import android.text.method.PasswordTransformationMethod; import android.util.Log; import android.view.View; import android.widget.FrameLayout; import android.widget.LinearLayout; +import android.widget.TextView; import androidx.appcompat.widget.AppCompatImageView; import com.kerwin.wumei.MyApp; import com.kerwin.wumei.R; import com.kerwin.wumei.activity.AddDeviceActivity; -import com.kerwin.wumei.activity.MainActivity; import com.kerwin.wumei.adapter.entity.EspTouchViewModel; import com.kerwin.wumei.core.BaseFragment; import com.xuexiang.xpage.annotation.Page; -import com.xuexiang.xpage.core.PageOption; -import com.xuexiang.xpage.enums.CoreAnim; -import com.xuexiang.xui.widget.spinner.materialspinner.MaterialSpinner; +import com.xuexiang.xui.widget.progress.CircleProgressView; +import com.xuexiang.xui.widget.textview.supertextview.SuperButton; import java.util.List; import butterknife.BindView; -@Page(name = "WIFI网络配置") -public class AddDeviceFragment extends BaseFragment { +@Page(name = "智能配网") +public class AddDeviceFragment extends BaseFragment implements CircleProgressView.CircleProgressUpdateListener { @BindView(R.id.advance_frame_layout) FrameLayout advanceFrameLayout; @BindView(R.id.advance_linear_layout) @@ -37,11 +48,24 @@ public class AddDeviceFragment extends BaseFragment { AppCompatImageView advanceIcon; @BindView(R.id.wifi_password_icon) AppCompatImageView wifiPasswordIcon; + @BindView(R.id.progressView_circle_main) + CircleProgressView progressViewCircleMain; + @BindView(R.id.progress_text_main) + TextView progressTextMain; + @BindView(R.id.btn_config_cancle) + SuperButton btnConfigCancle; + @BindView(R.id.btn_return) + SuperButton btnReturn; private static final String TAG = AddDeviceFragment.class.getSimpleName(); private static final int REQUEST_PERMISSION = 0x01; private EspTouchViewModel mViewModel; + private boolean bStart=false; + + private Handler mHander=new Handler(); + private int mCount=0; + /** * 布局的资源id * @@ -57,23 +81,30 @@ public class AddDeviceFragment extends BaseFragment { */ @Override protected void initViews() { + progressViewCircleMain.setGraduatedEnabled(true); + progressViewCircleMain.setProgressViewUpdateListener(this); //智能配网 mViewModel = ((AddDeviceActivity)this.getActivity()).GetMViewModel(); mViewModel.ssidSpinner = findViewById(R.id.ssid_spinner); mViewModel.apPasswordEdit = findViewById(R.id.wifi_password_txt); mViewModel.packageModeGroup = findViewById(R.id.packageModeGroup); - mViewModel.messageView = findViewById(R.id.messageView); - mViewModel.confirmBtn = findViewById(R.id.add_device_next_btn); + mViewModel.messageView = findViewById(R.id.txt_config_message); + mViewModel.messageView.setText(""); + mViewModel.xsbDeviceCount = findViewById(R.id.xsb_device_count); + mViewModel.xsbDeviceCount.setDefaultValue(1); + mViewModel.confirmBtn = findViewById(R.id.btn_begin); mViewModel.confirmBtn.setOnClickListener(v -> { - // ((AddDeviceActivity)this.getActivity()).executeEsptouch(); - PageOption.to(AddDeviceTwoFragment.class) //跳转的fragment - .setAnim(CoreAnim.slide) //页面转场动画 - .setRequestCode(100) //请求码,用于返回结果 - .setAddToBackStack(true) //是否加入堆栈 - .putString("device_mac","0908070605040306") - .open(this); //打开页面进行跳转 + + ((AddDeviceActivity)this.getActivity()).executeEsptouch(); + +// PageOption.to(AddDeviceTwoFragment.class) //跳转的fragment +// .setAnim(CoreAnim.slide) //页面转场动画 +// .setRequestCode(100) //请求码,用于返回结果 +// .setAddToBackStack(true) //是否加入堆栈 +// .putString("device_mac","0908070605040306") +// .open(this); //打开页面进行跳转 }); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { @@ -98,6 +129,41 @@ public class AddDeviceFragment extends BaseFragment { } }); + } + + + /** + * 进度条开始更新 + * + * @param view + */ + @Override + public void onCircleProgressStart(View view) { + + } + + /** + * 进度条更新结束 + * + * @param view + */ + @Override + public void onCircleProgressFinished(View view) { + progressViewCircleMain.startProgressAnimation(); + } + + + + /** + * 进度条更新中 + * + * @param view + * @param progress + */ + @Override + public void onCircleProgressUpdate(View view, float progress) { + +// progressTextMain.setText("10"); } @@ -135,8 +201,92 @@ public class AddDeviceFragment extends BaseFragment { } }); + btnConfigCancle.setOnClickListener(new View.OnClickListener(){ + @Override + public void onClick(View view){ + ((AddDeviceActivity)getActivity()).interruptEspTouchTask(); + endCounter(); + } + }); + btnReturn.setOnClickListener(new View.OnClickListener(){ + @Override + public void onClick(View view){ + popToBack(); + endCounter(); + } + }); } + @Override + public void onDestroyView() { + endCounter(); + super.onDestroyView(); + } + + /** + * 打开计时器 + */ + public void beginCounter(){ + progressViewCircleMain.startProgressAnimation(); + mHander.post(mCounter); + showMessage("配网中...",true); + mViewModel.confirmBtn.setEnabled(false); + btnConfigCancle.setEnabled(true); + } + + /** + * 关闭计时器 + */ + public void endCounter(){ + mHander.removeCallbacks(mCounter); + mViewModel.confirmBtn.setEnabled(true); + btnConfigCancle.setEnabled(false); + progressViewCircleMain.stopProgressAnimation(); + progressViewCircleMain.setProgressViewUpdateListener(null); + } + + /** + * 计时器 + */ + private Runnable mCounter=new Runnable() { + @Override + public void run() { + int delay=300; + if(mCount<30){ + mCount++; + }else if(mCount<50){ + mCount++; + delay=500; + }else if(mCount<80){ + mCount++; + delay=1000; + }else if(mCount<90){ + mCount++; + delay=3000; + }else if(mCount<98){ + mCount++; + delay=10000; + } + progressTextMain.setText(mCount + ""); + mHander.postDelayed(this, delay); + } + }; + + /** + * 消息提示 + * @param message + * @param isSuccess + */ + public void showMessage(String message,boolean isSuccess){ + if(isSuccess){ + mViewModel.messageView.setTextColor(Color.argb(255, 103, 194, 58)); // 绿色 + }else{ + mViewModel.messageView.setTextColor(Color.argb(255, 245, 108, 108)); //红色 + } + mViewModel.messageView.setText(message); + mViewModel.messageView.setVisibility(View.VISIBLE); + } + } diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/device/AddDeviceTwoFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/device/AddDeviceTwoFragment.java index 9003ba42..3193bb90 100644 --- a/android/app/src/main/java/com/kerwin/wumei/fragment/device/AddDeviceTwoFragment.java +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/device/AddDeviceTwoFragment.java @@ -1,3 +1,13 @@ +/*************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ***************************************************************************/ package com.kerwin.wumei.fragment.device; import android.Manifest; diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/device/DeviceDetailFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/device/DeviceDetailFragment.java new file mode 100644 index 00000000..90acf3b0 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/device/DeviceDetailFragment.java @@ -0,0 +1,78 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ + +package com.kerwin.wumei.fragment.device; + +import android.os.Bundle; +import android.util.Log; +import android.widget.TextView; + +import androidx.viewpager.widget.ViewPager; + +import com.kerwin.wumei.R; +import com.kerwin.wumei.core.BaseFragment; +import com.kerwin.wumei.core.webview.AgentWebActivity; +import com.kerwin.wumei.utils.XToastUtils; +import com.xuexiang.xpage.annotation.Page; +import com.xuexiang.xui.adapter.FragmentAdapter; +import com.xuexiang.xui.widget.actionbar.TitleBar; +import com.xuexiang.xui.widget.grouplist.XUIGroupListView; +import com.xuexiang.xui.widget.tabbar.TabSegment; +import com.xuexiang.xutil.app.AppUtils; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +import butterknife.BindView; + + +@Page(name = "设备详情") +public class DeviceDetailFragment extends BaseFragment { + @BindView(R.id.titlebar_min) + TitleBar titleBarMin; + @BindView(R.id.tabSegment) + TabSegment tabSegment; + @BindView(R.id.contentViewPager) + ViewPager contentViewPager; + + @Override + protected TitleBar initTitle() { + return null; + } + + @Override + protected int getLayoutId() { + return R.layout.fragment_device_detail; + } + + @Override + protected void initViews() { + titleBarMin.setLeftClickListener(v -> popToBack()); + + Bundle arguments = getArguments(); + Long device_id = arguments.getLong("device_id"); + String device_num=arguments.getString("device_num"); + tabSegment.addTab(new TabSegment.Tab("设备")); + tabSegment.addTab(new TabSegment.Tab("状态")); + tabSegment.addTab(new TabSegment.Tab("配置")); + + FragmentAdapter adapter = new FragmentAdapter<>(getChildFragmentManager()); + adapter.addFragment(new DeviceEditFragment(device_id,device_num), ""); + adapter.addFragment(new DeviceStatusFragment(device_id,device_num), ""); + adapter.addFragment(new DeviceSetFragment(device_id,device_num), ""); + + contentViewPager.setAdapter(adapter); + contentViewPager.setCurrentItem(0, false); + tabSegment.setupWithViewPager(contentViewPager, false); + tabSegment.setMode(TabSegment.MODE_FIXED); + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/device/DeviceEditFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/device/DeviceEditFragment.java new file mode 100644 index 00000000..c1f7bcee --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/device/DeviceEditFragment.java @@ -0,0 +1,238 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ +package com.kerwin.wumei.fragment.device; + +import android.util.Log; +import android.view.View; +import android.widget.TextView; + +import androidx.appcompat.widget.AppCompatImageView; + +import com.kerwin.wumei.R; +import com.kerwin.wumei.core.BaseFragment; +import com.kerwin.wumei.entity.DictData; +import com.kerwin.wumei.entity.IotDevice; +import com.kerwin.wumei.entity.IotDeviceStatus; +import com.kerwin.wumei.http.callback.TipRequestCallBack; +import com.kerwin.wumei.http.request.NoDataApiResult; +import com.kerwin.wumei.utils.XToastUtils; +import com.xuexiang.rxutil2.rxjava.RxJavaUtils; +import com.xuexiang.xaop.annotation.SingleClick; +import com.xuexiang.xhttp2.XHttp; +import com.xuexiang.xhttp2.callback.CallBackProxy; +import com.xuexiang.xhttp2.callback.SimpleCallBack; +import com.xuexiang.xhttp2.exception.ApiException; +import com.xuexiang.xpage.annotation.Page; +import com.xuexiang.xui.widget.actionbar.TitleBar; +import com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText; +import com.xuexiang.xui.widget.textview.supertextview.SuperButton; +import com.xuexiang.xutil.net.JsonUtil; + +import java.util.List; + +import butterknife.BindView; +import butterknife.OnClick; + +import static com.kerwin.wumei.utils.TokenUtils.clearToken; +import static com.kerwin.wumei.utils.TokenUtils.getToken; +import static com.kerwin.wumei.utils.TokenUtils.hasToken; + +@Page(name = "编辑设备") +public class DeviceEditFragment extends BaseFragment { + + @BindView(R.id.et_device_name) + MaterialEditText et_device_name; + @BindView(R.id.et_device_remark) + MaterialEditText et_device_remark; + @BindView(R.id.txt_device_num) + TextView txt_device_num; + @BindView(R.id.txt_device_category) + TextView txt_device_category; + @BindView(R.id.txt_firmware_version) + TextView txt_firmware_version; + @BindView(R.id.txt_create_time) + TextView txt_create_time; + @BindView(R.id.sp_device_temperature) + SuperButton sp_device_temperature; + @BindView(R.id.update_device_temp_icon) + AppCompatImageView update_temp_icon; + + private Long deviceId=0L; + private String deviceNum=""; + + public DeviceEditFragment(Long device_id,String device_num){ + deviceId=device_id; + deviceNum=device_num; + } + + /** + * @return 返回为 null意为不需要导航栏 + */ + @Override + protected TitleBar initTitle() { + return null; + } + + /** + * 布局的资源id + * + * @return + */ + @Override + protected int getLayoutId() { + return R.layout.fragment_device_edit; + } + + /** + * 初始化控件 + */ + @Override + protected void initViews() { + getDevice(deviceId); + } + + @SingleClick + @OnClick({ R.id.btn_save,R.id.btn_cancle_edit,R.id.update_device_temp_icon}) + public void onViewClicked(View view) { + switch (view.getId()) { + case R.id.btn_save: + updateDevice(buildDevice()); + break; + case R.id.btn_cancle_edit: + popToBack(); + break; + case R.id.update_device_temp_icon: + getNewStatusData(); + update_temp_icon.setVisibility(View.GONE); + break; + default: + break; + } + } + + + /** + * 构建设备数据 + */ + private IotDevice buildDevice(){ + IotDevice device=new IotDevice(); + device.setDeviceId(deviceId); + device.setDeviceNum((String) txt_device_num.getText()); + device.setDeviceName(et_device_name.getEditValue()); + device.setRemark(et_device_remark.getEditValue()); + return device; + } + + /** + * HTTP获取最新设备信息 + */ + private void getNewStatusData(){ + XHttp.get("/prod-api/system/status/getStatus/"+deviceNum) + .headers("Authorization","Bearer "+getToken()) + .execute(new CallBackProxy, String>(new TipRequestCallBack() { + @Override + public void onSuccess(String response) { + getDeviceStatus(deviceId); + } + @Override + public void onError(ApiException e) { + if(e.getCode()==401){ + XToastUtils.info("匿名登录状态,功能受限"); + clearToken(); + }else{ + XToastUtils.error(e.getMessage()); + } + } + }){}); + } + + /** + * HTTP获取设备状态 + */ + private void getDeviceStatus(Long device_id){ + XHttp.get("/prod-api/system/status/new/"+device_id) + .headers("Authorization","Bearer "+getToken()) + .execute(new SimpleCallBack() { + @Override + public void onSuccess(IotDeviceStatus status) throws Throwable { + //更新温度 + sp_device_temperature.setText(status.getDeviceTemperature()+"℃"); + update_temp_icon.setVisibility(View.VISIBLE); + } + @Override + public void onError(ApiException e) { + if(e.getCode()==401){ + XToastUtils.info("匿名登录状态,功能受限"); + clearToken(); + }else{ + XToastUtils.error(e.getMessage()); + } + } + }); + } + + /** + * HTTP获取设备信息 + */ + private void getDevice(Long device_id){ + XHttp.get("/prod-api/system/device/"+device_id) + .headers("Authorization","Bearer "+getToken()) + .execute(new SimpleCallBack() { + @Override + public void onSuccess(IotDevice device) throws Throwable { + //绑定数据 + Log.d("deviceName:",device.getDeviceName()); + et_device_name.setText(device.getDeviceName()); + et_device_remark.setText(device.getRemark()); + txt_device_num.setText(device.getDeviceNum()); + txt_device_category.setText(device.getCategoryName()); + txt_firmware_version.setText("v"+device.getFirmwareVersion()); + txt_create_time.setText(device.getCreateTime()); + sp_device_temperature.setText(device.getDeviceTemp()+"℃"); + } + @Override + public void onError(ApiException e) { + if(e.getCode()==401){ + XToastUtils.info("匿名登录状态,功能受限"); + clearToken(); + }else{ + XToastUtils.error(e.getMessage()); + } + } + }); + } + + /** + * HTTP更新设备信息 + */ + private void updateDevice(IotDevice device){ + if(!hasToken()) return; + XHttp.put("/prod-api/system/device") + .upJson(JsonUtil.toJson(device)) + .headers("Authorization","Bearer "+getToken()) + .execute(new CallBackProxy, String>(new TipRequestCallBack() { + @Override + public void onSuccess(String response) throws Throwable { + Log.d("response:",response); + XToastUtils.success("数据保存成功"); + } + @Override + public void onError(ApiException e) { + if(e.getCode()==401){ + XToastUtils.info("匿名登录状态,功能受限"); + clearToken(); + }else{ + XToastUtils.error(e.getMessage()); + } + } + }){}); + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/device/DeviceFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/device/DeviceFragment.java index 84b2a353..0237d400 100644 --- a/android/app/src/main/java/com/kerwin/wumei/fragment/device/DeviceFragment.java +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/device/DeviceFragment.java @@ -1,35 +1,61 @@ +/**************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ****************************************************************************/ package com.kerwin.wumei.fragment.device; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; -import android.view.View; -import android.widget.TextView; +import android.util.Log; -import androidx.appcompat.widget.AppCompatImageView; +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; import androidx.viewpager2.widget.ViewPager2; import com.google.android.material.tabs.TabLayout; import com.google.android.material.tabs.TabLayoutMediator; +import com.kerwin.wumei.activity.LoginActivity; import com.kerwin.wumei.core.BaseFragment; import com.kerwin.wumei.R; +import com.kerwin.wumei.entity.DictData; +import com.kerwin.wumei.entity.IotCategory; +import com.kerwin.wumei.entity.IotDevice; +import com.kerwin.wumei.entity.IotDeviceSet; +import com.kerwin.wumei.entity.IotDeviceStatus; +import com.kerwin.wumei.entity.IotGroup; +import com.kerwin.wumei.fragment.LoginFragment; +import com.kerwin.wumei.http.callback.TipRequestCallBack; +import com.kerwin.wumei.http.request.ListApiResult; +import com.kerwin.wumei.http.request.NoDataApiResult; import com.kerwin.wumei.utils.XToastUtils; -import com.xuexiang.xaop.annotation.SingleClick; +import com.xuexiang.xhttp2.XHttp; +import com.xuexiang.xhttp2.callback.CallBackProxy; +import com.xuexiang.xhttp2.callback.SimpleCallBack; +import com.xuexiang.xhttp2.exception.ApiException; import com.xuexiang.xpage.annotation.Page; -import com.xuexiang.xui.adapter.simple.AdapterItem; import com.xuexiang.xui.utils.WidgetUtils; import com.xuexiang.xui.widget.actionbar.TitleBar; -import com.xuexiang.xui.widget.popupwindow.popup.XUISimplePopup; -import com.xuexiang.xutil.display.ViewUtils; +import com.xuexiang.xui.widget.toast.XToast; +import com.xuexiang.xutil.app.ActivityUtils; +import com.xuexiang.xutil.net.JsonUtil; + +import java.util.ArrayList; +import java.util.List; import butterknife.BindView; -import butterknife.OnClick; import static com.google.android.material.tabs.TabLayout.MODE_SCROLLABLE; +import static com.kerwin.wumei.utils.TokenUtils.clearToken; +import static com.kerwin.wumei.utils.TokenUtils.getToken; +import static com.kerwin.wumei.utils.TokenUtils.hasToken; @Page(name = "设备") public class DeviceFragment extends BaseFragment implements TabLayout.OnTabSelectedListener{ + @BindView(R.id.tab_layout) TabLayout tabLayout; @BindView(R.id.view_pager) @@ -46,7 +72,6 @@ public class DeviceFragment extends BaseFragment implements TabLayout.OnTabSelec // mAdapter.addFragment(2, SimpleTabFragment.newInstance("动态加入"), "动态加入"); // mAdapter.removeFragment(2); // mAdapter.notifyDataSetChanged(); - return null; } @@ -65,27 +90,14 @@ public class DeviceFragment extends BaseFragment implements TabLayout.OnTabSelec */ @Override protected void initViews() { - mAdapter = new FragmentStateViewPager2Adapter(this); - tabLayout.setTabMode(MODE_SCROLLABLE); - tabLayout.addOnTabSelectedListener(this); - viewPager.setAdapter(mAdapter); - // 设置缓存的数量 - viewPager.setOffscreenPageLimit(1); - new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> tab.setText(mAdapter.getPageTitle(position))).attach(); - - // 动态加载选项卡内容 - for (String page : MultiPage.getPageNames()) { - mAdapter.addFragment(SimpleTabFragment.newInstance(page), page); - } - mAdapter.notifyDataSetChanged(); - viewPager.setCurrentItem(0, false); - WidgetUtils.setTabLayoutTextFont(tabLayout); + //获取分组列表 + getGroupList(this); } @Override public void onTabSelected(TabLayout.Tab tab) { - XToastUtils.toast("选中了:" + tab.getText()); + } @Override @@ -97,4 +109,198 @@ public class DeviceFragment extends BaseFragment implements TabLayout.OnTabSelec public void onTabReselected(TabLayout.Tab tab) { } + + /** + * 初始化设备列表 + * @param listener + * @param groupList + */ + private void initDeviceListView(@NonNull TabLayout.OnTabSelectedListener listener,List groupList){ + mAdapter = new FragmentStateViewPager2Adapter((Fragment) listener); + tabLayout.setTabMode(MODE_SCROLLABLE); + tabLayout.addOnTabSelectedListener(listener); + viewPager.setAdapter(mAdapter); + // 设置缓存的数量 + viewPager.setOffscreenPageLimit(10); + new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> tab.setText(mAdapter.getPageTitle(position))).attach(); + + // 动态加载选项卡内容 + for (IotGroup group: groupList) { + mAdapter.addFragment(SimpleTabFragment.newInstance(group.getGroupId()), group.getGroupName()); + } + mAdapter.notifyDataSetChanged(); + viewPager.setCurrentItem(0, false); + WidgetUtils.setTabLayoutTextFont(tabLayout); + } + + /** + * HTTP获取分组列表 + */ + private void getGroupList(@NonNull TabLayout.OnTabSelectedListener listener){ + XHttp.get("/prod-api/system/group/list?pageNum=1&pageSize=100") + .headers("Authorization","Bearer "+getToken()) + .execute(new CallBackProxy>, List>(new TipRequestCallBack>() { + @Override + public void onSuccess(List list) throws Throwable { + List groupList=list; + IotGroup iotGroup=new IotGroup(); + iotGroup.setGroupId(0L); + iotGroup.setGroupName("全部"); + iotGroup.setGroupOrder(0); + groupList.add(0,iotGroup); + + initDeviceListView(listener,groupList); + } + @Override + public void onError(ApiException e) { + if(e.getCode()==401){ + List groupList=new ArrayList(); + IotGroup group=new IotGroup(); + group.setGroupId(0L); + group.setGroupName("全部"); + groupList.add(group); + initDeviceListView(listener,groupList); + XToastUtils.info("匿名登录状态,功能受限"); + clearToken(); + }else{ + XToastUtils.error(e.getMessage()); + } + } + }){}); + } + + + + + + /** + * HTTP获取触发源字典列表 + */ + private void getTriggerSourceDic(){ + XHttp.get("/prod-api/system/dict/data/type/iot_trigger_source") + .headers("Authorization","Bearer "+getToken()) + .execute(new SimpleCallBack>() { + @Override + public void onSuccess(List response) { + Log.d("group name:",response.get(0).getDictLabel()); + } + @Override + public void onError(ApiException e) { + if(e.getCode()==401){ + XToastUtils.info("匿名登录状态,功能受限"); + clearToken(); + }else{ + XToastUtils.error(e.getMessage()); + } + } + + }); + } + + + /** + * HTTP获取分组详情 + */ + private void getGroup(Long groupId){ + if(!hasToken()) return; + XHttp.get("/prod-api/system/group/"+groupId) + .headers("Authorization","Bearer "+getToken()) + .execute(new SimpleCallBack(){ + @Override + public void onSuccess(IotGroup response) throws Throwable { + + Log.d("response:","response"); + XToastUtils.info("response"); + } + @Override + public void onError(ApiException e) { + if(e.getCode()==401){ + XToastUtils.info("匿名登录状态,功能受限"); + clearToken(); + }else{ + XToastUtils.error(e.getMessage()); + } + } + }); + } + + /** + * HTTP新增分组 + */ + private void addGroup(IotGroup group){ + if(!hasToken()) return; + XHttp.post("/prod-api/system/group") + .upJson(JsonUtil.toJson(group)) + .headers("Authorization","Bearer "+getToken()) + .execute(new CallBackProxy, String>(new TipRequestCallBack() { + @Override + public void onSuccess(String response) throws Throwable { + + Log.d("response:","response"); + XToastUtils.info("response"); + } + @Override + public void onError(ApiException e) { + if(e.getCode()==401){ + XToastUtils.info("匿名登录状态,功能受限"); + clearToken(); + }else{ + XToastUtils.error(e.getMessage()); + } + } + }){}); + } + + /** + * HTTP编辑分组 + */ + private void editGroup(IotGroup group){ + if(!hasToken()) return; + XHttp.put("/prod-api/system/group") + .upJson(JsonUtil.toJson(group)) + .headers("Authorization","Bearer "+getToken()) + .execute(new CallBackProxy, String>(new TipRequestCallBack() { + @Override + public void onSuccess(String response) throws Throwable { + Log.d("response:","response"); + XToastUtils.info("response"); + } + @Override + public void onError(ApiException e) { + if(e.getCode()==401){ + XToastUtils.info("匿名登录状态,功能受限"); + clearToken(); + }else{ + XToastUtils.error(e.getMessage()); + } + } + }){}); + } + + /** + * HTTP删除分组 + */ + private void deleteGroup(Long groupId){ + if(!hasToken()) return; + XHttp.delete("/prod-api/system/group/"+groupId) + .headers("Authorization","Bearer "+getToken()) + .execute(new CallBackProxy, String>(new TipRequestCallBack() { + @Override + public void onSuccess(String response) throws Throwable { + Log.d("response:","response"); + XToastUtils.info("response"); + } + @Override + public void onError(ApiException e) { + if(e.getCode()==401){ + XToastUtils.info("匿名登录状态,功能受限"); + clearToken(); + }else{ + XToastUtils.error(e.getMessage()); + } + } + }){}); + } + + } diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/device/DeviceSetFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/device/DeviceSetFragment.java new file mode 100644 index 00000000..a7c2a10e --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/device/DeviceSetFragment.java @@ -0,0 +1,268 @@ +/*************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ***************************************************************************/ +package com.kerwin.wumei.fragment.device; + +import android.util.Log; +import android.view.View; +import android.widget.Spinner; + +import com.kerwin.wumei.R; +import com.kerwin.wumei.core.BaseFragment; +import com.kerwin.wumei.entity.DictData; +import com.kerwin.wumei.entity.IotDevice; +import com.kerwin.wumei.entity.IotDeviceSet; +import com.kerwin.wumei.http.callback.TipRequestCallBack; +import com.kerwin.wumei.http.request.ListApiResult; +import com.kerwin.wumei.http.request.NoDataApiResult; +import com.kerwin.wumei.utils.XToastUtils; +import com.xuexiang.xaop.annotation.SingleClick; +import com.xuexiang.xhttp2.XHttp; +import com.xuexiang.xhttp2.callback.CallBackProxy; +import com.xuexiang.xhttp2.callback.SimpleCallBack; +import com.xuexiang.xhttp2.exception.ApiException; +import com.xuexiang.xpage.annotation.Page; +import com.xuexiang.xui.utils.WidgetUtils; +import com.xuexiang.xui.widget.actionbar.TitleBar; +import com.xuexiang.xui.widget.button.switchbutton.SwitchButton; +import com.xuexiang.xui.widget.picker.XSeekBar; +import com.xuexiang.xutil.net.JsonUtil; +import java.util.List; + +import butterknife.BindView; +import butterknife.OnClick; + +import static com.kerwin.wumei.utils.TokenUtils.clearToken; +import static com.kerwin.wumei.utils.TokenUtils.getToken; +import static com.kerwin.wumei.utils.TokenUtils.hasToken; + +@Page(name = "编辑设备配置") +public class DeviceSetFragment extends BaseFragment { + + @BindView(R.id.sb_radar) + SwitchButton sb_radar; + @BindView(R.id.sb_alarm) + SwitchButton sb_alarm; + @BindView(R.id.sb_rf_control) + SwitchButton sb_rf_control; + @BindView(R.id.sb_rf_learn) + SwitchButton sb_rf_learn; + @BindView(R.id.sb_rf_clear) + SwitchButton sb_rf_clear; + @BindView(R.id.sb_reset) + SwitchButton sb_reset; + @BindView(R.id.sb_open_ap) + SwitchButton sb_open_ap; + + @BindView(R.id.spinner_rf_func_one) + Spinner spinner_rf_func_one; + @BindView(R.id.spinner_rf_func_two) + Spinner spinner_rf_func_two; + @BindView(R.id.spinner_rf_func_three) + Spinner spinner_rf_func_three; + @BindView(R.id.spinner_rf_func_four) + Spinner spinner_rf_func_four; + + @BindView(R.id.xsb_radar_interval) + XSeekBar xsb_radar_interval; + + private Long deviceId=0L; + private String deviceNum=""; + private List rfFunctionList; + private String[] rfFunctionStrings; + + public DeviceSetFragment(Long device_id,String device_num){ + deviceId=device_id; + deviceNum=device_num; + } + + /** + * @return 返回为 null意为不需要导航栏 + */ + @Override + protected TitleBar initTitle() { + return null; + } + + /** + * 布局的资源id + * + * @return + */ + @Override + protected int getLayoutId() { + return R.layout.fragment_device_set; + } + + /** + * 初始化控件 + */ + @Override + protected void initViews() { + getRFFunctionDic(); + + } + + @SingleClick + @OnClick({ R.id.btn_apply_set,R.id.btn_cancle_set}) + public void onViewClicked(View view) { + switch (view.getId()) { + case R.id.btn_apply_set: + updateDeviceSet(buildDeviceSet()); + break; + case R.id.btn_cancle_set: + popToBack(); + default: + break; + } + } + + /** + * 构建设备配置数据 + */ + private IotDeviceSet buildDeviceSet(){ + IotDeviceSet deviceSet=new IotDeviceSet(); + deviceSet.setDeviceId(deviceId); + deviceSet.setDeviceNum(deviceNum); + deviceSet.setIsHost(0); //不托管 + deviceSet.setIsRadar(sb_radar.isChecked()==true?1:0); + deviceSet.setIsAlarm(sb_alarm.isChecked()==true?1:0); + deviceSet.setIsRfLearn(sb_rf_learn.isChecked()==true?1:0); + deviceSet.setIsRfClear(sb_rf_clear.isChecked()==true?1:0); + deviceSet.setIsAp(sb_open_ap.isChecked()==true?1:0); + deviceSet.setIsReset(sb_reset.isChecked()==true?1:0); + deviceSet.setIsRfControl(sb_rf_control.isChecked()==true?1:0); + deviceSet.setRadarInterval(xsb_radar_interval.getSelectedNumber()); + deviceSet.setRfOneFunc(getValueByDicString(spinner_rf_func_one.getSelectedItem().toString())); + deviceSet.setRfTwoFunc(getValueByDicString(spinner_rf_func_two.getSelectedItem().toString())); + deviceSet.setRfThreeFunc(getValueByDicString(spinner_rf_func_three.getSelectedItem().toString())); + deviceSet.setRfFourFunc(getValueByDicString(spinner_rf_func_four.getSelectedItem().toString())); + return deviceSet; + } + + /** + * 根据字典标签获取字典值 + * @param label + * @return + */ + private int getValueByDicString(String label){ + for(DictData dict:rfFunctionList){ + if(dict.getDictLabel().equals(label)){ + return dict.getDictValue(); + } + } + return 0; + } + + /** + * 根据字典值获取索引 + */ + private int getIndexByDicValue(int value){ + for(int i=0;i>() { + @Override + public void onSuccess(List list) { + //绑定数据 + rfFunctionList=list; + rfFunctionStrings=new String[rfFunctionList.size()]; + for(int i=0;i() { + @Override + public void onSuccess(IotDeviceSet set) throws Throwable { + //绑定数据 + Log.d("device num:",set.getDeviceNum()); + sb_radar.setChecked(set.getIsRadar()==1); + sb_alarm.setChecked(set.getIsAlarm()==1); + sb_rf_control.setChecked(set.getIsRfControl()==1); + xsb_radar_interval.setDefaultValue(set.getRadarInterval()); + spinner_rf_func_one.setSelection(getIndexByDicValue(set.getRfOneFunc())); + spinner_rf_func_two.setSelection(getIndexByDicValue(set.getRfTwoFunc())); + spinner_rf_func_three.setSelection(getIndexByDicValue(set.getRfThreeFunc())); + spinner_rf_func_four.setSelection(getIndexByDicValue(set.getRfFourFunc())); + } + @Override + public void onError(ApiException e) { + if(e.getCode()==401){ + XToastUtils.info("匿名登录状态,功能受限"); + clearToken(); + }else{ + XToastUtils.error(e.getMessage()); + } + } + }); + } + + /** + * HTTP更新设备配置 + */ + private void updateDeviceSet(IotDeviceSet deviceSet){ + if(!hasToken()) return; + XHttp.put("/prod-api/system/set") + .upJson(JsonUtil.toJson(deviceSet)) + .headers("Authorization","Bearer "+getToken()) + .execute(new CallBackProxy, String>(new TipRequestCallBack() { + @Override + public void onSuccess(String response) throws Throwable { + Log.d("response:",response); + XToastUtils.success("设备配置更新成功"); + sb_reset.setChecked(false); + sb_open_ap.setChecked(false); + sb_rf_clear.setChecked(false); + sb_rf_learn.setChecked(false); + } + @Override + public void onError(ApiException e) { + if(e.getCode()==401){ + XToastUtils.info("匿名登录状态,功能受限"); + clearToken(); + }else{ + XToastUtils.error(e.getMessage()); + } + } + }){}); + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/device/DeviceStatusFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/device/DeviceStatusFragment.java new file mode 100644 index 00000000..c02598d0 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/device/DeviceStatusFragment.java @@ -0,0 +1,307 @@ +/***************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + *****************************************************************************/ +package com.kerwin.wumei.fragment.device; + +import android.util.Log; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.CompoundButton; +import android.widget.FrameLayout; +import android.widget.Spinner; + +import androidx.appcompat.widget.AppCompatImageView; + +import com.kerwin.wumei.R; +import com.kerwin.wumei.core.BaseFragment; +import com.kerwin.wumei.entity.DictData; +import com.kerwin.wumei.entity.IotDeviceStatus; +import com.kerwin.wumei.http.callback.TipRequestCallBack; +import com.kerwin.wumei.http.request.NoDataApiResult; +import com.kerwin.wumei.utils.XToastUtils; +import com.xuexiang.rxutil2.rxjava.RxJavaUtils; +import com.xuexiang.xaop.annotation.SingleClick; +import com.xuexiang.xhttp2.XHttp; +import com.xuexiang.xhttp2.callback.CallBackProxy; +import com.xuexiang.xhttp2.callback.SimpleCallBack; +import com.xuexiang.xhttp2.exception.ApiException; +import com.xuexiang.xpage.annotation.Page; +import com.xuexiang.xui.utils.WidgetUtils; +import com.xuexiang.xui.widget.actionbar.TitleBar; +import com.xuexiang.xui.widget.button.switchbutton.SwitchButton; +import com.xuexiang.xui.widget.dialog.MiniLoadingDialog; +import com.xuexiang.xui.widget.picker.XSeekBar; +import com.xuexiang.xui.widget.textview.supertextview.SuperButton; +import com.xuexiang.xutil.net.JsonUtil; + +import java.util.ArrayList; +import java.util.List; +import butterknife.BindView; +import butterknife.OnClick; + +import static android.R.layout.simple_spinner_item; +import static com.kerwin.wumei.utils.TokenUtils.clearToken; +import static com.kerwin.wumei.utils.TokenUtils.getToken; +import static com.kerwin.wumei.utils.TokenUtils.hasToken; + +@Page(name = "编辑设备状态") +public class DeviceStatusFragment extends BaseFragment implements CompoundButton.OnCheckedChangeListener { + + @BindView(R.id.sb_relay) + SwitchButton sb_relay; + @BindView(R.id.sb_light) + SwitchButton sb_light; + @BindView(R.id.spinner_light_mode) + Spinner spinner_light_mode; + @BindView(R.id.xsb_fade_interval) + XSeekBar xsb_fade_interval; + @BindView(R.id.xsb_fade_time) + XSeekBar xsb_fade_time; + @BindView(R.id.xsb_brightness) + XSeekBar xsb_brightness; + @BindView(R.id.xsb_red) + XSeekBar xsb_red; + @BindView(R.id.xsb_green) + XSeekBar xsb_green; + @BindView(R.id.xsb_blue) + XSeekBar xsb_blue; + @BindView(R.id.sp_temperature) + SuperButton sp_temperature; + @BindView(R.id.sp_humidity) + SuperButton sp_humidity; + @BindView(R.id.frame_layout_loading_status) + FrameLayout frame_layout_loading_status; + + private Long deviceId=0L; + private String deviceNum=""; + private List lightModeList; + private String[] lightModeStrings; + + public DeviceStatusFragment(Long device_id,String device_num){ + deviceId=device_id; + deviceNum=device_num; + } + + /** + * @return 返回为 null意为不需要导航栏 + */ + @Override + protected TitleBar initTitle() { + return null; + } + + /** + * 布局的资源id + * + * @return + */ + @Override + protected int getLayoutId() { + return R.layout.fragment_device_status; + } + + /** + * 初始化控件 + */ + @Override + protected void initViews() { + getLightModeDic(); + + } + + /** + * 初始化监听 + */ + @Override + protected void initListeners() { + + } + + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + XToastUtils.toast("isChecked:" + isChecked); + } + + @SingleClick + @OnClick({ R.id.btn_apply_status,R.id.btn_cancle_status,R.id.frame_layout_loading_status}) + public void onViewClicked(View view) { + switch (view.getId()) { + case R.id.btn_apply_status: + updateDeviceStatus(buildDeviceStatus()); + break; + case R.id.btn_cancle_status: + popToBack(); + break; + case R.id.frame_layout_loading_status: + getNewStatusData(); + frame_layout_loading_status.setVisibility(View.INVISIBLE); + break; + default: + break; + } + } + + /** + * 构建设备状态数据 + */ + private IotDeviceStatus buildDeviceStatus(){ + IotDeviceStatus deviceStatus=new IotDeviceStatus(); + deviceStatus.setDeviceId(deviceId); + deviceStatus.setDeviceNum(deviceNum); + deviceStatus.setRelayStatus(sb_relay.isChecked()==true?1:0); + deviceStatus.setLightStatus(sb_light.isChecked()==true?1:0); + deviceStatus.setLightMode(getValueByDicString(spinner_light_mode.getSelectedItem().toString())); + deviceStatus.setLightInterval(xsb_fade_interval.getSelectedNumber()); + deviceStatus.setFadeTime(xsb_fade_time.getSelectedNumber()); + deviceStatus.setBrightness(xsb_brightness.getSelectedNumber()); + deviceStatus.setRed(xsb_red.getSelectedNumber()); + deviceStatus.setBlue(xsb_blue.getSelectedNumber()); + deviceStatus.setGreen(xsb_green.getSelectedNumber()); + deviceStatus.setTriggerSource(1); //0-无、1-按键、2.手机、3-浏览器、4-射频遥控、5-雷达、6-报警、7-定时 + return deviceStatus; + } + + /** + * 根据字典标签获取字典值 + */ + private int getValueByDicString(String label){ + for(DictData dict:lightModeList){ + if(dict.getDictLabel().equals(label)){ + return dict.getDictValue(); + } + } + return 0; + } + + /** + * 根据字典值获取索引 + */ + private int getIndexByDicValue(int value){ + for(int i=0;i, String>(new TipRequestCallBack() { + @Override + public void onSuccess(String response) { + getDeviceStatus(deviceId); + } + @Override + public void onError(ApiException e) { + if(e.getCode()==401){ + XToastUtils.info("匿名登录状态,功能受限"); + clearToken(); + }else{ + XToastUtils.error(e.getMessage()); + } + } + }){}); + } + + /** + * HTTP获取灯模式字典列表 + */ + private void getLightModeDic(){ + XHttp.get("/prod-api/system/dict/data/type/light_mode") + .headers("Authorization","Bearer "+getToken()) + .execute(new SimpleCallBack>() { + @Override + public void onSuccess(List list) { + lightModeList=list; + lightModeStrings=new String[lightModeList.size()]; + for (int i=0;i() { + @Override + public void onSuccess(IotDeviceStatus status) throws Throwable { + //绑定数据 + Log.d("device num:",status.getDeviceNum()); + sb_relay.setChecked(status.getRelayStatus()==1); + sb_light.setChecked(status.getLightStatus()==1); + xsb_fade_interval.setDefaultValue(status.getLightInterval()); + xsb_fade_time.setDefaultValue(status.getFadeTime()); + xsb_red.setDefaultValue(status.getRed()); + xsb_green.setDefaultValue(status.getGreen()); + xsb_blue.setDefaultValue(status.getBlue()); + xsb_blue.setDefaultValue(status.getBrightness()); + sp_temperature.setText(status.getAirTemperature()+"℃"); + sp_humidity.setText(status.getAirHumidity()+"RH%"); + spinner_light_mode.setSelection(getIndexByDicValue(status.getLightMode())); + frame_layout_loading_status.setVisibility(View.VISIBLE); + } + @Override + public void onError(ApiException e) { + if(e.getCode()==401){ + XToastUtils.info("匿名登录状态,功能受限"); + clearToken(); + }else{ + XToastUtils.error(e.getMessage()); + } + } + }); + } + + /** + * HTTP更新设备状态 + */ + private void updateDeviceStatus(IotDeviceStatus deviceStatus){ + if(!hasToken()) return; + XHttp.put("/prod-api/system/status") + .upJson(JsonUtil.toJson(deviceStatus)) + .headers("Authorization","Bearer "+getToken()) + .execute(new CallBackProxy, String>(new TipRequestCallBack() { + @Override + public void onSuccess(String response) throws Throwable { + Log.d("response:",response); + XToastUtils.success("设备状态更新成功"); + } + @Override + public void onError(ApiException e) { + if(e.getCode()==401){ + XToastUtils.info("匿名登录状态,功能受限"); + clearToken(); + }else{ + XToastUtils.error(e.getMessage()); + } + + } + }){}); + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/device/FragmentStateViewPager2Adapter.java b/android/app/src/main/java/com/kerwin/wumei/fragment/device/FragmentStateViewPager2Adapter.java index b0a75892..3ad33696 100644 --- a/android/app/src/main/java/com/kerwin/wumei/fragment/device/FragmentStateViewPager2Adapter.java +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/device/FragmentStateViewPager2Adapter.java @@ -1,3 +1,13 @@ +/***************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + *****************************************************************************/ package com.kerwin.wumei.fragment.device; import androidx.annotation.NonNull; diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/device/GroupFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/device/GroupFragment.java index d85115e1..d4e9c9f2 100644 --- a/android/app/src/main/java/com/kerwin/wumei/fragment/device/GroupFragment.java +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/device/GroupFragment.java @@ -1,3 +1,13 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ package com.kerwin.wumei.fragment.device; import com.kerwin.wumei.R; diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/device/SceneFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/device/SceneFragment.java index b07a69b8..9b79316d 100644 --- a/android/app/src/main/java/com/kerwin/wumei/fragment/device/SceneFragment.java +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/device/SceneFragment.java @@ -1,34 +1,67 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ package com.kerwin.wumei.fragment.device; -import android.Manifest; -import android.os.Build; -import android.text.method.HideReturnsTransformationMethod; -import android.text.method.PasswordTransformationMethod; -import android.util.Log; +import android.graphics.Color; import android.view.View; -import android.widget.FrameLayout; -import android.widget.LinearLayout; +import android.widget.TextView; -import androidx.appcompat.widget.AppCompatImageView; - -import com.kerwin.wumei.MyApp; import com.kerwin.wumei.R; -import com.kerwin.wumei.activity.MainActivity; -import com.kerwin.wumei.adapter.entity.EspTouchViewModel; import com.kerwin.wumei.core.BaseFragment; +import com.kerwin.wumei.core.webview.AgentWebActivity; +import com.kerwin.wumei.entity.bo.CaptureImage; +import com.kerwin.wumei.http.callback.TipRequestCallBack; +import com.kerwin.wumei.http.request.CaptchaImageApiResult; +import com.kerwin.wumei.utils.XToastUtils; +import com.xuexiang.xaop.annotation.SingleClick; +import com.xuexiang.xhttp2.XHttp; +import com.xuexiang.xhttp2.callback.CallBackProxy; +import com.xuexiang.xhttp2.exception.ApiException; import com.xuexiang.xpage.annotation.Page; import com.xuexiang.xpage.enums.CoreAnim; import com.xuexiang.xui.widget.actionbar.TitleBar; -import com.xuexiang.xui.widget.spinner.materialspinner.MaterialSpinner; - -import java.util.List; +import com.xuexiang.xui.widget.button.switchbutton.SwitchButton; +import com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText; +import com.xuexiang.xui.widget.textview.supertextview.SuperButton; import butterknife.BindView; +import butterknife.OnClick; + +import static com.kerwin.wumei.utils.SettingUtils.getApIp; +import static com.kerwin.wumei.utils.SettingUtils.getIsHttps; +import static com.kerwin.wumei.utils.SettingUtils.getServerPort; +import static com.kerwin.wumei.utils.SettingUtils.getServerip; +import static com.kerwin.wumei.utils.SettingUtils.setApIp; +import static com.kerwin.wumei.utils.SettingUtils.setServeUrl; +import static com.kerwin.wumei.utils.TokenUtils.clearToken; -@Page(anim = CoreAnim.none) +@Page(name = "用户信息") public class SceneFragment extends BaseFragment { + @BindView(R.id.btn_connect_test) + SuperButton btn_connect_test; + @BindView(R.id.btn_save_serve) + SuperButton btn_save_serve; + @BindView(R.id.txt_message) + TextView txt_message; + @BindView(R.id.et_serve) + MaterialEditText et_serve_ip; + @BindView(R.id.et_port) + MaterialEditText et_port; + @BindView(R.id.sb_https) + SwitchButton sb_https; + @BindView(R.id.et_ap_address) + MaterialEditText et_ap_address; + /** * @return 返回为 null意为不需要导航栏 */ @@ -51,9 +84,89 @@ public class SceneFragment extends BaseFragment { * 初始化控件 */ @Override - protected void initViews() { } + protected void initViews() { + et_serve_ip.setText(getServerip()); + et_port.setText(getServerPort()); + sb_https.setChecked(getIsHttps()); + et_ap_address.setText(getApIp()); + } @Override protected void initListeners() { } + @SingleClick + @OnClick({ R.id.btn_save_serve,R.id.btn_connect_test,R.id.btn_open_ap}) + public void onViewClicked(View view) { + if(!et_port.validate()) return; + if(et_serve_ip.getEditValue().length()==0) + { + showMessage("服务端地址不能为空",false); + return; + } + + switch (view.getId()) { + case R.id.btn_save_serve: + setServeUrl(et_serve_ip.getEditValue(),et_port.getEditValue(),sb_https.isChecked()); + clearToken(); + showMessage("服务端地址信息存储成功,请重新启动APP!",true); + break; + case R.id.btn_connect_test: + getCatpureImage(); + break; + case R.id.btn_open_ap: + if(et_ap_address.getEditValue()==null || et_ap_address.getEditValue().length()==0){ + XToastUtils.error("AP的地址不能为空"); + }else { + AgentWebActivity.goWeb(getContext(), et_ap_address.getEditValue()); + setApIp(et_ap_address.getEditValue()); + } + default: + break; + } + } + + private String buildServeString(){ + String address=""; + if(sb_https.isChecked()){ + address="https://"; + }else{ + address="http://"; + } + return address+et_serve_ip.getEditValue()+":"+et_port.getEditValue(); + } + + + /** + * HTTP获取验证码(用于连接测试) + */ + private void getCatpureImage(){ + XHttp.get(buildServeString() + "/prod-api/captchaImage") + .execute(new CallBackProxy, CaptureImage>(new TipRequestCallBack() { + @Override + public void onSuccess(CaptureImage image) throws Throwable { + String uuid=image.getUuid(); + showMessage("服务端连接成功",true); + } + @Override + public void onError(ApiException e) { + showMessage("服务端连接失败\n"+"连接地址:"+buildServeString()+"\n错误提示:"+e.getMessage(),false); + } + }){}); + } + + /** + * 显示提示 + * @param message + * @param isSuccess + */ + private void showMessage(String message,boolean isSuccess){ + if(isSuccess){ + txt_message.setTextColor(Color.argb(255, 103, 194, 58)); // 绿色 + }else{ + txt_message.setTextColor(Color.argb(255, 245, 108, 108)); //红色 + } + txt_message.setText(message); + txt_message.setVisibility(View.VISIBLE); + } + } diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/device/ShareDeviceFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/device/ShareDeviceFragment.java index 964c66e2..553a25e6 100644 --- a/android/app/src/main/java/com/kerwin/wumei/fragment/device/ShareDeviceFragment.java +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/device/ShareDeviceFragment.java @@ -1,3 +1,13 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ package com.kerwin.wumei.fragment.device; import com.kerwin.wumei.R; diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/device/SimpleTabFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/device/SimpleTabFragment.java index 965e7d08..67779605 100644 --- a/android/app/src/main/java/com/kerwin/wumei/fragment/device/SimpleTabFragment.java +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/device/SimpleTabFragment.java @@ -1,151 +1,141 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ package com.kerwin.wumei.fragment.device; +import android.annotation.SuppressLint; import android.content.Context; -import android.graphics.Point; -import android.graphics.drawable.Drawable; -import android.os.Bundle; +import android.graphics.Color; import android.os.Vibrator; -import android.text.method.HideReturnsTransformationMethod; -import android.text.method.PasswordTransformationMethod; -import android.util.DisplayMetrics; import android.util.Log; -import android.view.Display; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.widget.TextView; +import android.widget.FrameLayout; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatImageView; -import androidx.cardview.widget.CardView; -import androidx.core.content.ContextCompat; -import androidx.core.graphics.drawable.DrawableCompat; -import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.recyclerview.widget.RecyclerView; import com.alibaba.android.vlayout.DelegateAdapter; -import com.alibaba.android.vlayout.LayoutHelper; import com.alibaba.android.vlayout.VirtualLayoutManager; -import com.alibaba.android.vlayout.layout.GridLayoutHelper; -import com.alibaba.android.vlayout.layout.LinearLayoutHelper; import com.alibaba.android.vlayout.layout.StaggeredGridLayoutHelper; -import com.alibaba.android.vlayout.layout.StickyLayoutHelper; import com.kerwin.wumei.R; import com.kerwin.wumei.adapter.base.broccoli.BroccoliSimpleDelegateAdapter; import com.kerwin.wumei.adapter.base.delegate.SimpleDelegateAdapter; -import com.kerwin.wumei.adapter.base.delegate.SingleDelegateAdapter; -import com.kerwin.wumei.adapter.entity.NewInfo; -import com.kerwin.wumei.utils.DemoDataProvider; -import com.kerwin.wumei.utils.RandomUtils; -import com.kerwin.wumei.utils.Utils; +import com.kerwin.wumei.core.BaseFragment; +import com.kerwin.wumei.entity.IotCategory; +import com.kerwin.wumei.entity.IotDeviceStatus; +import com.kerwin.wumei.entity.vo.IotDeviceVo; +import com.kerwin.wumei.http.callback.TipRequestCallBack; +import com.kerwin.wumei.http.request.ListApiResult; +import com.kerwin.wumei.http.request.NoDataApiResult; import com.kerwin.wumei.utils.XToastUtils; import com.scwang.smartrefresh.layout.SmartRefreshLayout; -import com.xuexiang.xrouter.annotation.AutoWired; -import com.xuexiang.xrouter.launcher.XRouter; +import com.xuexiang.xhttp2.XHttp; +import com.xuexiang.xhttp2.callback.CallBackProxy; +import com.xuexiang.xhttp2.exception.ApiException; +import com.xuexiang.xpage.annotation.Page; +import com.xuexiang.xpage.base.XPageFragment; +import com.xuexiang.xpage.core.PageOption; import com.xuexiang.xui.adapter.recyclerview.RecyclerViewHolder; -import com.xuexiang.xui.adapter.simple.AdapterItem; -import com.xuexiang.xui.widget.banner.widget.banner.SimpleImageBanner; +import com.xuexiang.xui.widget.actionbar.TitleBar; import com.xuexiang.xui.widget.button.SwitchIconView; -import com.xuexiang.xui.widget.imageview.ImageLoader; -import com.xuexiang.xui.widget.imageview.RadiusImageView; -import com.xuexiang.xui.widget.textview.supertextview.SuperButton; +import com.xuexiang.xutil.net.JsonUtil; import java.util.ArrayList; -import java.util.Collection; +import java.util.List; import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.Unbinder; import me.samlss.broccoli.Broccoli; -import static com.xuexiang.xui.utils.Utils.getScreenWidth; +import static com.kerwin.wumei.utils.TokenUtils.clearToken; +import static com.kerwin.wumei.utils.TokenUtils.getToken; +import static com.kerwin.wumei.utils.TokenUtils.hasToken; import static com.xuexiang.xutil.display.DensityUtils.dip2px; -/** - * @author xuexiang - * @since 2020/4/21 12:24 AM - */ -public class SimpleTabFragment extends Fragment { +@Page(name = "设备") +public class SimpleTabFragment extends BaseFragment { private static final String TAG = "SimpleTabFragment"; - private static final String KEY_TITLE = "title"; - -// @BindView(R.id.tv_title) -// TextView tvTitle; -// @BindView(R.id.tv_explain) -// TextView tvExplain; @BindView(R.id.recyclerView) RecyclerView recyclerView; @BindView(R.id.refreshLayout) SmartRefreshLayout refreshLayout; -// @BindView(R.id.item_card_view) -// CardView itemCardView; - private Unbinder mUnbinder; - - private SimpleDelegateAdapter mNewsAdapter; - - @AutoWired(name = KEY_TITLE) - String title; + private SimpleDelegateAdapter deviceAdapter; + private List devices=new ArrayList() {}; + private int pageNum=1; + private int pageSize=10; + private Long groupId=0L; - public static SimpleTabFragment newInstance(String title) { - Bundle args = new Bundle(); - args.putString(KEY_TITLE, title); + public static SimpleTabFragment newInstance(Long groupId) { SimpleTabFragment fragment = new SimpleTabFragment(); - fragment.setArguments(args); + fragment.groupId=groupId; return fragment; } + /** + * 布局的资源id + * + * @return + */ + @Override + protected int getLayoutId() { + return R.layout.fragment_simple_tab; + } + + /** + * @return 返回为 null意为不需要导航栏 + */ + @Override + protected TitleBar initTitle() { + return null; + } + + /** + * 初始化控件 + */ + @Override + protected void initViews() { + initView(); + //Http获取设备列表 + getDeviceList(); + } + @Override public void onAttach(@NonNull Context context) { super.onAttach(context); - Log.e(TAG, "onAttach:" + title); + Log.e(TAG, "onAttach:" + groupId); } @Override public void onDetach() { super.onDetach(); - Log.e(TAG, "onDetach:" + title); + Log.e(TAG, "onDetach:" + groupId); } @Override public void onResume() { super.onResume(); - Log.e(TAG, "onResume:" + title); + Log.e(TAG, "onResume:" + groupId); } @Override public void onStop() { super.onStop(); - Log.e(TAG, "onStop:" + title); + Log.e(TAG, "onStop:" + groupId); } - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - XRouter.getInstance().inject(this); - } - - @Nullable - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_simple_tab, container, false); - mUnbinder = ButterKnife.bind(this, view); - initView(); - return view; - } private void initView() { -// int randomNumber = RandomUtils.getRandom(10, 100); -// Log.e(TAG, "initView, random number:" + randomNumber + ", " + title); -// tvTitle.setText(String.format("这个是%s页面的内容", title)); -// tvExplain.setText(String.format("这个是页面随机生成的数字:%d", randomNumber)); - VirtualLayoutManager virtualLayoutManager = new VirtualLayoutManager(getContext()); recyclerView.setLayoutManager(virtualLayoutManager); @@ -153,19 +143,14 @@ public class SimpleTabFragment extends Fragment { recyclerView.setRecycledViewPool(viewPool); viewPool.setMaxRecycledViews(0, 10); - //顶部按钮 -// SingleDelegateAdapter buttonAdapter = new SingleDelegateAdapter(R.layout.adapter_button_top_item) { -// @Override -// public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) { -// SuperButton superButton = holder.findViewById(R.id.device_item_all_open); -// } -// }; - // 设备 FragmentActivity activity=this.getActivity(); - mNewsAdapter = new BroccoliSimpleDelegateAdapter(R.layout.adapter_device_card_view_list_item, new StaggeredGridLayoutHelper(2,0), DemoDataProvider.getEmptyNewInfo()) { + XPageFragment fragment= this; + deviceAdapter = new BroccoliSimpleDelegateAdapter(R.layout.adapter_device_card_view_list_item, new StaggeredGridLayoutHelper(2,0), devices) { + @SuppressLint("ResourceType") @Override - protected void onBindData(RecyclerViewHolder holder, NewInfo model, int position) { + protected void onBindData(RecyclerViewHolder holder, IotDeviceVo device, int position) { + if (device == null) {return;} //设置item宽度,适配屏幕分辨率 // CardView view=holder.findViewById(R.id.device_item_card_view); @@ -174,82 +159,229 @@ public class SimpleTabFragment extends Fragment { // ViewGroup.LayoutParams cardViewParams=view.getLayoutParams(); // cardViewParams.width=(widthPixels-space)/2; - //设置开关按钮 + holder.text(R.id.device_item_title, device.getDeviceName()); + holder.text(R.id.device_item_temp, device.getDeviceTemperature()+"℃"); + holder.text(R.id.device_item_category, device.getCategoryName()); + + //图标设置状态 + SwitchIconView radarView=holder.findViewById(R.id.device_item_radar_icon); + SwitchIconView alarmView=holder.findViewById(R.id.device_item_alarm_icon); SwitchIconView switchIconView=holder.findViewById(R.id.device_item_switch_button); - holder.click(R.id.device_item_switch_button, v -> { + SwitchIconView lightIconView=holder.findViewById(R.id.device_item_light_button); + if(device.getIsRadar()!=1){ radarView.setIconEnabled(false);} + if(device.getIsAlarm()!=1){ alarmView.setIconEnabled(false);} + switchIconView.setIconEnabled(device.getRelayStatus()==1?true:false); + lightIconView.setIconEnabled(device.getLightStatus()==1?true:false); + + //根据分类显示图标 + AppCompatImageView stateView=holder.findViewById(R.id.device_item_category_icon); + stateView.setImageDrawable(getResources().getDrawable((R.drawable.category))); + + //显示网络信号:wifi信号强度(信号极好4格[-55—— 0],信号好3格[-70—— -55),信号一般2格[-85—— -70),信号差1格[-100—— -85)) + AppCompatImageView wifiView=holder.findViewById(R.id.device_item_wifi_icon); + if(device.getRssi()>=-55){ + wifiView.setImageDrawable(getResources().getDrawable((R.drawable.wifi_4))); + }else if(device.getRssi()>=70){ + wifiView.setImageDrawable(getResources().getDrawable((R.drawable.wifi_3))); + }else if(device.getRssi()>=-85){ + wifiView.setImageDrawable(getResources().getDrawable((R.drawable.wifi_2))); + }else if(device.getRssi()>=-100){ + wifiView.setImageDrawable(getResources().getDrawable((R.drawable.wifi_1))); + }else{ + wifiView.setImageDrawable(getResources().getDrawable((R.drawable.wifi_0))); + } + + //设置状态 + FrameLayout flTitle=holder.findViewById(R.id.device_item_fl_title); + if(device.getIsOnline()==1){ + holder.text(R.id.device_item_wifi, "在线"); + flTitle.setBackgroundColor(Color.argb(255, 201, 243, 218)); + }else{ + holder.text(R.id.device_item_wifi, "离线"); + flTitle.setBackgroundColor(Color.argb(255, 230, 230, 230)); + } + + holder.click(R.id.device_item_light_button, v -> { + if(device.getIsOnline()==0) return; + // 更新灯状态 + updateDeviceStatus(buildDeviceLightStatus(device.getDeviceId(), + device.getDeviceNum(), + lightIconView.isIconEnabled()==true?0:1)); + //震动 Vibrator vibrator = (Vibrator) activity.getSystemService(activity.VIBRATOR_SERVICE); vibrator.vibrate(100); - switchIconView.switchState(); + lightIconView.switchState(true); + + }); + holder.click(R.id.device_item_switch_button, v -> { + if(device.getIsOnline()==0) return; + // 更新继电器状态 + updateDeviceStatus(buildDeviceRelayStatus(device.getDeviceId(), + device.getDeviceNum(), + switchIconView.isIconEnabled()==true?0:1)); + //震动 + Vibrator vibrator = (Vibrator) activity.getSystemService(activity.VIBRATOR_SERVICE); + vibrator.vibrate(100); + switchIconView.switchState(true); + + }); + holder.click(R.id.device_item_card_view, v -> { + + PageOption.to(DeviceDetailFragment.class) //跳转的fragment + .setAddToBackStack(true) //是否加入堆栈 + .putLong("device_id", device.getDeviceId()) //传递的参数 + .putString("device_num",device.getDeviceNum()) + .setNewActivity(true) + .open(fragment); //打开页面进行跳转 + }); - AppCompatImageView stateView=holder.findViewById(R.id.device_item_state_icon); - stateView.setImageDrawable(getResources().getDrawable((R.drawable.state_a))); - - - if (model != null) { -// holder.text(R.id.tv_user_name, model.getUserName()); -// holder.text(R.id.tv_tag, model.getTag()); -// holder.text(R.id.tv_title, model.getTitle()); -// holder.text(R.id.tv_summary, model.getSummary()); -// holder.text(R.id.tv_praise, model.getPraise() == 0 ? "点赞" : String.valueOf(model.getPraise())); -// holder.text(R.id.tv_comment, model.getComment() == 0 ? "评论" : String.valueOf(model.getComment())); -// holder.text(R.id.tv_read, "阅读量 " + model.getRead()); -// holder.image(R.id.iv_image, model.getImageUrl()); -// -// holder.click(R.id.card_view, v -> Utils.goWeb(getContext(), model.getDetailUrl())); - } } @Override protected void onBindBroccoli(RecyclerViewHolder holder, Broccoli broccoli) { -// broccoli.addPlaceholders( -// holder.findView(R.id.device_item_title), -// holder.findView(R.id.device_item_title_icon), -// holder.findView(R.id.device_item_time), -// holder.findView(R.id.device_item_time_icon), -// holder.findView(R.id.device_item_temperature), -// holder.findView(R.id.device_item_humidity), -// holder.findView(R.id.device_item_wifi), -// holder.findView(R.id.device_item_wifi_icon), -// holder.findView(R.id.device_item_state), -// holder.findView(R.id.device_item_state_icon), -// holder.findView(R.id.device_item_switch_button) -// ); + broccoli.addPlaceholders( + holder.findView(R.id.device_item_title), + holder.findView(R.id.update_device_temp_icon), + holder.findView(R.id.device_item_category), + holder.findView(R.id.device_item_category_icon), + holder.findView(R.id.device_item_wifi), + holder.findView(R.id.device_item_wifi_icon), + holder.findView(R.id.device_item_temp), + holder.findView(R.id.device_item_temp_icon), + holder.findView(R.id.device_item_alarm_icon), + holder.findView(R.id.device_item_alarm), + holder.findView(R.id.device_item_radar), + holder.findView(R.id.device_item_radar_icon), + holder.findView(R.id.device_item_switch_button), + holder.findView(R.id.device_item_light_button) + ); } }; DelegateAdapter delegateAdapter = new DelegateAdapter(virtualLayoutManager); - delegateAdapter.addAdapter(mNewsAdapter); + delegateAdapter.addAdapter(deviceAdapter); recyclerView.setAdapter(delegateAdapter); - //下拉刷新 refreshLayout.setOnRefreshListener(refreshLayout -> { - // TODO: 2020-02-25 这里只是模拟了网络请求 refreshLayout.getLayout().postDelayed(() -> { - mNewsAdapter.refresh(DemoDataProvider.getDemoNewInfos()); - refreshLayout.finishRefresh(); + pageNum=1; + getDeviceList(); }, 1000); }); //上拉加载 refreshLayout.setOnLoadMoreListener(refreshLayout -> { - // TODO: 2020-02-25 这里只是模拟了网络请求 refreshLayout.getLayout().postDelayed(() -> { - mNewsAdapter.loadMore(DemoDataProvider.getDemoNewInfos()); - refreshLayout.finishLoadMore(); + pageNum=pageNum+1; + getDeviceList(); }, 1000); }); - refreshLayout.autoRefresh();//第一次进入触发自动刷新,演示效果 +// refreshLayout.autoRefresh();//第一次进入触发自动刷新 + } + + /** + * 构建设备状态数据 + */ + private IotDeviceStatus buildDeviceLightStatus(Long deviceId,String deviceNum,int lightStatus){ + IotDeviceStatus deviceStatus=new IotDeviceStatus(); + deviceStatus.setDeviceId(deviceId); + deviceStatus.setDeviceNum(deviceNum); + deviceStatus.setLightStatus(lightStatus); + deviceStatus.setTriggerSource(1); //0-无、1-按键、2.手机、3-浏览器、4-射频遥控、5-雷达、6-报警、7-定时 + return deviceStatus; + } + + /** + * 构建设备状态数据 + */ + private IotDeviceStatus buildDeviceRelayStatus(Long deviceId,String deviceNum,int relayStatus){ + IotDeviceStatus deviceStatus=new IotDeviceStatus(); + deviceStatus.setDeviceId(deviceId); + deviceStatus.setDeviceNum(deviceNum); + deviceStatus.setRelayStatus(relayStatus); + deviceStatus.setTriggerSource(1); //0-无、1-按键、2.手机、3-浏览器、4-射频遥控、5-雷达、6-报警、7-定时 + return deviceStatus; + } + + /** + * HTTP更新设备状态 + */ + private void updateDeviceStatus(IotDeviceStatus deviceStatus){ + if(!hasToken()) return; + XHttp.put("/prod-api/system/status") + .upJson(JsonUtil.toJson(deviceStatus)) + .headers("Authorization","Bearer "+getToken()) + .execute(new CallBackProxy, String>(new TipRequestCallBack() { + @Override + public void onSuccess(String response) throws Throwable { + Log.d("response:",response); + XToastUtils.success("设备状态更新成功"); + } + @Override + public void onError(ApiException e) { + if(e.getCode()==401){ + XToastUtils.info("匿名登录状态,功能受限"); + clearToken(); + }else{ + XToastUtils.error(e.getMessage()); + } + + } + }){}); + } + + /** + * HTTP获取设备列表 + */ + private void getDeviceList(){ + XHttp.get("/prod-api/system/device/list?"+"pageNum="+pageNum+"&pageSize="+pageSize+"&groupId="+groupId) + .headers("Authorization","Bearer "+getToken()) + .execute(new CallBackProxy>, List>(new TipRequestCallBack>() { + @Override + public void onSuccess(List list) throws Throwable { + if(pageNum==1) { + deviceAdapter.refresh(list); + refreshLayout.finishRefresh(); + }else { + deviceAdapter.loadMore(list); + refreshLayout.finishLoadMore(); + } + } + @Override + public void onError(ApiException e) { + if(e.getCode()==401){ + XToastUtils.info("匿名登录状态,功能受限"); + clearToken(); + }else{ + XToastUtils.error(e.getMessage()); + } + } + }){}); + } + + /** + * HTTP获取分类列表 + */ + private void getCategoryList(){ + XHttp.get("/prod-api/system/category/list?pageNum=1&pageSize=100") + .headers("Authorization","Bearer "+getToken()) + .execute(new CallBackProxy>, List>(new TipRequestCallBack>() { + @Override + public void onSuccess(List list) throws Throwable { + + } + @Override + public void onError(ApiException e) { + if(e.getCode()==401){ + XToastUtils.info("匿名登录状态,功能受限"); + clearToken(); + }else{ + XToastUtils.error(e.getMessage()); + } + } + }){}); } - @Override - public void onDestroyView() { - if (mUnbinder != null) { - mUnbinder.unbind(); - } - super.onDestroyView(); - Log.e(TAG, "onDestroyView:" + title); - - } } diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/news/HomePageFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/news/HomePageFragment.java new file mode 100644 index 00000000..f3d625a3 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/news/HomePageFragment.java @@ -0,0 +1,122 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ +package com.kerwin.wumei.fragment.news; + +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.webkit.WebViewClient; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.alibaba.android.vlayout.DelegateAdapter; +import com.alibaba.android.vlayout.VirtualLayoutManager; +import com.alibaba.android.vlayout.layout.GridLayoutHelper; +import com.alibaba.android.vlayout.layout.LinearLayoutHelper; +import com.kerwin.wumei.R; +import com.kerwin.wumei.adapter.base.broccoli.BroccoliSimpleDelegateAdapter; +import com.kerwin.wumei.adapter.base.delegate.SimpleDelegateAdapter; +import com.kerwin.wumei.adapter.base.delegate.SingleDelegateAdapter; +import com.kerwin.wumei.adapter.entity.NewInfo; +import com.kerwin.wumei.core.BaseFragment; +import com.kerwin.wumei.utils.DemoDataProvider; +import com.kerwin.wumei.utils.Utils; +import com.kerwin.wumei.utils.XToastUtils; +import com.scwang.smartrefresh.layout.SmartRefreshLayout; +import com.xuexiang.xpage.annotation.Page; +import com.xuexiang.xpage.enums.CoreAnim; +import com.xuexiang.xui.adapter.recyclerview.RecyclerViewHolder; +import com.xuexiang.xui.adapter.simple.AdapterItem; +import com.xuexiang.xui.widget.actionbar.TitleBar; +import com.xuexiang.xui.widget.banner.widget.banner.SimpleImageBanner; +import com.xuexiang.xui.widget.imageview.ImageLoader; +import com.xuexiang.xui.widget.imageview.RadiusImageView; + +import butterknife.BindView; +import me.samlss.broccoli.Broccoli; + +@Page(anim = CoreAnim.none) +public class HomePageFragment extends BaseFragment { + + @BindView(R.id.webview_home) + WebView webView; + @BindView(R.id.refreshLayout) + SmartRefreshLayout refreshLayout; + + private SimpleDelegateAdapter mNewsAdapter; + + /** + * @return 返回为 null意为不需要导航栏 + */ + @Override + protected TitleBar initTitle() { + return null; + } + + /** + * 布局的资源id + * + * @return + */ + @Override + protected int getLayoutId() { + return R.layout.fragment_home_page; + } + + /** + * 初始化控件 + */ + @Override + protected void initViews() { + webView.loadUrl("http://wumei.live"); + //系统默认会通过手机浏览器打开网页,为了能够直接通过WebView显示网页,则必须设置 + webView.setWebViewClient(new WebViewClient(){ + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + //使用WebView加载显示url + view.loadUrl(url); + //返回true + return true; + } + }); + // 支持js中alert弹窗提示 + webView.setWebChromeClient(new WebChromeClient()); + + //声明WebSettings子类 + WebSettings webSettings = webView.getSettings(); + //如果访问的页面中要与Javascript交互,则webview必须设置支持Javascript + webSettings.setJavaScriptEnabled(true); + webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //关闭webview中缓存 + webSettings.setLoadsImagesAutomatically(true); //支持自动加载图片 + webSettings.setDefaultTextEncodingName("utf-8");//设置编码格式 + } + + @Override + protected void initListeners() { + //下拉刷新 + refreshLayout.setOnRefreshListener(refreshLayout -> { + refreshLayout.getLayout().postDelayed(() -> { + webView.reload(); + refreshLayout.finishRefresh(); + }, 1000); + }); + //上拉加载 + refreshLayout.setOnLoadMoreListener(refreshLayout -> { + // TODO: 2020-02-25 这里只是模拟了网络请求 + refreshLayout.getLayout().postDelayed(() -> { + webView.reload(); + refreshLayout.finishLoadMore(); + }, 1000); + }); + refreshLayout.autoRefresh();//第一次进入触发自动刷新,演示效果 + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/news/NewsFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/news/NewsFragment.java index 21358614..03ef3381 100644 --- a/android/app/src/main/java/com/kerwin/wumei/fragment/news/NewsFragment.java +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/news/NewsFragment.java @@ -1,3 +1,13 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ package com.kerwin.wumei.fragment.news; import androidx.annotation.NonNull; diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/profile/AccountFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/profile/AccountFragment.java new file mode 100644 index 00000000..9d251778 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/profile/AccountFragment.java @@ -0,0 +1,133 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ +package com.kerwin.wumei.fragment.profile; + +import android.graphics.Color; +import android.util.Log; +import android.view.View; +import android.widget.TextView; + +import androidx.appcompat.widget.AppCompatImageView; + +import com.kerwin.wumei.R; +import com.kerwin.wumei.core.BaseFragment; +import com.kerwin.wumei.entity.User; +import com.kerwin.wumei.entity.bo.CaptureImage; +import com.kerwin.wumei.http.callback.TipRequestCallBack; +import com.kerwin.wumei.http.request.CaptchaImageApiResult; +import com.kerwin.wumei.http.request.UserInfoApiResult; +import com.kerwin.wumei.utils.XToastUtils; +import com.xuexiang.xaop.annotation.SingleClick; +import com.xuexiang.xhttp2.XHttp; +import com.xuexiang.xhttp2.callback.CallBackProxy; +import com.xuexiang.xhttp2.exception.ApiException; +import com.xuexiang.xpage.annotation.Page; +import com.xuexiang.xpage.enums.CoreAnim; +import com.xuexiang.xui.utils.ResUtils; +import com.xuexiang.xui.widget.actionbar.TitleBar; +import com.xuexiang.xui.widget.button.switchbutton.SwitchButton; +import com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText; +import com.xuexiang.xui.widget.imageview.RadiusImageView; +import com.xuexiang.xui.widget.textview.supertextview.SuperButton; + +import butterknife.BindView; +import butterknife.OnClick; + +import static com.kerwin.wumei.utils.SettingUtils.getIsHttps; +import static com.kerwin.wumei.utils.SettingUtils.getServerPort; +import static com.kerwin.wumei.utils.SettingUtils.getServerip; +import static com.kerwin.wumei.utils.SettingUtils.setServeUrl; +import static com.kerwin.wumei.utils.TokenUtils.clearToken; +import static com.kerwin.wumei.utils.TokenUtils.getToken; +import static com.kerwin.wumei.utils.TokenUtils.hasToken; + + +@Page(name = "账户信息") +public class AccountFragment extends BaseFragment { + @BindView(R.id.titlebar_min) + TitleBar titleBarMin; + + @BindView(R.id.txt_user_name) + TextView txt_user_name; + @BindView(R.id.txt_nick_name) + TextView txt_nick_name; + @BindView(R.id.txt_email) + TextView txt_email; + @BindView(R.id.txt_phone_num) + TextView txt_phone_num; + @BindView(R.id.txt_create_time) + TextView txt_create_time; + @BindView(R.id.txt_remark) + TextView txt_remark; + + @Override + protected TitleBar initTitle() { + return null; + } + + /** + * 布局的资源id + * + * @return + */ + @Override + protected int getLayoutId() { + return R.layout.fragment_account; + } + + /** + * 初始化控件 + */ + @Override + protected void initViews() { + titleBarMin.setLeftClickListener(v -> popToBack()); + getUserInfo(); + } + + @Override + protected void initListeners() { } + + @SingleClick + @OnClick({ R.id.btn_confirm}) + public void onViewClicked(View view) { + popToBack(); + } + + /** + * HTTP获取用户信息 + */ + private void getUserInfo(){ + if(!hasToken()) return; + XHttp.get("/prod-api/getInfo") + .headers("Authorization","Bearer "+getToken()) + .execute(new CallBackProxy, User>(new TipRequestCallBack() { + @Override + public void onSuccess(User user) throws Throwable { + txt_user_name.setText(user.getUserName()); + txt_nick_name.setText(user.getNickName()); + txt_email.setText(user.getEmail()); + txt_phone_num.setText(user.getPhonenumber()); + txt_remark.setText(user.getRemark()); + txt_create_time.setText(user.getCreateTime()); + } + @Override + public void onError(ApiException e) { + if(e.getCode()==401){ + XToastUtils.info("匿名登录状态,功能受限"); + clearToken(); + }else{ + XToastUtils.error(e.getMessage()); + } + } + }){}); + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/fragment/profile/ProfileFragment.java b/android/app/src/main/java/com/kerwin/wumei/fragment/profile/ProfileFragment.java index 50a7bc22..8bc85429 100644 --- a/android/app/src/main/java/com/kerwin/wumei/fragment/profile/ProfileFragment.java +++ b/android/app/src/main/java/com/kerwin/wumei/fragment/profile/ProfileFragment.java @@ -1,20 +1,47 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ package com.kerwin.wumei.fragment.profile; import android.graphics.drawable.ColorDrawable; +import android.widget.TextView; import com.kerwin.wumei.core.BaseFragment; import com.kerwin.wumei.R; +import com.kerwin.wumei.core.webview.AgentWebActivity; import com.kerwin.wumei.fragment.AboutFragment; import com.kerwin.wumei.fragment.FeedbackFragment; import com.kerwin.wumei.fragment.MessageFragment; import com.kerwin.wumei.fragment.SettingsFragment; +import com.kerwin.wumei.http.callback.TipRequestCallBack; +import com.kerwin.wumei.http.request.NoDataApiResult; +import com.kerwin.wumei.utils.TokenUtils; +import com.kerwin.wumei.utils.XToastUtils; import com.xuexiang.xaop.annotation.SingleClick; +import com.xuexiang.xhttp2.XHttp; +import com.xuexiang.xhttp2.callback.CallBackProxy; +import com.xuexiang.xhttp2.exception.ApiException; import com.xuexiang.xpage.annotation.Page; import com.xuexiang.xpage.enums.CoreAnim; import com.xuexiang.xpage.utils.Utils; import com.xuexiang.xui.widget.actionbar.TitleBar; +import com.xuexiang.xui.widget.dialog.DialogLoader; +import com.xuexiang.xui.widget.grouplist.XUIGroupListView; import com.xuexiang.xui.widget.imageview.RadiusImageView; import com.xuexiang.xui.widget.textview.supertextview.SuperTextView; +import com.xuexiang.xutil.XUtil; +import com.xuexiang.xutil.app.AppUtils; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; import butterknife.BindView; @@ -22,14 +49,16 @@ import butterknife.BindView; public class ProfileFragment extends BaseFragment implements SuperTextView.OnSuperTextViewClickListener { @BindView(R.id.riv_head_pic) RadiusImageView rivHeadPic; - @BindView(R.id.menu_settings) - SuperTextView menuSettings; - @BindView(R.id.menu_about) - SuperTextView menuAbout; - @BindView(R.id.menu_feedback) - SuperTextView menuFeedback; @BindView(R.id.menu_message) SuperTextView menuMessage; + @BindView(R.id.menu_logout) + SuperTextView menuLogout; + @BindView(R.id.about_list) + XUIGroupListView mAboutGroupListView; + @BindView(R.id.tv_copyright) + TextView mCopyrightTextView; + @BindView(R.id.menu_account) + SuperTextView menuAccount; /** * @return 返回为 null意为不需要导航栏 @@ -54,32 +83,65 @@ public class ProfileFragment extends BaseFragment implements SuperTextView.OnSup */ @Override protected void initViews() { + XUIGroupListView.newSection(getContext()) + .addItemView(mAboutGroupListView.createItemView(getResources().getString(R.string.about_item_author_github)), v -> AgentWebActivity.goWeb(getContext(), getString(R.string.url_author_github))) + .addItemView(mAboutGroupListView.createItemView(getResources().getString(R.string.about_item_add_qq_group)), v -> AgentWebActivity.goWeb(getContext(), getString(R.string.url_add_qq_group))) + .addItemView(mAboutGroupListView.createItemView("版本:v"+AppUtils.getAppVersionName()), v -> XToastUtils.toast("官网下载最新版本")) + .addTo(mAboutGroupListView); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy", Locale.CHINA); + String currentYear = dateFormat.format(new Date()); + mCopyrightTextView.setText(String.format(getResources().getString(R.string.about_copyright), currentYear)); } @Override protected void initListeners() { - menuSettings.setOnSuperTextViewClickListener(this); - menuAbout.setOnSuperTextViewClickListener(this); - menuFeedback.setOnSuperTextViewClickListener(this); menuMessage.setOnSuperTextViewClickListener(this); + menuLogout.setOnSuperTextViewClickListener(this); + menuAccount.setOnSuperTextViewClickListener(this); + } + + /** + * HTTP退出登录 + */ + private void logout(){ + XHttp.post("/prod-api/logout") + .execute(new CallBackProxy, String>(new TipRequestCallBack() { + @Override + public void onSuccess(String tokenResult) throws Throwable { + XToastUtils.success("登出成功" ); + } + @Override + public void onError(ApiException e) { + + } + }){}); } @SingleClick @Override public void onClick(SuperTextView view) { switch(view.getId()) { - case R.id.menu_settings: - openNewPage(SettingsFragment.class); - break; - case R.id.menu_about: - openNewPage(AboutFragment.class); - break; case R.id.menu_message: openNewPage(MessageFragment.class); break; - case R.id.menu_feedback: - openNewPage(FeedbackFragment.class); + case R.id.menu_account: + openNewPage(AccountFragment.class); + break; + case R.id.menu_logout: + DialogLoader.getInstance().showConfirmDialog( + getContext(), + getString(R.string.lab_logout_confirm), + getString(R.string.lab_yes), + (dialog, which) -> { + logout(); + dialog.dismiss(); + XUtil.getActivityLifecycleHelper().exit(); + TokenUtils.handleLogoutSuccess(); + }, + getString(R.string.lab_no), + (dialog, which) -> dialog.dismiss() + ); break; default: break; diff --git a/android/app/src/main/java/com/kerwin/wumei/http/callback/NoTipRequestCallBack.java b/android/app/src/main/java/com/kerwin/wumei/http/callback/NoTipRequestCallBack.java new file mode 100644 index 00000000..285b9827 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/http/callback/NoTipRequestCallBack.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2018 xuexiangjys(xuexiangjys@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.kerwin.wumei.http.callback; + +import com.xuexiang.xhttp2.callback.SimpleCallBack; +import com.xuexiang.xhttp2.exception.ApiException; +import com.xuexiang.xhttp2.model.XHttpRequest; +import com.xuexiang.xutil.common.StringUtils; +import com.xuexiang.xutil.common.logger.Logger; + +/** + * @author xuexiang + * @since 2018/8/8 上午10:23 + */ +public abstract class NoTipRequestCallBack extends SimpleCallBack { + /** + * 记录一下请求的url,确定出错的请求是哪个请求 + */ + private String mUrl; + + public NoTipRequestCallBack() { + + } + + public NoTipRequestCallBack(XHttpRequest req) { + this(req.getUrl()); + } + + public NoTipRequestCallBack(String url) { + mUrl = url; + } + + @Override + public void onError(ApiException e) { + if (!StringUtils.isEmpty(mUrl)) { + Logger.e("网络请求的url:" + mUrl, e); + } else { + Logger.e(e); + } + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/http/callback/TipRequestCallBack.java b/android/app/src/main/java/com/kerwin/wumei/http/callback/TipRequestCallBack.java new file mode 100644 index 00000000..5620f1a0 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/http/callback/TipRequestCallBack.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2018 xuexiangjys(xuexiangjys@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.kerwin.wumei.http.callback; + +import androidx.annotation.NonNull; + +import com.xuexiang.xhttp2.callback.SimpleCallBack; +import com.xuexiang.xhttp2.exception.ApiException; +import com.xuexiang.xhttp2.model.XHttpRequest; +import com.xuexiang.xutil.common.StringUtils; +import com.xuexiang.xutil.common.logger.Logger; +import com.xuexiang.xutil.tip.ToastUtils; + +/** + * @author xuexiang + * @since 2018/8/8 上午10:20 + */ +public abstract class TipRequestCallBack extends SimpleCallBack { + + /** + * 记录一下请求的url,确定出错的请求是哪个请求 + */ + private String mUrl; + + public TipRequestCallBack() { + + } + + public TipRequestCallBack(@NonNull XHttpRequest req) { + this(req.getUrl()); + } + + public TipRequestCallBack(String url) { + mUrl = url; + } + + @Override + public void onError(ApiException e) { + ToastUtils.toast(e.getDisplayMessage()); + if (!StringUtils.isEmpty(mUrl)) { + Logger.e("网络请求的url:" + mUrl, e); + } else { + Logger.e(e); + } + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/http/interceptor/CustomLoggingInterceptor.java b/android/app/src/main/java/com/kerwin/wumei/http/interceptor/CustomLoggingInterceptor.java new file mode 100644 index 00000000..178a4035 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/http/interceptor/CustomLoggingInterceptor.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2018 xuexiangjys(xuexiangjys@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.kerwin.wumei.http.interceptor; + +import com.xuexiang.xhttp2.interceptor.HttpLoggingInterceptor; +import com.xuexiang.xhttp2.utils.HttpUtils; + +import java.io.IOException; + +import okhttp3.Connection; +import okhttp3.Protocol; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; +import okhttp3.internal.http.HttpHeaders; + +/** + * 自定义日志拦截器【简单打印入参和出参】 + * + * @author xuexiang + * @since 2018/8/6 上午11:53 + */ +public class CustomLoggingInterceptor extends HttpLoggingInterceptor { + + public CustomLoggingInterceptor() { + super("custom"); + setLevel(Level.PARAM); + } + + @Override + protected void logForRequest(Request request, Connection connection) throws IOException { + RequestBody requestBody = request.body(); + boolean hasRequestBody = requestBody != null; + Protocol protocol = connection != null ? connection.protocol() : Protocol.HTTP_1_1; + + StringBuilder logBuilder = new StringBuilder(); + try { + logBuilder.append("--> ") + .append(request.method()) + .append(' ') + .append(request.url()) + .append(' ') + .append(protocol) + .append("\r\n"); + if (hasRequestBody) { + logBuilder.append("入参:"); + if (HttpUtils.isPlaintext(requestBody.contentType())) { + logBuilder.append(bodyToString(request)); + } else { + logBuilder.append("maybe [file part] , too large too print , ignored!"); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + log(logBuilder.toString()); + } + + @Override + protected Response logForResponse(Response response, long tookMs) { + Response clone = response.newBuilder().build(); + ResponseBody responseBody = clone.body(); + log("<-- " + clone.code() + ' ' + clone.message() + ' ' + clone.request().url() + " (" + tookMs + "ms)"); + try { + if (HttpHeaders.hasBody(clone)) { + if (responseBody == null) { + return response; + } + if (HttpUtils.isPlaintext(responseBody.contentType())) { + String body = responseBody.string(); + log("\t出参:" + body); + responseBody = ResponseBody.create(responseBody.contentType(), body); + return response.newBuilder().body(responseBody).build(); + } else { + log("\t出参: maybe [file part] , too large too print , ignored!"); + } + } + } catch (IOException e) { + e.printStackTrace(); + } + return response; + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/http/request/CaptchaImageApiResult.java b/android/app/src/main/java/com/kerwin/wumei/http/request/CaptchaImageApiResult.java new file mode 100644 index 00000000..5390c95e --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/http/request/CaptchaImageApiResult.java @@ -0,0 +1,61 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ + +package com.kerwin.wumei.http.request; + +import com.kerwin.wumei.entity.bo.CaptureImage; +import com.xuexiang.xhttp2.model.ApiResult; + + +public class CaptchaImageApiResult extends ApiResult { + private String uuid; + private String img; + + public String getUuid() { + return uuid; + } + public CaptchaImageApiResult setUuid(String uuid) { + this.uuid = uuid; + return this; + } + + public String getImg() { + return img; + } + public CaptchaImageApiResult setImg(String img) { + this.img = img; + return this; + } + + + @Override + public boolean isSuccess() { + return getCode()==200; + } + + @Override + public T getData() { + CaptureImage image=new CaptureImage(); + image.setImg(getImg()); + image.setUuid(getUuid()); + return (T) image; + } + + @Override + public String toString() { + return "ApiResult{" + + "code='" + CODE + '\'' + + ", msg='" + MSG + '\'' + + ", uuid='" + uuid + '\'' + + ", img=" + img + + '}'; + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/http/request/CustomApiResult.java b/android/app/src/main/java/com/kerwin/wumei/http/request/CustomApiResult.java new file mode 100644 index 00000000..e05a3f3b --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/http/request/CustomApiResult.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2018 xuexiangjys(xuexiangjys@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.kerwin.wumei.http.request; + +import com.xuexiang.xhttp2.model.ApiResult; + +/** + * @author xuexiang + * @since 2018/8/7 下午5:23 + */ +public class CustomApiResult extends ApiResult { + + private int errorCode; + private String errorInfo; + private T result; + private long timeStamp; + + public int getErrorCode() { + return errorCode; + } + + public CustomApiResult setErrorCode(int errorCode) { + this.errorCode = errorCode; + return this; + } + + public String getErrorInfo() { + return errorInfo; + } + + public CustomApiResult setErrorInfo(String errorInfo) { + this.errorInfo = errorInfo; + return this; + } + + public T getResult() { + return result; + } + + public CustomApiResult setResult(T result) { + this.result = result; + return this; + } + + public long getTimeStamp() { + return timeStamp; + } + + public CustomApiResult setTimeStamp(long timeStamp) { + this.timeStamp = timeStamp; + return this; + } + + @Override + public int getCode() { + return errorCode; + } + + @Override + public String getMsg() { + return errorInfo; + } + + @Override + public boolean isSuccess() { + return errorCode == 0; + } + + @Override + public T getData() { + return result; + } + + @Override + public String toString() { + return "ApiResult{" + + "errorCode='" + errorCode + '\'' + + ", errorInfo='" + errorInfo + '\'' + + ", timeStamp='" + timeStamp + '\'' + + ", result=" + result + + '}'; + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/http/request/CustomGetRequest.java b/android/app/src/main/java/com/kerwin/wumei/http/request/CustomGetRequest.java new file mode 100644 index 00000000..b915a3a7 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/http/request/CustomGetRequest.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2018 xuexiangjys(xuexiangjys@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.kerwin.wumei.http.request; + +import com.xuexiang.xhttp2.callback.CallBack; +import com.xuexiang.xhttp2.callback.CallBackProxy; +import com.xuexiang.xhttp2.callback.CallClazzProxy; +import com.xuexiang.xhttp2.model.ApiResult; +import com.xuexiang.xhttp2.request.GetRequest; + +import java.lang.reflect.Type; + +import io.reactivex.Observable; +import io.reactivex.disposables.Disposable; + +/** + * 自定义请求的形式 + * + * @author xuexiang + * @since 2018/8/7 下午6:09 + */ +public class CustomGetRequest extends GetRequest { + + public CustomGetRequest(String url) { + super(url); + } + + @Override + public Observable execute(Type type) { + return execute(new CallClazzProxy, T>(type) { + }); + } + + @Override + public Disposable execute(CallBack callBack) { + return execute(new CallBackProxy, T>(callBack) { + }); + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/http/request/ListApiResult.java b/android/app/src/main/java/com/kerwin/wumei/http/request/ListApiResult.java new file mode 100644 index 00000000..07f47016 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/http/request/ListApiResult.java @@ -0,0 +1,52 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ + +package com.kerwin.wumei.http.request; + +import com.xuexiang.xhttp2.model.ApiResult; + +public class ListApiResult extends ApiResult { + + private T rows; + private int total; + + public T getRows() { + return rows; + } + public ListApiResult setRows(T rows) { + this.rows = rows; + return this; + } + + public int getTotal(){return total;} + public ListApiResult setTotal(int total){ + this.total=total; + return this; + } + + @Override + public boolean isSuccess() { + return getCode() == 200; + } + + @Override + public T getData() { + return rows; + } + + @Override + public String toString() { + return "ApiResult{" + + "code='" + CODE + '\'' + + ", msg='" + MSG + '\'' + + '}'; + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/http/request/NoDataApiResult.java b/android/app/src/main/java/com/kerwin/wumei/http/request/NoDataApiResult.java new file mode 100644 index 00000000..ebf9cc91 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/http/request/NoDataApiResult.java @@ -0,0 +1,36 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ + +package com.kerwin.wumei.http.request; + +import com.xuexiang.xhttp2.model.ApiResult; + + +public class NoDataApiResult extends ApiResult { + + @Override + public boolean isSuccess() { + return getCode() == 200; + } + + @Override + public T getData() { + return (T) ""; + } + + @Override + public String toString() { + return "ApiResult{" + + "code='" + CODE + '\'' + + ", msg='" + MSG + '\'' + + '}'; + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/http/request/TokenApiResult.java b/android/app/src/main/java/com/kerwin/wumei/http/request/TokenApiResult.java new file mode 100644 index 00000000..102fd3a2 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/http/request/TokenApiResult.java @@ -0,0 +1,48 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ + +package com.kerwin.wumei.http.request; + +import com.xuexiang.xhttp2.model.ApiResult; + + +public class TokenApiResult extends ApiResult { + + private T token= (T) ""; + + public T getToken() { + return token; + } + + public TokenApiResult setToken(T token) { + this.token = token; + return this; + } + + @Override + public boolean isSuccess() { + return getCode() == 200; + } + + @Override + public T getData() { + return token; + } + + @Override + public String toString() { + return "ApiResult{" + + "code='" + CODE + '\'' + + ", msg='" + MSG + '\'' + + ", token=" + token + + '}'; + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/http/request/UserInfoApiResult.java b/android/app/src/main/java/com/kerwin/wumei/http/request/UserInfoApiResult.java new file mode 100644 index 00000000..2e4df350 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/http/request/UserInfoApiResult.java @@ -0,0 +1,48 @@ +/****************************************************************************** + * 作者:kerwincui + * 时间:2021-06-08 + * 邮箱:164770707@qq.com + * 源码地址:https://gitee.com/kerwincui/wumei-smart + * author: kerwincui + * create: 2021-06-08 + * email:164770707@qq.com + * source:https://github.com/kerwincui/wumei-smart + ******************************************************************************/ + +package com.kerwin.wumei.http.request; + +import com.xuexiang.xhttp2.model.ApiResult; + + +public class UserInfoApiResult extends ApiResult { + + private T user; + + public T getUser() { + return user; + } + + public UserInfoApiResult setUser(T user) { + this.user = user; + return this; + } + + @Override + public boolean isSuccess() { + return getCode() == 200; + } + + @Override + public T getData() { + return user; + } + + @Override + public String toString() { + return "ApiResult{" + + "code='" + CODE + '\'' + + ", msg='" + MSG + '\'' + + ", user=" + user + + '}'; + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/http/subscriber/NoTipRequestSubscriber.java b/android/app/src/main/java/com/kerwin/wumei/http/subscriber/NoTipRequestSubscriber.java new file mode 100644 index 00000000..33803826 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/http/subscriber/NoTipRequestSubscriber.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2018 xuexiangjys(xuexiangjys@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.kerwin.wumei.http.subscriber; + +import com.xuexiang.xhttp2.exception.ApiException; +import com.xuexiang.xhttp2.model.XHttpRequest; +import com.xuexiang.xhttp2.subsciber.BaseSubscriber; +import com.xuexiang.xutil.common.StringUtils; +import com.xuexiang.xutil.common.logger.Logger; + +/** + * 网络请求的订阅,只存储错误的日志 + * + * @author xuexiang + * @since 2018/8/2 下午3:37 + */ +public abstract class NoTipRequestSubscriber extends BaseSubscriber { + + /** + * 记录一下请求的url,确定出错的请求是哪个请求 + */ + private String mUrl; + + public NoTipRequestSubscriber() { + + } + + public NoTipRequestSubscriber(XHttpRequest req) { + this(req.getUrl()); + } + + public NoTipRequestSubscriber(String url) { + mUrl = url; + } + + @Override + public void onError(ApiException e) { + if (!StringUtils.isEmpty(mUrl)) { + Logger.e("网络请求的url:" + mUrl, e); + } else { + Logger.e(e); + } + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/http/subscriber/TipRequestSubscriber.java b/android/app/src/main/java/com/kerwin/wumei/http/subscriber/TipRequestSubscriber.java new file mode 100644 index 00000000..40d33abd --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/http/subscriber/TipRequestSubscriber.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2018 xuexiangjys(xuexiangjys@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.kerwin.wumei.http.subscriber; + + +import androidx.annotation.NonNull; + +import com.xuexiang.xhttp2.exception.ApiException; +import com.xuexiang.xhttp2.model.XHttpRequest; +import com.xuexiang.xhttp2.subsciber.BaseSubscriber; +import com.xuexiang.xutil.common.StringUtils; +import com.xuexiang.xutil.common.logger.Logger; +import com.xuexiang.xutil.tip.ToastUtils; + +/** + * 网络请求的订阅,toast提示 + * + * @author xuexiang + * @since 2018/8/2 下午3:42 + */ +public abstract class TipRequestSubscriber extends BaseSubscriber { + /** + * 记录一下请求的url,确定出错的请求是哪个请求 + */ + private String mUrl; + + public TipRequestSubscriber() { + + } + + public TipRequestSubscriber(@NonNull XHttpRequest req) { + this(req.getUrl()); + } + + public TipRequestSubscriber(String url) { + mUrl = url; + } + + + @Override + public void onError(ApiException e) { + ToastUtils.toast(e.getDisplayMessage()); + if (!StringUtils.isEmpty(mUrl)) { + Logger.e("网络请求的url:" + mUrl, e); + } else { + Logger.e(e); + } + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/utils/DemoDataProvider.java b/android/app/src/main/java/com/kerwin/wumei/utils/DemoDataProvider.java index 9597d62f..7428959f 100644 --- a/android/app/src/main/java/com/kerwin/wumei/utils/DemoDataProvider.java +++ b/android/app/src/main/java/com/kerwin/wumei/utils/DemoDataProvider.java @@ -145,7 +145,7 @@ public class DemoDataProvider { @MemoryCache public static List getEmptyNewInfo() { List list = new ArrayList<>(); - for (int i = 0; i < 10; i++) { + for (int i = 0; i < 5; i++) { list.add(new NewInfo()); } return list; diff --git a/android/app/src/main/java/com/kerwin/wumei/utils/DialogUtils.java b/android/app/src/main/java/com/kerwin/wumei/utils/DialogUtils.java new file mode 100644 index 00000000..20f6ac3c --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/utils/DialogUtils.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 xuexiangjys(xuexiangjys@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.kerwin.wumei.utils; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; + +/** + * @author xuexiang + * @since 2018/8/3 下午3:59 + */ +public final class DialogUtils { + + private DialogUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + public static AlertDialog getConfirmDialog(Context context, String title, String message, DialogInterface.OnClickListener yesListener) { + return new AlertDialog.Builder(context) + .setTitle(title) + .setMessage(message) + .setPositiveButton(android.R.string.yes, yesListener) + .setNegativeButton(android.R.string.cancel, null) + .create(); + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/utils/HProgressDialogUtils.java b/android/app/src/main/java/com/kerwin/wumei/utils/HProgressDialogUtils.java new file mode 100644 index 00000000..e7606e27 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/utils/HProgressDialogUtils.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2018 xuexiangjys(xuexiangjys@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.kerwin.wumei.utils; + +import android.annotation.SuppressLint; +import android.app.ProgressDialog; +import android.content.Context; +import android.text.TextUtils; + +/** + * + * + * @author xuexiang + * @since 2018/8/3 下午6:47 + */ +public class HProgressDialogUtils { + private static ProgressDialog sHorizontalProgressDialog; + + private HProgressDialogUtils() { + throw new UnsupportedOperationException("cannot be instantiated"); + } + + @SuppressLint("NewApi") + public static void showHorizontalProgressDialog(Context context, String msg, boolean isShowSize) { + cancel(); + + if (sHorizontalProgressDialog == null) { + sHorizontalProgressDialog = new ProgressDialog(context); + sHorizontalProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); + sHorizontalProgressDialog.setCancelable(false); + if (isShowSize) { + sHorizontalProgressDialog.setProgressNumberFormat("%2dMB/%1dMB"); + } + + } + if (!TextUtils.isEmpty(msg)) { + sHorizontalProgressDialog.setMessage(msg); + } + sHorizontalProgressDialog.show(); + + } + + public static void setMax(long total) { + if (sHorizontalProgressDialog != null) { + sHorizontalProgressDialog.setMax(((int) total) / (1024 * 1024)); + } + } + + public static void cancel() { + if (sHorizontalProgressDialog != null) { + sHorizontalProgressDialog.dismiss(); + sHorizontalProgressDialog = null; + } + } + + public static void setProgress(int current) { + if (sHorizontalProgressDialog == null) { + return; + } + sHorizontalProgressDialog.setProgress(current); + if (sHorizontalProgressDialog.getProgress() >= sHorizontalProgressDialog.getMax()) { + sHorizontalProgressDialog.dismiss(); + sHorizontalProgressDialog = null; + } + } + + public static void setProgress(long current) { + if (sHorizontalProgressDialog == null) { + return; + } + sHorizontalProgressDialog.setProgress(((int) current) / (1024 * 1024)); + if (sHorizontalProgressDialog.getProgress() >= sHorizontalProgressDialog.getMax()) { + sHorizontalProgressDialog.dismiss(); + sHorizontalProgressDialog = null; + } + } + + public static void onLoading(long total, long current) { + if (sHorizontalProgressDialog == null) { + return; + } + if (current == 0) { + sHorizontalProgressDialog.setMax(((int) total) / (1024 * 1024)); + } + sHorizontalProgressDialog.setProgress(((int) current) / (1024 * 1024)); + if (sHorizontalProgressDialog.getProgress() >= sHorizontalProgressDialog.getMax()) { + sHorizontalProgressDialog.dismiss(); + sHorizontalProgressDialog = null; + } + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/utils/RouterUtils.java b/android/app/src/main/java/com/kerwin/wumei/utils/RouterUtils.java new file mode 100644 index 00000000..4e03860c --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/utils/RouterUtils.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2018 xuexiangjys(xuexiangjys@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.kerwin.wumei.utils; + +import android.os.Bundle; +import androidx.annotation.NonNull; + +import com.xuexiang.xrouter.facade.service.SerializationService; +import com.xuexiang.xrouter.launcher.XRouter; + +/** + * @author xuexiang + * @since 2018/8/3 下午2:54 + */ +public final class RouterUtils { + + private RouterUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + public static Bundle getBundle(String key, Object value) { + Bundle bundle = new Bundle(); + bundle.putString(key, XRouter.getInstance().navigation(SerializationService.class).object2Json(value)); + return bundle; + } + + /** + * 注入依赖 + * + * @param target + */ + public static void inject(@NonNull Object target) { + XRouter.getInstance().inject(target); + } + +} diff --git a/android/app/src/main/java/com/kerwin/wumei/utils/SettingSPUtils.java b/android/app/src/main/java/com/kerwin/wumei/utils/SettingSPUtils.java new file mode 100644 index 00000000..a8937da5 --- /dev/null +++ b/android/app/src/main/java/com/kerwin/wumei/utils/SettingSPUtils.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2018 xuexiangjys(xuexiangjys@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.kerwin.wumei.utils; + +import android.content.Context; + +import com.kerwin.wumei.R; +import com.xuexiang.xutil.XUtil; +import com.xuexiang.xutil.data.BaseSPUtil; + +/** + * @author xuexiang + * @since 2018/7/16 下午3:38 + */ +public class SettingSPUtils extends BaseSPUtil { + + private static SettingSPUtils sInstance; + + private SettingSPUtils(Context context) { + super(context); + } + + public static SettingSPUtils getInstance() { + if (sInstance == null) { + synchronized (SettingSPUtils.class) { + if (sInstance == null) { + sInstance = new SettingSPUtils(XUtil.getContext()); + } + } + } + return sInstance; + } + + /** + * 获取服务器地址 + * + * @return + */ + public String getApiURL() { + return getString(getString(R.string.service_api_key), getString(R.string.default_service_api)); + } + + /** + * 获取服务器地址 + * + * @return + */ + public boolean setApiURL(String apiUrl) { + return putString(getString(R.string.service_api_key), apiUrl); + } +} diff --git a/android/app/src/main/java/com/kerwin/wumei/utils/SettingUtils.java b/android/app/src/main/java/com/kerwin/wumei/utils/SettingUtils.java index cab09bb4..adf4d010 100644 --- a/android/app/src/main/java/com/kerwin/wumei/utils/SettingUtils.java +++ b/android/app/src/main/java/com/kerwin/wumei/utils/SettingUtils.java @@ -29,11 +29,14 @@ public final class SettingUtils { private SettingUtils() { throw new UnsupportedOperationException("u can't instantiate me..."); } - private static final String IS_FIRST_OPEN_KEY = "is_first_open_key"; - private static final String IS_AGREE_PRIVACY_KEY = "is_agree_privacy_key"; - + private static final String USER_NAME="user_name"; + private static final String PASSWORD="password"; + private static final String SERVERIP="serve_ip"; + private static final String SERVERPORT="serve_port"; + private static final String ISHTTPS="is_https"; + private static final String APIP="ap_ip"; /** * 是否是第一次启动 */ @@ -48,6 +51,100 @@ public final class SettingUtils { MMKVUtils.put(IS_FIRST_OPEN_KEY, isFirstOpen); } + /** + * 设置用户名和密码 + */ + public static void setAccount(String userName,String password){ + MMKVUtils.put(USER_NAME,userName); + MMKVUtils.put(PASSWORD,password); + } + + /** + * 设置服务端地址 + */ + public static void setServeUrl(String serveIp, String servePort, Boolean isHttps){ + MMKVUtils.put(SERVERIP,serveIp); + MMKVUtils.put(SERVERPORT,servePort); + MMKVUtils.put(ISHTTPS,isHttps); + } + + /** + * 获取服务端地址 + */ + public static String getServeUrl(){ + String address=""; + if(getIsHttps()){ + address="https://"; + }else{ + address="http://"; + } + address=address+getServerip()+":"+getServerPort(); + return address; + } + + /** + * 设置设备AP地址 + * @return + */ + public static void setApIp(String apIp){ + MMKVUtils.put(APIP,apIp); + } + + /** + * 获取设备AP地址 + * @return + */ + public static String getApIp(){ + return MMKVUtils.getString(APIP,"192.168.4.1"); + } + + /** + * 获取服务端ip + * @return + */ + public static String getServerip(){ + return MMKVUtils.getString(SERVERIP,""); + } + + /** + * 获取服务端端口 + * @return + */ + public static String getServerPort(){ + return MMKVUtils.getString(SERVERPORT,""); + } + + /** + * 获取是否使用https + * @return + */ + public static Boolean getIsHttps(){ + return MMKVUtils.getBoolean(ISHTTPS,false); + } + + /** + * 获取登录用户名 + * @return + */ + public static String getUserName(){ + return MMKVUtils.getString(USER_NAME,""); + } + + /** + * 获取登录密码 + * @return + */ + public static String getPassword(){ + return MMKVUtils.getString(PASSWORD,""); + } + + /** + * 清空登录密码 + */ + public static void clearPassword(){ + MMKVUtils.put(PASSWORD,""); + } + /** * @return 是否同意隐私政策 */ diff --git a/android/app/src/main/java/com/kerwin/wumei/utils/TokenUtils.java b/android/app/src/main/java/com/kerwin/wumei/utils/TokenUtils.java index b4897847..ee3e2c5c 100644 --- a/android/app/src/main/java/com/kerwin/wumei/utils/TokenUtils.java +++ b/android/app/src/main/java/com/kerwin/wumei/utils/TokenUtils.java @@ -34,13 +34,13 @@ public final class TokenUtils { private static String sToken; - private static final String KEY_TOKEN = "com.xuexiang.templateproject.utils.KEY_TOKEN"; + private static final String KEY_TOKEN = "com.kerwin.wumei.utils.KEY_TOKEN"; private TokenUtils() { throw new UnsupportedOperationException("u can't instantiate me..."); } - private static final String KEY_PROFILE_CHANNEL = "github"; + private static final String KEY_PROFILE_CHANNEL = "gitee"; /** * 初始化Token信息 @@ -80,7 +80,7 @@ public final class TokenUtils { setToken(token); return true; } else { - XToastUtils.error("登录失败!"); +// XToastUtils.error("匿名用户"); return false; } } @@ -92,7 +92,7 @@ public final class TokenUtils { MobclickAgent.onProfileSignOff(); //登出时,清除账号信息 clearToken(); - XToastUtils.success("登出成功!"); +// XToastUtils.success("登出成功!"); //跳转到登录页 ActivityUtils.startActivity(LoginActivity.class); } diff --git a/android/app/src/main/java/com/kerwin/wumei/utils/sdkinit/XUpdateInit.java b/android/app/src/main/java/com/kerwin/wumei/utils/sdkinit/XUpdateInit.java index a092c277..41f6d340 100644 --- a/android/app/src/main/java/com/kerwin/wumei/utils/sdkinit/XUpdateInit.java +++ b/android/app/src/main/java/com/kerwin/wumei/utils/sdkinit/XUpdateInit.java @@ -26,6 +26,7 @@ import com.kerwin.wumei.utils.update.CustomUpdateFailureListener; import com.kerwin.wumei.utils.update.XHttpUpdateHttpServiceImpl; import com.xuexiang.xupdate.XUpdate; import com.xuexiang.xupdate.utils.UpdateUtils; +import com.xuexiang.xutil.common.StringUtils; /** * XUpdate 版本更新 SDK 初始化 @@ -42,6 +43,7 @@ public final class XUpdateInit { /** * 应用版本更新的检查地址 */ + // TODO: 2021/5/26 需要开启版本更新功能的话,就需要配置一下版本更新的地址 private static final String KEY_UPDATE_URL = ""; public static void init(Application application) { @@ -67,7 +69,21 @@ public final class XUpdateInit { * 进行版本更新检查 */ public static void checkUpdate(Context context, boolean needErrorTip) { - XUpdate.newBuild(context).updateUrl(KEY_UPDATE_URL).update(); + checkUpdate(context, KEY_UPDATE_URL, needErrorTip); + } + + /** + * 进行版本更新检查 + * + * @param context 上下文 + * @param url 版本更新检查的地址 + * @param needErrorTip 是否需要错误的提示 + */ + private static void checkUpdate(Context context, String url, boolean needErrorTip) { + if (StringUtils.isEmpty(url)) { + return; + } + XUpdate.newBuild(context).updateUrl(url).update(); XUpdate.get().setOnUpdateFailureListener(new CustomUpdateFailureListener(needErrorTip)); } } diff --git a/android/app/src/main/java/com/kerwin/wumei/widget/GuideTipsDialog.java b/android/app/src/main/java/com/kerwin/wumei/widget/GuideTipsDialog.java index 4e44f4cb..9e3ef0a0 100644 --- a/android/app/src/main/java/com/kerwin/wumei/widget/GuideTipsDialog.java +++ b/android/app/src/main/java/com/kerwin/wumei/widget/GuideTipsDialog.java @@ -99,6 +99,7 @@ public class GuideTipsDialog extends BaseDialog implements View.OnClickListener, mTvNext = findViewById(R.id.tv_next); if (cbIgnore != null) { + cbIgnore.setChecked(isIgnoreTips()); cbIgnore.setOnCheckedChangeListener(this); } if (ivClose != null) { diff --git a/android/app/src/main/res/drawable-hdpi/alarm.png b/android/app/src/main/res/drawable-hdpi/alarm.png new file mode 100644 index 0000000000000000000000000000000000000000..5d620df805b1ec25c3e1e1a37b78934196da2082 GIT binary patch literal 5665 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 N4MrEMQ=?^%`#;mFS&;w$ literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/category.png b/android/app/src/main/res/drawable-hdpi/category.png index 496f8c045190680db0d39aa67ab865cb50cc3ecc..ff5dcb042b8537017793b4af3b1975afcfaf047b 100644 GIT binary patch literal 5129 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 CQaOwO literal 6520 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 diff --git a/android/app/src/main/res/drawable-hdpi/image.png b/android/app/src/main/res/drawable-hdpi/image.png new file mode 100644 index 0000000000000000000000000000000000000000..284681f810f9af4010e576563da801b441d6da4d GIT binary patch literal 4571 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/logo.png b/android/app/src/main/res/drawable-hdpi/logo.png index ab5daf5e036f3b4f2b0809428f7a802498bfabeb..d9d32c86a5cb2cda415414ed02825b7e4a945e8c 100644 GIT binary patch delta 2106 zcmZ{ldpOhk1IIt#&CK1BYfLkjBDC3N=GK@yxfJn3wTXq~dT<M2^c8zjTn4 zOPb1UlYb~vQOX1Z4#}nZRh6Z?vLJ?nVI=8C*r>sCEnTz zD%uf=MD(?X%z`zzCJRY)wzKj6^{ucpXQa|VhOHl~)U(EVR~hSSTk~MyZ(*Ol#r;l| z<{51=ENHWw{1v|RzmX>=aa#ukD@o>W%i#?*m7fYwmz(M>|8OHNr5x`cSu53aY(-Kv zJ*Y_&Kk^SDsX3LOcE@RKu714wx_poYj?A@H$bKpAn3(*bk!-yjO#{kc$a?$eL```4 zTVofAgn+G@eNdhbL1k}JkOG!_#YH7!4jETupT-@}=9VzN7bC%~I4<E9xw=Aba^F-|Ei(4auuhM`FhY=! z^cIox?WyVoP!}A0(3?7S6x$iU2Dz=~7k+X_V9+M=UMxQe7{=SARk%^%nY;&k(E<3` zi}xP!KgTjRnmfjUdQ*_>yS`Pm5(xG$)7je`nv(Q^1(+dy>^vd@s{nSvaN2}%Ou0&F zSb7qYI;utYL`Y=t-j05_d@gQvR$JFqJ0bL2Q|0qM;mUdT$4)7cqi;2enmD zzdYtspmT4N;T4_I^dg_gdU!*87Fsb$9K6?5(dlEsOB*Yxe)acE(VV-8ZYMZ>Gdu=C zN68YCudJkIKBUPCHd{At#w}G>iKXSn-v_E1zZ*6iS;aqGe7PgX?t&Mjw+G)>uz{aP zRH(CGLFN!@dJ>>y!oL(*c7#rfVfMn&)Dnz1d&{cd^-9+OTps?PxgZ4hM4{d2Y_?Vm z%d350-V|(t69Okrb!9zgC<8WxBF-)ZvTv89K@?iNN?HHrHQ5bC1p?SsX6J8{<;4ev zV>rlyl2ogx?i0J65Qrm*0Y0U|1z zWa)%MpV*}O>H3hgm!MV$6yl63EBDU;1G>aq9LT@4Ap=g~g=M`k;8XX25BoO*+3RUk z>1~;k=CuOOxfccn1&Ce?|pW(Mw3P7kC!flZi?{? zZA^W0v^`Fb!+|53=i`XGn(wERirNLKLD4X^!jV}*4fa;-VxAHNq3X#9MKY!H<+bbW z;sO`-Yp}4xc}$qp8#`B#P#pG`zctNBjJjVtd|BNZcq%}?E+?09?CMpV-a!|ihW191 z&D=_julEaDQxc0H?&+FlE!q}iqi@+xslI?yYjGsSG`FzWluTp5L6+$zg73}8W_LQw z1{JU$lR?5CiBaIQ8vqTr^s)$0kN1&QGkZ~)Js^1u z=+-*P&~2W`oH^Mwm9}eulRg{)VU&GQ`hb}#xR$_b%UwDQjB0MW<&E~xm8k_fLNN#D zygLY)=sWV_cp*cE;g0sXI7 zioF~wg}@8C{BY{yZ%UxQvGTh(*!QT%YkGYw(m*Cc(c{L^+(GH^_doZG*JmXw&(=9HX!6@v|K`Q7SbRp4AXz|6j{HiL#eM&30n5;|&CF^g(S z&$~3NZ4sUlAOO`jG2SE~Lw(U*K5{G|6r>xU2}#v2dD->|iP}Y64Ze%}cKgGA85iz^ zdq&oL1b`729=u9dGGbSR4|l_}{AeHj%>2Cq7gTxe``ODGku2(++fwJXc#5Dj!1UCm zDHQeT>%tJT$F(8juSeY0<$$%+o5;azy2Gh{U94;^!@7ZA#YGMk+XqiyXVH0EKAgC{ z(qjBsJd zfTVecL2gkxUmHD$7afv!N6KTu7~iBwy~9Y4 zr-@ZKGqN&|dMD4(4{Ecn)EpXNUlt;+PW%>z1m>yHJ053vfs?tU3KUM~=@-qo&Ueh= z2+u85Udq3em>*jmU*npRs}f-qhLaub`lL50O*|5Dc~V&gbDvzv%i!N`Fxa9WVfd>A zc#+(!#;FdK?D`*F{s|WP%*3*#`R=on<5t`K955h=j;M7;`mJ1U?`|-z@+3v5oz?O_ zr%Crseq`ZZ@75Njh21#aTDS9_8P<$#iwyN|`)ct5+v2+(q(1LDVY|MdEP~e67Y;$< Z;CZuTl6>xs+Mj0(obBE1?%C4Q{sHwElOg~B delta 2527 zcmV<52_W|07J(WeiBL{Q4GJ0x0000DNk~Le0004A0000w2m=5B0MF;a(6J#o0w6;+ zK`=o=F*7zqL`5+%MM615K{GfoF)&3qH$*lyL^6|l0vsSiHbF2!LNPKnL_|d~F-1Z- zL_sq+FflMiI5$K#HAFI#wgO)xHZ?FcGBY`5Ei^VcIW1#1G-NGeIX7c1W@R)oFkxgd zI5uRHI0Jt`zy)sL0000mP)t-sXlQ8h^!T^8x7gU&s?7h5jg0_p{zjGl)#m?esQxsG z{)@c-5_SH(*#9Gb{{R2~A$m4*llKE2e+bq|L_t(|+U%U!qQWW+MGZ)S(&7LA_S!Nf z5L!_0Y@SYMU8I`~cpm%D{zQBH5d84|@c!(F_lNg~_h&!6KfFJ@Kl>lx6{n3}L$~E= zLk|@H9K2>dEN)o0LeEvJvkq@t>r8!?d>l6RWyNs?rm4=G^inxZHIKtzjaN^He}xTq z{Jq(mOYD4{wxEytJa3|1aiS*!BOeDUKm}f?9acgwUQmkvG;q8jFSl1p`Kw*6sht3B@SfZzcY`3@E{_6)=dHCPzP_tK=D!CqU`FI28+b*{N1e|Ix4FTq z;;rTRY1C*qkZ7XPo=Q&Oqh$&{Ls7K^P00K(9Qq@`m zh{+vZksio=wroK0PS4_rTRh+n6o7VM|1#RSC&6nAue@fp|8jCbK)apdUH;)7?ue;Mzc%%RtO z1TUmLGD}3jD-`eVR821N<^h-c6<*=-CX6$1&UNB-CsK>lf}CbCUKjPcVNbs_iDZDP-Gdz!8F7d`>H*W8U&o+br`RgkWH8N7GD2V zWOPYEV>LgkQM}Q)AfKn|f44vhZYmU=fmxCg5m>%xDlU9H@GhLBqTObP*(2Q;9kB)8 zwMFYayaz2&1;4U-l|?~U7Sj;HD0`?_@l|8XX@m5 zYSZ7v`ywg!e!PItkXc+I$Aw)0|F++0DZWDOU3jzjZooRbfh7LB$?*4cJm{)`A{R^)o6Uvs?E>}1e^!)S(3zE zGO2R1@GQ2fAyZV{i+5dW@kKHaW%z{@stnrs7}uX360y~Df7M<&KEhkQ@(TDu#6`XG z1S3$e_26O+)mM-NlJj=q<>FcNq9+-C(mDi+%Ti!wJ;)VF#Pf5!q6B$`m;IiMzyiIu z?8Gb36Fc$hD&R^47UZ&)YDO9vgDPhFtl(-t6*}+Bw!jN3F)#fy-MQ9Dz7olS$MIHk zUJ=QO?s7Wfe~XKxim96hytVk^1OnH24N5lR47lKeBy4LqD=6^mMBNU&?gBIHE;4)C z8+eP-TMApnqpsHX6eJ6WZwF>H3ag|ym(+BfL9YQ!&e|Yu*&sUmCwMd5^UH{vV!#F7 zBNNCeoh-yuj5LD;C-)b4v-s*d>dmNKk!_rO_4ya+e^xw$dz;|?1n<;uEAo`!Z4x`) z1zsACUY@UNl6NH?$&kFlTNV?rTF{DGok2fM*{xUt&N!ugfHwxEDM%8BG+cIqm@LEh zf6hR^?zIW8JJ=qzj*616*!%I8@$8InTQcvl88pS4T5a=$DnW1J1vOd@;PDbSmWqa9 z_d!7Ef65^C0la%r1>BJIQsKaL$_no*!PQ|nw&?ceGrUMKNAOnSfbc@mYZGc8#@kV? zkO=QaiV4_7%V|&7Wry9YdHS;nO)LcYOI+Ctx;N8oX5QkhrnZC^s)@<>6^8JtP|@tg zOPlPt>+?hraCz*g&cuw3T8iOpiI-XMaI&=5e-p`<@S;dW+{GJhyx_a`{djQ&hgNRN zl!Jx!X}qruJLX+%OWIK0mw7m2wu@lqlfT{c-vmQL;?)nm7zq|2jv{=W{7JM<4(IBqb#?g692;Q}O ze`eDk;B7<>d?RysjaiBk1p8vC3NMLg9eT&>e3^>xOt7xz7!H@k+gZYl0Hi_7tw-M@$T8&g~C0SWmD-dv{W z#!EUvHvI`qt&((voGY`oL)2hK&TB}cf9dbV8@Mv!JAhZE!`*mEN602eeol23F*n-r zs77n?Y`7A3+|d$MU_!6mqFKfExG1-vF6O+pm|xZ z0yDwda9Z&>UU^r+LV zt{uQD${KwSUcf6Q=MeSs3#6EKe7yiQX{VW5cvqcjaq-~`v-DB&dn?if^ckzzJ`V?~Po$b0u<9lB`MXa?~De&h(=e;JAIiVEWO z#8fY6kKP;kI$VV#jY`Y8Zv2@B=e+OY6?8>It5ZCRS76^4Y`)Ip#cLb(+=FC(7qCuz zohQEIA%M-|o993ReRI%=CGd#6897Lt1s9!Sviwx`TDZ*-8K|Okb{m-Ov?aXNeIV{f zLu(y5%+qFYom^{2d_TS!D~=y*Zu`H$;O3{w5B9e}FI{+UbbFOhO poo3AbAF$s)9Qfh=_u3x<3;>~F50*VhsTBYK002ovPDHLkV1f$S+kF54 diff --git a/android/app/src/main/res/drawable-hdpi/radar.png b/android/app/src/main/res/drawable-hdpi/radar.png new file mode 100644 index 0000000000000000000000000000000000000000..6717179e48935d7959868c663c1f6fd58744756c GIT binary patch literal 7200 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 IsWB@MF-yI5vYhL&L# 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/set.png b/android/app/src/main/res/drawable-hdpi/set.png new file mode 100644 index 0000000000000000000000000000000000000000..a5d477c7dd305701abd08dbaefb82398f1cdc670 GIT binary patch literal 17516 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 D>^U?l literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/switch_c.png b/android/app/src/main/res/drawable-hdpi/switch_c.png new file mode 100644 index 0000000000000000000000000000000000000000..43ca7ab3abcd2c81fb7c3d6fb60e3b0b02ec7fa4 GIT binary patch literal 7244 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 EKai<9v;Y7A literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/user.png b/android/app/src/main/res/drawable-hdpi/user.png new file mode 100644 index 0000000000000000000000000000000000000000..dae14050a7567562def0043eb6a8fadc51a383d9 GIT binary patch literal 21499 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 Rd+XnGYQyw2bJgvM{{`Faw$=au literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/wifi_0.png b/android/app/src/main/res/drawable-hdpi/wifi_0.png new file mode 100644 index 0000000000000000000000000000000000000000..1ea15d39934e2fdbc812402092e272cf5aa3eac7 GIT binary patch literal 6302 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 KFlE|ziT?*C&ds6# literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/wifi_2.png b/android/app/src/main/res/drawable-hdpi/wifi_2.png new file mode 100644 index 0000000000000000000000000000000000000000..b9510594077fb71acdf71628444b5d1113aea01c GIT binary patch literal 6438 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°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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable/ic_default_head.xml b/android/app/src/main/res/drawable/ic_default_head.xml index f68423ec..767ace29 100644 --- a/android/app/src/main/res/drawable/ic_default_head.xml +++ b/android/app/src/main/res/drawable/ic_default_head.xml @@ -23,4 +23,4 @@ - + \ No newline at end of file diff --git a/android/app/src/main/res/layout/adapter_device_card_view_list_item.xml b/android/app/src/main/res/layout/adapter_device_card_view_list_item.xml index 2d97ef8a..dd0b8e82 100644 --- a/android/app/src/main/res/layout/adapter_device_card_view_list_item.xml +++ b/android/app/src/main/res/layout/adapter_device_card_view_list_item.xml @@ -1,4 +1,14 @@ + + android:layout_marginRight="5dp" + android:background="#C9F3DA"> + android:layout_marginTop="2dp" + android:tint="@color/white" + app:srcCompat="@drawable/title" /> @@ -56,41 +70,43 @@ + + android:orientation="vertical"> + android:layout_marginTop="15dp" + android:layout_marginBottom="12dp"> + android:tint="@color/primary" + app:srcCompat="@drawable/category" /> + android:textSize="12sp" /> + + android:layout_marginBottom="12dp"> - - - - - - - - - - - + app:srcCompat="@drawable/wifi_2" /> + android:textSize="12sp" /> + android:layout_marginStart="48dp" + android:tint="@color/success" + app:srcCompat="@drawable/temperature" /> + android:textSize="12sp" /> + + + + + + + + + + + + + - + + + + + + + + diff --git a/android/app/src/main/res/layout/dialog_guide_tips.xml b/android/app/src/main/res/layout/dialog_guide_tips.xml index 59d2a3d3..693eff65 100644 --- a/android/app/src/main/res/layout/dialog_guide_tips.xml +++ b/android/app/src/main/res/layout/dialog_guide_tips.xml @@ -81,11 +81,13 @@ android:id="@+id/cb_ignore" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:button="@drawable/icon_checkbox" /> + android:button="@drawable/icon_checkbox" + android:scaleX="0.8" + android:scaleY="0.8" /> diff --git a/android/app/src/main/res/layout/fragment_about.xml b/android/app/src/main/res/layout/fragment_about.xml index a70c8934..29951ae0 100644 --- a/android/app/src/main/res/layout/fragment_about.xml +++ b/android/app/src/main/res/layout/fragment_about.xml @@ -1,26 +1,32 @@ - + + - + + @@ -33,9 +39,9 @@ android:paddingBottom="25dp"> @@ -47,6 +53,15 @@ android:textColor="@color/xui_config_color_gray_3" android:textSize="16sp" /> + + - \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_account.xml b/android/app/src/main/res/layout/fragment_account.xml new file mode 100644 index 00000000..b3bac343 --- /dev/null +++ b/android/app/src/main/res/layout/fragment_account.xml @@ -0,0 +1,194 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_add_device.xml b/android/app/src/main/res/layout/fragment_add_device.xml index 1bc283d9..29a0c3d0 100644 --- a/android/app/src/main/res/layout/fragment_add_device.xml +++ b/android/app/src/main/res/layout/fragment_add_device.xml @@ -1,29 +1,98 @@ + + + + + android:layout_height="wrap_content" + android:layout_margin="10dp" + android:background="@color/cardview_light_background" + android:orientation="vertical" + android:padding="10dp"> + + + + + + + + + + + + + + + android:id="@+id/txt_config_message" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="0dp" + android:layout_marginBottom="10dp" + android:gravity="center_horizontal|top" + android:text="消息提示" + android:textColor="@color/danger" /> @@ -85,7 +155,8 @@ android:layout_height="42dp" android:gravity="center_vertical" android:inputType="textMultiLine" - android:text="目前仅支持2.4GHz的WIFI网络" + android:text="提示:目前仅支持2.4GHz的WIFI网络" + android:textColor="@color/colorAccent" android:textSize="12sp" /> - + android:visibility="gone"> + + + + + + + + + - + android:layout_height="wrap_content"> - + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_add_device_two.xml b/android/app/src/main/res/layout/fragment_add_device_two.xml index 30f3d5ab..7b63d3f4 100644 --- a/android/app/src/main/res/layout/fragment_add_device_two.xml +++ b/android/app/src/main/res/layout/fragment_add_device_two.xml @@ -1,4 +1,14 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_device_edit.xml b/android/app/src/main/res/layout/fragment_device_edit.xml new file mode 100644 index 00000000..f07af32e --- /dev/null +++ b/android/app/src/main/res/layout/fragment_device_edit.xml @@ -0,0 +1,224 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_device_set.xml b/android/app/src/main/res/layout/fragment_device_set.xml new file mode 100644 index 00000000..6e44365d --- /dev/null +++ b/android/app/src/main/res/layout/fragment_device_set.xml @@ -0,0 +1,337 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/layout/fragment_device_status.xml b/android/app/src/main/res/layout/fragment_device_status.xml new file mode 100644 index 00000000..54fa76ac --- /dev/null +++ b/android/app/src/main/res/layout/fragment_device_status.xml @@ -0,0 +1,389 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_group.xml b/android/app/src/main/res/layout/fragment_group.xml index ebfaaf34..5134a593 100644 --- a/android/app/src/main/res/layout/fragment_group.xml +++ b/android/app/src/main/res/layout/fragment_group.xml @@ -1,5 +1,14 @@ - + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_login.xml b/android/app/src/main/res/layout/fragment_login.xml index 36e05ea0..5ad85490 100644 --- a/android/app/src/main/res/layout/fragment_login.xml +++ b/android/app/src/main/res/layout/fragment_login.xml @@ -1,19 +1,5 @@ - + + @@ -61,22 +47,17 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="36dp" - android:hint="@string/tip_please_input_phone_number" - android:inputType="number" + android:hint="请输入账号" + android:inputType="text" app:met_clearButton="true" - app:met_errorMessage="@string/tip_phone_number_error" + app:met_errorMessage="账号有误" app:met_floatingLabel="normal" - app:met_floatingLabelText="@string/title_phone_number" - app:met_regexp="@string/regex_phone_number" /> - + app:met_floatingLabelText="登录账号" /> - + android:layout_height="wrap_content"> + app:met_floatingLabelText="密码" /> - + android:layout_height="wrap_content" + android:layout_marginTop="12dp"> - + - + + + android:text="登录" /> - - - - - - diff --git a/android/app/src/main/res/layout/fragment_message.xml b/android/app/src/main/res/layout/fragment_message.xml index a80e943e..40c306aa 100644 --- a/android/app/src/main/res/layout/fragment_message.xml +++ b/android/app/src/main/res/layout/fragment_message.xml @@ -1,14 +1,26 @@ - + + + + android:layout_marginTop="10dp" + android:text="暂无消息" /> \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_profile.xml b/android/app/src/main/res/layout/fragment_profile.xml index 2761c921..fecce4fa 100644 --- a/android/app/src/main/res/layout/fragment_profile.xml +++ b/android/app/src/main/res/layout/fragment_profile.xml @@ -1,32 +1,26 @@ - + + - - @@ -47,6 +41,7 @@ @@ -55,31 +50,36 @@ style="@style/InfoItem.Account" app:sLeftTextString="消息" /> - + + + + android:id="@+id/menu_logout" + style="@style/InfoItem" + android:layout_marginTop="16dp" + app:sCenterTextColor="@color/xui_config_color_red" + app:sCenterTextString="退出登录" + app:sDividerLineType="none" /> - - - + - \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_scene.xml b/android/app/src/main/res/layout/fragment_scene.xml index c7094c94..67b817d6 100644 --- a/android/app/src/main/res/layout/fragment_scene.xml +++ b/android/app/src/main/res/layout/fragment_scene.xml @@ -1,35 +1,235 @@ - + + - + android:layout_height="wrap_content" + android:orientation="vertical"> - + android:layout_height="wrap_content" + android:layout_margin="@dimen/config_margin_10dp" + android:background="@color/cardview_light_background" + android:orientation="vertical" + android:padding="@dimen/config_padding_20dp" + android:paddingEnd="@dimen/config_padding_20dp"> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + android:layout_height="wrap_content" + android:layout_marginStart="10dp" + android:layout_marginEnd="10dp" + android:background="@color/cardview_light_background" + android:orientation="vertical" + android:padding="@dimen/config_padding_20dp" + android:paddingEnd="@dimen/config_padding_20dp"> - - + - + + + + + + + + + + + + + - \ No newline at end of file + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/fragment_share_device.xml b/android/app/src/main/res/layout/fragment_share_device.xml index ebfaaf34..5134a593 100644 --- a/android/app/src/main/res/layout/fragment_share_device.xml +++ b/android/app/src/main/res/layout/fragment_share_device.xml @@ -1,5 +1,14 @@ - + - - - - - - - - - - - - - - - + android:icon="@drawable/set" + android:title="服务配置" /> - + android:title="@string/menu_device" /> + android:icon="@drawable/set" + android:title="@string/menu_scene" /> + android:title="@string/menu_news" /> 24dp - - 16dp - 14dp - 10dp - 20dp - 8dp + 4dp 5dp - 18dp - 30dp + 6dp + 8dp + 10dp 12dp + 14dp + 16dp + 18dp + 20dp 24dp + 30dp + + 4dp + 5dp + 6dp + 8dp + 10dp + 12dp + 14dp + 16dp + 18dp + 20dp + 24dp + 30dp \ No newline at end of file diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index fe495a1d..19626e44 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -1,13 +1,15 @@ - 物美 + 物美智能 通用浏览器 + service_api_key + http://wumei.live Open navigation drawer Close navigation drawer 设备 - 动态 - 场景 + 官网 + 配置 添加 我的 添加设备 @@ -21,13 +23,13 @@ 设置 关于 - © %1$s wumei All rights reserved. + © %1$s wumei-smart All rights reserved. 访问官网 - 关于作者 - QQ联系 + 访问源码 + 加入QQ群 http://wumei.live - https://gitee.com/kerwincui - http://wpa.qq.com/msgrd?v=3&uin=164770707&site=qq&menu=yes + https://gitee.com/kerwincui/wumei-smart + https://qm.qq.com/cgi-bin/qm/qr?k=P_oc91N6KC39zp2PEV_-BY3xMnAokeZ8 @@ -95,9 +97,7 @@ 在 Android M 及以上版本,如果您禁止授权位置权限,APP将无法获取 Wi-Fi 信息。 Wi-Fi 已断开或发生了变化 Esptouch 正在执行配网, 请稍等片刻… - EspTouch 配网失败 - 建立 EspTouch 任务失败, 端口可能被其他程序占用 EspTouch 完成 - BSSID: %1$s, 地址: %2$s + diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml index 29400246..dfc91efc 100644 --- a/android/app/src/main/res/values/styles.xml +++ b/android/app/src/main/res/values/styles.xml @@ -35,10 +35,10 @@ @drawable/begin - + + + + + + + + + + +