531 Commits

Author SHA1 Message Date
随遇而安
780e5477d8 update README.md. 2022-06-20 04:46:15 +00:00
kerwincui
f302f8c8bc 配置文件改善 2022-06-18 23:46:35 +08:00
kerwincui
468ec83bfe 设备名称的bug处理 2022-06-18 23:23:48 +08:00
kerwincui
c2d884e910 设备日志界面优化 2022-06-18 23:15:04 +08:00
kerwincui
381ff00ea4 TDengine测试和优化 2022-06-18 23:14:43 +08:00
kerwincui
452c5a5903 界面优化 2022-06-18 12:28:42 +08:00
kerwincui
3795bc067b 固件版本类型调整为float 2022-06-17 01:45:20 +08:00
kerwincui
5b8f1f39f3 改进esp8266的OTA升级 2022-06-17 01:43:55 +08:00
kerwincui
0e2dd62f9c 树莓派改进ota升级 2022-06-17 01:42:19 +08:00
kerwincui
5fca93c76a esp32固件改进ota升级 2022-06-17 01:42:01 +08:00
kerwincui
1b11ffc4c8 Merge remote-tracking branch 'origin/master' into version1.2 2022-06-17 00:32:43 +08:00
kerwincui
cb338037d2 bug修复 2022-06-17 00:31:48 +08:00
kerwincui
19a6b28cb8 更新sql,增加固件状态 2022-06-16 23:44:22 +08:00
kerwincui
b9f56459d4 固件升级完善 2022-06-16 23:41:30 +08:00
kerwincui
a574bcc5aa 固件升级完善 2022-06-16 23:41:15 +08:00
kerwincui
b2fb001618 设备认证改为认证方式 2022-06-16 16:18:26 +08:00
kerwincui
5ebdb8d05e 设备摘要bug修复 2022-06-16 16:18:09 +08:00
kerwincui
13663aad63 授权界面优化 2022-06-16 01:10:50 +08:00
kerwincui
4f9ac0dca5 设备删除优化 2022-06-16 00:56:42 +08:00
kerwincui
6562746f1e 界面优化 2022-06-16 00:56:29 +08:00
kerwincui
fb75e72a43 细节调整 2022-06-15 23:09:21 +08:00
kerwincui
5cef61cc04 界面优化 2022-06-15 20:50:18 +08:00
kerwincui
e70385bd26 界面优化 2022-06-15 20:36:23 +08:00
kerwincui
f7b6883dff 图片显示优化 2022-06-15 20:30:17 +08:00
kerwincui
82d3f73eeb 分组更新问题 2022-06-15 19:12:23 +08:00
kerwincui
c9434d4be7 授权码改进 2022-06-15 17:08:15 +08:00
kerwincui
422ebf51d8 设备授权码改进 2022-06-15 16:59:42 +08:00
kerwincui
a908ca60a9 设备授权码改进 2022-06-15 16:59:27 +08:00
kerwincui
c883ec828f 后端支持我的分组筛选 2022-06-15 15:27:47 +08:00
kerwincui
b87a1dc6f0 设备分组筛选和细节优化 2022-06-15 15:27:24 +08:00
kerwincui
146d84dcab 设备认证bug处理 2022-06-14 23:45:25 +08:00
kerwincui
e32153c222 细节调整 2022-06-14 21:07:09 +08:00
随遇而安
1c56c7709b update README.md. 2022-06-14 13:03:22 +00:00
随遇而安
d0f48cfd77 update README.md. 2022-06-14 13:01:07 +00:00
随遇而安
fc34514bb3 update README.md. 2022-06-14 12:57:56 +00:00
kerwincui
a640f3f17e 解决设备列表分页问题 2022-06-14 16:48:01 +08:00
kerwincui
d8990643f4 更新日志配置 2022-06-14 16:46:51 +08:00
kerwincui
98cb6da924 更新sql文件 2022-06-14 16:46:28 +08:00
kerwincui
54ca3ab0d2 设备编辑详情报错处理 2022-06-14 16:36:46 +08:00
kerwincui
2b79c5df16 修改配置文件 2022-06-14 15:06:36 +08:00
kerwincui
31867085ea bug处理 2022-06-12 14:59:43 +08:00
kerwincui
6df3279909 Merge remote-tracking branch 'origin/master' into version1.2 2022-06-12 12:50:56 +08:00
kerwincui
550a390703 更新SDK 2022-06-12 12:50:33 +08:00
kerwincui
8b42e52db0 界面调整 2022-06-12 12:13:23 +08:00
kerwincui
2b1b73abff 细节优化 2022-06-12 02:30:02 +08:00
kerwincui
9cd08b74d1 bug处理 2022-06-12 02:06:03 +08:00
随遇而安
8355faf39e update README.md. 2022-06-11 16:14:02 +00:00
随遇而安
228b741ba5 update README.md. 2022-06-11 16:12:24 +00:00
随遇而安
e286465946 update README.md. 2022-06-11 16:12:03 +00:00
随遇而安
2904f0b43d update README.md. 2022-06-11 16:11:37 +00:00
kerwincui
5f675aa796 用户中心调整 2022-06-11 23:26:22 +08:00
kerwincui
eeac05745f 设备日志改进 2022-06-11 16:41:19 +08:00
kerwincui
33a7ba9645 多租户测试调整 2022-06-11 02:32:48 +08:00
kerwincui
8571f899da 设备列表重复问题处理 2022-06-10 21:29:46 +08:00
kerwincui
34b0cd53ea 界面细节调整 2022-06-10 17:42:15 +08:00
kerwincui
fdb2d71d2e 首页地图单击跳转 2022-06-10 16:10:29 +08:00
kerwincui
a8f6dcf882 日志添加租户和用户信息 2022-06-10 15:10:58 +08:00
kerwincui
6f2800cdb8 设备筛选bug处理 2022-06-10 13:52:44 +08:00
kerwincui
72cd1e95fd 多租户的测试调整 2022-06-10 01:34:31 +08:00
kerwincui
b6af649c30 固件添加链接 2022-06-09 17:52:21 +08:00
kerwincui
44ed5a27b3 设备解绑功能完善 2022-06-09 17:09:07 +08:00
kerwincui
0052178b5a 设备界面优化 2022-06-09 14:10:55 +08:00
kerwincui
87f7a6eb86 设备列表bug修复 2022-06-09 13:28:29 +08:00
kerwincui
5660a399b8 授权码导出功能 2022-06-09 00:04:38 +08:00
kerwincui
9dd368c883 完善设备授权 2022-06-08 23:57:40 +08:00
kerwincui
f2b80eaf2f 物模型界面细节调整 2022-06-08 15:10:22 +08:00
kerwincui
f2af26998a 解决物模型修改枚举和数组界面不更新问题 2022-06-08 14:18:21 +08:00
kerwincui
952c2e09c0 细节优化 2022-06-08 12:41:34 +08:00
kerwincui
40d6a49bfc 界面和细节优化 2022-06-08 01:58:26 +08:00
kerwincui
267d60fb1a 设备授权界面调整 2022-06-07 17:56:23 +08:00
kerwincui
70098975d5 设备授权添加状态和筛选 2022-06-07 17:56:08 +08:00
kerwincui
54dc335b02 前端bug处理 2022-06-07 14:23:57 +08:00
kerwincui
d8e35ebfc3 后端TDengine统计分类数量 2022-06-07 14:23:42 +08:00
kerwincui
653eee4e76 设备统计接口 2022-06-06 17:45:36 +08:00
kerwincui
1aa94d3e50 设备统计界面 2022-06-06 17:45:16 +08:00
kerwincui
e6ccf6ee58 分组中添加设备前端 2022-06-06 15:52:48 +08:00
kerwincui
1f7a127499 分组中添加设备 2022-06-06 15:52:32 +08:00
kerwincui
24f2e65f2b 设备修改定位字段名称,添加设备摘要 2022-06-06 13:11:06 +08:00
kerwincui
c9a036043e 完成多租户测试 2022-06-05 17:41:12 +08:00
kerwincui
edf36d3dd1 bug修复 2022-06-05 17:40:54 +08:00
kerwincui
39e7e78b3a 通知公告和新闻咨询完善 2022-06-05 15:57:06 +08:00
kerwincui
12b88d2a93 图片和文件上传优化 2022-06-05 14:51:10 +08:00
kerwincui
ba128edd40 设备添加初始化信息 2022-06-05 13:17:46 +08:00
kerwincui
ed1401ccb8 认证匹配加密认证和简单认证 2022-06-05 13:07:32 +08:00
kerwincui
4632e69def 界面调整 2022-06-05 01:18:23 +08:00
kerwincui
b7b693b6d6 界面优化 2022-06-05 00:18:42 +08:00
kerwincui
6e0becee7c 多租户调整 2022-06-05 00:18:29 +08:00
kerwincui
3fea5132ce 新闻和通知的多租户修改 2022-06-04 19:40:12 +08:00
kerwincui
c3d3d524de 添加信息栏 2022-06-04 17:00:42 +08:00
kerwincui
5423f2fb7f 界面调整 2022-06-04 13:27:49 +08:00
kerwincui
d6c69594b9 登录界面调整 2022-06-04 13:27:02 +08:00
kerwincui
f8eb314bd0 租户只能查看自己的产品、固件、分组和产品下设备以及系统定义的物模型和分类 2022-06-04 13:19:15 +08:00
kerwincui
dad1d22d69 接口 2022-06-04 00:55:52 +08:00
kerwincui
cb2aa585c4 多租户前端调整 2022-06-04 00:52:24 +08:00
kerwincui
46aa17f320 多租户接口调整 2022-06-04 00:51:14 +08:00
kerwincui
4999c2abcb 后端多租户调整 2022-06-03 17:21:51 +08:00
kerwincui
168d987779 前端多租户调整 2022-06-03 17:21:31 +08:00
kerwincui
c9623a5ec6 权限调整 2022-06-03 14:29:50 +08:00
kerwincui
f281ccc1da 界面和权限调整 2022-06-03 12:39:28 +08:00
kerwincui
e36c9849a8 界面调整 2022-06-01 14:37:33 +08:00
kerwincui
b78bf54e21 界面响应式调整 2022-05-31 22:51:59 +08:00
kerwincui
c226922f07 产品和设备编辑界面调整 2022-05-31 17:21:38 +08:00
kerwincui
1cf1a60583 登录和注册界面调整 2022-05-31 16:55:33 +08:00
kerwincui
1f9636ac96 代码优化 2022-05-30 23:07:18 +08:00
kerwincui
c768af6cf9 Arduino开发的SDK更新 2022-05-30 21:39:11 +08:00
kerwincui
1a5c9b8c39 树莓派sdk更新 2022-05-30 21:33:48 +08:00
kerwincui
96715753b0 登录注册界面调整 2022-05-30 17:47:19 +08:00
kerwincui
b6cd6975f8 设备定位优化 2022-05-30 17:01:23 +08:00
kerwincui
aab50e5a78 产品模块完善 2022-05-30 16:08:39 +08:00
kerwincui
ed5b747844 Merge remote-tracking branch 'origin/master' into version1.2 2022-05-30 14:14:49 +08:00
kerwincui
8fb9d5dba9 代码优化 2022-05-30 14:13:52 +08:00
kerwincui
6a3fab6198 docker构建测试失败,emqx安装不了 2022-05-30 03:38:09 +08:00
kerwincui
9b23b5e712 emqx安装失败 2022-05-30 03:31:19 +08:00
kerwincui
ad0cd5dd11 测试dockerfile 2022-05-30 03:27:20 +08:00
kerwincui
d057601c72 测试dockerfile 2022-05-30 03:24:04 +08:00
kerwincui
68fbd6caa0 测试镜像构建 2022-05-30 03:05:02 +08:00
kerwincui
a8f0c72a3f 测试构建 2022-05-30 02:46:24 +08:00
kerwincui
bc4686e598 测试构建 2022-05-30 02:41:35 +08:00
kerwincui
b7a5b69619 测试 2022-05-30 02:33:35 +08:00
kerwincui
4a251eccc4 测试 2022-05-30 02:29:27 +08:00
kerwincui
e944b695b1 构建镜像测试 2022-05-30 02:27:49 +08:00
kerwincui
24a0d67a33 构建镜像测试 2022-05-30 02:25:41 +08:00
随遇而安
89a85a295e update pipeline-docker.yml for Gitee Go updated_at:2022-05-29 18:24:37 2022-05-29 18:24:37 +00:00
kerwincui
9790bff15c 测试构建docker镜像 2022-05-30 02:24:00 +08:00
kerwincui
dd8747f66b 测试镜像构建 2022-05-30 02:10:23 +08:00
随遇而安
e1b0231490 update pipeline-vue.yml for Gitee Go updated_at:2022-05-29 17:37:26 2022-05-29 17:37:27 +00:00
随遇而安
17dbdcb66a update pipeline-java.yml for Gitee Go updated_at:2022-05-29 17:36:56 2022-05-29 17:36:56 +00:00
随遇而安
badd1e414f update pipeline-docker.yml for Gitee Go updated_at:2022-05-29 17:36:29 2022-05-29 17:36:29 +00:00
kerwincui
b6d02938fd 更新流水线配置 2022-05-30 01:34:31 +08:00
随遇而安
8e2e910b5f update pipeline-docker.yml for Gitee Go updated_at:2022-05-29 17:25:50 2022-05-29 17:25:50 +00:00
kerwincui
1337db3dff 测试流水线docker构建镜像 2022-05-30 01:21:05 +08:00
随遇而安
36dab8cd5a update pipeline-docker.yml for Gitee Go updated_at:2022-05-29 17:17:26 2022-05-29 17:17:27 +00:00
随遇而安
cf1fa1a0f1 update pipeline-docker.yml for Gitee Go updated_at:2022-05-29 17:13:31 2022-05-29 17:13:31 +00:00
kerwincui
a116e4d44b 测试流水线docker构建镜像 2022-05-30 01:12:17 +08:00
随遇而安
fe122ce31a update pipeline-docker.yml for Gitee Go updated_at:2022-05-29 16:33:22 2022-05-29 16:33:22 +00:00
随遇而安
dc59b81841 update pipeline-docker.yml for Gitee Go updated_at:2022-05-29 16:30:44 2022-05-29 16:30:44 +00:00
kerwincui
34571698ee 删除输出目录 2022-05-29 23:54:23 +08:00
随遇而安
ed1a940238 update pipeline-docker.yml for Gitee Go updated_at:2022-05-29 15:20:36 2022-05-29 15:20:36 +00:00
随遇而安
51b9389128 update pipeline-docker.yml for Gitee Go updated_at:2022-05-29 15:09:50 2022-05-29 15:09:50 +00:00
随遇而安
84573a7283 update pipeline-vue.yml for Gitee Go updated_at:2022-05-29 14:51:32 2022-05-29 14:51:33 +00:00
随遇而安
2883c0c553 update pipeline-docker.yml for Gitee Go updated_at:2022-05-29 14:31:24 2022-05-29 14:31:24 +00:00
随遇而安
497f480cad update pipeline-docker.yml for Gitee Go updated_at:2022-05-29 14:17:34 2022-05-29 14:17:35 +00:00
随遇而安
aa9efa0121 update pipeline-vue.yml for Gitee Go updated_at:2022-05-29 14:15:13 2022-05-29 14:15:13 +00:00
随遇而安
d8010fce1e update pipeline-java.yml for Gitee Go updated_at:2022-05-29 14:14:03 2022-05-29 14:14:03 +00:00
随遇而安
076a5c2905 update pipeline-docker.yml for Gitee Go updated_at:2022-05-29 14:01:03 2022-05-29 14:01:03 +00:00
随遇而安
5866624317 add pipeline-docker.yml for Gitee Go created_at:2022-05-29 14:00:25 2022-05-29 14:00:25 +00:00
随遇而安
c9bc4ba0e2 update pipeline-vue.yml for Gitee Go updated_at:2022-05-29 13:47:32 2022-05-29 13:47:32 +00:00
随遇而安
be2fcad8dc update pipeline-java.yml for Gitee Go updated_at:2022-05-29 13:44:57 2022-05-29 13:44:57 +00:00
随遇而安
f06383e46b update .workflow/pipeline-java.yml. 2022-05-29 13:34:25 +00:00
随遇而安
16d3d26a31 重命名 .workflow/pipeline-deploy.yml 为 .workflow/pipeline-java.yml 2022-05-29 13:34:08 +00:00
随遇而安
2e0fd23695 add pipeline-vue.yml for Gitee Go created_at:2022-05-29 13:33:16 2022-05-29 13:33:16 +00:00
随遇而安
0bec7efd5c update pipeline-deploy.yml for Gitee Go updated_at:2022-05-29 13:22:32 2022-05-29 13:22:33 +00:00
随遇而安
f3a80259eb update pipeline-deploy.yml for Gitee Go updated_at:2022-05-29 13:07:06 2022-05-29 13:07:06 +00:00
随遇而安
d25592232b update pipeline-deploy.yml for Gitee Go updated_at:2022-05-29 13:01:53 2022-05-29 13:01:53 +00:00
随遇而安
042761259e update pipeline-deploy.yml for Gitee Go updated_at:2022-05-29 12:50:08 2022-05-29 12:50:08 +00:00
随遇而安
7f524eb48b update pipeline-deploy.yml for Gitee Go updated_at:2022-05-29 12:44:07 2022-05-29 12:44:07 +00:00
随遇而安
bcca79dfc1 update pipeline-deploy.yml for Gitee Go updated_at:2022-05-29 12:39:09 2022-05-29 12:39:09 +00:00
随遇而安
5c40f81e3d update pipeline-deploy.yml for Gitee Go updated_at:2022-05-29 12:34:15 2022-05-29 12:34:15 +00:00
kerwincui
1f54ec3a85 添加构建目录 2022-05-29 20:33:18 +08:00
kerwincui
4429882b60 测试持续集成 2022-05-29 20:15:28 +08:00
随遇而安
00e11e7cb6 update pipeline-deploy.yml for Gitee Go updated_at:2022-05-29 12:00:30 2022-05-29 12:00:31 +00:00
随遇而安
2714fc076f update pipeline-deploy.yml for Gitee Go updated_at:2022-05-29 11:55:44 2022-05-29 11:55:44 +00:00
随遇而安
d7fc72e45d update pipeline-deploy.yml for Gitee Go updated_at:2022-05-29 10:36:29 2022-05-29 10:36:29 +00:00
随遇而安
214a55898c update pipeline-deploy.yml for Gitee Go updated_at:2022-05-29 10:33:26 2022-05-29 10:33:26 +00:00
随遇而安
90b1eb2da0 add pipeline-deploy.yml for Gitee Go created_at:2022-05-29 10:10:48 2022-05-29 10:10:48 +00:00
随遇而安
391a5310e0 update app/README.md. 2022-05-28 18:02:39 +00:00
随遇而安
b339724a25 update README.md. 2022-05-28 15:12:49 +00:00
kerwincui
ea403c0be5 Merge remote-tracking branch 'origin/master' into version1.2 2022-05-25 16:22:39 +08:00
随遇而安
6ed91b856a update README.md. 2022-05-25 02:27:10 +00:00
kerwincui
17ef0b28ef yml文件还原 2022-05-24 19:41:14 +08:00
随遇而安
f793b62627 !36 修复查询日志和监控数据报错问题
Merge pull request !36 from xxmfl/master
2022-05-24 11:39:47 +00:00
wxy001
2788764430 2022年5月24日19:20:31 修复查询设备日志和检测数据报错问题 2022-05-24 19:20:54 +08:00
随遇而安
d31fae1077 !35 增加启动时创建TDengine数据库和日志表
Merge pull request !35 from xxmfl/master
2022-05-24 07:33:31 +00:00
wxy001
14197e7436 2022年5月24日14:34:18 增加初始化时创建数据库功能 2022-05-24 15:28:39 +08:00
wxy001
4dde2bd121 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/init/ApplicationStarted.java
2022-05-24 15:15:52 +08:00
wxy001
6c58e34bec 2022年5月24日14:34:18 增加初始化时创建数据库功能 2022-05-24 14:34:39 +08:00
kerwincui
f07b05eaa1 Merge remote-tracking branch 'origin/master' into version1.2 2022-05-24 13:58:57 +08:00
随遇而安
315f9f8d18 update springboot/wumei-admin/src/main/resources/application-druid.yml. 2022-05-24 05:23:24 +00:00
kerwincui
ca688aa975 备注信息 2022-05-24 13:21:59 +08:00
随遇而安
d25d81967d update README.md. 2022-05-24 04:28:07 +00:00
kerwincui
8a1db44119 提示信息调整 2022-05-24 12:21:00 +08:00
随遇而安
1970b9f007 update README.md. 2022-05-24 04:16:43 +00:00
随遇而安
416935e530 update README.md. 2022-05-24 04:14:00 +00:00
kerwincui
6fc2a47527 还原配置 2022-05-24 10:29:06 +08:00
随遇而安
ba91433bb1 !33 将TDEngine相关配置移到同一个包中
Merge pull request !33 from xxmfl/master
2022-05-24 02:25:27 +00:00
wxy001
f783503b51 2022年5月24日01:05:38 还原ApplicationStart,讲TDengine相关类型和配置归于同一个包 2022-05-24 01:53:27 +08:00
wxy001
5219a0c766 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	springboot/wumei-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java
#	springboot/wumei-iot/src/main/java/com/ruoyi/iot/mqtt/EmqxService.java
#	springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/config/TDengineConfig.java
#	springboot/wumei-iot/src/main/resources/mapper/tdengine/DatabaseMapper.xml
#	springboot/wumei-iot/src/main/resources/mapper/tdengine/TDDeviceLogMapper.xml
2022-05-24 01:18:18 +08:00
wxy001
d032413a56 2022年5月24日01:05:38 还原ApplicationStart,讲TDengine相关类型和配置归于同一个包 2022-05-24 01:06:40 +08:00
随遇而安
8fb4f017e5 !32 增加时序数据库TDengine支持
Merge pull request !32 from xxmfl/master
2022-05-23 03:40:19 +00:00
wxy001
c43459e987 增加时序数据库TDengine存储设备日志和设备监测数据 2022-05-23 00:48:30 +08:00
wxy001
81232fbb04 2022年5月22日23:48:54 增加TDengine存储日志功能,
提供基础的新增和查询功能
2022-05-22 23:50:01 +08:00
kerwincui
34d6a676ea 设备定位方式界面 2022-05-22 01:33:38 +08:00
kerwincui
eb755f7e6f 图表样式调整 2022-05-21 10:45:01 +08:00
kerwincui
177a8fbba8 更新统计的最大数量 2022-05-20 23:54:42 +08:00
kerwincui
28ead10408 监测统计进行日期范围查询 2022-05-20 21:54:42 +08:00
wxy001
44f682c3ba 2022年5月20日19:30:44
1.集成TDengine作为日志和监测数据存储库使用
2.实现简单的新增和查询功能接口
2022-05-20 19:32:14 +08:00
kerwincui
1113ed0c50 统计 2022-05-20 17:55:02 +08:00
kerwincui
6e052c64ab 统计添加时间筛选 2022-05-20 17:54:44 +08:00
kerwincui
a2bbaeb15a 产品和设备图片同步问题处理 2022-05-20 15:54:14 +08:00
kerwincui
317c728f37 解决设备激活时间查询报错问题 2022-05-20 15:20:18 +08:00
kerwincui
767fdebe2c 解决新增、编辑产品和设备的缓存问题 2022-05-20 15:19:46 +08:00
kerwincui
475cb507cf 设备认证bug处理 2022-05-19 17:51:22 +08:00
kerwincui
eaf2eac028 字符串比较错误处理 2022-05-19 17:08:07 +08:00
kerwincui
9412466747 解决加密认证解密失败bug 2022-05-19 16:50:44 +08:00
kerwincui
b98b326674 解决分类新闻列表查询报错 2022-05-19 16:50:13 +08:00
kerwincui
dbc229b1b7 登录页修改文字 2022-05-19 16:49:02 +08:00
kerwincui
8ea10bb813 设备认证统一 2022-05-19 10:56:02 +08:00
kerwincui
7e00d8c0d6 解决多租户导致设备不显示问题 2022-05-18 20:57:05 +08:00
随遇而安
86940906ca update app/README.md. 2022-05-18 12:55:16 +00:00
随遇而安
568e4fbb25 update README.md. 2022-05-17 13:13:16 +00:00
随遇而安
2094e117c1 update README.md. 2022-05-17 07:28:10 +00:00
kerwincui
ccb0da2779 实时监测的bug修复 2022-05-16 18:55:55 +08:00
kerwincui
32f284b3c4 后端启动bug处理 2022-05-16 16:15:31 +08:00
kerwincui
3172f37090 暂时注释授权码的判断 2022-05-15 17:40:22 +08:00
kerwincui
85e3f1f6c8 还原设备实时监测代码,取消注释。 2022-05-15 17:38:35 +08:00
随遇而安
c82e65eea4 update sdk/RaspberryPi/README.md. 2022-05-14 02:58:44 +00:00
随遇而安
a0e8628e8a update sdk/RaspberryPi/README.md. 2022-05-14 02:56:57 +00:00
kerwincui
1b6f4ae53c 文档更新 2022-05-14 10:55:21 +08:00
随遇而安
7f91d1cbaa update sdk/RaspberryPi/README.md. 2022-05-14 02:50:59 +00:00
随遇而安
4018b2b02b update sdk/RaspberryPi/更多参考教程.txt. 2022-05-14 02:50:08 +00:00
kerwincui
ddd3b77182 修改文档 2022-05-14 10:49:08 +08:00
随遇而安
59cc0ad683 update sdk/RaspberryPi/README.md. 2022-05-14 02:46:27 +00:00
kerwincui
6511c32b02 更新markdown 2022-05-14 10:44:45 +08:00
kerwincui
d523a1bf1f 更新markdown文件 2022-05-14 10:39:55 +08:00
随遇而安
b65a19ad7f !31 增加对树莓派SDK的说明文件
Merge pull request !31 from YBZX/master
2022-05-14 02:31:35 +00:00
YBZX
3b75b121c4 增加对树莓派sdk说明文件 2022-05-13 15:59:09 +08:00
kerwincui
747eac3879 emq管理的权限控制调整 2022-05-13 13:43:50 +08:00
随遇而安
881bc88f5c update README.md. 2022-05-13 04:52:09 +00:00
随遇而安
23fe83f85c !30 开发完成的树莓派sdk
Merge pull request !30 from YBZX/master
2022-05-13 03:55:27 +00:00
kerwincui
0a59ea9478 规则引擎界面调整 2022-05-13 00:48:19 +08:00
YBZX
091782d000 添加树莓派sdk 2022-05-13 00:09:05 +08:00
kerwincui
bc147649c7 调整客户端界面 2022-05-12 18:07:39 +08:00
kerwincui
1b345cbbdd 第三方登录页面调整 2022-05-12 17:48:34 +08:00
kerwincui
70173b9b82 首页修改 2022-05-12 17:05:41 +08:00
kerwincui
bd4dd405d2 首页修改 2022-05-12 16:39:38 +08:00
kerwincui
bc694b8a6f 设备列表取消订阅 2022-05-12 14:25:42 +08:00
kerwincui
cd63e1eba4 注册和登录页面修改 2022-05-12 14:25:18 +08:00
kerwincui
303d6dc6b0 添加ios包文件 2022-05-10 14:10:21 +08:00
kerwincui
50e478317c apk更新 2022-05-09 20:14:16 +08:00
随遇而安
72467de6b9 update app/README.md. 2022-05-09 12:13:08 +00:00
随遇而安
0997fb4eed update app/README.md. 2022-05-09 12:12:23 +00:00
随遇而安
a6b2bed0f8 update app/README.md. 2022-05-09 12:11:25 +00:00
随遇而安
118c4814fb update app/README.md. 2022-05-09 12:10:24 +00:00
随遇而安
14f49580b9 update README.md. 2022-05-09 11:47:09 +00:00
kerwincui
1625cd0628 修改图片目录 2022-05-09 16:34:21 +08:00
随遇而安
e18d1de429 update README.md. 2022-05-09 06:35:27 +00:00
随遇而安
24b1fa84e5 update README.md. 2022-05-06 17:58:39 +00:00
随遇而安
7b715ea6e3 update app/README.md. 2022-05-06 17:58:20 +00:00
随遇而安
64c5834901 update README.md. 2022-05-06 17:57:22 +00:00
随遇而安
4217347366 update app/README.md. 2022-05-01 06:43:12 +00:00
随遇而安
cbc180ac9f update app/README.md. 2022-05-01 06:42:50 +00:00
随遇而安
2fad6d3213 重命名 sdk/arduino 为 sdk/Arduino 2022-05-01 06:29:57 +00:00
kerwincui
992e6503fd 删除无用文件 2022-05-01 14:29:25 +08:00
kerwincui
be51ff7e4d 添加目录 2022-05-01 14:27:47 +08:00
kerwincui
025c127707 添加新闻的分类Id查询 2022-04-28 15:23:11 +08:00
随遇而安
b016b32154 update README.md. 2022-04-28 06:37:44 +00:00
随遇而安
c26a7183ae update README.md. 2022-04-27 14:50:56 +00:00
随遇而安
a9e2013138 update README.md. 2022-04-27 14:47:49 +00:00
随遇而安
69e527416c !29 分享设备列表
Merge pull request !29 from woaibjb/master
2022-04-27 14:45:25 +00:00
hp
224d4e1f7e 分享设备列表接口以及sql修改 2022-04-27 18:56:51 +08:00
随遇而安
4a5d29e87e !28 设备分享
Merge pull request !28 from woaibjb/master
2022-04-27 06:16:55 +00:00
hp
cabc91f3bc 分享单个或全部设备功能实现,用户设备列表接口调整,新增别人分享给自己的设备 2022-04-27 13:05:36 +08:00
随遇而安
f5c4042f58 update README.md. 2022-04-27 04:46:27 +00:00
随遇而安
b020aa4561 update README.md. 2022-04-27 04:13:28 +00:00
随遇而安
9236004a26 update README.md. 2022-04-27 04:12:50 +00:00
随遇而安
c5b544771b update README.md. 2022-04-27 04:10:01 +00:00
随遇而安
909bc54249 update README.md. 2022-04-24 15:29:18 +00:00
随遇而安
5d49f84949 update README.md. 2022-04-24 15:27:50 +00:00
随遇而安
08b3607123 !27 qq解绑和重新绑定+ 优化登录管理界面UI
Merge pull request !27 from LemonTree/json_social_login
2022-04-24 15:23:36 +00:00
kerwincui
e86407130c 更新esp8266的SDK 2022-04-24 21:20:27 +08:00
LemonTree
afa550986a [功能]:1、跳转url 放到配置文件里面 2、优化登录管理界面 3、添加qq登录解绑和重新绑定功能 4、个人中心增加 qq绑定信息 展示view 2022-04-24 19:10:35 +08:00
LemonTree
6a5d0169a7 Merge branch 'master' into json_social_login 2022-04-24 18:26:30 +08:00
随遇而安
b6ccc1531e !26 规则引擎页面 ,错误修复
Merge pull request !26 from sxh/master
2022-04-22 08:36:20 +00:00
sxh
17438df5da 规则引擎前端错误修改 2022-04-22 16:33:33 +08:00
随遇而安
08a9aad8ab !25 EMQX模块前端优化
Merge pull request !25 from sxh/master
2022-04-22 06:29:11 +00:00
sxh
7a83ba8984 EMQX模块前端优化 2022-04-22 14:25:04 +08:00
kerwincui
83d3e58bb3 更新sql文件 2022-04-22 01:36:20 +08:00
kerwincui
e9f94c4344 配置文件修改 2022-04-22 01:31:23 +08:00
kerwincui
412bc8e5d0 界面调整 2022-04-22 01:27:20 +08:00
随遇而安
d443ebe790 update README.md. 2022-04-21 05:27:39 +00:00
随遇而安
480d82e422 update README.md. 2022-04-21 05:20:04 +00:00
随遇而安
c3185f324f update README.md. 2022-04-21 05:00:32 +00:00
随遇而安
3015b7d576 update README.md. 2022-04-21 04:58:58 +00:00
随遇而安
5a0b0ae6e2 update README.md. 2022-04-21 04:54:28 +00:00
随遇而安
6a5dc2a6c5 !24 Emqx管理功能完善
Merge pull request !24 from sxh/master
2022-04-21 04:47:03 +00:00
sxh
a236687ecd 新增以下内容1.客户端查看详情和断开连接,2.规则引擎的增删改查,3.资源的增删改查, 2022-04-21 12:43:59 +08:00
sxh
d8435da52c 细节完善 2022-04-21 09:14:21 +08:00
sxh
b0c2ed9b13 增加客户端查看详情和断开连接;规则引擎的增删改查;资源的增删改查 2022-04-21 09:01:01 +08:00
随遇而安
45a497af97 update README.md. 2022-04-20 12:11:55 +00:00
LemonTree
6510c04154 [功能]:1、只在iot使用 去除外层依赖 2022-04-20 19:58:11 +08:00
随遇而安
d8650dcaa1 !21 qq第三方登录开发
Merge pull request !21 from LemonTree/json_social_login
2022-04-20 11:54:32 +00:00
LemonTree
9bdcf7a60d [功能]:1、添加http通用接口forest 2、引入justoauth 处理第三方登录 3、大致完成qq登录代码 4、前端界面修改适配第三方登录逻辑 2022-04-20 18:31:04 +08:00
LemonTree
bb2cdebac3 [功能]:1、添加http通用接口forest 2、引入justoauth 处理第三方登录 3、大致完成qq登录代码 4、前端界面修改适配第三方登录逻辑 2022-04-20 18:30:27 +08:00
随遇而安
28bfe461dc update app/README.md. 2022-04-20 06:40:52 +00:00
kerwincui
5326e8543e bug修复 2022-04-18 14:21:36 +08:00
kerwincui
513b10d939 修改响应式界面 2022-04-17 00:44:48 +08:00
kerwincui
47d702ee76 更新sql 2022-04-17 00:44:10 +08:00
随遇而安
e44a2fe9fd update vue/src/views/iot/device/mqtt-client.vue. 2022-04-16 15:56:32 +00:00
随遇而安
9d2f87496b update vue/vue.config.js. 2022-04-16 15:55:40 +00:00
kerwincui
e2a1b673d6 添加设备重置接口 2022-04-16 23:46:39 +08:00
kerwincui
5152eb5239 登录界面修改 2022-04-16 23:45:53 +08:00
kerwincui
5b277fa130 mqtt完善 2022-04-16 21:31:09 +08:00
kerwincui
a8ab4bf2e2 修复bug 2022-04-16 20:38:37 +08:00
kerwincui
2abaae21b0 界面颜色调整 2022-04-16 16:56:52 +08:00
kerwincui
1a8d39f92d 响应式布局 2022-04-16 16:51:23 +08:00
kerwincui
a0a3987209 修改为响应式布局 2022-04-16 16:42:56 +08:00
随遇而安
63c3f0b6a2 !20 代码规范化
Merge pull request !20 from redamancy_zxp/master
2022-04-16 06:15:26 +00:00
redamancy-qian
36afa809c4 代码规范化 2022-04-16 13:57:26 +08:00
随遇而安
00d9340825 !19 update vue/src/views/iot/group/device-list.vue.
Merge pull request !19 from redamancy_zxp/N/A
2022-04-16 05:29:37 +00:00
redamancy_zxp
4de11c5f96 update vue/src/views/iot/group/device-list.vue.
修改分组添加设备可以看见其他的设备
2022-04-16 05:10:52 +00:00
随遇而安
d95e625297 update README.md. 2022-04-16 04:53:03 +00:00
随遇而安
31a64b6638 !18 多租户修改3
Merge pull request !18 from redamancy_zxp/master
2022-04-16 04:11:34 +00:00
redamancy-qian
f052bda831 zhaothird 2022-04-16 00:48:53 +08:00
随遇而安
4bc2b41a38 !17 update springboot/wumei-iot/src/main/resources/mapper/iot/FirmwareMapper.xml.
Merge pull request !17 from redamancy_zxp/N/A
2022-04-15 03:43:50 +00:00
redamancy_zxp
843492ccba update springboot/wumei-iot/src/main/resources/mapper/iot/FirmwareMapper.xml.
对于租户固件查询处做出修改,保证租户只能查看系统定义的固件和自己创建的固件
2022-04-15 03:39:53 +00:00
随遇而安
81e9ef6373 update sdk/arduino/Arduino-ESP8266/Helper.cpp. 2022-04-14 17:52:32 +00:00
随遇而安
9b1ecf7bf3 update sdk/arduino/Arduino-ESP32/Helper.h. 2022-04-14 17:51:54 +00:00
随遇而安
2651004e1c update sdk/arduino/Arduino-ESP32/Arduino-ESP32.ino. 2022-04-14 17:51:33 +00:00
随遇而安
eb2e3b911f update sdk/arduino/Arduino-ESP32/Helper.cpp. 2022-04-14 17:51:15 +00:00
随遇而安
1d4361b2cf update sdk/arduino/Arduino-ESP32/Helper.cpp. 2022-04-14 17:50:43 +00:00
kerwincui
3ac00be115 添加esp32的支持 2022-04-15 01:38:27 +08:00
随遇而安
2009fe796c !16 多租户修改2
Merge pull request !16 from redamancy_zxp/master
2022-04-14 15:48:02 +00:00
redamancy-qian
1a5df34c4f zhaoSecond 2022-04-14 23:38:46 +08:00
kerwincui
217f2d2773 界面修改 2022-04-14 20:32:44 +08:00
kerwincui
81f1ca8a23 新增App资讯相关接口 2022-04-14 20:32:28 +08:00
kerwincui
6b759faeb9 更新前端配置 2022-04-14 00:49:19 +08:00
kerwincui
3163364da3 后端新增新闻模块 2022-04-14 00:49:19 +08:00
kerwincui
69c4111f02 完善前端 2022-04-14 00:49:19 +08:00
随遇而安
8c50fe34a0 update app/README.md. 2022-04-12 04:04:09 +00:00
随遇而安
cd067db4a7 update app/README.md. 2022-04-12 04:03:19 +00:00
随遇而安
e9790da1a2 !10 授权码页面微调
Merge pull request !10 from kami0314/master
2022-04-11 09:53:42 +00:00
kami
3e65de2837 授权码页面微调 2022-04-11 17:17:20 +08:00
kerwincui
fe2ab6da14 界面调整 2022-04-11 15:10:53 +08:00
随遇而安
7a89e5646f update README.md. 2022-04-11 06:25:26 +00:00
随遇而安
1cddbd94bc !9 新增授权码功能
Merge pull request !9 from kami0314/master
2022-04-11 05:57:33 +00:00
kami
95da9027e6 +f;新增授权码功能
1、产品表添加 is_authorize 是否启用授权码字段;
2、产品授权码功能:基础增删改查、批量生成授权码、绑定设备。
2022-04-11 13:45:27 +08:00
随遇而安
0afd5fab02 update README.md. 2022-04-10 16:27:09 +00:00
随遇而安
68ed6c1c24 update README.md. 2022-04-10 15:52:22 +00:00
随遇而安
8ec1311675 update README.md. 2022-04-10 05:10:58 +00:00
随遇而安
27882d8f23 update README.md. 2022-04-10 05:08:20 +00:00
随遇而安
5623a6dd64 update README.md. 2022-04-10 05:05:19 +00:00
随遇而安
736d269c3b update app/README.md. 2022-04-10 04:41:35 +00:00
随遇而安
5bb5fbf334 update app/README.md. 2022-04-10 04:07:48 +00:00
随遇而安
3bdaeb0c29 update README.md. 2022-04-10 04:06:16 +00:00
随遇而安
4f383d9d77 update README.md. 2022-04-10 04:05:19 +00:00
随遇而安
4e0d01d5ea update app/README.md. 2022-04-09 19:41:33 +00:00
随遇而安
7f4a87722b update README.md. 2022-04-09 19:39:09 +00:00
随遇而安
1e6d392a24 update README.md. 2022-04-09 19:38:05 +00:00
随遇而安
0998dae5d4 update README.md. 2022-04-09 19:36:54 +00:00
随遇而安
446119aa5e update README.md. 2022-04-09 19:35:51 +00:00
随遇而安
182689204d update app/README.md. 2022-04-09 19:32:55 +00:00
随遇而安
8fdfcf1251 update app/README.md. 2022-04-09 19:30:54 +00:00
随遇而安
873fe19f9e update README.md. 2022-04-09 17:54:02 +00:00
kerwincui
462d5d38f8 Revert "!8 APP显示新闻模块"
This reverts commit e28c829613, reversing
changes made to 734f3e7f9d.
2022-04-09 18:53:14 +08:00
随遇而安
e28c829613 !8 APP显示新闻模块
Merge pull request !8 from sxh/master
2022-04-09 07:17:33 +00:00
sxh
af30a8d2cd 新增新闻模块(新闻分类和新闻资讯),采取多对一的模式,前端富文本新增三个依赖(支持图片拖放与缩放) 2022-04-09 14:59:05 +08:00
随遇而安
734f3e7f9d update app/README.md. 2022-04-09 05:52:59 +00:00
随遇而安
e2df0340cf update app/README.md. 2022-04-09 05:48:14 +00:00
随遇而安
e80e04351e update README.md. 2022-04-09 04:55:24 +00:00
kerwincui
cffa1ec5e8 添加apk 2022-04-09 12:49:58 +08:00
随遇而安
e6d67faaf9 update README.md. 2022-04-08 06:46:29 +00:00
kerwincui
8dde2fea92 修复bug 2022-04-08 13:23:30 +08:00
kerwincui
77178e05e8 更新图片上传组件 2022-04-08 11:24:37 +08:00
kerwincui
0521511dfd 暂时注释oauth配置 2022-04-08 11:24:09 +08:00
kerwincui
f646a360ad 添加配置 2022-04-07 01:36:43 +08:00
kerwincui
187e0e2244 修复前端bug 2022-04-07 01:35:59 +08:00
随遇而安
ee56d4ab64 update README.md. 2022-04-06 05:47:39 +00:00
随遇而安
c8207a007b update README.md. 2022-04-06 05:41:37 +00:00
随遇而安
c8a2c752c4 update README.md. 2022-04-04 07:55:11 +00:00
随遇而安
d3a8ec0a1e update README.md. 2022-04-04 07:53:55 +00:00
随遇而安
abf4229bae update README.md. 2022-04-04 07:52:41 +00:00
随遇而安
775da3c22b update README.md. 2022-04-04 07:30:16 +00:00
随遇而安
c1891dc005 update README.md. 2022-04-04 07:04:46 +00:00
随遇而安
9ab21a2d8d update README.md. 2022-04-02 05:24:40 +00:00
随遇而安
0d31f3aef9 update README.md. 2022-03-27 14:20:27 +00:00
随遇而安
02f7bd8969 update README.md. 2022-03-27 05:35:10 +00:00
随遇而安
ba0ee06f63 update README.md. 2022-03-27 05:29:02 +00:00
随遇而安
f649065d6c update README.md. 2022-03-25 12:21:01 +00:00
随遇而安
b91a823c95 update README.md. 2022-03-25 12:06:08 +00:00
随遇而安
00d5bd9bb5 update README.md. 2022-03-25 12:04:58 +00:00
随遇而安
28aa2f32bc update README.md. 2022-03-25 11:59:36 +00:00
随遇而安
5170305537 update vue/src/views/monitor/cache/index.vue. 2022-03-24 09:13:30 +00:00
随遇而安
9d923b3a08 update README.md. 2022-03-23 07:44:57 +00:00
随遇而安
41a6fdb6cd update README.md. 2022-03-23 07:42:41 +00:00
kerwincui
e3c0946553 更新yml配置 2022-03-23 14:42:02 +08:00
kerwincui
977261156b 更新配置 2022-03-23 14:27:22 +08:00
kerwincui
ff37b79f4d 忽略配置 2022-03-23 14:25:56 +08:00
kerwincui
06e7186e13 删除无用的配置 2022-03-23 14:24:19 +08:00
kerwincui
6b5ae7d2f6 更新忽略文件 2022-03-23 14:23:38 +08:00
kerwincui
5852c2ae20 更新配置 2022-03-23 14:18:44 +08:00
kerwincui
5c79a1d839 删除无用的配置文件 2022-03-23 14:17:09 +08:00
随遇而安
ad1a7a0c4c update springboot/wumei-admin/src/main/resources/application.yml. 2022-03-23 05:42:45 +00:00
随遇而安
4bbcb17f9f update springboot/wumei-admin/src/main/resources/application.yml. 2022-03-23 05:05:44 +00:00
随遇而安
be5b940a9f !7 线程池配置
Merge pull request !7 from guanshubiao/master
2022-03-23 04:56:57 +00:00
guanshubiao
600c3a4f0e 线程池的配置 2022-03-23 12:53:46 +08:00
kerwincui
503c0dddd6 update spring boot yml config 2022-03-23 00:20:43 +08:00
随遇而安
f118ab4cc7 !6 mqtt异步客户端+接收主题的业务在线程池处理
Merge pull request !6 from guanshubiao/master
2022-03-22 16:16:40 +00:00
guanshubiao
c3a991cf9c Merge remote-tracking branch 'origin/master'
# Conflicts:
#	springboot/wumei-admin/src/main/resources/application.yml
2022-03-22 23:53:35 +08:00
随遇而安
9793885107 update README.md. 2022-03-22 13:46:29 +00:00
随遇而安
401cb9846d update README.md. 2022-03-22 13:43:52 +00:00
随遇而安
8d8b2d2bb0 update README.md. 2022-03-22 13:43:02 +00:00
随遇而安
4cb4d209cf update README.md. 2022-03-22 13:41:40 +00:00
kerwincui
f34697803f 更新图片 2022-03-22 20:24:19 +08:00
kerwincui
b205f9a922 更新配置文件 2022-03-22 17:32:50 +08:00
随遇而安
bb94b3f003 update springboot/wumei-admin/src/main/resources/application.yml. 2022-03-22 09:28:21 +00:00
kerwincui
3253ef9ab4 docker配置文件更新 2022-03-22 17:03:10 +08:00
kerwincui
7a7e9827ca 更新sql 2022-03-22 17:02:56 +08:00
kerwincui
d5367fc414 修复实时监测报错问题 2022-03-22 17:02:46 +08:00
guanshubiao
940a9eda63 1.添加异步客户端MqttAsyncClient,创建client加锁,确保client唯一
2.添加线程池处理接收主题的业务事件
2022-03-22 16:06:36 +08:00
kerwincui
36f98dc3cb 更新图片 2022-03-22 10:54:04 +08:00
kerwincui
47c94df5cf 更新配置文件 2022-03-21 17:59:15 +08:00
kerwincui
389fb975c3 更新图片 2022-03-21 00:05:47 +08:00
kerwincui
cdb13035ea 添加docker相关文件 2022-03-20 23:57:07 +08:00
kerwincui
d05dd8fc62 添加Docker相关文件 2022-03-20 12:59:49 +08:00
随遇而安
6c7b3549ce update README.md. 2022-03-20 02:14:42 +00:00
随遇而安
7eb45e1590 update vue/.env.staging. 2022-03-19 14:23:56 +00:00
随遇而安
24049b5e54 update vue/.env.production. 2022-03-19 14:23:39 +00:00
随遇而安
8ed517e181 update vue/.env.development. 2022-03-19 14:23:24 +00:00
随遇而安
1f3326f16f update README.md. 2022-03-18 17:58:24 +00:00
随遇而安
9b38ba2fce update README.md. 2022-03-18 17:56:25 +00:00
随遇而安
6a35304341 update README.md. 2022-03-18 17:53:41 +00:00
随遇而安
5a39be4df6 update README.md. 2022-03-18 17:53:10 +00:00
随遇而安
e47b417f4e update README.md. 2022-03-18 17:50:12 +00:00
kerwincui
23edf7e794 接收设备消息的异常处理 2022-03-18 22:02:20 +08:00
kerwincui
1bc1fbb354 修复设备显示和Webhook时间戳问题 2022-03-18 20:28:15 +08:00
随遇而安
d81d612b1c !4 修复mqtt相关bug
Merge pull request !4 from guanshubiao/master
2022-03-18 12:14:31 +00:00
guanshubiao
3cd360e429 修复bug1-mqtt断开重连时,topic没有订阅。
修复bug2-上报property数据,如果数据解析异常,客户端将断开。
2022-03-18 14:45:07 +08:00
随遇而安
9b2c23f51a !3 修改bug
Merge pull request !3 from guanshubiao/master
2022-03-17 16:02:07 +00:00
guanshubiao
7d06b42ea6 修改bug-添加认证失败处理类 导致启用自定义认证会导致oauth授权地址不能访问 2022-03-17 23:33:48 +08:00
随遇而安
ef8e262d08 update README.md. 2022-03-17 06:36:50 +00:00
随遇而安
4eb4b43673 update README.md. 2022-03-17 06:35:13 +00:00
kerwincui
cb2bb065f9 添加图片 2022-03-17 13:26:09 +08:00
kerwincui
78fe543e5b 更新图片 2022-03-17 13:20:59 +08:00
随遇而安
759323313b update README.md. 2022-03-17 05:19:21 +00:00
kerwincui
89ecf1f29a 更新图片 2022-03-17 13:16:36 +08:00
随遇而安
5122c3f932 update README.md. 2022-03-17 05:05:15 +00:00
kerwincui
c28dc9c663 添加图片 2022-03-17 13:04:05 +08:00
随遇而安
012b373289 update README.md. 2022-03-17 04:55:44 +00:00
随遇而安
9c10303c47 update README.md. 2022-03-17 04:52:34 +00:00
随遇而安
50399c2271 update README.md. 2022-03-17 04:47:18 +00:00
随遇而安
1adcfae81d update README.md. 2022-03-17 04:45:14 +00:00
kerwincui
3486bff376 更新图片 2022-03-17 12:29:55 +08:00
随遇而安
7b796183d1 update README.md. 2022-03-16 06:16:18 +00:00
kerwincui
8b9b34ce41 发布v1.1版本 2022-03-16 14:10:17 +08:00
kerwincui
808b7a20bf 更新springboot文件夹 2022-03-16 14:03:55 +08:00
kerwincui
5baa1af72e 更新vue文件夹 2022-03-16 14:03:27 +08:00
kerwincui
3a8973a50a 更新小程序文件夹 2022-03-16 14:02:36 +08:00
kerwincui
f52751af82 更新docker文件夹 2022-03-16 14:02:09 +08:00
kerwincui
8bb86e9501 更新安卓文件夹 2022-03-16 14:01:34 +08:00
kerwincui
a8b82e97f7 更新firmware文件夹 2022-03-16 14:01:11 +08:00
kerwincui
8dabf88501 update license 2022-03-16 13:59:46 +08:00
kerwincui
2763de5f2e update document 2022-03-16 13:58:16 +08:00
随遇而安
7aa4bbe8b3 update spring-boot/pom.xml. 2022-03-07 03:57:26 +00:00
随遇而安
e813fd6ec9 update README.md. 2022-02-27 04:56:08 +00:00
kerwincui
a3336ccc3f 添加sql和安卓app 2022-02-27 12:51:02 +08:00
随遇而安
04a603732d update README.md. 2022-02-24 14:07:20 +00:00
随遇而安
b84193b053 update README.md. 2022-02-12 08:05:32 +00:00
随遇而安
ffd5a1269b update README.md. 2022-02-09 18:36:56 +00:00
随遇而安
9c8a3e8779 update README.md. 2022-02-07 16:02:45 +00:00
随遇而安
2427259171 update README.md. 2022-02-07 16:01:45 +00:00
随遇而安
ff7da228f1 update README.md. 2022-01-26 18:56:17 +00:00
随遇而安
050ff7c2d3 update README.md. 2022-01-26 15:01:45 +00:00
随遇而安
d66ada3b0b update README.md. 2022-01-15 11:26:34 +00:00
xiaoyi
836fd3f85b [fix] 更新数据库,调整编码格式为utf8_general_ci,解决前端部署数据库异常问题 2022-01-10 14:54:51 +08:00
随遇而安
14d64c6f73 update README.md. 2021-12-29 16:45:11 +00:00
随遇而安
2fcdca1274 update README.md. 2021-12-01 13:58:37 +00:00
xiaoyi
b9cddf96a8 [update] 更新配置参数和SQL内容 2021-11-24 11:02:08 +08:00
xiaoyi
9cd0c02dfc [update] 支持通过小程序下发自定义命令,优化管理员可彻底删除页面功能 2021-11-18 20:28:31 +08:00
随遇而安
542f9fa448 !2 修改了用户管理界面报错问题
Merge pull request !2 from crazyDull/bugfix/修改用户管理报错问题
2021-09-28 15:36:15 +00:00
[347954141@qq.com]
0580fbb8e7 修改错误问题 2021-09-28 19:09:29 +08:00
kerwincui
ffc733aa2d 删除idea配置 2021-09-12 18:11:42 +08:00
kerwincui
da7b3e9b3b 删除stm32代码 2021-09-12 18:10:28 +08:00
kerwincui
0d904cdc23 删除stm32代码 2021-09-12 18:10:08 +08:00
kerwincui
0613cd4373 删除stm32代码 2021-09-12 18:09:54 +08:00
kerwincui
45a3e7d140 删除stm32代码 2021-09-12 18:09:42 +08:00
kerwincui
bfd491b1bd 删除stm32代码 2021-09-12 18:09:29 +08:00
kerwincui
5bbdd075b1 删除stm32代码 2021-09-12 18:09:07 +08:00
kerwincui
128eea7f82 删除stm32代码 2021-09-12 18:08:50 +08:00
kerwincui
ae938f5dec 删除stm32代码 2021-09-12 18:07:05 +08:00
kerwincui
232feec794 删除stm32代码 2021-09-12 18:06:38 +08:00
kerwincui
fa91c71ce1 删除stm32代码 2021-09-12 18:06:07 +08:00
kerwincui
7b96b852af 删除stm32代码 2021-09-12 18:05:51 +08:00
kerwincui
ad430ea6f3 删除stm32代码 2021-09-12 18:05:10 +08:00
kerwincui
dfb021b1af 删除stm32代码 2021-09-12 18:04:59 +08:00
kerwincui
8c14d18802 删除stm32代码 2021-09-12 18:04:49 +08:00
kerwincui
abc22ba4bc 删除stm32代码 2021-09-12 18:04:37 +08:00
kerwincui
8d8c5b7d3b 删除stm32代码 2021-09-12 18:04:23 +08:00
kerwincui
4998ceb93b 删除stm32代码 2021-09-12 18:04:05 +08:00
kerwincui
8aca9b4c7d 删除stm32代码 2021-09-12 18:03:50 +08:00
kerwincui
1f7f14d214 删除stm32代码 2021-09-12 18:03:39 +08:00
kerwincui
ae57373818 删除stm32代码 2021-09-12 18:03:04 +08:00
kerwincui
1d1df08df8 删除stm32代码 2021-09-12 18:02:38 +08:00
随遇而安
1fb37828a7 !1 增加微信登录接口
Merge pull request !1 from 小驿物联/master
2021-09-12 09:50:08 +00:00
yueming
b0605eb980 修订 2021-09-06 15:06:35 +08:00
qianlile
f23caa6742 Merge branch 'master' of gitee.com:iot_camp/wumei-smart 2021-09-06 11:55:01 +08:00
qianlile
c708b0f16f 更新页面显示效果 2021-09-06 11:54:30 +08:00
月明L星稀
437143e01a update firmware/stm32-esp/README.md. 2021-09-05 16:25:07 +00:00
yueming
c71f437b98 修改简介 2021-09-06 00:22:06 +08:00
yueming
d9c4185983 连接服务器 2021-09-06 00:02:30 +08:00
随遇而安
e6b48fdc13 update README.md. 2021-09-05 09:32:32 +00:00
随遇而安
77d8ebabc6 update README.md. 2021-09-05 09:31:32 +00:00
xxmfl
a8bc50f67c 2021年9月2日10:07:12 1.增加微信小程序接口 2.4G开关功能接口 2021-09-02 10:08:27 +08:00
yueming
5c97293269 配网部分 2021-09-01 18:05:49 +08:00
月明L星稀
2365b8aab7 删除文件 firmware/stm32-esp/.keep 2021-09-01 06:04:46 +00:00
yueming
975adfb602 初始版本 2021-09-01 14:03:46 +08:00
月明L星稀
4e0dc1ed9d clear 2021-09-01 05:56:49 +00:00
乐明
d6ff7a2077 新建 stm32-esp 2021-09-01 01:49:15 +00:00
qianlile
7b673421ad Merge branch 'master' of gitee.com:iot_camp/wumei-smart 2021-08-30 19:27:14 +08:00
qianlile
df355a880b 添加意见反馈页面 2021-08-30 19:26:45 +08:00
xiaoyi
e8b5fffe19 [update] MQTT协议连接云平台成功 2021-08-30 18:51:08 +08:00
qianlile
e50ba21896 删除无用文件夹 2021-08-30 09:56:13 +08:00
随遇而安
bee5ff48f4 update README.md. 2021-08-28 07:58:00 +00:00
qianlile
33aecb6bda 微信登录版 2021-08-28 11:30:34 +08:00
qianlile
7af68fee6b 添加注册页面,修改4G设备的添加页面 2021-08-24 18:32:04 +08:00
kerwincui
545e8f45da 新增PCB文件、bom清单和v2.0版本数据库物理模型 2021-08-22 14:46:17 +08:00
xiaoyi
7838cfcbe0 compile ok after transfering mqtt protocol 2021-08-21 22:45:50 +08:00
qianlile
dbaee1db02 添加部分页面 2021-08-21 20:11:09 +08:00
qianlile
fe4902da1c Merge branch 'master' of gitee.com:iot_camp/wumei-smart 2021-08-17 13:36:57 +08:00
qianlile
a341927725 添加了一些页面 2021-08-17 13:36:34 +08:00
xiaoyi
cd72875761 Merge branch 'master' of gitee.com:kerwincui/wumei-smart 2021-08-17 11:44:05 +08:00
xiaoyi
10a6553c96 [update] 移植设备mqtt协议,暂未完成 2021-08-17 11:39:54 +08:00
kerwincui
a2898581bc 替换友盟仓库地址,解决gradle无法下载umeng问题 2021-08-14 12:46:17 +08:00
kerwincui
f85dc2e8d5 更新图片 2021-08-13 01:19:08 +08:00
kerwincui
fbd3fe258d 更新图片 2021-08-09 16:32:54 +08:00
随遇而安
8ef3e805db update README.md. 2021-08-06 14:42:31 +00:00
kerwincui
5a980a7043 添加系统结构图片 2021-08-05 15:39:33 +08:00
qianlile
7c061bbb9b 添加控制功能和页面逻辑 2021-07-29 11:11:14 +08:00
solitary
2096a6e755 Merge branch 'master' of gitee.com:iot_camp/wumei-smart 2021-07-27 23:28:23 +08:00
solitary
1e2280f69d [update] 串口使用DMA接收数据 2021-07-27 23:28:14 +08:00
qianlile
b16621221e 智慧宿舍系统小程序 2021-07-27 21:57:03 +08:00
solitary
8b2c22efe2 [update] 增加STM32智慧宿舍基础代码 2021-07-27 21:28:13 +08:00
4251 changed files with 75722 additions and 343352 deletions

View File

@@ -1,13 +0,0 @@
### 该问题是怎么引起的?
### 重现步骤
### 报错信息

View File

@@ -1,14 +0,0 @@
### 相关的Issue
### 原因(目的、解决的问题等)
### 描述(做了什么,变更了什么)
### 测试用例(新增、改动、可能影响的功能)

View File

@@ -0,0 +1,95 @@
version: '1.0'
name: pipeline-docker
displayName: 构建镜像
triggers:
trigger: auto
push:
branches:
precise:
- master
commitMessages:
include:
- ^deploy-docker
stages:
- name: stage-5ecf171c
displayName: 项目打包
strategy: naturally
trigger: auto
executor:
- kerwincui
steps:
- step: build@maven
name: build_maven
displayName: Maven 构建后端
jdkVersion: '8'
mavenVersion: 3.6.1
commands:
- cd ./springboot
- mvn -B clean package -Dmaven.test.skip=true
artifacts:
- name: BUILD_JAVA
path:
- ./springboot/wumei-admin/target/wumei-admin.jar
settings: []
strategy:
retry: '0'
- step: build@nodejs
name: build_nodejs
displayName: Nodejs 构建前端
nodeVersion: 14.16.0
commands:
- cd ./vue
- npm install --registry=https://registry.npm.taobao.org \
- '&& rm -rf ./dist && npm run build:prod'
artifacts:
- name: BUILD_VUE
path:
- ./vue/dist
strategy:
retry: '0'
- name: stage-f5631c9e
displayName: 上传打包文件
strategy: naturally
trigger: auto
executor:
- kerwincui
steps:
- step: publish@general_artifacts
name: publish_general_artifacts_java
displayName: 上传后端制品
dependArtifact: BUILD_JAVA
artifactName: springboot
strategy:
retry: '0'
- step: publish@general_artifacts
name: publish_general_artifacts_vue
displayName: 上传前端制品
dependArtifact: BUILD_VUE
artifactName: vue
strategy:
retry: '0'
- name: stage-59a550ac
displayName: 构建镜像
strategy: naturally
trigger: auto
executor:
- kerwincui
steps:
- step: build@docker
name: build_docker
displayName: 镜像构建
type: cert
certificate: kerwincui-docker
tag: kerwincui/wumei-smart:1.01
dockerfile: ./docker/Dockerfile
context: ./docker
artifacts:
- ${BUILD_JAVA}
- ${BUILD_VUE}
isCache: true
strategy:
retry: '0'
permissions:
- role: admin
members:
- kerwincui

View File

@@ -0,0 +1,64 @@
version: '1.0'
name: pipeline-java
displayName: 部署后端
triggers:
trigger: auto
push:
branches:
precise:
- master
commitMessages:
include:
- ^deploy-server
stages:
- name: stage-2c3f9607
displayName: 构建后端
strategy: naturally
trigger: auto
executor:
- kerwincui
steps:
- step: build@maven
name: build_maven
displayName: Maven 构建
jdkVersion: '8'
mavenVersion: 3.6.1
commands:
- cd ./springboot
- mvn -B clean package -Dmaven.test.skip=true
artifacts:
- name: BUILD_JAVA
path:
- ./springboot/wumei-admin/target/wumei-admin.jar
settings: []
strategy:
retry: '0'
- name: stage-b6625c4a
displayName: 部署后端
strategy: naturally
trigger: auto
executor:
- kerwincui
steps:
- step: deploy@agent
name: deploy_agent
displayName: 主机部署
hostGroupID: alicloud
deployArtifact:
- source: build
name: springboot
target: ~/gitee_go/deploy
dependArtifact: BUILD_JAVA
script: |-
# 请在此输入部署脚本如启动Java应用如下
# nohup java -jar test.jar > nohup.out &
echo 'Hello Gitee!'
touch springboot
strategy:
retry: '0'
strategy:
blocking: true
permissions:
- role: admin
members:
- kerwincui

View File

@@ -0,0 +1,60 @@
version: '1.0'
name: pipeline-vue
displayName: 部署前端
triggers:
trigger: auto
push:
branches:
precise:
- master
commitMessages:
include:
- ^deploy-vue
stages:
- name: stage-3761fd9a
displayName: 构建前端
strategy: naturally
trigger: auto
executor:
- kerwincui
steps:
- step: build@nodejs
name: build_nodejs
displayName: Nodejs 构建
nodeVersion: 14.16.0
commands:
- cd ./vue
- npm install --registry=https://registry.npm.taobao.org \
- '&& rm -rf ./dist && npm run build:prod'
artifacts:
- name: BUILD_VUE
path:
- ./vue/dist
strategy:
retry: '0'
- name: stage-79a96375
displayName: 部署前端
strategy: naturally
trigger: auto
executor:
- kerwincui
steps:
- step: deploy@agent
name: deploy_agent
displayName: 主机部署
hostGroupID: alicloud
deployArtifact:
- source: build
name: vue
target: ~/gitee_go/deploy
dependArtifact: BUILD_VUE
script: |-
# 请在此输入部署脚本如启动Java应用如下
# nohup java -jar test.jar > nohup.out &
echo 'Hello Gitee!' && touch vuetest
touch vue
strategy:
retry: '0'
permissions:
- role: admin
members: []

328
LICENSE
View File

@@ -1,127 +1,201 @@
木兰宽松许可证, 第2版
木兰宽松许可证, 第2版
2020年1月 http://license.coscl.org.cn/MulanPSL2
您对“软件”的复制、使用、修改及分发受木兰宽松许可证第2版“本许可证”的如下条款的约束
0. 定义
“软件”是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。
“贡献”是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。
“贡献者”是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。
“法人实体”是指提交贡献的机构及其“关联实体”。
“关联实体”是指对“本许可证”下的行为方而言控制、受控制或与其共同受控制的机构此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。
1. 授予版权许可
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。
2. 授予专利许可
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。
3. 无商标许可
“本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可但您为满足第4条规定的声明义务而必须使用除外。
4. 分发限制
您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。
5. 免责声明与责任限制
“软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。
6. 语言
“本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文版为准。
条款结束
如何将木兰宽松许可证第2版应用到您的软件
如果您希望将木兰宽松许可证第2版应用到您的新软件为了方便接收者查阅建议您完成如下三步
1 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字;
2 请您在软件包的一级目录下创建以“LICENSE”为名的文件将整个许可证文本放入该文件中
3 请将如下声明文本放入每个源文件的头部注释中。
Copyright (c) [Year] [name of copyright holder]
[Software Name] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
Mulan Permissive Software LicenseVersion 2
Mulan Permissive Software LicenseVersion 2 (Mulan PSL v2)
January 2020 http://license.coscl.org.cn/MulanPSL2
Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions:
0. Definition
Software means the program and related documents which are licensed under this License and comprise all Contribution(s).
Contribution means the copyrightable work licensed by a particular Contributor under this License.
Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License.
Legal Entity means the entity making a Contribution and all its Affiliates.
Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, control means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity.
1. Grant of Copyright License
Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not.
2. Grant of Patent License
Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken.
3. No Trademark License
No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in Section 4.
4. Distribution Restriction
You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software.
5. Disclaimer of Warranty and Limitation of Liability
THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW ITS CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
6. Language
THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL.
END OF THE TERMS AND CONDITIONS
How to Apply the Mulan Permissive Software LicenseVersion 2 (Mulan PSL v2) to Your Software
To apply the Mulan PSL v2 to your work, for easy identification by recipients, you are suggested to complete following three steps:
i Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner;
ii Create a file named “LICENSE” which contains the whole context of this License in the first directory of your software package;
iii Attach the statement to the appropriate annotated syntax at the beginning of each source file.
Copyright (c) [Year] [name of copyright holder]
[Software Name] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

192
README.md
View File

@@ -1,110 +1,156 @@
### 一、项目简介
1. **物美智能([wumei-smart](http://www.wumei.live/introduce.html))]是一套开源的软硬件系统,可用于二次开发和学习,快速搭建自己的智能家居系统。** 硬件工程师可以把自己的设备集成到系统;软件工程师可以使用项目中的设备熟悉软硬件交互。[演示视频 >>](https://space.bilibili.com/471004321)<br />
![说明](https://gitee.com/kerwincui/wumei-smart/raw/master/document/desc.png)<br /><br />
#### 1. 物美智能 [wumei-smart](http://wumei.live/) 是一个简单易用的生活物联网平台。可用于搭建物联网平台以及二次开发和学习。
2. 服务端使用spring boot、数据库mysql和redis、前端vue、移动端android、硬件端ESP-IDF和Arduino等。软硬件交互基于Mqtt协议使用EMQ代理服务器。系统架构图如下:
<br /><br />
![图片](https://gitee.com/kerwincui/wumei-smart/raw/master/document/sys.png)
![图片](https://gitee.com/kerwincui/wumei-smart/raw/master/document/sys2.png)
![图片](https://gitee.com/kerwincui/wumei-smart/raw/master/document/directory.png)
#### 2. 设备接入使用EMQX消息服务器加密认证后端采用Spring boot前端采用Vue移动端采用Uniapp数据库采用Mysql、TDengine和Redis设备端支持ESP32、ESP8266、树莓派等系统架构图如下:
<img src="https://oscimg.oschina.net/oscnet/up-98eefff896394066a60d664b875a3d05d1d.png" max-width="800" />
3. 硬件端提供接入文档需要设备支持网络功能项目里面包含ESP-IDF和Arduino的硬件代码和接入示例。同时制作了智能开关wifi通断器板子可用于学习和生活中控制2500W以下的用电设备。硬件完整示例代码采用ESP-IDF框架4.2版本基于乐鑫ESP32S2芯片安信可ESP-12K模组。[详情和购买方式 >> ](https://gitee.com/kerwincui/wumei-smart/wikis/pages?sort_id=4233922&doc_id=1506495)<br /><br />
![案例](https://gitee.com/kerwincui/wumei-smart/raw/master/document/case2.gif) <br />
* 手机、电脑远程控制
* 遥控配对、清码和控制
* 空气温湿度监控
* 雷达感应和报警
* 220V和5V电压供电阻性负载2500W感性负载250W
#### 3. 项目可用于个人学习和使用,商业用途需要赞助项目,获得授权。[查看详情 >>](https://wumei.live/doc/pages/sponsor/)
<br />
#### 4. 参考设备
| [空气检测仪](https://item.taobao.com/item.htm?spm=a1z10.1-c.w4004-22657217218.2.355d14963FSV69&id=623332279126) | [Wifi通断器](https://item.taobao.com/item.htm?spm=a1z10.3-c.w4002-22657217231.57.74076af5XpmsRi&id=651305232489&qq-pf-to=pcqq.group) | [智能插座](https://item.taobao.com/item.htm?spm=a1z0d.6639537.1997196601.63.4cc47484zEjJ34&id=675275353501) | [智能开关](https://item.taobao.com/item.htm?spm=a1z0d.6639537.1997196601.72.4cc47484zEjJ34&id=675278061047) | [Wifi通断器](https://item.taobao.com/item.htm?spm=a1z0d.6639537.1997196601.31.4cc47484zEjJ34&id=662773208714) |
| :----: | :----------: |:----------: |:----------: |:----------: |
| ![](https://oscimg.oschina.net/oscnet/up-ad98a81677e5e68d660866770e3266ca4cf.png) | ![](https://oscimg.oschina.net/oscnet/up-c38ce010e18349cfa526600c60e49792738.png) | ![](https://oscimg.oschina.net/oscnet/up-4ce09be3599e3ff7ed91fe182572abd258b.jpg) | ![](https://oscimg.oschina.net/oscnet/up-c4a7971510127324d6566dd6ea95d571483.jpg) | ![](https://oscimg.oschina.net/oscnet/up-e99eb758dc5abe387e880dbcb30ee21c063.jpg) |
### 二、相关开发板
1. NodeMCU开发板制作一个智能开关
![案例](https://gitee.com/kerwincui/wumei-smart/raw/master/document/case1.gif)
2. Wifi控制器和LED灯板制作七彩智能灯
![案例](https://gitee.com/kerwincui/wumei-smart/raw/master/document/case3.gif)
3. 物联网开发板 [详情和购买方式 >>](https://gitee.com/kerwincui/wumei-smart/wikis/pages?sort_id=4233922&doc_id=1506495)
![案例](https://gitee.com/kerwincui/wumei-smart/raw/master/document/case5.gif)
4. 物联网入门学习套件 [详情和购买方式 >>](https://gitee.com/kerwincui/wumei-smart/wikis/pages?sort_id=4233922&doc_id=1506495)
![案例](https://gitee.com/kerwincui/wumei-smart/raw/master/document/case4.gif)
<br />
### 三、技术栈
* 后端
- 相关技术Spring boot、MyBatis、Spring Security、Jwt、Mysql、Redis、Mongodb、Mqtt
### 二、功能
- 权限管理: 用户管理、部门管理、岗位管理、菜单管理、角色管理、字典和参数管理等
- 系统监控: 操作日志、登录日志、系统日志、在线用户、服务监控、连接池监控、缓存监控等
- 产品管理: 产品、产品物模型、产品分类、产品固件、授权码等
- 设备管理: 控制、分组、定时、日志、统计、定位、分享、配置、OTA升级、影子模式、实时监测、加密认证
- EMQ管理 Mqtt客户端、监听器、消息主题、消息订阅、插件管理、规则引擎、资源
- 硬件 SDK 支持WIFI和MQTT连接、物模型响应、实时监测、定时上报监测数据、AES加密、NTP时间等
- 物模型管理: 属性(设备状态和监测数据),功能(执行特定任务),事件(设备主动上报给云端)
- 其他功能多租户、统计、新闻资讯、通知公告、支持TDengine时序数据库
- 计划开发完善功能设备告警、场景联动、云云对接智能音箱、设备配网、第三方登录、短信登录、APP界面自定义、视频流处理
### 四、技术栈
* 服务端
- 相关技术Spring boot、MyBatis、Spring Security、Jwt、Mysql、Redis、TDengine、EMQX、Mqtt等
- 开发工具IDEA
*
* Web
- 相关技术ES6、Vue、Vuex、Vue-router、Vue-cli、Axios、Element-ui等
- 开发工具Visual Studio Code
* 安卓
- 相关技术:XUI、XPage、XAop、XHttp2等
- 开发工具:Android Studio
* 移动端Android / Ios / 微信小程序 / H5
- 相关技术:uniapp、[uView](https://www.uviewui.com/)、[uChart](https://www.ucharts.cn/)
- 开发工具:HBuilder
* 硬件端
- 相关技术: ESP-IDF、Arduino、FreeRTOS等
- 开发工具Visual Studio Code 和 Arduino
<br />
### 五、硬件接入
1. 设备认证
* 加密认证(推荐)
* 简单认证
* EMQX支持的其他认证方式
2. 设备交互
* 发布物模型、设备信息、时钟同步相关Mqtt主题
* 订阅物模型、设备升级、时钟同步相关Mqtt主题
### 四、快速部署系统
#### 1. 安装docker
#### 2. 命令窗口运行如下命令(完成后端、前端、数据库、EMQX部署)
###### 项目提供了示例SDK使用ESP8266芯片基于Arduino开发。设备烧录使用串口模块例如Ch340接线图如下
![烧录代码](https://oscimg.oschina.net/oscnet/up-ed61da9a62390de451715686d6a6b37c190.png)
### 六、项目目录
&nbsp;&nbsp;&nbsp;&nbsp; spring-boot --------------- 后端<br/>
&nbsp;&nbsp;&nbsp;&nbsp; vue ----------------------- 前端<br />
&nbsp;&nbsp;&nbsp;&nbsp; docker -------------------- docker部署文件<br />
&nbsp;&nbsp;&nbsp;&nbsp; sdk ----------------------- 硬件SDK<br />
&nbsp;&nbsp;&nbsp;&nbsp; app ----------------------- 移动端打包文件
###### 移动端适配多端
|安卓/Android|苹果/IOS|微信小程序| 网页/H5|Vue2.0
| :---: | :---: | :---: | :---: |:---: |
| √ | √| √ | √ | √ |
### 七、相关文档
##### 权限管理基于ruoyi-vue系统Mqtt消息服务器基于EMQX4.0开源版SDK示例使用ESP8266 Core For Arduino开发
* [项目文档](https://wumei.live/doc/)
* [物美智能官网](http://wumei.live/)
* [权限管理系统ruoyi-vue](https://gitee.com/y_project/RuoYi-Vue)
* [Mqtt消息服务器EMQX4.0](https://github.com/emqx/emqx)
* [ESP8266 Core For Arduino](https://github.com/esp8266/Arduino)
* [uCharts高性能跨平台图表库](https://www.ucharts.cn)
* [TDengine时序数据库](https://www.taosdata.com/?zh)
##### Docker快速安装
* Mysql中创建wumei-smart数据库[导入Sql脚本](https://gitee.com/kerwincui/wumei-smart/tree/master/springboot/sql)
* 修改命令中的Mysql配置并执行
```
docker run \
--name wumei-smart \
--env DB_HOST=localhost:3306 \
--env DB_NAME=wumei-smart \
--env DB_USER=root \
--env DB_PASSWORD=wumei-smart \
--publish 80:80 \
--publish 18083:18083 \
--publish 1883:1883 \
--publish 3306:3306 \
--publish 6379:6379 \
--restart always \
--publish 8083:8083 \
--volume /var/wumei-smart/java/uploadPath:/var/wumei-smart/java/uploadPath \
--restart unless-stopped \
--detach \
registry.cn-chengdu.aliyuncs.com/kerwincui/wumei-smart:1.0
kerwincui/wumei-smart:1.1
```
#### 3. 扫码下载APP安装,打开APP跳过登录配置服务端地址
![APP下载](https://gitee.com/kerwincui/wumei-smart/raw/master/document/download.png)
测试账号wumei admin123配置成功后默认账号admin admin123
### 八、其他
* 互助交流群1073236354
* [演示地址>>](https://iot.wumei.live/)
* 小程序演示
#### 4. 硬件代码烧录到设备
* [Arduino接入Demo](https://gitee.com/kerwincui/wumei-smart/tree/master/firmware/arduino)
* [ESP-IDF接入Demo](https://gitee.com/kerwincui/wumei-smart/tree/master/firmware/esp-idf)
![](https://oscimg.oschina.net/oscnet/up-a6feaa7aa6ea54551bd9feb97ebfb0ff206.jpg)
<br />
##### 项目贡献者
### 五、系统部分图片
![分类](https://gitee.com/kerwincui/wumei-smart/raw/master/document/a.png)
![设备列表](https://gitee.com/kerwincui/wumei-smart/raw/master/document/b.png)
![EMQX](https://gitee.com/kerwincui/wumei-smart/raw/master/document/c.png)
![设备详情](https://gitee.com/kerwincui/wumei-smart/raw/master/document/d.png)
![配置](https://gitee.com/kerwincui/wumei-smart/raw/master/document/e.png)
|[小驿物联](https://gitee.com/iot-xiaoyi) |[Guanshubiao](https://gitee.com/guanshubiao)|[CrazyDull](https://gitee.com/crazyDull) |[Kami0314](https://github.com/kami0314)|[YBZX](https://github.com/YBZX)
|--|--|--|--|--|
<br />
| [SXH](https://gitee.com/sixiaohu) | [Redamancy_zxp](https://gitee.com/redamancy-zxp) | [LEE](https://gitee.com/yueming188) | [LemonTree](https://gitee.com/fishhunterplus) | [Tang](https://gitee.com/mexiaotang)
|--|--|--|--|--|
### 六、相关教程
| [xxmfl](https://gitee.com/xxmfl) |
|--|
* [项目文档](https://gitee.com/kerwincui/wumei-smart/wikis/pages)
* [ESP-IDF完整固件代码](https://gitee.com/kerwincui/wumei-smart/tree/master/firmware/esp-idf/wumei-smart-firmware)
* [演示视频](https://space.bilibili.com/471004321)
* [硬件详情和购买方式](https://gitee.com/kerwincui/wumei-smart/wikis/pages?sort_id=4233922&doc_id=1506495)
* [物美智能官网](http://wumei.live)
* [若依文档](http://doc.ruoyi.vip/ruoyi-vue/)前端和后端基于Ruoyi-Vue前后端分离权限管理系统
* [XUI](https://gitee.com/xuexiangjys/XUI)Android基于XUI开发是一个简洁而优雅的原生UI框架
* [ESP-IDF编程指南](https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/index.html)
* [EMQ文档](https://docs.emqx.cn)
<br />
### 九、部分图片
![](https://oscimg.oschina.net/oscnet/up-75a392de73aff6110e7345399aed1cc78fb.png)
![](https://oscimg.oschina.net/oscnet/up-94aa4573358d29b485d71bb251964d2bfb3.png)
<table>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-60ff517f5362f4c7b98bb4cb3df543e4ecb.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-d9dd014cec34b6424eb6d768e362356a622.png"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-cefbaf28d2ea5438b17dbad53638852519b.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-20672c691106771f3a38168c0f6c6a7bf20.png"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-75e099216e1fa33f5e83989838ffd1b16fa.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-51d2ae913a83a542fc2c3b6f802dc34369f.png"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-287864587ec8116ee8be115a94d1d6f9302.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-2b0a744a83f939b6694dc33c7b80193029b.png"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-c8c388b20e70f6a668749aab94d214b8270.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-cc512e6367b55a3afa78bee7e1cd8c8cab9.png"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-457424f66db64e5e66d200d94a0d42358ad.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-bf47113b636fa96ceaf9607df795f8b3a17.png"/></td>
</tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-e05690366e11fb173cebafcba57b5567e38.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-f7856cca6a3dd60afafd1cb0e1ae67c596e.png"/></td>
</tr>
</table>
### 七、加入互助交流群:1073236354
<a target="_blank" href="https://qm.qq.com/cgi-bin/qm/qr?k=P_oc91N6KC39zp2PEV_-BY3xMnAokeZ8&jump_from=webapi"><img border="0" src="//pub.idqqimg.com/wpa/images/group.png" alt="物美智能wumeismart" title="物美智能wumeismart"></a>
<br /><br />
### 八、APP和管理端登录 &emsp;&emsp;测试账号wumei &emsp;密码admin123
* APP[进入下载界面>>>](https://gitee.com/kerwincui/wumei-smart/wikis/pages?sort_id=4203153&doc_id=1506495)
* 管理端:[进入登录界面>>>](http://iot.wumei.live/)

16
android/.gitignore vendored
View File

@@ -1,16 +0,0 @@
*.iml
.gradle
/LocalRepository
/keystores
/local.properties
/.idea/caches
/.idea/codeStyles
/.idea/inspectionProfiles
/.idea/libraries
/.idea/dictionaries
/.idea/markdown-navigator
/.idea/*.xml
.DS_Store
/build
/captures
.externalNativeBuild

View File

@@ -1,7 +0,0 @@
<component name="CopyrightManager">
<settings default="xuexiang">
<module2copyright>
<element module="Project Files" copyright="xuexiang" />
</module2copyright>
</settings>
</component>

View File

@@ -1,6 +0,0 @@
<component name="CopyrightManager">
<copyright>
<option name="notice" value="Copyright (C) &amp;#36;today.year xuexiangjys(xuexiangjys@163.com)&#10; &#10;Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);&#10;you may not use this file except in compliance with the License.&#10;You may obtain a copy of the License at&#10;&#10; http://www.apache.org/licenses/LICENSE-2.0&#10;&#10;Unless required by applicable law or agreed to in writing, software&#10;distributed under the License is distributed on an &quot;AS IS&quot; BASIS,&#10;WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&#10;See the License for the specific language governing permissions and&#10;limitations under the License.&#10;" />
<option name="myName" value="xuexiang" />
</copyright>
</component>

View File

@@ -1,191 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, "control" means (i) the power, direct or
indirect, to cause the direction or management of such entity, whether by
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising
permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.
"Object" form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object code,
generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made
available under the License, as indicated by a copyright notice that is included
in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative Works
thereof, that is intentionally submitted to Licensor for inclusion in the Work
by the copyright owner or by an individual or Legal Entity authorized to submit
on behalf of the copyright owner. For the purposes of this definition,
"submitted" means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor for
the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.
2. Grant of Copyright License.
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.
3. Grant of Patent License.
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
such license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by combination
of their Contribution(s) with the Work to which such Contribution(s) was
submitted. If You institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
Contribution incorporated within the Work constitutes direct or contributory
patent infringement, then any patent licenses granted to You under this License
for that Work shall terminate as of the date such litigation is filed.
4. Redistribution.
You may reproduce and distribute copies of the Work or Derivative Works thereof
in any medium, with or without modifications, and in Source or Object form,
provided that You meet the following conditions:
You must give any other recipients of the Work or Derivative Works a copy of
this License; and
You must cause any modified files to carry prominent notices stating that You
changed the files; and
You must retain, in the Source form of any Derivative Works that You distribute,
all copyright, patent, trademark, and attribution notices from the Source form
of the Work, excluding those notices that do not pertain to any part of the
Derivative Works; and
If the Work includes a "NOTICE" text file as part of its distribution, then any
Derivative Works that You distribute must include a readable copy of the
attribution notices contained within such NOTICE file, excluding those notices
that do not pertain to any part of the Derivative Works, in at least one of the
following places: within a NOTICE text file distributed as part of the
Derivative Works; within the Source form or documentation, if provided along
with the Derivative Works; or, within a display generated by the Derivative
Works, if and wherever such third-party notices normally appear. The contents of
the NOTICE file are for informational purposes only and do not modify the
License. You may add Your own attribution notices within Derivative Works that
You distribute, alongside or as an addendum to the NOTICE text from the Work,
provided that such additional attribution notices cannot be construed as
modifying the License.
You may add Your own copyright statement to Your modifications and may provide
additional or different license terms and conditions for use, reproduction, or
distribution of Your modifications, or for any such Derivative Works as a whole,
provided Your use, reproduction, and distribution of the Work otherwise complies
with the conditions stated in this License.
5. Submission of Contributions.
Unless You explicitly state otherwise, any Contribution intentionally submitted
for inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the terms of
any separate license agreement you may have executed with Licensor regarding
such Contributions.
6. Trademarks.
This License does not grant permission to use the trade names, trademarks,
service marks, or product names of the Licensor, except as required for
reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.
7. Disclaimer of Warranty.
Unless required by applicable law or agreed to in writing, Licensor provides the
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
including, without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise of
permissions under this License.
8. Limitation of Liability.
In no event and under no legal theory, whether in tort (including negligence),
contract, or otherwise, unless required by applicable law (such as deliberate
and grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special, incidental,
or consequential damages of any character arising as a result of this License or
out of the use or inability to use the Work (including but not limited to
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
any and all other commercial damages or losses), even if such Contributor has
been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability.
While redistributing the Work or Derivative Works thereof, You may choose to
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
other liability obligations and/or rights consistent with this License. However,
in accepting such obligations, You may act only on Your own behalf and on Your
sole responsibility, not on behalf of any other Contributor, and only if You
agree to indemnify, defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason of your
accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work
To apply the Apache License to your work, attach the following boilerplate
notice, with the fields enclosed by brackets "{}" replaced with your own
identifying information. (Don't include the brackets!) The text should be
enclosed in the appropriate comment syntax for the file format. We also
recommend that a file or class name and description of purpose be included on
the same "printed page" as the copyright notice for easier identification within
third-party archives.
Copyright 2018 xuexiangjys
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.

View File

@@ -1,5 +0,0 @@
Android项目打包
1. 修改工程根目录的gradle.properties中的isNeedPackage=true。
2. 添加并配置keystore在versions.gradle中修改app_release相关参数。
3. 如果考虑使用友盟统计的话在local.properties中设置应用的友盟ID:APP_ID_UMENG。
4. 使用./gradlew clean assembleReleaseChannels进行多渠道打包。

View File

@@ -1 +0,0 @@
/build

View File

@@ -1,138 +0,0 @@
apply plugin: 'com.android.application'
apply plugin: 'img-optimizer'
//打包时记得设置true启用
if (isNeedPackage.toBoolean() && isUseBooster.toBoolean()) {
apply plugin: 'com.didiglobal.booster'
}
android {
compileSdkVersion build_versions.target_sdk
buildToolsVersion build_versions.build_tools
defaultConfig {
applicationId "com.kerwin.wumei"
minSdkVersion 17
targetSdkVersion build_versions.target_sdk
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
vectorDrawables.useSupportLibrary = true
javaCompileOptions {
annotationProcessorOptions {
arguments = [ moduleName : project.getName() ]
}
}
}
signingConfigs {
if (isNeedPackage.toBoolean()) {
release {
storeFile file(app_release.storeFile)
storePassword app_release.storePassword
keyAlias app_release.keyAlias
keyPassword app_release.keyPassword
}
}
debug {
storeFile file("./debug.jks")
storePassword "123456"
keyAlias "debug"
keyPassword "123456"
}
}
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
if (isNeedPackage.toBoolean()) {
signingConfig signingConfigs.release
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
def appID = properties.getProperty("APP_ID_UMENG")
if (appID != null) {
buildConfigField "String", "APP_ID_UMENG", appID
} else {
buildConfigField "String", "APP_ID_UMENG", '""'
}
} else {
signingConfig signingConfigs.debug
buildConfigField "String", "APP_ID_UMENG", '""'
}
}
debug {
debuggable true
minifyEnabled false
signingConfig signingConfigs.debug
buildConfigField "String", "APP_ID_UMENG", '""'
}
}
lintOptions {
abortOnError false
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(path: ':esptouch')
testImplementation deps.junit
androidTestImplementation deps.runner
androidTestImplementation deps.espresso.core
//分包
implementation deps.androidx.multidex
implementation 'com.alibaba.android:vlayout:1.2.36'
//下拉刷新
implementation 'com.github.xuexiangjys.SmartRefreshLayout:refresh-header:1.1.5'
implementation 'com.github.xuexiangjys.SmartRefreshLayout:refresh-layout:1.1.5'
//WebView
implementation 'com.github.xuexiangjys.AgentWeb:agentweb-core:1.0.0'
implementation 'com.github.xuexiangjys.AgentWeb:agentweb-download:1.0.0'//选填
//腾讯的键值对存储mmkv
implementation 'com.tencent:mmkv:1.0.22'
//屏幕适配AutoSize
implementation 'me.jessyan:autosize:1.1.2'
//umeng统计
implementation 'com.umeng.umsdk:analytics:8.0.2'
implementation 'com.umeng.umsdk:common:2.0.2'
//预加载占位控件
implementation 'me.samlss:broccoli:1.0.0'
implementation 'com.zzhoujay.richtext:richtext:3.0.8'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
//ANR异常捕获
implementation 'com.github.anrwatchdog:anrwatchdog:1.4.0'
//美团多渠道打包
implementation 'com.meituan.android.walle:library:1.1.6'
//rxutil2
implementation deps.rxbinding
implementation 'com.github.xuexiangjys:rxutil2:1.2.0'
// circleprogressview 圆形进度动画控件
implementation 'com.king.view:circleprogressview:1.1.2'
}
//自动添加X-Library依赖
apply from: 'x-library.gradle'
//walle多渠道打包
apply from: 'multiple-channel.gradle'

View File

@@ -1,25 +0,0 @@
# 美团
meituan
# 三星
samsungapps
# 小米
xiaomi
# 91助手
91com
# 魅族
meizu
# 豌豆荚
wandou
# Google Play
googleplay
# 百度
baidu
# 360
360cn
# 应用宝
myapp
# 华为
huawei
# 蒲公英
pgyer
github

Binary file not shown.

View File

@@ -1,10 +0,0 @@
apply plugin: 'walle'
walle {
// 指定渠道包的输出路径
apkOutputFolder = new File("${project.buildDir}/outputs/channels")
// 定制渠道包的APK的文件名称
apkFileNameFormat = '${appName}-${packageName}-${channel}-${buildType}-v${versionName}-${versionCode}-${buildTime}.apk'
// 渠道配置文件
channelFile = new File("${project.getProjectDir()}/channel")
}

View File

@@ -1,276 +0,0 @@
#=========================================基础不变的混淆配置=========================================##
#指定代码的压缩级别
-optimizationpasses 5
#包名不混合大小写
-dontusemixedcaseclassnames
#不去忽略非公共的库类
-dontskipnonpubliclibraryclasses
# 指定不去忽略非公共的库的类的成员
-dontskipnonpubliclibraryclassmembers
#优化 不优化输入的类文件
-dontoptimize
#预校验
-dontpreverify
#混淆时是否记录日志
-verbose
# 混淆时所采用的算法
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
#保护注解
-keepattributes *Annotation*
#忽略警告
-ignorewarnings
##记录生成的日志数据,gradle build时在本项目根目录输出##
#apk 包内所有 class 的内部结构
-dump class_files.txt
#未混淆的类和成员
-printseeds seeds.txt
#列出从 apk 中删除的代码
-printusage unused.txt
#混淆前后的映射
-printmapping mapping.txt
# 并保留源文件名为"Proguard"字符串,而非原始的类名 并保留行号
-keepattributes SourceFile,LineNumberTable
########记录生成的日志数据gradle build时 在本项目根目录输出-end#####
#需要保留的东西
# 保持哪些类不被混淆
-keep public class * extends android.app.Fragment
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.support.v4.**
-keep public class com.android.vending.licensing.ILicensingService
#如果有引用v4包可以添加下面这行
-keep public class * extends android.support.v4.app.Fragment
##########JS接口类不混淆否则执行不了
-dontwarn com.android.JsInterface.**
-keep class com.android.JsInterface.** {*; }
#极光推送和百度lbs android sdk一起使用proguard 混淆的问题#http的类被混淆后导致apk定位失败保持apache 的http类不被混淆就好了
-dontwarn org.apache.**
-keep class org.apache.**{ *; }
-keep public class * extends android.view.View {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
public void set*(...);
}
#保持 native 方法不被混淆
-keepclasseswithmembernames class * {
native <methods>;
}
#保持自定义控件类不被混淆
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
#保持自定义控件类不被混淆
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
#保持 Parcelable 不被混淆
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
#保持 Serializable 不被混淆
-keepnames class * implements java.io.Serializable
#保持 Serializable 不被混淆并且enum 类也不被混淆
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
!private <fields>;
!private <methods>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
#保持枚举 enum 类不被混淆 如果混淆报错,建议直接使用上面的 -keepclassmembers class * implements java.io.Serializable即可
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keepclassmembers class * {
public void *ButtonClicked(android.view.View);
}
#不混淆资源类
-keep class **.R$* {*;}
#===================================混淆保护自己项目的部分代码以及引用的第三方jar包library=============================#######
#如果引用了v4或者v7包
-dontwarn android.support.**
# AndroidX 防止混淆
-dontwarn com.google.android.material.**
-dontnote com.google.android.material.**
-dontwarn androidx.**
-keep class com.google.android.material.** {*;}
-keep class androidx.** {*;}
-keep public class * extends androidx.**
-keep interface androidx.** {*;}
-keepclassmembers class * {
@androidx.annotation.Keep *;
}
# zxing
-dontwarn com.google.zxing.**
-keep class com.google.zxing.**{*;}
#SignalR推送
-keep class microsoft.aspnet.signalr.** { *; }
# 极光推送混淆
-dontoptimize
-dontpreverify
-dontwarn cn.jpush.**
-keep class cn.jpush.** { *; }
-dontwarn cn.jiguang.**
-keep class cn.jiguang.** { *; }
# 数据库框架OrmLite
-keepattributes *DatabaseField*
-keepattributes *DatabaseTable*
-keepattributes *SerializedName*
-keep class com.j256.**
-keepclassmembers class com.j256.** { *; }
-keep enum com.j256.**
-keepclassmembers enum com.j256.** { *; }
-keep interface com.j256.**
-keepclassmembers interface com.j256.** { *; }
#XHttp2
-keep class com.xuexiang.xhttp2.model.** { *; }
-keep class com.xuexiang.xhttp2.cache.model.** { *; }
-keep class com.xuexiang.xhttp2.cache.stategy.**{*;}
-keep class com.xuexiang.xhttp2.annotation.** { *; }
#okhttp
-dontwarn com.squareup.okhttp3.**
-keep class com.squareup.okhttp3.** { *;}
-dontwarn okio.**
-dontwarn javax.annotation.Nullable
-dontwarn javax.annotation.ParametersAreNonnullByDefault
-dontwarn javax.annotation.**
#如果用到Gson解析包的直接添加下面这几行就能成功混淆不然会报错
-keepattributes Signature
-keep class com.google.gson.stream.** { *; }
-keepattributes EnclosingMethod
-keep class org.xz_sale.entity.**{*;}
-keep class com.google.gson.** {*;}
-keep class com.google.**{*;}
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }
-keep class com.google.gson.examples.android.model.** { *; }
# Glide
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
# Retrofit
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Exceptions
# RxJava RxAndroid
-dontwarn sun.misc.**
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
long producerIndex;
long consumerIndex;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
rx.internal.util.atomic.LinkedQueueNode producerNode;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
rx.internal.util.atomic.LinkedQueueNode consumerNode;
}
-dontwarn okio.**
-dontwarn javax.annotation.Nullable
-dontwarn javax.annotation.ParametersAreNonnullByDefault
-dontwarn javax.annotation.**
# fastjson
-dontwarn com.alibaba.fastjson.**
-keep class com.alibaba.fastjson.** { *; }
-keepattributes Signature
# xpage
-keep class com.xuexiang.xpage.annotation.** { *; }
-keep class com.xuexiang.xpage.config.** { *; }
# xaop
-keep @com.xuexiang.xaop.annotation.* class * {*;}
-keep @org.aspectj.lang.annotation.* class * {*;}
-keep class * {
@com.xuexiang.xaop.annotation.* <fields>;
@org.aspectj.lang.annotation.* <fields>;
}
-keepclassmembers class * {
@com.xuexiang.xaop.annotation.* <methods>;
@org.aspectj.lang.annotation.* <methods>;
}
# xrouter
-keep public class com.xuexiang.xrouter.routes.**{*;}
-keep class * implements com.xuexiang.xrouter.facade.template.ISyringe{*;}
# 如果使用了 byType 的方式获取 Service需添加下面规则保护接口
-keep interface * implements com.xuexiang.xrouter.facade.template.IProvider
# 如果使用了 单类注入,即不定义接口实现 IProvider需添加下面规则保护实现
-keep class * implements com.xuexiang.xrouter.facade.template.IProvider
# xupdate
-keep class com.xuexiang.xupdate.entity.** { *; }
# xvideo
-keep class com.xuexiang.xvideo.jniinterface.** { *; }
# xipc
-keep @com.xuexiang.xipc.annotation.* class * {*;}
-keep class * {
@com.xuexiang.xipc.annotation.* <fields>;
}
-keepclassmembers class * {
@com.xuexiang.xipc.annotation.* <methods>;
}
# umeng统计
-keep class com.umeng.** {*;}
-keepclassmembers class * {
public <init> (org.json.JSONObject);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class com.xuexiang.xui.widget.edittext.materialedittext.** { *; }
## 接口请求使用了gson序列化的对象
-keep class com.kerwin.wumei.entity.** { *; }
-keep class com.kerwin.wumei.entity.vo.** { *; }
-keep class com.kerwin.wumei.entity.bo.** { *; }
-keep class com.kerwin.wumei.http.request.** { *; }
-keep class com.kerwin.wumei.http.** { *; }

View File

@@ -1,44 +0,0 @@
/*
* 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;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.kerwin.wumei", appContext.getPackageName());
}
}

View File

@@ -1,150 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.kerwin.wumei">
<!--进程杀死-->
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<application
android:name="com.kerwin.wumei.MyApp"
android:allowBackup="false"
android:configChanges="screenSize|keyboardHidden|orientation|keyboard"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:windowSoftInputMode="adjustPan|stateHidden"
tools:ignore="LockedOrientationActivity"
tools:targetApi="n">
<activity
android:name="com.kerwin.wumei.activity.SplashActivity"
android:configChanges="screenSize|keyboardHidden|orientation|keyboard"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.Launch.App"
android:windowSoftInputMode="adjustPan|stateHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.kerwin.wumei.activity.MainActivity"
android:configChanges="screenSize|keyboardHidden|orientation|keyboard"
android:screenOrientation="portrait"
android:theme="@style/AppTheme"
android:windowSoftInputMode="adjustPan|stateHidden" />
<activity
android:name="com.kerwin.wumei.activity.LoginActivity"
android:configChanges="screenSize|keyboardHidden|orientation|keyboard"
android:launchMode="singleInstance"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustPan|stateHidden" />
<activity
android:name="com.kerwin.wumei.activity.AddDeviceActivity"
android:configChanges="screenSize|keyboardHidden|orientation|keyboard"
android:screenOrientation="portrait"
android:launchMode="singleInstance"
android:theme="@style/AppTheme"
android:windowSoftInputMode="adjustPan|stateHidden" />
<!--通用浏览器-->
<activity
android:name="com.kerwin.wumei.core.webview.AgentWebActivity"
android:configChanges="screenSize|keyboardHidden|orientation|keyboard"
android:hardwareAccelerated="true"
android:label="@string/app_browser_name"
android:theme="@style/AppTheme">
<!-- Scheme -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="com.xuexiang.xui.applink" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:scheme="about" />
<data android:scheme="javascript" />
<!-- 设置自己的deeplink -->
<!-- <data-->
<!-- android:host="xxx.com"-->
<!-- android:scheme="xui"/>-->
</intent-filter>
<!-- AppLink -->
<intent-filter
android:autoVerify="true"
tools:targetApi="m">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:scheme="inline" />
<data android:mimeType="text/html" />
<data android:mimeType="text/plain" />
<data android:mimeType="application/xhtml+xml" />
<data android:mimeType="application/vnd.wap.xhtml+xml" />
<!-- 设置自己的applink -->
<!-- <data-->
<!-- android:host="xxx.com"-->
<!-- android:scheme="http"/>-->
<!-- <data-->
<!-- android:host="xxx.com"-->
<!-- android:scheme="https"/>-->
</intent-filter>
</activity>
<!--fragment的页面容器-->
<activity
android:name="com.kerwin.wumei.core.BaseActivity"
android:configChanges="screenSize|keyboardHidden|orientation|keyboard"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustPan|stateHidden" />
<!-- 版本更新提示-->
<activity
android:name="com.kerwin.wumei.utils.update.UpdateTipDialog"
android:screenOrientation="portrait"
android:theme="@style/DialogTheme" />
<!-- Webview拦截提示弹窗-->
<activity
android:name="com.kerwin.wumei.core.webview.WebViewInterceptDialog"
android:screenOrientation="portrait"
android:theme="@style/DialogTheme" />
<!-- applink的中转页面 -->
<activity
android:name="com.kerwin.wumei.core.XPageTransferActivity"
android:configChanges="screenSize|keyboardHidden|orientation|keyboard"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustPan|stateHidden" />
<!--屏幕自适应设计图-->
<meta-data
android:name="design_width_in_dp"
android:value="360" />
<meta-data
android:name="design_height_in_dp"
android:value="640" />
</application>
</manifest>

View File

@@ -1,17 +0,0 @@
{
"Code": 0,
"Data": [
{
"title": "微信公众号",
"content": "<a href=\"http://www.wumei.live\">获取更多资讯内容,欢迎微信搜索公众号:「我的Android开源之旅」</a>"
},
{
"title": "关于作者",
"content": "点击关注作者,了解最新动态!<br /><a href=\"https://gitee.com/kerwincui/wumei-smart\"><font color=\"#800080\">Gitee</font></a><br />"
},
{
"title": "QQ交流群",
"content": "<a href=\"https://qm.qq.com/cgi-bin/qm/qr?k=P_oc91N6KC39zp2PEV_-BY3xMnAokeZ8\">物美智能交流群</a><br />"
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -1,115 +0,0 @@
package com.kerwin.wumei;
import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.LocationManager;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.util.Log;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;
import androidx.multidex.MultiDex;
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;
/**
* @author xuexiang
* @since 2018/11/7 下午1:12
*/
public class MyApp extends Application {
private static MyApp app;
private MutableLiveData<String> mBroadcastData;
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action == null) {
return;
}
switch (action) {
case WifiManager.NETWORK_STATE_CHANGED_ACTION:
case LocationManager.PROVIDERS_CHANGED_ACTION:
mBroadcastData.setValue(action);
break;
}
}
};
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
//解决4.x运行崩溃的问题
MultiDex.install(this);
}
@Override
public void onCreate() {
super.onCreate();
initLibs();
app = this;
mBroadcastData = new MutableLiveData<>();
IntentFilter filter = new IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
filter.addAction(LocationManager.PROVIDERS_CHANGED_ACTION);
}
registerReceiver(mReceiver, filter);
}
@Override
public void onTerminate() {
super.onTerminate();
unregisterReceiver(mReceiver);
}
public static MyApp getInstance() {
return app;
}
public void observeBroadcast(LifecycleOwner owner, Observer<String> observer) {
mBroadcastData.observe(owner, observer);
}
/**
* 初始化基础库
*/
private void initLibs() {
XBasicLibInit.init(this);
XUpdateInit.init(this);
//运营统计数据运行时不初始化
if (!MyApp.isDebug()) {
UMengInit.init(this);
}
//ANR监控
ANRWatchDogInit.init();
}
/**
* @return 当前app是否是调试开发模式
*/
public static boolean isDebug() {
return BuildConfig.DEBUG;
}
}

View File

@@ -1,384 +0,0 @@
package com.kerwin.wumei.activity;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.LocationManager;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.core.location.LocationManagerCompat;
import com.espressif.iot.esptouch.EsptouchTask;
import com.espressif.iot.esptouch.IEsptouchResult;
import com.espressif.iot.esptouch.IEsptouchTask;
import com.espressif.iot.esptouch.util.ByteUtil;
import com.espressif.iot.esptouch.util.TouchNetUtil;
import com.kerwin.wumei.R;
import com.kerwin.wumei.adapter.entity.EspTouchViewModel;
import com.kerwin.wumei.core.BaseActivity;
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.xutil.display.Colors;
import java.lang.ref.WeakReference;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class AddDeviceActivity extends BaseActivity {
// begin esptouch -------------------------------------
private static final String TAG = AddDeviceActivity.class.getSimpleName();
private static final int REQUEST_PERMISSION = 0x01;
private EspTouchViewModel mViewModel;
private EsptouchAsyncTask4 mTask;
private WifiManager mWifiManager;
private List<String> ssids;
private String selectedSSID;
public String GetSelectedSSID(){
return selectedSSID;
}
public List<String> GetSsids(){
return ssids;
}
public EspTouchViewModel GetMViewModel(){
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;
CharSequence ssidStr=mViewModel.ssidSpinner.getText();
byte[] ssid= ByteUtil.getBytesByString(ssidStr.toString());
CharSequence pwdStr = mViewModel.apPasswordEdit.getText();
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)};
int count = mViewModel.xsbDeviceCount.getSelectedNumber();
byte[] deviceCount = String.valueOf(count).getBytes();
if (mTask != null) {
mTask.cancelEsptouch();
}
mTask = new EsptouchAsyncTask4(this);
mTask.execute(ssid, bssid, password, deviceCount, broadcast);
}
public void onWifiChanged() {
StateResult stateResult = check();
mViewModel.message = stateResult.message;
mViewModel.ssid = stateResult.ssid;
mViewModel.ssidBytes = stateResult.ssidBytes;
mViewModel.bssid = stateResult.bssid;
mViewModel.confirmEnable = false;
if (stateResult.wifiConnected) {
mViewModel.confirmEnable = true;
if (stateResult.is5G) {
mViewModel.message = getString(R.string.esptouch1_wifi_5g_message);
}
} else {
if (mTask != null) {
mTask.cancelEsptouch();
mTask = null;
new AlertDialog.Builder(AddDeviceActivity.this)
.setMessage(R.string.esptouch1_configure_wifi_change_message)
.setNegativeButton(android.R.string.cancel, null)
.show();
}
}
mViewModel.invalidateAll();
}
protected static class StateResult {
public CharSequence message = null;
public boolean permissionGranted = false;
public boolean locationRequirement = false;
public boolean wifiConnected = false;
public boolean is5G = false;
public InetAddress address = null;
public String ssid = null;
public byte[] ssidBytes = null;
public String bssid = null;
}
private StateResult check() {
StateResult result = checkPermission();
if (!result.permissionGranted) {
return result;
}
result = checkLocation();
result.permissionGranted = true;
if (result.locationRequirement) {
return result;
}
result = checkWifi();
result.permissionGranted = true;
result.locationRequirement = false;
return result;
}
protected StateResult checkWifi() {
StateResult result = new StateResult();
result.wifiConnected = false;
WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
// 获取wifi列表
mWifiManager.startScan();
List<ScanResult> scanWifiList = mWifiManager.getScanResults();
List<ScanResult> wifiList = new ArrayList<>();
ssids=new ArrayList<>();
if (scanWifiList != null && scanWifiList.size() > 0) {
HashMap<String, Integer> signalStrength = new HashMap<String, Integer>();
for (int i = 0; i < scanWifiList.size(); i++) {
ScanResult scanResult = scanWifiList.get(i);
Log.e(TAG, "搜索的wifi-ssid:" + scanResult.SSID);
if (!scanResult.SSID.isEmpty()) {
String key = scanResult.SSID + " " + scanResult.capabilities;
if (!signalStrength.containsKey(key)) {
signalStrength.put(key, i);
wifiList.add(scanResult);
ssids.add(scanResult.SSID);
}
}
}
}
boolean connected = NetUtils.isWifiConnected(mWifiManager);
if (!connected) {
result.message = getString(R.string.esptouch_message_wifi_connection);
return result;
}
String ssid = NetUtils.getSsidString(wifiInfo);
selectedSSID=ssid;
int ipValue = wifiInfo.getIpAddress();
if (ipValue != 0) {
result.address = NetUtils.getAddress(wifiInfo.getIpAddress());
} else {
result.address = NetUtils.getIPv4Address();
if (result.address == null) {
result.address = NetUtils.getIPv6Address();
}
}
result.wifiConnected = true;
result.message = "";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
result.is5G = NetUtils.is5G(wifiInfo.getFrequency());
}
if (result.is5G) {
result.message = getString(R.string.esptouch_message_wifi_frequency);
}
result.ssid = ssid;
result.ssidBytes = NetUtils.getRawSsidBytesOrElse(wifiInfo, ssid.getBytes());
result.bssid = wifiInfo.getBSSID();
return result;
}
protected StateResult checkLocation() {
StateResult result = new StateResult();
result.locationRequirement = true;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
LocationManager manager = getSystemService(LocationManager.class);
boolean enable = manager != null && LocationManagerCompat.isLocationEnabled(manager);
if (!enable) {
result.message = getString(R.string.esptouch_message_location);
return result;
}
}
result.locationRequirement = false;
return result;
}
protected StateResult checkPermission() {
StateResult result = new StateResult();
result.permissionGranted = false;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
boolean locationGranted = checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED;
if (!locationGranted) {
String[] splits = getString(R.string.esptouch_message_permission).split("\n");
if (splits.length != 2) {
throw new IllegalArgumentException("Invalid String @RES esptouch_message_permission");
}
SpannableStringBuilder ssb = new SpannableStringBuilder(splits[0]);
ssb.append('\n');
SpannableString clickMsg = new SpannableString(splits[1]);
ForegroundColorSpan clickSpan = new ForegroundColorSpan(0xFF0022FF);
clickMsg.setSpan(clickSpan, 0, clickMsg.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
ssb.append(clickMsg);
result.message = ssb;
return result;
}
}
result.permissionGranted = true;
return result;
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == REQUEST_PERMISSION) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
onWifiChanged();
} else {
new AlertDialog.Builder(this)
.setTitle(R.string.esptouch1_location_permission_title)
.setMessage(R.string.esptouch1_location_permission_message)
.setCancelable(false)
.setPositiveButton(android.R.string.ok, (dialog, which) -> finish())
.show();
}
return;
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
/**
* 中断配网任务
*/
public void interruptEspTouchTask(){
if (mEsptouchTask != null) {
mEsptouchTask.interrupt();
}
}
public class EsptouchAsyncTask4 extends AsyncTask<byte[], IEsptouchResult, List<IEsptouchResult>> {
private WeakReference<AddDeviceActivity> mActivity;
private final Object mLock = new Object();
EsptouchAsyncTask4(AddDeviceActivity activity) {
mActivity = new WeakReference<>(activity);
}
public void cancelEsptouch() {
cancel(true);
if (mEsptouchTask != null) {
mEsptouchTask.interrupt();
}
}
@Override
protected void onPreExecute() {
addDeviceFragment = (AddDeviceFragment) getSupportFragmentManager().getFragments().get(0);
addDeviceFragment.beginCounter();
}
@Override
protected void onProgressUpdate(IEsptouchResult... values) {
Context context = mActivity.get();
if (context != null) {
IEsptouchResult result = values[0];
Log.i(TAG, "EspTouchResult: " + result);
String text = result.getBssid() + " is connected to the wifi";
Toast.makeText(context, text, Toast.LENGTH_SHORT).show();
}
}
@Override
protected List<IEsptouchResult> doInBackground(byte[]... params) {
AddDeviceActivity activity = mActivity.get();
int taskResultCount;
synchronized (mLock) {
byte[] apSsid = params[0];
byte[] apBssid = params[1];
byte[] apPassword = params[2];
byte[] deviceCountData = params[3];
byte[] broadcastData = params[4];
taskResultCount = deviceCountData.length == 0 ? -1 : Integer.parseInt(new String(deviceCountData));
Context context = activity.getApplicationContext();
mEsptouchTask = new EsptouchTask(apSsid, apBssid, apPassword, context);
mEsptouchTask.setPackageBroadcast(broadcastData[0] == 1);
mEsptouchTask.setEsptouchListener(this::publishProgress);
}
return mEsptouchTask.executeForResults(taskResultCount);
}
@Override
protected void onPostExecute(List<IEsptouchResult> result) {
AddDeviceActivity activity = mActivity.get();
activity.mTask = null;
if (result == null) {
addDeviceFragment.showMessage("建立 EspTouch 任务失败, 端口可能被其他程序占用",false);
addDeviceFragment.cancleCounter();
return;
}
// check whether the task is cancelled and no results received
IEsptouchResult firstResult = result.get(0);
if (firstResult.isCancelled()) {
return;
}
if (!firstResult.isSuc()) {
addDeviceFragment.showMessage("配网失败",false);
addDeviceFragment.cancleCounter();
return;
}
String message="";
for (IEsptouchResult touchResult : result) {
message += "BSSID: "+touchResult.getBssid()+"\n 地址: "+touchResult.getInetAddress().getHostAddress()+"\n";
}
addDeviceFragment.completeCounter();
addDeviceFragment.showMessage("完成配网\n"+message,true);
}
}
// end esptouch ----------------------------------------
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mWifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE);
mViewModel = new EspTouchViewModel();
}
@Override
protected boolean isSupportSlideBack() {
return true;
}
@Override
protected void initStatusBarStyle() {
StatusBarUtils.initStatusBarStyle(this, false, Colors.WHITE);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return KeyboardUtils.onDisableBackKeyDown(keyCode) && super.onKeyDown(keyCode, event);
}
}

View File

@@ -1,37 +0,0 @@
package com.kerwin.wumei.activity;
import android.os.Bundle;
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;
public class LoginActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
openPage(LoginFragment.class, getIntent().getExtras());
}
@Override
protected boolean isSupportSlideBack() {
return false;
}
@Override
protected void initStatusBarStyle() {
StatusBarUtils.initStatusBarStyle(this, false, Colors.WHITE);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return KeyboardUtils.onDisableBackKeyDown(keyCode) && super.onKeyDown(keyCode, event);
}
}

View File

@@ -1,380 +0,0 @@
/*
* 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.activity;
import android.Manifest;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.location.LocationManager;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
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;
import com.espressif.iot.esptouch.util.ByteUtil;
import com.espressif.iot.esptouch.util.TouchNetUtil;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.google.android.material.navigation.NavigationView;
import com.kerwin.wumei.R;
import com.kerwin.wumei.adapter.entity.EspTouchViewModel;
import com.kerwin.wumei.core.BaseActivity;
import com.kerwin.wumei.core.BaseFragment;
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.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;
import com.kerwin.wumei.utils.NetUtils;
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;
import com.xuexiang.xui.adapter.simple.AdapterItem;
import com.xuexiang.xui.utils.ResUtils;
import com.xuexiang.xui.utils.ThemeUtils;
import com.xuexiang.xui.widget.imageview.RadiusImageView;
import com.xuexiang.xui.widget.popupwindow.popup.XUISimplePopup;
import com.xuexiang.xutil.XUtil;
import com.xuexiang.xutil.common.ClickUtils;
import com.xuexiang.xutil.common.CollectionUtils;
import com.xuexiang.xutil.display.Colors;
import java.lang.ref.WeakReference;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import butterknife.BindView;
import static com.kerwin.wumei.utils.SettingUtils.getServerPath;
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)
Toolbar toolbar;
@BindView(R.id.view_pager)
ViewPager viewPager;
/**
* 底部导航栏
*/
@BindView(R.id.bottom_navigation)
BottomNavigationView bottomNavigation;
/**
* 侧边栏
*/
@BindView(R.id.nav_view)
NavigationView navView;
@BindView(R.id.drawer_layout)
DrawerLayout drawerLayout;
private String[] mTitles;
@Override
protected int getLayoutId() {
return R.layout.activity_main;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initViews();
// initData();
initListeners();
}
@Override
protected boolean isSupportSlideBack() {
return true;
}
private void initViews() {
mTitles = ResUtils.getStringArray(R.array.home_titles);
toolbar.setTitle(mTitles[0]);
toolbar.inflateMenu(R.menu.menu_main);
toolbar.setOnMenuItemClickListener(this);
initHeader();
//主页内容填充
BaseFragment[] fragments = new BaseFragment[]{
new DeviceFragment(),
new SceneFragment(),
new HomePageFragment(),
new ProfileFragment(),
};
FragmentAdapter<BaseFragment> 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);
}
/**
* 侧边栏头部
*/
private void initHeader() {
navView.setItemIconTintList(null);
View headerView = navView.getHeaderView(0);
LinearLayout navHeader = headerView.findViewById(R.id.nav_header);
RadiusImageView ivAvatar = headerView.findViewById(R.id.iv_avatar);
TextView tvAvatar = headerView.findViewById(R.id.tv_avatar);
TextView tvSign = headerView.findViewById(R.id.tv_sign);
if (Utils.isColorDark(ThemeUtils.resolveColor(this, R.attr.colorAccent))) {
tvAvatar.setTextColor(Colors.WHITE);
tvSign.setTextColor(Colors.WHITE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
ivAvatar.setImageTintList(ResUtils.getColors(R.color.xui_config_color_white));
}
} else {
tvAvatar.setTextColor(ThemeUtils.resolveColor(this, R.attr.xui_config_color_title_text));
tvSign.setTextColor(ThemeUtils.resolveColor(this, R.attr.xui_config_color_explain_text));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
ivAvatar.setImageTintList(ResUtils.getColors(R.color.xui_config_color_gray_3));
}
}
// 绑定数据
ivAvatar.setImageResource(R.drawable.ic_default_head);
tvAvatar.setText("匿名用户");
tvSign.setText("物美智能点亮智慧生活...");
getUserInfo(tvAvatar,tvSign );
navHeader.setOnClickListener(this);
}
protected void initListeners() {
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawerLayout.addDrawerListener(toggle);
toggle.syncState();
//侧边栏点击事件
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_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;
});
//主页事件监听
viewPager.addOnPageChangeListener(this);
bottomNavigation.setOnNavigationItemSelectedListener(this);
}
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.add_device:
PageOption.to(AddDeviceFragment.class) //跳转的fragment
.setAnim(CoreAnim.slide) //页面转场动画
.setRequestCode(100) //请求码,用于返回结果
.setAddToBackStack(true) //是否加入堆栈
.setNewActivity(true, AddDeviceActivity.class) //是否使用新的Activity打开
.open(this); //打开页面进行跳转
break;
default:
break;
}
return false;
}
@SingleClick
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.nav_header:
openNewPage(AccountFragment.class);
break;
default:
break;
}
}
//=============ViewPager===================//
@Override
public void onPageScrolled(int i, float v, int i1) {
}
@Override
public void onPageSelected(int position) {
MenuItem item = bottomNavigation.getMenu().getItem(position);
toolbar.setTitle(item.getTitle());
item.setChecked(true);
}
@Override
public void onPageScrollStateChanged(int i) {
}
//================Navigation================//
/**
* 底部导航栏点击事件
*
* @param menuItem
* @return
*/
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
int index = CollectionUtils.arrayIndexOf(mTitles, menuItem.getTitle());
if (index != -1) {
toolbar.setTitle(menuItem.getTitle());
viewPager.setCurrentItem(index, false);
return true;
}
return false;
}
/**
* 菜单、返回键响应
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
ClickUtils.exitBy2Click(2000, this);
}
return true;
}
@Override
public void onRetry() {
XToastUtils.toast("再按一次退出程序");
}
@Override
public void onExit() {
XUtil.exitApp();
}
/**
* HTTP获取用户信息
*/
private void getUserInfo(TextView avatar,TextView sign){
if(!hasToken()) return;
XHttp.get(getServerPath()+"/getInfo")
.headers("Authorization","Bearer "+getToken())
.execute(new CallBackProxy<UserInfoApiResult<User>, User>(new TipRequestCallBack<User>() {
@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());
}
}
}){});
}
}

View File

@@ -1,69 +0,0 @@
package com.kerwin.wumei.activity;
import android.view.KeyEvent;
import com.kerwin.wumei.R;
import com.kerwin.wumei.utils.SettingUtils;
import com.kerwin.wumei.utils.TokenUtils;
import com.kerwin.wumei.utils.Utils;
import com.xuexiang.xui.utils.KeyboardUtils;
import com.xuexiang.xui.widget.activity.BaseSplashActivity;
import com.xuexiang.xutil.app.ActivityUtils;
import me.jessyan.autosize.internal.CancelAdapt;
/**
* 启动页【无需适配屏幕大小】
*
*/
public class SplashActivity extends BaseSplashActivity implements CancelAdapt {
@Override
protected long getSplashDurationMillis() {
return 500;
}
/**
* activity启动后的初始化
*/
@Override
protected void onCreateActivity() {
initSplashView(R.drawable.xui_config_bg_splash);
startSplash(false);
}
/**
* 启动页结束后的动作
*/
@Override
protected void onSplashFinished() {
loginOrGoMainPage();
// if (SettingUtils.isAgreePrivacy()) {
// loginOrGoMainPage();
// } else {
// Utils.showPrivacyDialog(this, (dialog, which) -> {
// dialog.dismiss();
// SettingUtils.setIsAgreePrivacy(true);
// loginOrGoMainPage();
// });
// }
}
private void loginOrGoMainPage() {
if (TokenUtils.hasToken()) {
ActivityUtils.startActivity(MainActivity.class);
} else {
ActivityUtils.startActivity(LoginActivity.class);
}
finish();
}
/**
* 菜单、返回键响应
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return KeyboardUtils.onDisableBackKeyDown(keyCode) && super.onKeyDown(keyCode, event);
}
}

View File

@@ -1,102 +0,0 @@
/*
* 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.base.broccoli;
import android.view.View;
import androidx.annotation.NonNull;
import com.xuexiang.xui.adapter.recyclerview.BaseRecyclerAdapter;
import com.xuexiang.xui.adapter.recyclerview.RecyclerViewHolder;
import com.xuexiang.xui.adapter.recyclerview.XRecyclerAdapter;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import me.samlss.broccoli.Broccoli;
/**
* 使用Broccoli占位的基础适配器
*
* @author XUE
* @since 2019/4/8 16:33
*/
public abstract class BroccoliRecyclerAdapter<T> extends BaseRecyclerAdapter<T> {
/**
* 是否已经加载成功
*/
private boolean mHasLoad = false;
private Map<View, Broccoli> mBroccoliMap = new HashMap<>();
public BroccoliRecyclerAdapter(Collection<T> collection) {
super(collection);
}
@Override
protected void bindData(@NonNull RecyclerViewHolder holder, int position, T item) {
Broccoli broccoli = mBroccoliMap.get(holder.itemView);
if (broccoli == null) {
broccoli = new Broccoli();
mBroccoliMap.put(holder.itemView, broccoli);
}
if (mHasLoad) {
broccoli.removeAllPlaceholders();
onBindData(holder, item, position);
} else {
onBindBroccoli(holder, broccoli);
broccoli.show();
}
}
/**
* 绑定控件
*
* @param holder
* @param model
* @param position
*/
protected abstract void onBindData(RecyclerViewHolder holder, T model, int position);
/**
* 绑定占位控件
*
* @param broccoli
*/
protected abstract void onBindBroccoli(RecyclerViewHolder holder, Broccoli broccoli);
@Override
public XRecyclerAdapter refresh(Collection<T> collection) {
mHasLoad = true;
return super.refresh(collection);
}
/**
* 资源释放,防止内存泄漏
*/
public void recycle() {
for (Broccoli broccoli : mBroccoliMap.values()) {
broccoli.removeAllPlaceholders();
}
mBroccoliMap.clear();
clear();
}
}

View File

@@ -1,112 +0,0 @@
/*
* 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.base.broccoli;
import android.view.View;
import androidx.annotation.NonNull;
import com.alibaba.android.vlayout.LayoutHelper;
import com.kerwin.wumei.adapter.base.delegate.SimpleDelegateAdapter;
import com.kerwin.wumei.adapter.base.delegate.XDelegateAdapter;
import com.xuexiang.xui.adapter.recyclerview.RecyclerViewHolder;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import me.samlss.broccoli.Broccoli;
/**
* 使用Broccoli占位的基础适配器
*
* @author xuexiang
* @since 2021/1/9 4:52 PM
*/
public abstract class BroccoliSimpleDelegateAdapter<T> extends SimpleDelegateAdapter<T> {
/**
* 是否已经加载成功
*/
private boolean mHasLoad = false;
private Map<View, Broccoli> mBroccoliMap = new HashMap<>();
public BroccoliSimpleDelegateAdapter(int layoutId, LayoutHelper layoutHelper) {
super(layoutId, layoutHelper);
}
public BroccoliSimpleDelegateAdapter(int layoutId, LayoutHelper layoutHelper, Collection<T> list) {
super(layoutId, layoutHelper, list);
}
public BroccoliSimpleDelegateAdapter(int layoutId, LayoutHelper layoutHelper, T[] data) {
super(layoutId, layoutHelper, data);
}
@Override
protected void bindData(@NonNull RecyclerViewHolder holder, int position, T item) {
Broccoli broccoli = mBroccoliMap.get(holder.itemView);
if (broccoli == null) {
broccoli = new Broccoli();
mBroccoliMap.put(holder.itemView, broccoli);
}
if (mHasLoad) {
broccoli.removeAllPlaceholders();
onBindData(holder, item, position);
} else {
onBindBroccoli(holder, broccoli);
broccoli.show();
}
}
/**
* 绑定控件
*
* @param holder
* @param model
* @param position
*/
protected abstract void onBindData(RecyclerViewHolder holder, T model, int position);
/**
* 绑定占位控件
*
* @param holder
* @param broccoli
*/
protected abstract void onBindBroccoli(RecyclerViewHolder holder, Broccoli broccoli);
@Override
public XDelegateAdapter refresh(Collection<T> collection) {
mHasLoad = true;
return super.refresh(collection);
}
/**
* 资源释放,防止内存泄漏
*/
public void recycle() {
for (Broccoli broccoli : mBroccoliMap.values()) {
broccoli.removeAllPlaceholders();
}
mBroccoliMap.clear();
clear();
}
}

View File

@@ -1,61 +0,0 @@
/*
* 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.base.delegate;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import com.xuexiang.xui.adapter.recyclerview.RecyclerViewHolder;
import java.util.Collection;
/**
* 通用的DelegateAdapter适配器
*
* @author xuexiang
* @since 2020/3/20 12:44 AM
*/
public abstract class BaseDelegateAdapter<T> extends XDelegateAdapter<T, RecyclerViewHolder> {
public BaseDelegateAdapter() {
super();
}
public BaseDelegateAdapter(Collection<T> list) {
super(list);
}
public BaseDelegateAdapter(T[] data) {
super(data);
}
/**
* 适配的布局
*
* @param viewType
* @return
*/
protected abstract int getItemLayoutId(int viewType);
@NonNull
@Override
protected RecyclerViewHolder getViewHolder(@NonNull ViewGroup parent, int viewType) {
return new RecyclerViewHolder(inflateView(parent, getItemLayoutId(viewType)));
}
}

View File

@@ -1,64 +0,0 @@
/*
* 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.base.delegate;
import com.alibaba.android.vlayout.LayoutHelper;
import java.util.Collection;
/**
* 简易DelegateAdapter适配器
*
* @author xuexiang
* @since 2020/3/20 12:55 AM
*/
public abstract class SimpleDelegateAdapter<T> extends BaseDelegateAdapter<T> {
private int mLayoutId;
private LayoutHelper mLayoutHelper;
public SimpleDelegateAdapter(int layoutId, LayoutHelper layoutHelper) {
super();
mLayoutId = layoutId;
mLayoutHelper = layoutHelper;
}
public SimpleDelegateAdapter(int layoutId, LayoutHelper layoutHelper, Collection<T> list) {
super(list);
mLayoutId = layoutId;
mLayoutHelper = layoutHelper;
}
public SimpleDelegateAdapter(int layoutId, LayoutHelper layoutHelper, T[] data) {
super(data);
mLayoutId = layoutId;
mLayoutHelper = layoutHelper;
}
@Override
protected int getItemLayoutId(int viewType) {
return mLayoutId;
}
@Override
public LayoutHelper onCreateLayoutHelper() {
return mLayoutHelper;
}
}

View File

@@ -1,72 +0,0 @@
/*
* 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.base.delegate;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import com.alibaba.android.vlayout.DelegateAdapter;
import com.alibaba.android.vlayout.LayoutHelper;
import com.alibaba.android.vlayout.layout.SingleLayoutHelper;
import com.xuexiang.xui.adapter.recyclerview.RecyclerViewHolder;
/**
* 单独布局的DelegateAdapter
*
* @author xuexiang
* @since 2020/3/20 1:04 AM
*/
public abstract class SingleDelegateAdapter extends DelegateAdapter.Adapter<RecyclerViewHolder> {
private int mLayoutId;
public SingleDelegateAdapter(int layoutId) {
mLayoutId = layoutId;
}
@Override
public LayoutHelper onCreateLayoutHelper() {
return new SingleLayoutHelper();
}
/**
* 加载布局获取控件
*
* @param parent 父布局
* @param layoutId 布局ID
* @return
*/
protected View inflateView(ViewGroup parent, @LayoutRes int layoutId) {
return LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
}
@NonNull
@Override
public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new RecyclerViewHolder(inflateView(parent, mLayoutId));
}
@Override
public int getItemCount() {
return 1;
}
}

View File

@@ -1,300 +0,0 @@
/*
* 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.base.delegate;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.alibaba.android.vlayout.DelegateAdapter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/**
* 基础DelegateAdapter
*
* @author xuexiang
* @since 2020/3/20 12:17 AM
*/
public abstract class XDelegateAdapter<T, V extends RecyclerView.ViewHolder> extends DelegateAdapter.Adapter<V> {
/**
* 数据源
*/
protected final List<T> mData = new ArrayList<>();
/**
* 当前点击的条目
*/
protected int mSelectPosition = -1;
public XDelegateAdapter() {
}
public XDelegateAdapter(Collection<T> list) {
if (list != null) {
mData.addAll(list);
}
}
public XDelegateAdapter(T[] data) {
if (data != null && data.length > 0) {
mData.addAll(Arrays.asList(data));
}
}
/**
* 构建自定义的ViewHolder
*
* @param parent
* @param viewType
* @return
*/
@NonNull
protected abstract V getViewHolder(@NonNull ViewGroup parent, int viewType);
/**
* 绑定数据
*
* @param holder
* @param position 索引
* @param item 列表项
*/
protected abstract void bindData(@NonNull V holder, int position, T item);
/**
* 加载布局获取控件
*
* @param parent 父布局
* @param layoutId 布局ID
* @return
*/
protected View inflateView(ViewGroup parent, @LayoutRes int layoutId) {
return LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
}
@NonNull
@Override
public V onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return getViewHolder(parent, viewType);
}
@Override
public void onBindViewHolder(@NonNull V holder, int position) {
bindData(holder, position, mData.get(position));
}
/**
* 获取列表项
*
* @param position
* @return
*/
public T getItem(int position) {
return checkPosition(position) ? mData.get(position) : null;
}
private boolean checkPosition(int position) {
return position >= 0 && position <= mData.size() - 1;
}
public boolean isEmpty() {
return getItemCount() == 0;
}
@Override
public int getItemCount() {
return mData.size();
}
/**
* @return 数据源
*/
public List<T> getData() {
return mData;
}
/**
* 给指定位置添加一项
*
* @param pos
* @param item
* @return
*/
public XDelegateAdapter add(int pos, T item) {
mData.add(pos, item);
notifyItemInserted(pos);
return this;
}
/**
* 在列表末端增加一项
*
* @param item
* @return
*/
public XDelegateAdapter add(T item) {
mData.add(item);
notifyItemInserted(mData.size() - 1);
return this;
}
/**
* 删除列表中指定索引的数据
*
* @param pos
* @return
*/
public XDelegateAdapter delete(int pos) {
mData.remove(pos);
notifyItemRemoved(pos);
return this;
}
/**
* 刷新列表中指定位置的数据
*
* @param pos
* @param item
* @return
*/
public XDelegateAdapter refresh(int pos, T item) {
mData.set(pos, item);
notifyItemChanged(pos);
return this;
}
/**
* 刷新列表数据
*
* @param collection
* @return
*/
public XDelegateAdapter refresh(Collection<T> collection) {
if (collection != null) {
mData.clear();
mData.addAll(collection);
mSelectPosition = -1;
notifyDataSetChanged();
}
return this;
}
/**
* 刷新列表数据
*
* @param array
* @return
*/
public XDelegateAdapter refresh(T[] array) {
if (array != null && array.length > 0) {
mData.clear();
mData.addAll(Arrays.asList(array));
mSelectPosition = -1;
notifyDataSetChanged();
}
return this;
}
/**
* 加载更多
*
* @param collection
* @return
*/
public XDelegateAdapter loadMore(Collection<T> collection) {
if (collection != null) {
mData.addAll(collection);
notifyDataSetChanged();
}
return this;
}
/**
* 加载更多
*
* @param array
* @return
*/
public XDelegateAdapter loadMore(T[] array) {
if (array != null && array.length > 0) {
mData.addAll(Arrays.asList(array));
notifyDataSetChanged();
}
return this;
}
/**
* 添加一个
*
* @param item
* @return
*/
public XDelegateAdapter load(T item) {
if (item != null) {
mData.add(item);
notifyDataSetChanged();
}
return this;
}
/**
* @return 当前列表的选中项
*/
public int getSelectPosition() {
return mSelectPosition;
}
/**
* 设置当前列表的选中项
*
* @param selectPosition
* @return
*/
public XDelegateAdapter setSelectPosition(int selectPosition) {
mSelectPosition = selectPosition;
notifyDataSetChanged();
return this;
}
/**
* 获取当前列表选中项
*
* @return 当前列表选中项
*/
public T getSelectItem() {
return getItem(mSelectPosition);
}
/**
* 清除数据
*/
public void clear() {
if (!isEmpty()) {
mData.clear();
mSelectPosition = -1;
notifyDataSetChanged();
}
}
}

View File

@@ -1,32 +0,0 @@
package com.kerwin.wumei.adapter.entity;
import android.widget.Button;
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 XSeekBar xsbDeviceCount;
public RadioGroup packageModeGroup;
public TextView messageView;
public Button confirmBtn;
public String ssid;
public byte[] ssidBytes;
public String bssid;
public CharSequence message;
public boolean confirmEnable;
public void invalidateAll() {
ssidSpinner.setText(ssid);
messageView.setText(message);
confirmBtn.setEnabled(confirmEnable);
}
}

View File

@@ -1,183 +0,0 @@
package com.kerwin.wumei.adapter.entity;
/**
* 新闻信息
*
* @author xuexiang
* @since 2019/4/7 下午12:07
*/
public class NewInfo {
/**
* 用户名
*/
private String UserName = "kerwin";
/**
* 标签
*/
private String Tag;
/**
* 标题
*/
private String Title;
/**
* 摘要
*/
private String Summary;
/**
* 图片
*/
private String ImageUrl;
/**
* 点赞数
*/
private int Praise;
/**
* 评论数
*/
private int Comment;
/**
* 阅读量
*/
private int Read;
/**
* 新闻的详情地址
*/
private String DetailUrl;
public NewInfo() {
}
public NewInfo(String userName, String tag, String title, String summary, String imageUrl, int praise, int comment, int read, String detailUrl) {
UserName = userName;
Tag = tag;
Title = title;
Summary = summary;
ImageUrl = imageUrl;
Praise = praise;
Comment = comment;
Read = read;
DetailUrl = detailUrl;
}
public NewInfo(String tag, String title, String summary, String imageUrl, String detailUrl) {
Tag = tag;
Title = title;
Summary = summary;
ImageUrl = imageUrl;
DetailUrl = detailUrl;
}
public NewInfo(String tag, String title) {
Tag = tag;
Title = title;
Praise = (int) (Math.random() * 100 + 5);
Comment = (int) (Math.random() * 50 + 5);
Read = (int) (Math.random() * 500 + 50);
}
public String getUserName() {
return UserName;
}
public NewInfo setUserName(String userName) {
UserName = userName;
return this;
}
public String getTag() {
return Tag;
}
public NewInfo setTag(String tag) {
Tag = tag;
return this;
}
public String getTitle() {
return Title;
}
public NewInfo setTitle(String title) {
Title = title;
return this;
}
public String getSummary() {
return Summary;
}
public NewInfo setSummary(String summary) {
Summary = summary;
return this;
}
public String getImageUrl() {
return ImageUrl;
}
public NewInfo setImageUrl(String imageUrl) {
ImageUrl = imageUrl;
return this;
}
public int getPraise() {
return Praise;
}
public NewInfo setPraise(int praise) {
Praise = praise;
return this;
}
public int getComment() {
return Comment;
}
public NewInfo setComment(int comment) {
Comment = comment;
return this;
}
public int getRead() {
return Read;
}
public NewInfo setRead(int read) {
Read = read;
return this;
}
public String getDetailUrl() {
return DetailUrl;
}
public NewInfo setDetailUrl(String detailUrl) {
DetailUrl = detailUrl;
return this;
}
@Override
public String toString() {
return "NewInfo{" +
"UserName='" + UserName + '\'' +
", Tag='" + Tag + '\'' +
", Title='" + Title + '\'' +
", Summary='" + Summary + '\'' +
", ImageUrl='" + ImageUrl + '\'' +
", Praise=" + Praise +
", Comment=" + Comment +
", Read=" + Read +
", DetailUrl='" + DetailUrl + '\'' +
'}';
}
}

View File

@@ -1,153 +0,0 @@
/*
* 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.core;
import android.content.Context;
import android.os.Bundle;
import com.xuexiang.xpage.base.XPageActivity;
import com.xuexiang.xpage.base.XPageFragment;
import com.xuexiang.xpage.core.CoreSwitchBean;
import com.xuexiang.xrouter.facade.service.SerializationService;
import com.xuexiang.xrouter.launcher.XRouter;
import com.xuexiang.xui.utils.ResUtils;
import com.xuexiang.xui.widget.slideback.SlideBack;
import butterknife.ButterKnife;
import butterknife.Unbinder;
import io.github.inflationx.viewpump.ViewPumpContextWrapper;
/**
* 基础容器Activity
*
* @author XUE
* @since 2019/3/22 11:21
*/
public class BaseActivity extends XPageActivity {
Unbinder mUnbinder;
@Override
protected void attachBaseContext(Context newBase) {
//注入字体
super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase));
}
/**
* 是否支持侧滑返回
*/
public static final String KEY_SUPPORT_SLIDE_BACK = "key_support_slide_back";
@Override
protected void onCreate(Bundle savedInstanceState) {
initStatusBarStyle();
super.onCreate(savedInstanceState);
mUnbinder = ButterKnife.bind(this);
registerSlideBack();
}
/**
* 初始化状态栏的样式
*/
protected void initStatusBarStyle() {
}
/**
* 打开fragment
*
* @param clazz 页面类
* @param addToBackStack 是否添加到栈中
* @return 打开的fragment对象
*/
public <T extends XPageFragment> T openPage(Class<T> clazz, boolean addToBackStack) {
CoreSwitchBean page = new CoreSwitchBean(clazz)
.setAddToBackStack(addToBackStack);
return (T) openPage(page);
}
/**
* 打开fragment
*
* @return 打开的fragment对象
*/
public <T extends XPageFragment> T openNewPage(Class<T> clazz) {
CoreSwitchBean page = new CoreSwitchBean(clazz)
.setNewActivity(true);
return (T) openPage(page);
}
/**
* 切换fragment
*
* @param clazz 页面类
* @return 打开的fragment对象
*/
public <T extends XPageFragment> T switchPage(Class<T> clazz) {
return openPage(clazz, false);
}
/**
* 序列化对象
*
* @param object
* @return
*/
public String serializeObject(Object object) {
return XRouter.getInstance().navigation(SerializationService.class).object2Json(object);
}
@Override
protected void onRelease() {
mUnbinder.unbind();
unregisterSlideBack();
super.onRelease();
}
/**
* 注册侧滑回调
*/
protected void registerSlideBack() {
if (isSupportSlideBack()) {
SlideBack.with(this)
.haveScroll(true)
.edgeMode(ResUtils.isRtl() ? SlideBack.EDGE_RIGHT : SlideBack.EDGE_LEFT)
.callBack(this::popPage)
.register();
}
}
/**
* 注销侧滑回调
*/
protected void unregisterSlideBack() {
if (isSupportSlideBack()) {
SlideBack.unregister(this);
}
}
/**
* @return 是否支持侧滑返回
*/
protected boolean isSupportSlideBack() {
CoreSwitchBean page = getIntent().getParcelableExtra(CoreSwitchBean.KEY_SWITCH_BEAN);
return page == null || page.getBundle() == null || page.getBundle().getBoolean(KEY_SUPPORT_SLIDE_BACK, true);
}
}

View File

@@ -1,123 +0,0 @@
/*
* 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.core;
import android.content.res.Configuration;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import com.umeng.analytics.MobclickAgent;
import com.xuexiang.xaop.annotation.SingleClick;
import com.xuexiang.xpage.base.XPageContainerListFragment;
import com.xuexiang.xui.widget.actionbar.TitleBar;
import com.xuexiang.xui.widget.actionbar.TitleUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.kerwin.wumei.core.SimpleListAdapter.KEY_SUB_TITLE;
import static com.kerwin.wumei.core.SimpleListAdapter.KEY_TITLE;
/**
* 修改列表样式为主副标题显示
*
* @author xuexiang
* @since 2018/11/22 上午11:26
*/
public abstract class BaseContainerFragment extends XPageContainerListFragment {
@Override
protected void initPage() {
initTitle();
initViews();
initListeners();
}
protected TitleBar initTitle() {
return TitleUtils.addTitleBarDynamic((ViewGroup) getRootView(), getPageTitle(), new View.OnClickListener() {
@Override
public void onClick(View v) {
popToBack();
}
});
}
@Override
protected void initData() {
mSimpleData = initSimpleData(mSimpleData);
List<Map<String, String>> data = new ArrayList<>();
for (String content : mSimpleData) {
Map<String, String> item = new HashMap<>();
int index = content.indexOf("\n");
if (index > 0) {
item.put(KEY_TITLE, String.valueOf(content.subSequence(0, index)));
item.put(KEY_SUB_TITLE, String.valueOf(content.subSequence(index + 1, content.length())));
} else {
item.put(KEY_TITLE, content);
item.put(KEY_SUB_TITLE, "");
}
data.add(item);
}
getListView().setAdapter(new SimpleListAdapter(getContext(), data));
initSimply();
}
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
onItemClick(view, position);
}
@SingleClick
private void onItemClick(View view, int position) {
onItemClick(position);
}
@Override
public void onDestroyView() {
getListView().setOnItemClickListener(null);
super.onDestroyView();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
//屏幕旋转时刷新一下title
super.onConfigurationChanged(newConfig);
ViewGroup root = (ViewGroup) getRootView();
if (root.getChildAt(0) instanceof TitleBar) {
root.removeViewAt(0);
initTitle();
}
}
@Override
public void onResume() {
super.onResume();
MobclickAgent.onPageStart(getPageName());
}
@Override
public void onPause() {
super.onPause();
MobclickAgent.onPageEnd(getPageName());
}
}

View File

@@ -1,346 +0,0 @@
/*
* 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.core;
import android.content.res.Configuration;
import android.os.Parcelable;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import com.umeng.analytics.MobclickAgent;
import com.kerwin.wumei.core.http.loader.ProgressLoader;
import com.xuexiang.xhttp2.subsciber.impl.IProgressLoader;
import com.xuexiang.xpage.base.XPageActivity;
import com.xuexiang.xpage.base.XPageFragment;
import com.xuexiang.xpage.core.PageOption;
import com.xuexiang.xpage.enums.CoreAnim;
import com.xuexiang.xpage.utils.Utils;
import com.xuexiang.xrouter.facade.service.SerializationService;
import com.xuexiang.xrouter.launcher.XRouter;
import com.xuexiang.xui.widget.actionbar.TitleBar;
import com.xuexiang.xui.widget.actionbar.TitleUtils;
import java.io.Serializable;
import java.lang.reflect.Type;
/**
* 基础fragment
*
* @author xuexiang
* @since 2018/5/25 下午3:44
*/
public abstract class BaseFragment extends XPageFragment {
private IProgressLoader mIProgressLoader;
@Override
protected void initPage() {
initTitle();
initViews();
initListeners();
}
protected TitleBar initTitle() {
return TitleUtils.addTitleBarDynamic((ViewGroup) getRootView(), getPageTitle(), v -> popToBack());
}
@Override
protected void initListeners() {
}
/**
* 获取进度条加载者
*
* @return 进度条加载者
*/
public IProgressLoader getProgressLoader() {
if (mIProgressLoader == null) {
mIProgressLoader = ProgressLoader.create(getContext());
}
return mIProgressLoader;
}
/**
* 获取进度条加载者
*
* @param message
* @return 进度条加载者
*/
public IProgressLoader getProgressLoader(String message) {
if (mIProgressLoader == null) {
mIProgressLoader = ProgressLoader.create(getContext(), message);
} else {
mIProgressLoader.updateMessage(message);
}
return mIProgressLoader;
}
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
//屏幕旋转时刷新一下title
super.onConfigurationChanged(newConfig);
ViewGroup root = (ViewGroup) getRootView();
if (root.getChildAt(0) instanceof TitleBar) {
root.removeViewAt(0);
initTitle();
}
}
@Override
public void onDestroyView() {
if (mIProgressLoader != null) {
mIProgressLoader.dismissLoading();
}
super.onDestroyView();
}
@Override
public void onResume() {
super.onResume();
MobclickAgent.onPageStart(getPageName());
}
@Override
public void onPause() {
super.onPause();
MobclickAgent.onPageEnd(getPageName());
}
//==============================页面跳转api===================================//
/**
* 打开一个新的页面【建议只在主tab页使用】
*
* @param clazz 页面的类
* @param <T>
* @return
*/
public <T extends XPageFragment> Fragment openNewPage(Class<T> clazz) {
return new PageOption(clazz)
.setNewActivity(true)
.open(this);
}
/**
* 打开一个新的页面【建议只在主tab页使用】
*
* @param pageName 页面名
* @param <T>
* @return
*/
public <T extends XPageFragment> Fragment openNewPage(String pageName) {
return new PageOption(pageName)
.setAnim(CoreAnim.slide)
.setNewActivity(true)
.open(this);
}
/**
* 打开一个新的页面【建议只在主tab页使用】
*
* @param clazz 页面的类
* @param containActivityClazz 页面容器
* @param <T>
* @return
*/
public <T extends XPageFragment> Fragment openNewPage(Class<T> clazz, @NonNull Class<? extends XPageActivity> containActivityClazz) {
return new PageOption(clazz)
.setNewActivity(true)
.setContainActivityClazz(containActivityClazz)
.open(this);
}
/**
* 打开一个新的页面【建议只在主tab页使用】
*
* @param clazz 页面的类
* @param key 入参的键
* @param value 入参的值
* @param <T>
* @return
*/
public <T extends XPageFragment> Fragment openNewPage(Class<T> clazz, String key, Object value) {
PageOption option = new PageOption(clazz).setNewActivity(true);
return openPage(option, key, value);
}
public Fragment openPage(PageOption option, String key, Object value) {
if (value instanceof Integer) {
option.putInt(key, (Integer) value);
} else if (value instanceof Float) {
option.putFloat(key, (Float) value);
} else if (value instanceof String) {
option.putString(key, (String) value);
} else if (value instanceof Boolean) {
option.putBoolean(key, (Boolean) value);
} else if (value instanceof Long) {
option.putLong(key, (Long) value);
} else if (value instanceof Double) {
option.putDouble(key, (Double) value);
} else if (value instanceof Parcelable) {
option.putParcelable(key, (Parcelable) value);
} else if (value instanceof Serializable) {
option.putSerializable(key, (Serializable) value);
} else {
option.putString(key, serializeObject(value));
}
return option.open(this);
}
/**
* 打开页面
*
* @param clazz 页面的类
* @param addToBackStack 是否加入回退栈
* @param key 入参的键
* @param value 入参的值
* @param <T>
* @return
*/
public <T extends XPageFragment> Fragment openPage(Class<T> clazz, boolean addToBackStack, String key, String value) {
return new PageOption(clazz)
.setAddToBackStack(addToBackStack)
.putString(key, value)
.open(this);
}
/**
* 打开页面
*
* @param clazz 页面的类
* @param key 入参的键
* @param value 入参的值
* @param <T>
* @return
*/
public <T extends XPageFragment> Fragment openPage(Class<T> clazz, String key, Object value) {
return openPage(clazz, true, key, value);
}
/**
* 打开页面
*
* @param clazz 页面的类
* @param addToBackStack 是否加入回退栈
* @param key 入参的键
* @param value 入参的值
* @param <T>
* @return
*/
public <T extends XPageFragment> Fragment openPage(Class<T> clazz, boolean addToBackStack, String key, Object value) {
PageOption option = new PageOption(clazz).setAddToBackStack(addToBackStack);
return openPage(option, key, value);
}
/**
* 打开页面
*
* @param clazz 页面的类
* @param key 入参的键
* @param value 入参的值
* @param <T>
* @return
*/
public <T extends XPageFragment> Fragment openPage(Class<T> clazz, String key, String value) {
return new PageOption(clazz)
.putString(key, value)
.open(this);
}
/**
* 打开页面,需要结果返回
*
* @param clazz 页面的类
* @param key 入参的键
* @param value 入参的值
* @param requestCode 请求码
* @param <T>
* @return
*/
public <T extends XPageFragment> Fragment openPageForResult(Class<T> clazz, String key, Object value, int requestCode) {
PageOption option = new PageOption(clazz).setRequestCode(requestCode);
return openPage(option, key, value);
}
/**
* 打开页面,需要结果返回
*
* @param clazz 页面的类
* @param key 入参的键
* @param value 入参的值
* @param requestCode 请求码
* @param <T>
* @return
*/
public <T extends XPageFragment> Fragment openPageForResult(Class<T> clazz, String key, String value, int requestCode) {
return new PageOption(clazz)
.setRequestCode(requestCode)
.putString(key, value)
.open(this);
}
/**
* 打开页面,需要结果返回
*
* @param clazz 页面的类
* @param requestCode 请求码
* @param <T>
* @return
*/
public <T extends XPageFragment> Fragment openPageForResult(Class<T> clazz, int requestCode) {
return new PageOption(clazz)
.setRequestCode(requestCode)
.open(this);
}
/**
* 序列化对象
*
* @param object 需要序列化的对象
* @return 序列化结果
*/
public String serializeObject(Object object) {
return XRouter.getInstance().navigation(SerializationService.class).object2Json(object);
}
/**
* 反序列化对象
*
* @param input 反序列化的内容
* @param clazz 类型
* @return 反序列化结果
*/
public <T> T deserializeObject(String input, Type clazz) {
return XRouter.getInstance().navigation(SerializationService.class).parseObject(input, clazz);
}
@Override
protected void hideCurrentPageSoftInput() {
if (getActivity() == null) {
return;
}
// 记住要在xml的父布局加上android:focusable="true" 和 android:focusableInTouchMode="true"
Utils.hideSoftInputClearFocus(getActivity().getCurrentFocus());
}
}

View File

@@ -1,284 +0,0 @@
/*
* 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.core;
import android.content.res.Configuration;
import android.os.Parcelable;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import com.umeng.analytics.MobclickAgent;
import com.xuexiang.xpage.base.XPageActivity;
import com.xuexiang.xpage.base.XPageFragment;
import com.xuexiang.xpage.base.XPageSimpleListFragment;
import com.xuexiang.xpage.core.PageOption;
import com.xuexiang.xpage.enums.CoreAnim;
import com.xuexiang.xrouter.facade.service.SerializationService;
import com.xuexiang.xrouter.launcher.XRouter;
import com.xuexiang.xui.widget.actionbar.TitleBar;
import com.xuexiang.xui.widget.actionbar.TitleUtils;
import java.io.Serializable;
/**
* @author xuexiang
* @since 2018/12/29 下午12:41
*/
public abstract class BaseSimpleListFragment extends XPageSimpleListFragment {
@Override
protected void initPage() {
initTitle();
initViews();
initListeners();
}
protected TitleBar initTitle() {
return TitleUtils.addTitleBarDynamic((ViewGroup) getRootView(), getPageTitle(), new View.OnClickListener() {
@Override
public void onClick(View v) {
popToBack();
}
});
}
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
//屏幕旋转时刷新一下title
super.onConfigurationChanged(newConfig);
ViewGroup root = (ViewGroup) getRootView();
if (root.getChildAt(0) instanceof TitleBar) {
root.removeViewAt(0);
initTitle();
}
}
@Override
public void onResume() {
super.onResume();
MobclickAgent.onPageStart(getPageName());
}
@Override
public void onPause() {
super.onPause();
MobclickAgent.onPageEnd(getPageName());
}
//==============================页面跳转api===================================//
/**
* 打开一个新的页面【建议只在主tab页使用】
*
* @param clazz 页面的类
* @param <T>
* @return
*/
public <T extends XPageFragment> Fragment openNewPage(Class<T> clazz) {
return new PageOption(clazz)
.setNewActivity(true)
.open(this);
}
/**
* 打开一个新的页面【建议只在主tab页使用】
*
* @param pageName 页面名
* @param <T>
* @return
*/
public <T extends XPageFragment> Fragment openNewPage(String pageName) {
return new PageOption(pageName)
.setAnim(CoreAnim.slide)
.setNewActivity(true)
.open(this);
}
/**
* 打开一个新的页面【建议只在主tab页使用】
*
* @param clazz 页面的类
* @param containActivityClazz 页面容器
* @param <T>
* @return
*/
public <T extends XPageFragment> Fragment openNewPage(Class<T> clazz, @NonNull Class<? extends XPageActivity> containActivityClazz) {
return new PageOption(clazz)
.setNewActivity(true)
.setContainActivityClazz(containActivityClazz)
.open(this);
}
/**
* 打开一个新的页面【建议只在主tab页使用】
*
* @param clazz 页面的类
* @param key 入参的键
* @param value 入参的值
* @param <T>
* @return
*/
public <T extends XPageFragment> Fragment openNewPage(Class<T> clazz, String key, Object value) {
PageOption option = new PageOption(clazz).setNewActivity(true);
return openPage(option, key, value);
}
public Fragment openPage(PageOption option, String key, Object value) {
if (value instanceof Integer) {
option.putInt(key, (Integer) value);
} else if (value instanceof Float) {
option.putFloat(key, (Float) value);
} else if (value instanceof String) {
option.putString(key, (String) value);
} else if (value instanceof Boolean) {
option.putBoolean(key, (Boolean) value);
} else if (value instanceof Long) {
option.putLong(key, (Long) value);
} else if (value instanceof Double) {
option.putDouble(key, (Double) value);
} else if (value instanceof Parcelable) {
option.putParcelable(key, (Parcelable) value);
} else if (value instanceof Serializable) {
option.putSerializable(key, (Serializable) value);
} else {
option.putString(key, serializeObject(value));
}
return option.open(this);
}
/**
* 打开页面
*
* @param clazz 页面的类
* @param addToBackStack 是否加入回退栈
* @param key 入参的键
* @param value 入参的值
* @param <T>
* @return
*/
public <T extends XPageFragment> Fragment openPage(Class<T> clazz, boolean addToBackStack, String key, String value) {
return new PageOption(clazz)
.setAddToBackStack(addToBackStack)
.putString(key, value)
.open(this);
}
/**
* 打开页面
*
* @param clazz 页面的类
* @param key 入参的键
* @param value 入参的值
* @param <T>
* @return
*/
public <T extends XPageFragment> Fragment openPage(Class<T> clazz, String key, Object value) {
return openPage(clazz, true, key, value);
}
/**
* 打开页面
*
* @param clazz 页面的类
* @param addToBackStack 是否加入回退栈
* @param key 入参的键
* @param value 入参的值
* @param <T>
* @return
*/
public <T extends XPageFragment> Fragment openPage(Class<T> clazz, boolean addToBackStack, String key, Object value) {
PageOption option = new PageOption(clazz).setAddToBackStack(addToBackStack);
return openPage(option, key, value);
}
/**
* 打开页面
*
* @param clazz 页面的类
* @param key 入参的键
* @param value 入参的值
* @param <T>
* @return
*/
public <T extends XPageFragment> Fragment openPage(Class<T> clazz, String key, String value) {
return new PageOption(clazz)
.putString(key, value)
.open(this);
}
/**
* 打开页面,需要结果返回
*
* @param clazz 页面的类
* @param key 入参的键
* @param value 入参的值
* @param requestCode 请求码
* @param <T>
* @return
*/
public <T extends XPageFragment> Fragment openPageForResult(Class<T> clazz, String key, Object value, int requestCode) {
PageOption option = new PageOption(clazz).setRequestCode(requestCode);
return openPage(option, key, value);
}
/**
* 打开页面,需要结果返回
*
* @param clazz 页面的类
* @param key 入参的键
* @param value 入参的值
* @param requestCode 请求码
* @param <T>
* @return
*/
public <T extends XPageFragment> Fragment openPageForResult(Class<T> clazz, String key, String value, int requestCode) {
return new PageOption(clazz)
.setRequestCode(requestCode)
.putString(key, value)
.open(this);
}
/**
* 打开页面,需要结果返回
*
* @param clazz 页面的类
* @param requestCode 请求码
* @param <T>
* @return
*/
public <T extends XPageFragment> Fragment openPageForResult(Class<T> clazz, int requestCode) {
return new PageOption(clazz)
.setRequestCode(requestCode)
.open(this);
}
/**
* 序列化对象
*
* @param object 需要序列化的对象
* @return 序列化结果
*/
public String serializeObject(Object object) {
return XRouter.getInstance().navigation(SerializationService.class).object2Json(object);
}
}

View File

@@ -1,80 +0,0 @@
/*
* 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.core;
import android.content.Context;
import android.view.View;
import android.widget.TextView;
import com.kerwin.wumei.R;
import com.xuexiang.xui.adapter.listview.BaseListAdapter;
import com.xuexiang.xutil.common.StringUtils;
import java.util.List;
import java.util.Map;
/**
* 主副标题显示适配器
*
* @author xuexiang
* @since 2018/12/19 上午12:19
*/
public class SimpleListAdapter extends BaseListAdapter<Map<String, String>, SimpleListAdapter.ViewHolder> {
public static final String KEY_TITLE = "key_title";
public static final String KEY_SUB_TITLE = "key_sub_title";
public SimpleListAdapter(Context context, List<Map<String, String>> data) {
super(context, data);
}
@Override
protected ViewHolder newViewHolder(View convertView) {
ViewHolder holder = new ViewHolder();
holder.mTvTitle = convertView.findViewById(R.id.device_item_title);
holder.mTvSubTitle = convertView.findViewById(R.id.tv_sub_title);
return holder;
}
@Override
protected int getLayoutId() {
return R.layout.adapter_item_simple_list_2;
}
@Override
protected void convert(ViewHolder holder, Map<String, String> item, int position) {
holder.mTvTitle.setText(item.get(KEY_TITLE));
if (!StringUtils.isEmpty(item.get(KEY_SUB_TITLE))) {
holder.mTvSubTitle.setText(item.get(KEY_SUB_TITLE));
holder.mTvSubTitle.setVisibility(View.VISIBLE);
} else {
holder.mTvSubTitle.setVisibility(View.GONE);
}
}
public static class ViewHolder {
/**
* 标题
*/
public TextView mTvTitle;
/**
* 副标题
*/
public TextView mTvSubTitle;
}
}

View File

@@ -1,56 +0,0 @@
/*
* 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.core;
import android.os.Bundle;
import com.kerwin.wumei.utils.XToastUtils;
import com.xuexiang.xrouter.annotation.AutoWired;
import com.xuexiang.xrouter.annotation.Router;
import com.xuexiang.xrouter.launcher.XRouter;
import com.xuexiang.xutil.common.StringUtils;
/**
* https://xuexiangjys.club/xpage/transfer?pageName=xxxxx&....
* applink的中转
*
* @author xuexiang
* @since 2019-07-06 9:37
*/
@Router(path = "/xpage/transfer")
public class XPageTransferActivity extends BaseActivity {
@AutoWired(name = "pageName")
String pageName;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
XRouter.getInstance().inject(this);
if (!StringUtils.isEmpty(pageName)) {
if (openPage(pageName, getIntent().getExtras()) == null) {
XToastUtils.error("页面未找到!");
finish();
}
} else {
XToastUtils.error("页面未找到!");
finish();
}
}
}

View File

@@ -1,46 +0,0 @@
/*
* 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.core.http.api;
import com.kerwin.wumei.core.http.entity.TipInfo;
import com.xuexiang.xhttp2.model.ApiResult;
import java.util.List;
import io.reactivex.Observable;
import retrofit2.http.GET;
/**
* @author xuexiang
* @since 2021/1/9 7:01 PM
*/
public class ApiService {
/**
* 使用的是retrofit的接口定义
*/
public interface IGetService {
/**
* 获得小贴士
*/
@GET("http://wumei.live/tips.json")
Observable<ApiResult<List<TipInfo>>> getTips();
}
}

View File

@@ -1,59 +0,0 @@
/*
* 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.core.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 2019-11-18 23:02
*/
public abstract class NoTipCallBack<T> extends SimpleCallBack<T> {
/**
* 记录一下请求的url,确定出错的请求是哪个请求
*/
private String mUrl;
public NoTipCallBack() {
}
public NoTipCallBack(XHttpRequest req) {
this(req.getUrl());
}
public NoTipCallBack(String url) {
mUrl = url;
}
@Override
public void onError(ApiException e) {
if (!StringUtils.isEmpty(mUrl)) {
Logger.e("网络请求的url:" + mUrl, e);
} else {
Logger.e(e);
}
}
}

View File

@@ -1,62 +0,0 @@
/*
* 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.core.http.callback;
import com.kerwin.wumei.utils.XToastUtils;
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;
/**
* 带错误toast提示的网络请求回调
*
* @author xuexiang
* @since 2019-11-18 23:02
*/
public abstract class TipCallBack<T> extends SimpleCallBack<T> {
/**
* 记录一下请求的url,确定出错的请求是哪个请求
*/
private String mUrl;
public TipCallBack() {
}
public TipCallBack(XHttpRequest req) {
this(req.getUrl());
}
public TipCallBack(String url) {
mUrl = url;
}
@Override
public void onError(ApiException e) {
XToastUtils.error(e);
if (!StringUtils.isEmpty(mUrl)) {
Logger.e("网络请求的url:" + mUrl, e);
} else {
Logger.e(e);
}
}
}

View File

@@ -1,70 +0,0 @@
/*
* 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.core.http.callback;
import androidx.annotation.NonNull;
import com.kerwin.wumei.core.BaseFragment;
import com.kerwin.wumei.utils.XToastUtils;
import com.xuexiang.xhttp2.callback.ProgressLoadingCallBack;
import com.xuexiang.xhttp2.exception.ApiException;
import com.xuexiang.xhttp2.model.XHttpRequest;
import com.xuexiang.xhttp2.subsciber.impl.IProgressLoader;
import com.xuexiang.xutil.common.StringUtils;
import com.xuexiang.xutil.common.logger.Logger;
/**
* 带错误toast提示和加载进度条的网络请求回调
*
* @author xuexiang
* @since 2019-11-18 23:16
*/
public abstract class TipProgressLoadingCallBack<T> extends ProgressLoadingCallBack<T> {
/**
* 记录一下请求的url,确定出错的请求是哪个请求
*/
private String mUrl;
public TipProgressLoadingCallBack(BaseFragment fragment) {
super(fragment.getProgressLoader());
}
public TipProgressLoadingCallBack(IProgressLoader iProgressLoader) {
super(iProgressLoader);
}
public TipProgressLoadingCallBack(@NonNull XHttpRequest req, IProgressLoader iProgressLoader) {
this(req.getUrl(), iProgressLoader);
}
public TipProgressLoadingCallBack(String url, IProgressLoader iProgressLoader) {
super(iProgressLoader);
mUrl = url;
}
@Override
public void onError(ApiException e) {
super.onError(e);
XToastUtils.error(e);
if (!StringUtils.isEmpty(mUrl)) {
Logger.e("网络请求的url:" + mUrl, e);
} else {
Logger.e(e);
}
}
}

View File

@@ -1,60 +0,0 @@
/*
* 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.core.http.entity;
import androidx.annotation.Keep;
/**
* @author xuexiang
* @since 2019-08-28 15:35
*/
@Keep
public class TipInfo {
/**
* title : 小贴士3
* content : <p style=";font-family:'Microsoft YaHei';font-size:15px">欢迎关注我的微信公众号我的Android开源之旅。</p><p><br/></p>
*/
private String title;
private String content;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return "TipInfo{" +
"title='" + title + '\'' +
", content='" + content + '\'' +
'}';
}
}

View File

@@ -1,50 +0,0 @@
/*
* 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.core.http.loader;
import android.content.Context;
import com.xuexiang.xhttp2.subsciber.impl.IProgressLoader;
/**
* IProgressLoader的创建工厂实现接口
*
* @author xuexiang
* @since 2019-11-18 23:17
*/
public interface IProgressLoaderFactory {
/**
* 创建进度加载者
*
* @param context
* @return
*/
IProgressLoader create(Context context);
/**
* 创建进度加载者
*
* @param context
* @param message 默认提示
* @return
*/
IProgressLoader create(Context context, String message);
}

View File

@@ -1,96 +0,0 @@
/*
* 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.core.http.loader;
import android.content.Context;
import android.content.DialogInterface;
import com.xuexiang.xhttp2.subsciber.impl.IProgressLoader;
import com.xuexiang.xhttp2.subsciber.impl.OnProgressCancelListener;
import com.xuexiang.xui.widget.dialog.MiniLoadingDialog;
/**
* 默认进度加载
*
* @author xuexiang
* @since 2019-11-18 23:07
*/
public class MiniLoadingDialogLoader implements IProgressLoader {
/**
* 进度loading弹窗
*/
private MiniLoadingDialog mDialog;
/**
* 进度框取消监听
*/
private OnProgressCancelListener mOnProgressCancelListener;
public MiniLoadingDialogLoader(Context context) {
this(context, "请求中...");
}
public MiniLoadingDialogLoader(Context context, String msg) {
mDialog = new MiniLoadingDialog(context, msg);
}
@Override
public boolean isLoading() {
return mDialog != null && mDialog.isShowing();
}
@Override
public void updateMessage(String msg) {
if (mDialog != null) {
mDialog.updateMessage(msg);
}
}
@Override
public void showLoading() {
if (mDialog != null && !mDialog.isShowing()) {
mDialog.show();
}
}
@Override
public void dismissLoading() {
if (mDialog != null && mDialog.isShowing()) {
mDialog.dismiss();
}
}
@Override
public void setCancelable(boolean flag) {
mDialog.setCancelable(flag);
if (flag) {
mDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialogInterface) {
if (mOnProgressCancelListener != null) {
mOnProgressCancelListener.onCancelProgress();
}
}
});
}
}
@Override
public void setOnProgressCancelListener(OnProgressCancelListener listener) {
mOnProgressCancelListener = listener;
}
}

View File

@@ -1,41 +0,0 @@
/*
* 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.core.http.loader;
import android.content.Context;
import com.xuexiang.xhttp2.subsciber.impl.IProgressLoader;
/**
* 迷你加载框创建工厂
*
* @author xuexiang
* @since 2019-11-18 23:23
*/
public class MiniProgressLoaderFactory implements IProgressLoaderFactory {
@Override
public IProgressLoader create(Context context) {
return new MiniLoadingDialogLoader(context);
}
@Override
public IProgressLoader create(Context context, String message) {
return new MiniLoadingDialogLoader(context, message);
}
}

View File

@@ -1,62 +0,0 @@
/*
* 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.core.http.loader;
import android.content.Context;
import com.xuexiang.xhttp2.subsciber.impl.IProgressLoader;
/**
* 创建进度加载者
*
* @author xuexiang
* @since 2019-07-02 12:51
*/
public final class ProgressLoader {
private ProgressLoader() {
throw new UnsupportedOperationException("u can't instantiate me...");
}
private static IProgressLoaderFactory sIProgressLoaderFactory = new MiniProgressLoaderFactory();
public static void setIProgressLoaderFactory(IProgressLoaderFactory sIProgressLoaderFactory) {
ProgressLoader.sIProgressLoaderFactory = sIProgressLoaderFactory;
}
/**
* 创建进度加载者
*
* @param context
* @return
*/
public static IProgressLoader create(Context context) {
return sIProgressLoaderFactory.create(context);
}
/**
* 创建进度加载者
*
* @param context
* @param message 默认提示信息
* @return
*/
public static IProgressLoader create(Context context, String message) {
return sIProgressLoaderFactory.create(context, message);
}
}

View File

@@ -1,59 +0,0 @@
/*
* 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.core.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;
/**
* 不带错误toast提示的网络请求订阅只存储错误的日志
*
* @author xuexiang
* @since 2019-11-18 23:11
*/
public abstract class NoTipRequestSubscriber<T> extends BaseSubscriber<T> {
/**
* 记录一下请求的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);
}
}
}

View File

@@ -1,75 +0,0 @@
/*
* 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.core.http.subscriber;
import androidx.annotation.NonNull;
import com.kerwin.wumei.core.BaseFragment;
import com.kerwin.wumei.utils.XToastUtils;
import com.xuexiang.xhttp2.exception.ApiException;
import com.xuexiang.xhttp2.model.XHttpRequest;
import com.xuexiang.xhttp2.subsciber.ProgressLoadingSubscriber;
import com.xuexiang.xhttp2.subsciber.impl.IProgressLoader;
import com.xuexiang.xutil.common.StringUtils;
import com.xuexiang.xutil.common.logger.Logger;
/**
* 带错误toast提示和加载进度条的网络请求订阅
*
* @author xuexiang
* @since 2019-11-18 23:11
*/
public abstract class TipProgressLoadingSubscriber<T> extends ProgressLoadingSubscriber<T> {
/**
* 记录一下请求的url,确定出错的请求是哪个请求
*/
private String mUrl;
public TipProgressLoadingSubscriber() {
super();
}
public TipProgressLoadingSubscriber(BaseFragment fragment) {
super(fragment.getProgressLoader());
}
public TipProgressLoadingSubscriber(IProgressLoader iProgressLoader) {
super(iProgressLoader);
}
public TipProgressLoadingSubscriber(@NonNull XHttpRequest req) {
this(req.getUrl());
}
public TipProgressLoadingSubscriber(String url) {
super();
mUrl = url;
}
@Override
public void onError(ApiException e) {
super.onError(e);
XToastUtils.error(e);
if (!StringUtils.isEmpty(mUrl)) {
Logger.e("网络请求的url:" + mUrl, e);
} else {
Logger.e(e);
}
}
}

View File

@@ -1,64 +0,0 @@
/*
* 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.core.http.subscriber;
import androidx.annotation.NonNull;
import com.kerwin.wumei.utils.XToastUtils;
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;
/**
* 带错误toast提示的网络请求订阅
*
* @author xuexiang
* @since 2019-11-18 23:10
*/
public abstract class TipRequestSubscriber<T> extends BaseSubscriber<T> {
/**
* 记录一下请求的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) {
XToastUtils.error(e);
if (!StringUtils.isEmpty(mUrl)) {
Logger.e("网络请求的url:" + mUrl, e);
} else {
Logger.e(e);
}
}
}

View File

@@ -1,127 +0,0 @@
/*
* 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.core.webview;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.KeyEvent;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentTransaction;
import com.kerwin.wumei.R;
import com.kerwin.wumei.utils.XToastUtils;
import com.xuexiang.xrouter.facade.Postcard;
import com.xuexiang.xrouter.facade.callback.NavCallback;
import com.xuexiang.xrouter.launcher.XRouter;
import com.xuexiang.xui.widget.slideback.SlideBack;
/**
* 壳浏览器
*
* @author xuexiang
* @since 2019/1/5 上午12:15
*/
public class AgentWebActivity extends AppCompatActivity {
/**
* 请求浏览器
*
* @param url
*/
public static void goWeb(Context context, final String url) {
Intent intent = new Intent(context, AgentWebActivity.class);
intent.putExtra(AgentWebFragment.KEY_URL, url);
context.startActivity(intent);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_agent_web);
SlideBack.with(this)
.haveScroll(true)
.callBack(this::finish)
.register();
Uri uri = getIntent().getData();
if (uri != null) {
XRouter.getInstance().build(uri).navigation(this, new NavCallback() {
@Override
public void onArrival(Postcard postcard) {
finish();
}
@Override
public void onLost(Postcard postcard) {
loadUrl(uri.toString());
}
});
} else {
String url = getIntent().getStringExtra(AgentWebFragment.KEY_URL);
loadUrl(url);
}
}
private void loadUrl(String url) {
if (url != null) {
openFragment(url);
} else {
XToastUtils.error("数据出错!");
finish();
}
}
private AgentWebFragment mAgentWebFragment;
private void openFragment(String url) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.container_frame_layout, mAgentWebFragment = AgentWebFragment.getInstance(url));
ft.commit();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
AgentWebFragment agentWebFragment = mAgentWebFragment;
if (agentWebFragment != null) {
if (((FragmentKeyDown) agentWebFragment).onFragmentKeyDown(keyCode, event)) {
return true;
} else {
return super.onKeyDown(keyCode, event);
}
}
return super.onKeyDown(keyCode, event);
}
@Override
protected void onDestroy() {
SlideBack.unregister(this);
super.onDestroy();
}
}

View File

@@ -1,658 +0,0 @@
/*
* 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.core.webview;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.widget.PopupMenu;
import androidx.fragment.app.Fragment;
import com.just.agentweb.action.PermissionInterceptor;
import com.just.agentweb.core.AgentWeb;
import com.just.agentweb.core.client.MiddlewareWebChromeBase;
import com.just.agentweb.core.client.MiddlewareWebClientBase;
import com.just.agentweb.core.client.WebListenerManager;
import com.just.agentweb.core.web.AbsAgentWebSettings;
import com.just.agentweb.core.web.AgentWebConfig;
import com.just.agentweb.core.web.IAgentWebSettings;
import com.just.agentweb.download.AgentWebDownloader;
import com.just.agentweb.download.DefaultDownloadImpl;
import com.just.agentweb.download.DownloadListenerAdapter;
import com.just.agentweb.download.DownloadingService;
import com.just.agentweb.utils.LogUtils;
import com.just.agentweb.widget.IWebLayout;
import com.kerwin.wumei.MyApp;
import com.kerwin.wumei.R;
import com.kerwin.wumei.utils.XToastUtils;
import com.xuexiang.xutil.net.JsonUtil;
import java.util.HashMap;
/**
* 通用WebView页面
*
* @author xuexiang
* @since 2019/1/4 下午11:13
*/
public class AgentWebFragment extends Fragment implements FragmentKeyDown {
public static final String KEY_URL = "com.xuexiang.xuidemo.base.webview.key_url";
private ImageView mBackImageView;
private View mLineView;
private ImageView mFinishImageView;
private TextView mTitleTextView;
private AgentWeb mAgentWeb;
private ImageView mMoreImageView;
private PopupMenu mPopupMenu;
public static final String TAG = AgentWebFragment.class.getSimpleName();
private DownloadingService mDownloadingService;
public static AgentWebFragment getInstance(String url) {
Bundle bundle = new Bundle();
bundle.putString(KEY_URL, url);
return getInstance(bundle);
}
public static AgentWebFragment getInstance(Bundle bundle) {
AgentWebFragment fragment = new AgentWebFragment();
if (bundle != null) {
fragment.setArguments(bundle);
}
return fragment;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_agentweb, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mAgentWeb = AgentWeb.with(this)
//传入AgentWeb的父控件。
.setAgentWebParent((LinearLayout) view, -1, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT))
//设置进度条颜色与高度,-1为默认值高度为2单位为dp。
.useDefaultIndicator(-1, 3)
//设置 IAgentWebSettings。
.setAgentWebWebSettings(getSettings())
//WebViewClient 与 WebView 使用一致 但是请勿获取WebView调用setWebViewClient(xx)方法了,会覆盖AgentWeb DefaultWebClient,同时相应的中间件也会失效。
.setWebViewClient(mWebViewClient)
//WebChromeClient
.setWebChromeClient(mWebChromeClient)
//设置WebChromeClient中间件支持多个WebChromeClientAgentWeb 3.0.0 加入。
.useMiddlewareWebChrome(getMiddlewareWebChrome())
//设置WebViewClient中间件支持多个WebViewClient AgentWeb 3.0.0 加入。
.useMiddlewareWebClient(getMiddlewareWebClient())
//权限拦截 2.0.0 加入。
.setPermissionInterceptor(mPermissionInterceptor)
//严格模式 Android 4.2.2 以下会放弃注入对象 使用AgentWebView没影响。
.setSecurityType(AgentWeb.SecurityType.STRICT_CHECK)
//自定义UI AgentWeb3.0.0 加入。
.setAgentWebUIController(new UIController(getActivity()))
//参数1是错误显示的布局参数2点击刷新控件ID -1表示点击整个布局都刷新 AgentWeb 3.0.0 加入。
.setMainFrameErrorView(R.layout.agentweb_error_page, -1)
.setWebLayout(getWebLayout())
.interceptUnkownUrl()
//创建AgentWeb。
.createAgentWeb()
.ready()//设置 WebSettings。
//WebView载入该url地址的页面并显示。
.go(getUrl());
if (MyApp.isDebug()) {
AgentWebConfig.debug();
}
// 得到 AgentWeb 最底层的控件
addBackgroundChild(mAgentWeb.getWebCreator().getWebParentLayout());
initView(view);
// AgentWeb 没有把WebView的功能全面覆盖 ,所以某些设置 AgentWeb 没有提供请从WebView方面入手设置。
mAgentWeb.getWebCreator().getWebView().setOverScrollMode(WebView.OVER_SCROLL_NEVER);
}
protected IWebLayout getWebLayout() {
return new WebLayout(getActivity());
}
protected void initView(View view) {
mBackImageView = view.findViewById(R.id.iv_back);
mLineView = view.findViewById(R.id.view_line);
mFinishImageView = view.findViewById(R.id.iv_finish);
mTitleTextView = view.findViewById(R.id.toolbar_title);
mBackImageView.setOnClickListener(mOnClickListener);
mFinishImageView.setOnClickListener(mOnClickListener);
mMoreImageView = view.findViewById(R.id.iv_more);
mMoreImageView.setOnClickListener(mOnClickListener);
pageNavigator(View.GONE);
}
protected void addBackgroundChild(FrameLayout frameLayout) {
TextView textView = new TextView(frameLayout.getContext());
textView.setText("技术由 AgentWeb 提供");
textView.setTextSize(16);
textView.setTextColor(Color.parseColor("#727779"));
frameLayout.setBackgroundColor(Color.parseColor("#272b2d"));
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(-2, -2);
params.gravity = Gravity.CENTER_HORIZONTAL;
final float scale = frameLayout.getContext().getResources().getDisplayMetrics().density;
params.topMargin = (int) (15 * scale + 0.5f);
frameLayout.addView(textView, 0, params);
}
private void pageNavigator(int tag) {
mBackImageView.setVisibility(tag);
mLineView.setVisibility(tag);
}
private View.OnClickListener mOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.iv_back:
// true表示AgentWeb处理了该事件
if (!mAgentWeb.back()) {
AgentWebFragment.this.getActivity().finish();
}
break;
case R.id.iv_finish:
AgentWebFragment.this.getActivity().finish();
break;
case R.id.iv_more:
showPoPup(v);
break;
default:
break;
}
}
};
//========================================//
/**
* 权限申请拦截器
*/
protected PermissionInterceptor mPermissionInterceptor = new PermissionInterceptor() {
/**
* PermissionInterceptor 能达到 url1 允许授权, url2 拒绝授权的效果。
* @param url
* @param permissions
* @param action
* @return true 该Url对应页面请求权限进行拦截 false 表示不拦截。
*/
@Override
public boolean intercept(String url, String[] permissions, String action) {
Log.i(TAG, "mUrl:" + url + " permission:" + JsonUtil.toJson(permissions) + " action:" + action);
return false;
}
};
//=====================下载============================//
/**
* 更新于 AgentWeb 4.0.0,下载监听
*/
protected DownloadListenerAdapter mDownloadListenerAdapter = new DownloadListenerAdapter() {
/**
*
* @param url 下载链接
* @param userAgent UserAgent
* @param contentDisposition ContentDisposition
* @param mimetype 资源的媒体类型
* @param contentLength 文件长度
* @param extra 下载配置 用户可以通过 Extra 修改下载icon 关闭进度条 是否强制下载。
* @return true 表示用户处理了该下载事件 false 交给 AgentWeb 下载
*/
@Override
public boolean onStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength, AgentWebDownloader.Extra extra) {
LogUtils.i(TAG, "onStart:" + url);
// 是否开启断点续传
extra.setOpenBreakPointDownload(true)
//下载通知的icon
.setIcon(R.drawable.ic_file_download_black_24dp)
// 连接的超时时间
.setConnectTimeOut(6000)
// 以8KB位单位默认60s 如果60s内无法从网络流中读满8KB数据则抛出异常
.setBlockMaxTime(10 * 60 * 1000)
// 下载的超时时间
.setDownloadTimeOut(Long.MAX_VALUE)
// 串行下载更节省资源哦
.setParallelDownload(false)
// false 关闭进度通知
.setEnableIndicator(true)
// 自定义请求头
.addHeader("Cookie", "xx")
// 下载完成自动打开
.setAutoOpen(true)
// 强制下载,不管网络网络类型
.setForceDownload(true);
return false;
}
/**
*
* 不需要暂停或者停止下载该方法可以不必实现
* @param url
* @param downloadingService 用户可以通过 DownloadingService#shutdownNow 终止下载
*/
@Override
public void onBindService(String url, DownloadingService downloadingService) {
super.onBindService(url, downloadingService);
mDownloadingService = downloadingService;
LogUtils.i(TAG, "onBindService:" + url + " DownloadingService:" + downloadingService);
}
/**
* 回调onUnbindService方法让用户释放掉 DownloadingService。
* @param url
* @param downloadingService
*/
@Override
public void onUnbindService(String url, DownloadingService downloadingService) {
super.onUnbindService(url, downloadingService);
mDownloadingService = null;
LogUtils.i(TAG, "onUnbindService:" + url);
}
/**
*
* @param url 下载链接
* @param loaded 已经下载的长度
* @param length 文件的总大小
* @param usedTime 耗时 单位ms
* 注意该方法回调在子线程 ,线程名 AsyncTask #XX 或者 AgentWeb # XX
*/
@Override
public void onProgress(String url, long loaded, long length, long usedTime) {
int mProgress = (int) ((loaded) / Float.valueOf(length) * 100);
LogUtils.i(TAG, "onProgress:" + mProgress);
super.onProgress(url, loaded, length, usedTime);
}
/**
*
* @param path 文件的绝对路径
* @param url 下载地址
* @param throwable 如果异常,返回给用户异常
* @return true 表示用户处理了下载完成后续的事件 false 默认交给AgentWeb 处理
*/
@Override
public boolean onResult(String path, String url, Throwable throwable) {
//下载成功
if (null == throwable) {
//do you work
} else {//下载失败
}
// true 不会发出下载完成的通知 , 或者打开文件
return false;
}
};
/**
* @return IAgentWebSettings
*/
public IAgentWebSettings getSettings() {
return new AbsAgentWebSettings() {
private AgentWeb mAgentWeb;
@Override
protected void bindAgentWebSupport(AgentWeb agentWeb) {
this.mAgentWeb = agentWeb;
}
/**
* AgentWeb 4.0.0 内部删除了 DownloadListener 监听 以及相关API ,将 Download 部分完全抽离出来独立一个库,
* 如果你需要使用 AgentWeb Download 部分 请依赖上 compile 'com.just.agentweb:download:4.0.0
* 如果你需要监听下载结果,请自定义 AgentWebSetting New 出 DefaultDownloadImpl传入DownloadListenerAdapter
* 实现进度或者结果监听,例如下面这个例子,如果你不需要监听进度,或者下载结果,下面 setDownloader 的例子可以忽略。
* @param webView
* @param downloadListener
* @return WebListenerManager
*/
@Override
public WebListenerManager setDownloader(WebView webView, android.webkit.DownloadListener downloadListener) {
return super.setDownloader(webView,
DefaultDownloadImpl
.create(getActivity(),
webView,
mDownloadListenerAdapter,
mDownloadListenerAdapter,
this.mAgentWeb.getPermissionInterceptor()));
}
};
}
//===================WebChromeClient 和 WebViewClient===========================//
/**
* 页面空白请检查scheme是否加上 scheme://host:port/path?query&query 。
*
* @return mUrl
*/
public String getUrl() {
String target = "";
Bundle bundle = getArguments();
if (bundle != null) {
target = bundle.getString(KEY_URL);
}
if (TextUtils.isEmpty(target)) {
target = "https://github.com/xuexiangjys";
}
return target;
}
protected WebChromeClient mWebChromeClient = new WebChromeClient() {
@Override
public void onProgressChanged(WebView view, int newProgress) {
Log.i(TAG, "onProgressChanged:" + newProgress + " view:" + view);
}
@Override
public void onReceivedTitle(WebView view, String title) {
super.onReceivedTitle(view, title);
if (mTitleTextView != null && !TextUtils.isEmpty(title)) {
if (title.length() > 10) {
title = title.substring(0, 10).concat("...");
}
mTitleTextView.setText(title);
}
}
};
protected WebViewClient mWebViewClient = new WebViewClient() {
private HashMap<String, Long> timer = new HashMap<>();
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
super.onReceivedError(view, request, error);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
return shouldOverrideUrlLoading(view, request.getUrl() + "");
}
@Nullable
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
return super.shouldInterceptRequest(view, request);
}
//
@Override
public boolean shouldOverrideUrlLoading(final WebView view, String url) {
//intent:// scheme的处理 如果返回false 则交给 DefaultWebClient 处理 默认会打开该Activity 如果Activity不存在则跳到应用市场上去. true 表示拦截
//例如优酷视频播放 intent://play?...package=com.youku.phone;end;
//优酷想唤起自己应用播放该视频 下面拦截地址返回 true 则会在应用内 H5 播放 ,禁止优酷唤起播放该视频, 如果返回 false DefaultWebClient 会根据intent 协议处理 该地址 首先匹配该应用存不存在 ,如果存在 唤起该应用播放 如果不存在 则跳到应用市场下载该应用 .
if (url.startsWith("intent://") && url.contains("com.youku.phone")) {
return true;
}
return false;
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
Log.i(TAG, "mUrl:" + url + " onPageStarted target:" + getUrl());
timer.put(url, System.currentTimeMillis());
if (url.equals(getUrl())) {
pageNavigator(View.GONE);
} else {
pageNavigator(View.VISIBLE);
}
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
if (timer.get(url) != null) {
long overTime = System.currentTimeMillis();
Long startTime = timer.get(url);
Log.i(TAG, " page mUrl:" + url + " used time:" + (overTime - startTime));
}
}
@Override
public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
super.onReceivedHttpError(view, request, errorResponse);
}
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
}
};
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
//========================菜单功能================================//
/**
* 打开浏览器
*
* @param targetUrl 外部浏览器打开的地址
*/
private void openBrowser(String targetUrl) {
if (TextUtils.isEmpty(targetUrl) || targetUrl.startsWith("file://")) {
XToastUtils.toast(targetUrl + " 该链接无法使用浏览器打开。");
return;
}
Intent intent = new Intent();
intent.setAction("android.intent.action.VIEW");
Uri uri = Uri.parse(targetUrl);
intent.setData(uri);
startActivity(intent);
}
/**
* 显示更多菜单
*
* @param view 菜单依附在该View下面
*/
private void showPoPup(View view) {
if (mPopupMenu == null) {
mPopupMenu = new PopupMenu(getContext(), view);
mPopupMenu.inflate(R.menu.menu_toolbar_web);
mPopupMenu.setOnMenuItemClickListener(mOnMenuItemClickListener);
}
mPopupMenu.show();
}
/**
* 菜单事件
*/
private PopupMenu.OnMenuItemClickListener mOnMenuItemClickListener = new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.refresh:
if (mAgentWeb != null) {
mAgentWeb.getUrlLoader().reload(); // 刷新
}
return true;
case R.id.copy:
if (mAgentWeb != null) {
toCopy(getContext(), mAgentWeb.getWebCreator().getWebView().getUrl());
}
return true;
case R.id.default_browser:
if (mAgentWeb != null) {
openBrowser(mAgentWeb.getWebCreator().getWebView().getUrl());
}
return true;
case R.id.share:
if (mAgentWeb != null) {
shareWebUrl(mAgentWeb.getWebCreator().getWebView().getUrl());
}
return true;
default:
return false;
}
}
};
/**
* 分享网页链接
*
* @param url 网页链接
*/
private void shareWebUrl(String url) {
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_TEXT, url);
shareIntent.setType("text/plain");
//设置分享列表的标题,并且每次都显示分享列表
startActivity(Intent.createChooser(shareIntent, "分享到"));
}
/**
* 复制字符串
*
* @param context
* @param text
*/
private void toCopy(Context context, String text) {
ClipboardManager manager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
if (manager == null) {
return;
}
manager.setPrimaryClip(ClipData.newPlainText(null, text));
}
//===================生命周期管理===========================//
@Override
public void onResume() {
mAgentWeb.getWebLifeCycle().onResume();//恢复
super.onResume();
}
@Override
public void onPause() {
mAgentWeb.getWebLifeCycle().onPause(); //暂停应用内所有WebView 调用mWebView.resumeTimers();/mAgentWeb.getWebLifeCycle().onResume(); 恢复。
super.onPause();
}
@Override
public boolean onFragmentKeyDown(int keyCode, KeyEvent event) {
return mAgentWeb.handleKeyEvent(keyCode, event);
}
@Override
public void onDestroyView() {
mAgentWeb.getWebLifeCycle().onDestroy();
super.onDestroyView();
}
//===================中间键===========================//
/**
* MiddlewareWebClientBase 是 AgentWeb 3.0.0 提供一个强大的功能,
* 如果用户需要使用 AgentWeb 提供的功能, 不想重写 WebClientView方
* 法覆盖AgentWeb提供的功能那么 MiddlewareWebClientBase 是一个
* 不错的选择 。
*
* @return
*/
protected MiddlewareWebClientBase getMiddlewareWebClient() {
return new MiddlewareWebViewClient() {
/**
*
* @param view
* @param url
* @return
*/
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// 拦截 url不执行 DefaultWebClient#shouldOverrideUrlLoading
if (url.startsWith("agentweb")) {
Log.i(TAG, "agentweb scheme ~");
return true;
}
// 执行 DefaultWebClient#shouldOverrideUrlLoading
if (super.shouldOverrideUrlLoading(view, url)) {
return true;
}
// do you work
return false;
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
return super.shouldOverrideUrlLoading(view, request);
}
};
}
protected MiddlewareWebChromeBase getMiddlewareWebChrome() {
return new MiddlewareChromeClient() {
};
}
}

View File

@@ -1,66 +0,0 @@
/*
* 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.core.webview;
import android.view.KeyEvent;
import com.just.agentweb.core.AgentWeb;
import com.kerwin.wumei.core.BaseFragment;
/**
* 基础web
*
* @author xuexiang
* @since 2019/5/28 10:22
*/
public abstract class BaseWebViewFragment extends BaseFragment {
protected AgentWeb mAgentWeb;
//===================生命周期管理===========================//
@Override
public void onResume() {
if (mAgentWeb != null) {
//恢复
mAgentWeb.getWebLifeCycle().onResume();
}
super.onResume();
}
@Override
public void onPause() {
if (mAgentWeb != null) {
//暂停应用内所有WebView 调用mWebView.resumeTimers();/mAgentWeb.getWebLifeCycle().onResume(); 恢复。
mAgentWeb.getWebLifeCycle().onPause();
}
super.onPause();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return mAgentWeb != null && mAgentWeb.handleKeyEvent(keyCode, event);
}
@Override
public void onDestroyView() {
if (mAgentWeb != null) {
mAgentWeb.destroy();
}
super.onDestroyView();
}
}

View File

@@ -1,37 +0,0 @@
/*
* 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.core.webview;
import android.view.KeyEvent;
/**
*
*
* @author xuexiang
* @since 2019/1/4 下午11:32
*/
public interface FragmentKeyDown {
/**
* fragment按键监听
* @param keyCode
* @param event
* @return
*/
boolean onFragmentKeyDown(int keyCode, KeyEvent event);
}

View File

@@ -1,66 +0,0 @@
/*
* 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.core.webview;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Build;
import android.util.AttributeSet;
import android.webkit.WebView;
/**
* 修复 Android 5.0 & 5.1 打开 WebView 闪退问题:
* 参阅 https://stackoverflow.com/questions/41025200/android-view-inflateexception-error-inflating-class-android-webkit-webview
*/
@SuppressWarnings("unused")
public class LollipopFixedWebView extends WebView {
public LollipopFixedWebView(Context context) {
super(getFixedContext(context));
}
public LollipopFixedWebView(Context context, AttributeSet attrs) {
super(getFixedContext(context), attrs);
}
public LollipopFixedWebView(Context context, AttributeSet attrs, int defStyleAttr) {
super(getFixedContext(context), attrs, defStyleAttr);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public LollipopFixedWebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(getFixedContext(context), attrs, defStyleAttr, defStyleRes);
}
public LollipopFixedWebView(Context context, AttributeSet attrs, int defStyleAttr, boolean privateBrowsing) {
super(getFixedContext(context), attrs, defStyleAttr, privateBrowsing);
}
public static Context getFixedContext(Context context) {
if (isLollipopWebViewBug()) {
// Avoid crashing on Android 5 and 6 (API level 21 to 23)
return context.createConfigurationContext(new Configuration());
}
return context;
}
public static boolean isLollipopWebViewBug() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && Build.VERSION.SDK_INT < Build.VERSION_CODES.M;
}
}

View File

@@ -1,49 +0,0 @@
/*
* 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.core.webview;
import android.util.Log;
import android.webkit.JsResult;
import android.webkit.WebView;
import com.just.agentweb.core.client.MiddlewareWebChromeBase;
/**
* WebChromeWebChromeClient主要辅助WebView处理JavaScript的对话框、网站图片、网站title、加载进度等中间件
* 【浏览器】
* @author xuexiang
* @since 2019/1/4 下午11:31
*/
public class MiddlewareChromeClient extends MiddlewareWebChromeBase {
public MiddlewareChromeClient() {
}
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
Log.i("Info", "onJsAlert:" + url);
return super.onJsAlert(view, url, message, result);
}
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
Log.i("Info", "onProgressChanged:");
}
}

View File

@@ -1,146 +0,0 @@
/*
* 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.core.webview;
import android.net.Uri;
import android.os.Build;
import android.util.Log;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
import androidx.annotation.RequiresApi;
import com.just.agentweb.core.client.MiddlewareWebClientBase;
import com.kerwin.wumei.R;
import com.xuexiang.xui.utils.ResUtils;
/**
* 【网络请求、加载】
* WebClientWebViewClient 这个类主要帮助WebView处理各种通知、url加载请求时间的中间件
* <p>
* <p>
* 方法的执行顺序例如下面用了7个中间件一个 WebViewClient
* <p>
* .useMiddlewareWebClient(getMiddlewareWebClient()) // 1
* .useMiddlewareWebClient(getMiddlewareWebClient()) // 2
* .useMiddlewareWebClient(getMiddlewareWebClient()) // 3
* .useMiddlewareWebClient(getMiddlewareWebClient()) // 4
* .useMiddlewareWebClient(getMiddlewareWebClient()) // 5
* .useMiddlewareWebClient(getMiddlewareWebClient()) // 6
* .useMiddlewareWebClient(getMiddlewareWebClient()) // 7
* DefaultWebClient // 8
* .setWebViewClient(mWebViewClient) // 9
* <p>
* <p>
* 典型的洋葱模型
* 对象内部的方法执行顺序: 1->2->3->4->5->6->7->8->9->8->7->6->5->4->3->2->1
* <p>
* <p>
* 中断中间件的执行, 删除super.methodName(...) 这行即可
* <p>
* 这里主要是做去广告的工作
*/
public class MiddlewareWebViewClient extends MiddlewareWebClientBase {
public MiddlewareWebViewClient() {
}
private static int count = 1;
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
Log.i("Info", "MiddlewareWebViewClient -- > shouldOverrideUrlLoading:" + request.getUrl().toString() + " c:" + (count++));
if (shouldOverrideUrlLoadingByApp(view, request.getUrl().toString())) {
return true;
}
return super.shouldOverrideUrlLoading(view, request);
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Log.i("Info", "MiddlewareWebViewClient -- > shouldOverrideUrlLoading:" + url + " c:" + (count++));
if (shouldOverrideUrlLoadingByApp(view, url)) {
return true;
}
return super.shouldOverrideUrlLoading(view, url);
}
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
url = url.toLowerCase();
if (!hasAdUrl(url)) {
//正常加载
return super.shouldInterceptRequest(view, url);
} else {
//含有广告资源屏蔽请求
return new WebResourceResponse(null, null, null);
}
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
String url = request.getUrl().toString().toLowerCase();
if (!hasAdUrl(url)) {
//正常加载
return super.shouldInterceptRequest(view, request);
} else {
//含有广告资源屏蔽请求
return new WebResourceResponse(null, null, null);
}
}
/**
* 判断是否存在广告的链接
*
* @param url
* @return
*/
private static boolean hasAdUrl(String url) {
String[] adUrls = ResUtils.getStringArray(R.array.adBlockUrl);
for (String adUrl : adUrls) {
if (url.contains(adUrl)) {
return true;
}
}
return false;
}
/**
* 根据url的scheme处理跳转第三方app的业务,true代表拦截false代表不拦截
*/
private boolean shouldOverrideUrlLoadingByApp(WebView webView, final String url) {
if (url.startsWith("http") || url.startsWith("https") || url.startsWith("ftp")) {
//不拦截http, https, ftp的请求
Uri uri = Uri.parse(url);
if (uri != null && !(WebViewInterceptDialog.APP_LINK_HOST.equals(uri.getHost())
//防止xui官网被拦截
&& url.contains("xpage"))) {
return false;
}
}
WebViewInterceptDialog.show(url);
return true;
}
}

View File

@@ -1,56 +0,0 @@
/*
* 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.core.webview;
import android.app.Activity;
import android.os.Handler;
import android.util.Log;
import android.webkit.WebView;
import com.just.agentweb.core.web.AgentWebUIControllerImplBase;
import java.lang.ref.WeakReference;
/**
* 如果你需要修改某一个AgentWeb 内部的某一个弹窗 ,请看下面的例子
* 注意写法一定要参照 DefaultUIController 的写法 因为UI自由定制但是回调的方式是固定的并且一定要回调。
*
* @author xuexiang
* @since 2019-10-30 23:18
*/
public class UIController extends AgentWebUIControllerImplBase {
private WeakReference<Activity> mActivity;
public UIController(Activity activity) {
mActivity = new WeakReference<>(activity);
}
@Override
public void onShowMessage(String message, String from) {
super.onShowMessage(message, from);
Log.i(TAG, "message:" + message);
}
@Override
public void onSelectItemsPrompt(WebView view, String url, String[] items, Handler.Callback callback) {
// 使用默认的UI
super.onSelectItemsPrompt(view, url, items, callback);
}
}

View File

@@ -1,61 +0,0 @@
/*
* 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.core.webview;
import android.app.Activity;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.webkit.WebView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.just.agentweb.widget.IWebLayout;
import com.scwang.smartrefresh.layout.SmartRefreshLayout;
import com.kerwin.wumei.R;
/**
* 定义支持下来回弹的WebView
*
* @author xuexiang
* @since 2019/1/5 上午2:01
*/
public class WebLayout implements IWebLayout {
private final SmartRefreshLayout mSmartRefreshLayout;
private WebView mWebView;
public WebLayout(Activity activity) {
mSmartRefreshLayout = (SmartRefreshLayout) LayoutInflater.from(activity).inflate(R.layout.fragment_pulldown_web, null);
mWebView = mSmartRefreshLayout.findViewById(R.id.webView);
}
@NonNull
@Override
public ViewGroup getLayout() {
return mSmartRefreshLayout;
}
@Nullable
@Override
public WebView getWebView() {
return mWebView;
}
}

View File

@@ -1,137 +0,0 @@
/*
* 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.core.webview;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.kerwin.wumei.R;
import com.kerwin.wumei.utils.XToastUtils;
import com.xuexiang.xui.utils.ResUtils;
import com.xuexiang.xui.widget.dialog.DialogLoader;
import com.xuexiang.xutil.XUtil;
import com.xuexiang.xutil.app.ActivityUtils;
import java.net.URISyntaxException;
/**
* WebView拦截提示
*
* @author xuexiang
* @since 2019-10-21 9:51
*/
public class WebViewInterceptDialog extends AppCompatActivity implements DialogInterface.OnDismissListener {
private static final String KEY_INTERCEPT_URL = "key_intercept_url";
// TODO: 2019-10-30 这里修改你的applink
public static final String APP_LINK_HOST = "xuexiangjys.club";
public static final String APP_LINK_ACTION = "com.xuexiang.xui.applink";
/**
* 显示WebView拦截提示
*
* @param url 需要拦截处理的url
*/
public static void show(String url) {
ActivityUtils.startActivity(WebViewInterceptDialog.class, KEY_INTERCEPT_URL, url);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String url = getIntent().getStringExtra(KEY_INTERCEPT_URL);
DialogLoader.getInstance().showConfirmDialog(
this,
getOpenTitle(url),
ResUtils.getString(R.string.lab_yes),
(dialog, which) -> {
dialog.dismiss();
if (isAppLink(url)) {
openAppLink(this, url);
} else {
openApp(url);
}
},
ResUtils.getString(R.string.lab_no),
(dialog, which) -> dialog.dismiss()
).setOnDismissListener(this);
}
private String getOpenTitle(String url) {
String scheme = getScheme(url);
if ("mqqopensdkapi".equals(scheme)) {
return "是否允许页面打开\"QQ\"?";
} else {
return ResUtils.getString(R.string.lab_open_third_app);
}
}
private String getScheme(String url) {
try {
Intent intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
return intent.getScheme();
} catch (URISyntaxException e) {
e.printStackTrace();
}
return "";
}
private boolean isAppLink(String url) {
Uri uri = Uri.parse(url);
return uri != null
&& APP_LINK_HOST.equals(uri.getHost())
&& (url.startsWith("http") || url.startsWith("https"));
}
private void openApp(String url) {
Intent intent;
try {
intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
XUtil.getContext().startActivity(intent);
} catch (Exception e) {
XToastUtils.error("您所打开的第三方App未安装");
}
}
private void openAppLink(Context context, String url) {
try {
Intent intent = new Intent(APP_LINK_ACTION);
intent.setData(Uri.parse(url));
context.startActivity(intent);
} catch (Exception e) {
XToastUtils.error("您所打开的第三方App未安装");
}
}
@Override
public void onDismiss(DialogInterface dialog) {
finish();
}
}

View File

@@ -1,677 +0,0 @@
/*
* 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.core.webview;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.appcompat.widget.PopupMenu;
import androidx.fragment.app.Fragment;
import com.just.agentweb.action.PermissionInterceptor;
import com.just.agentweb.core.AgentWeb;
import com.just.agentweb.core.client.DefaultWebClient;
import com.just.agentweb.core.client.MiddlewareWebChromeBase;
import com.just.agentweb.core.client.MiddlewareWebClientBase;
import com.just.agentweb.core.client.WebListenerManager;
import com.just.agentweb.core.web.AbsAgentWebSettings;
import com.just.agentweb.core.web.AgentWebConfig;
import com.just.agentweb.core.web.IAgentWebSettings;
import com.just.agentweb.download.AgentWebDownloader;
import com.just.agentweb.download.DefaultDownloadImpl;
import com.just.agentweb.download.DownloadListenerAdapter;
import com.just.agentweb.download.DownloadingService;
import com.just.agentweb.widget.IWebLayout;
import com.kerwin.wumei.MyApp;
import com.kerwin.wumei.core.BaseFragment;
import com.kerwin.wumei.R;
import com.kerwin.wumei.utils.XToastUtils;
import com.xuexiang.xaop.annotation.SingleClick;
import com.xuexiang.xpage.annotation.Page;
import com.xuexiang.xpage.base.XPageActivity;
import com.xuexiang.xpage.base.XPageFragment;
import com.xuexiang.xpage.core.PageOption;
import com.xuexiang.xui.widget.actionbar.TitleBar;
import com.xuexiang.xutil.common.logger.Logger;
import com.xuexiang.xutil.net.JsonUtil;
import java.util.HashMap;
import butterknife.BindView;
import butterknife.OnClick;
/**
* 使用XPageFragment
*
* @author xuexiang
* @since 2019-05-26 18:15
*/
@Page(params = {AgentWebFragment.KEY_URL})
public class XPageWebViewFragment extends BaseFragment {
@BindView(R.id.iv_back)
AppCompatImageView mIvBack;
@BindView(R.id.view_line)
View mLineView;
@BindView(R.id.toolbar_title)
TextView mTvTitle;
protected AgentWeb mAgentWeb;
private PopupMenu mPopupMenu;
private DownloadingService mDownloadingService;
/**
* 打开网页
*
* @param xPageActivity
* @param url
* @return
*/
public static Fragment openUrl(XPageActivity xPageActivity, String url) {
return PageOption.to(XPageWebViewFragment.class)
.putString(AgentWebFragment.KEY_URL, url)
.open(xPageActivity);
}
/**
* 打开网页
*
* @param fragment
* @param url
* @return
*/
public static Fragment openUrl(XPageFragment fragment, String url) {
return PageOption.to(XPageWebViewFragment.class)
.setNewActivity(true)
.putString(AgentWebFragment.KEY_URL, url)
.open(fragment);
}
@Override
protected TitleBar initTitle() {
return null;
}
/**
* 布局的资源id
*
* @return
*/
@Override
protected int getLayoutId() {
return R.layout.fragment_agentweb;
}
/**
* 初始化控件
*/
@Override
protected void initViews() {
mAgentWeb = AgentWeb.with(this)
//传入AgentWeb的父控件。
.setAgentWebParent((LinearLayout) getRootView(), -1, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT))
//设置进度条颜色与高度,-1为默认值高度为2单位为dp。
.useDefaultIndicator(-1, 3)
//设置 IAgentWebSettings。
.setAgentWebWebSettings(getSettings())
//WebViewClient 与 WebView 使用一致 但是请勿获取WebView调用setWebViewClient(xx)方法了,会覆盖AgentWeb DefaultWebClient,同时相应的中间件也会失效。
.setWebViewClient(mWebViewClient)
//WebChromeClient
.setWebChromeClient(mWebChromeClient)
//设置WebChromeClient中间件支持多个WebChromeClientAgentWeb 3.0.0 加入。
.useMiddlewareWebChrome(getMiddlewareWebChrome())
//设置WebViewClient中间件支持多个WebViewClient AgentWeb 3.0.0 加入。
.useMiddlewareWebClient(getMiddlewareWebClient())
//权限拦截 2.0.0 加入。
.setPermissionInterceptor(mPermissionInterceptor)
//严格模式 Android 4.2.2 以下会放弃注入对象 使用AgentWebView没影响。
.setSecurityType(AgentWeb.SecurityType.STRICT_CHECK)
//自定义UI AgentWeb3.0.0 加入。
.setAgentWebUIController(new UIController(getActivity()))
//参数1是错误显示的布局参数2点击刷新控件ID -1表示点击整个布局都刷新 AgentWeb 3.0.0 加入。
.setMainFrameErrorView(R.layout.agentweb_error_page, -1)
.setWebLayout(getWebLayout())
//打开其他页面时,弹窗质询用户前往其他应用 AgentWeb 3.0.0 加入。
.setOpenOtherPageWays(DefaultWebClient.OpenOtherPageWays.DISALLOW)
//拦截找不到相关页面的Url AgentWeb 3.0.0 加入。
.interceptUnkownUrl()
//创建AgentWeb。
.createAgentWeb()
.ready()//设置 WebSettings。
//WebView载入该url地址的页面并显示。
.go(getUrl());
if (MyApp.isDebug()) {
AgentWebConfig.debug();
}
pageNavigator(View.GONE);
// 得到 AgentWeb 最底层的控件
addBackgroundChild(mAgentWeb.getWebCreator().getWebParentLayout());
// AgentWeb 没有把WebView的功能全面覆盖 ,所以某些设置 AgentWeb 没有提供请从WebView方面入手设置。
mAgentWeb.getWebCreator().getWebView().setOverScrollMode(WebView.OVER_SCROLL_NEVER);
}
protected IWebLayout getWebLayout() {
return new WebLayout(getActivity());
}
protected void addBackgroundChild(FrameLayout frameLayout) {
TextView textView = new TextView(frameLayout.getContext());
textView.setText("技术由 AgentWeb 提供");
textView.setTextSize(16);
textView.setTextColor(Color.parseColor("#727779"));
frameLayout.setBackgroundColor(Color.parseColor("#272b2d"));
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(-2, -2);
params.gravity = Gravity.CENTER_HORIZONTAL;
final float scale = frameLayout.getContext().getResources().getDisplayMetrics().density;
params.topMargin = (int) (15 * scale + 0.5f);
frameLayout.addView(textView, 0, params);
}
private void pageNavigator(int tag) {
//返回的导航按钮
mIvBack.setVisibility(tag);
mLineView.setVisibility(tag);
}
@SingleClick
@OnClick({R.id.iv_back, R.id.iv_finish, R.id.iv_more})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.iv_back:
// true表示AgentWeb处理了该事件
if (!mAgentWeb.back()) {
popToBack();
}
break;
case R.id.iv_finish:
popToBack();
break;
case R.id.iv_more:
showPoPup(view);
break;
default:
break;
}
}
//=====================下载============================//
/**
* 更新于 AgentWeb 4.0.0,下载监听
*/
protected DownloadListenerAdapter mDownloadListenerAdapter = new DownloadListenerAdapter() {
/**
*
* @param url 下载链接
* @param userAgent UserAgent
* @param contentDisposition ContentDisposition
* @param mimeType 资源的媒体类型
* @param contentLength 文件长度
* @param extra 下载配置 用户可以通过 Extra 修改下载icon 关闭进度条 是否强制下载。
* @return true 表示用户处理了该下载事件 false 交给 AgentWeb 下载
*/
@Override
public boolean onStart(String url, String userAgent, String contentDisposition, String mimeType, long contentLength, AgentWebDownloader.Extra extra) {
Logger.i("onStart:" + url);
// 是否开启断点续传
extra.setOpenBreakPointDownload(true)
//下载通知的icon
.setIcon(R.drawable.ic_file_download_black_24dp)
// 连接的超时时间
.setConnectTimeOut(6000)
// 以8KB位单位默认60s 如果60s内无法从网络流中读满8KB数据则抛出异常
.setBlockMaxTime(10 * 60 * 1000)
// 下载的超时时间
.setDownloadTimeOut(Long.MAX_VALUE)
// 串行下载更节省资源哦
.setParallelDownload(false)
// false 关闭进度通知
.setEnableIndicator(true)
// 自定义请求头
.addHeader("Cookie", "xx")
// 下载完成自动打开
.setAutoOpen(true)
// 强制下载,不管网络网络类型
.setForceDownload(true);
return false;
}
/**
*
* 不需要暂停或者停止下载该方法可以不必实现
* @param url
* @param downloadingService 用户可以通过 DownloadingService#shutdownNow 终止下载
*/
@Override
public void onBindService(String url, DownloadingService downloadingService) {
super.onBindService(url, downloadingService);
mDownloadingService = downloadingService;
Logger.i("onBindService:" + url + " DownloadingService:" + downloadingService);
}
/**
* 回调onUnbindService方法让用户释放掉 DownloadingService。
* @param url
* @param downloadingService
*/
@Override
public void onUnbindService(String url, DownloadingService downloadingService) {
super.onUnbindService(url, downloadingService);
mDownloadingService = null;
Logger.i("onUnbindService:" + url);
}
/**
*
* @param url 下载链接
* @param loaded 已经下载的长度
* @param length 文件的总大小
* @param usedTime 耗时 单位ms
* 注意该方法回调在子线程 ,线程名 AsyncTask #XX 或者 AgentWeb # XX
*/
@Override
public void onProgress(String url, long loaded, long length, long usedTime) {
int mProgress = (int) ((loaded) / (float) length * 100);
Logger.i("onProgress:" + mProgress);
super.onProgress(url, loaded, length, usedTime);
}
/**
*
* @param path 文件的绝对路径
* @param url 下载地址
* @param throwable 如果异常,返回给用户异常
* @return true 表示用户处理了下载完成后续的事件 false 默认交给AgentWeb 处理
*/
@Override
public boolean onResult(String path, String url, Throwable throwable) {
//下载成功
if (null == throwable) {
//do you work
} else {//下载失败
}
// true 不会发出下载完成的通知 , 或者打开文件
return false;
}
};
/**
* 下载服务设置
*
* @return IAgentWebSettings
*/
public IAgentWebSettings getSettings() {
return new AbsAgentWebSettings() {
private AgentWeb mAgentWeb;
@Override
protected void bindAgentWebSupport(AgentWeb agentWeb) {
this.mAgentWeb = agentWeb;
}
/**
* AgentWeb 4.0.0 内部删除了 DownloadListener 监听 以及相关API ,将 Download 部分完全抽离出来独立一个库,
* 如果你需要使用 AgentWeb Download 部分 请依赖上 compile 'com.just.agentweb:download:4.0.0
* 如果你需要监听下载结果,请自定义 AgentWebSetting New 出 DefaultDownloadImpl传入DownloadListenerAdapter
* 实现进度或者结果监听,例如下面这个例子,如果你不需要监听进度,或者下载结果,下面 setDownloader 的例子可以忽略。
* @param webView
* @param downloadListener
* @return WebListenerManager
*/
@Override
public WebListenerManager setDownloader(WebView webView, android.webkit.DownloadListener downloadListener) {
return super.setDownloader(webView,
DefaultDownloadImpl
.create(getActivity(),
webView,
mDownloadListenerAdapter,
mDownloadListenerAdapter,
mAgentWeb.getPermissionInterceptor()));
}
};
}
//===================WebChromeClient 和 WebViewClient===========================//
/**
* 页面空白请检查scheme是否加上 scheme://host:port/path?query&query 。
*
* @return mUrl
*/
public String getUrl() {
String target = "";
Bundle bundle = getArguments();
if (bundle != null) {
target = bundle.getString(AgentWebFragment.KEY_URL);
}
if (TextUtils.isEmpty(target)) {
target = "https://github.com/xuexiangjys";
}
return target;
}
/**
* 和浏览器相关包括和JS的交互
*/
protected WebChromeClient mWebChromeClient = new WebChromeClient() {
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
//网页加载进度
}
@Override
public void onReceivedTitle(WebView view, String title) {
super.onReceivedTitle(view, title);
if (mTvTitle != null && !TextUtils.isEmpty(title)) {
if (title.length() > 10) {
title = title.substring(0, 10).concat("...");
}
mTvTitle.setText(title);
}
}
};
/**
* 和网页url加载相关统计加载时间
*/
protected WebViewClient mWebViewClient = new WebViewClient() {
private HashMap<String, Long> mTimer = new HashMap<>();
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
super.onReceivedError(view, request, error);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
return shouldOverrideUrlLoading(view, request.getUrl() + "");
}
@Nullable
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
return super.shouldInterceptRequest(view, request);
}
@Override
public boolean shouldOverrideUrlLoading(final WebView view, String url) {
//intent:// scheme的处理 如果返回false 则交给 DefaultWebClient 处理 默认会打开该Activity 如果Activity不存在则跳到应用市场上去. true 表示拦截
//例如优酷视频播放 intent://play?...package=com.youku.phone;end;
//优酷想唤起自己应用播放该视频 下面拦截地址返回 true 则会在应用内 H5 播放 ,禁止优酷唤起播放该视频, 如果返回 false DefaultWebClient 会根据intent 协议处理 该地址 首先匹配该应用存不存在 ,如果存在 唤起该应用播放 如果不存在 则跳到应用市场下载该应用 .
if (url.startsWith("intent://") && url.contains("com.youku.phone")) {
return true;
}
return false;
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
mTimer.put(url, System.currentTimeMillis());
if (url.equals(getUrl())) {
pageNavigator(View.GONE);
} else {
pageNavigator(View.VISIBLE);
}
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
if (mTimer.get(url) != null) {
long overTime = System.currentTimeMillis();
Long startTime = mTimer.get(url);
//统计页面的使用时长
Logger.i(" page mUrl:" + url + " used time:" + (overTime - startTime));
}
}
@Override
public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
super.onReceivedHttpError(view, request, errorResponse);
}
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
}
};
//=====================菜单========================//
/**
* 显示更多菜单
*
* @param view 菜单依附在该View下面
*/
private void showPoPup(View view) {
if (mPopupMenu == null) {
mPopupMenu = new PopupMenu(getContext(), view);
mPopupMenu.inflate(R.menu.menu_toolbar_web);
mPopupMenu.setOnMenuItemClickListener(mOnMenuItemClickListener);
}
mPopupMenu.show();
}
/**
* 菜单事件
*/
private PopupMenu.OnMenuItemClickListener mOnMenuItemClickListener = new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.refresh:
if (mAgentWeb != null) {
mAgentWeb.getUrlLoader().reload(); // 刷新
}
return true;
case R.id.copy:
if (mAgentWeb != null) {
toCopy(getContext(), mAgentWeb.getWebCreator().getWebView().getUrl());
}
return true;
case R.id.default_browser:
if (mAgentWeb != null) {
openBrowser(mAgentWeb.getWebCreator().getWebView().getUrl());
}
return true;
case R.id.share:
if (mAgentWeb != null) {
shareWebUrl(mAgentWeb.getWebCreator().getWebView().getUrl());
}
return true;
default:
return false;
}
}
};
/**
* 打开浏览器
*
* @param targetUrl 外部浏览器打开的地址
*/
private void openBrowser(String targetUrl) {
if (TextUtils.isEmpty(targetUrl) || targetUrl.startsWith("file://")) {
XToastUtils.toast(targetUrl + " 该链接无法使用浏览器打开。");
return;
}
Intent intent = new Intent();
intent.setAction("android.intent.action.VIEW");
Uri uri = Uri.parse(targetUrl);
intent.setData(uri);
startActivity(intent);
}
/**
* 分享网页链接
*
* @param url 网页链接
*/
private void shareWebUrl(String url) {
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_TEXT, url);
shareIntent.setType("text/plain");
//设置分享列表的标题,并且每次都显示分享列表
startActivity(Intent.createChooser(shareIntent, "分享到"));
}
/**
* 复制字符串
*
* @param context
* @param text
*/
private void toCopy(Context context, String text) {
ClipboardManager manager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
if (manager == null) {
return;
}
manager.setPrimaryClip(ClipData.newPlainText(null, text));
}
//===================生命周期管理===========================//
@Override
public void onResume() {
if (mAgentWeb != null) {
mAgentWeb.getWebLifeCycle().onResume();//恢复
}
super.onResume();
}
@Override
public void onPause() {
if (mAgentWeb != null) {
mAgentWeb.getWebLifeCycle().onPause(); //暂停应用内所有WebView 调用mWebView.resumeTimers();/mAgentWeb.getWebLifeCycle().onResume(); 恢复。
}
super.onPause();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return mAgentWeb != null && mAgentWeb.handleKeyEvent(keyCode, event);
}
@Override
public void onDestroyView() {
if (mAgentWeb != null) {
mAgentWeb.destroy();
}
super.onDestroyView();
}
//===================中间键===========================//
/**
* MiddlewareWebClientBase 是 AgentWeb 3.0.0 提供一个强大的功能,
* 如果用户需要使用 AgentWeb 提供的功能, 不想重写 WebClientView方
* 法覆盖AgentWeb提供的功能那么 MiddlewareWebClientBase 是一个
* 不错的选择 。
*
* @return
*/
protected MiddlewareWebClientBase getMiddlewareWebClient() {
return new MiddlewareWebViewClient() {
/**
*
* @param view
* @param url
* @return
*/
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// 拦截 url不执行 DefaultWebClient#shouldOverrideUrlLoading
if (url.startsWith("agentweb")) {
return true;
}
// 执行 DefaultWebClient#shouldOverrideUrlLoading
if (super.shouldOverrideUrlLoading(view, url)) {
return true;
}
// do you work
return false;
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
return super.shouldOverrideUrlLoading(view, request);
}
};
}
protected MiddlewareWebChromeBase getMiddlewareWebChrome() {
return new MiddlewareChromeClient() {
};
}
/**
* 权限申请拦截器
*/
protected PermissionInterceptor mPermissionInterceptor = new PermissionInterceptor() {
/**
* PermissionInterceptor 能达到 url1 允许授权, url2 拒绝授权的效果。
* @param url
* @param permissions
* @param action
* @return true 该Url对应页面请求权限进行拦截 false 表示不拦截。
*/
@Override
public boolean intercept(String url, String[] permissions, String action) {
Logger.i("mUrl:" + url + " permission:" + JsonUtil.toJson(permissions) + " action:" + action);
return false;
}
};
}

View File

@@ -1,121 +0,0 @@
/******************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@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<Dept> 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<Dept> children){
this.children = children;
}
public List<Dept> getChildren(){
return this.children;
}
}

View File

@@ -1,65 +0,0 @@
/******************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@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;
}
}

View File

@@ -1,39 +0,0 @@
/******************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@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;
}
}

View File

@@ -1,126 +0,0 @@
/******************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@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;
}
}

View File

@@ -1,282 +0,0 @@
/******************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@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;
}
}

View File

@@ -1,234 +0,0 @@
/******************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@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;
}
}

View File

@@ -1,63 +0,0 @@
/******************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@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;
}
}

View File

@@ -1,119 +0,0 @@
/******************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@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;
}
}

View File

@@ -1,162 +0,0 @@
/******************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@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> 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> roles){
this.roles = roles;
}
public List<Roles> 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;
}
}

View File

@@ -1,33 +0,0 @@
/******************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@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 ;
}
}

View File

@@ -1,222 +0,0 @@
/******************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@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;
}
}

View File

@@ -1,73 +0,0 @@
/******************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@qq.com
* source:https://github.com/kerwincui/wumei-smart
******************************************************************************/
package com.kerwin.wumei.fragment;
import android.widget.TextView;
import com.kerwin.wumei.core.BaseFragment;
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;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import butterknife.BindView;
@Page(name = "关于")
public class AboutFragment extends BaseFragment {
@BindView(R.id.titlebar_min)
TitleBar titleBarMin;
@BindView(R.id.tv_version)
TextView mVersionTextView;
@BindView(R.id.about_list)
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() {
return R.layout.fragment_about;
}
@Override
protected void initViews() {
titleBarMin.setLeftClickListener(v -> popToBack());
mVersionTextView.setText(String.format("版本号:%s", AppUtils.getAppVersionName()));
tvAutho.setText("Authorkerwinci Websitewww.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(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);
String currentYear = dateFormat.format(new Date());
mCopyrightTextView.setText(String.format(getResources().getString(R.string.about_copyright), currentYear));
}
}

View File

@@ -1,40 +0,0 @@
/******************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@qq.com
* source:https://github.com/kerwincui/wumei-smart
******************************************************************************/
package com.kerwin.wumei.fragment;
import android.widget.TextView;
import com.kerwin.wumei.R;
import com.kerwin.wumei.core.BaseFragment;
import com.kerwin.wumei.core.webview.AgentWebActivity;
import com.xuexiang.xpage.annotation.Page;
import com.xuexiang.xui.widget.grouplist.XUIGroupListView;
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 FeedbackFragment extends BaseFragment {
@Override
protected int getLayoutId() {
return R.layout.fragment_feedback;
}
@Override
protected void initViews() {
}
}

View File

@@ -1,213 +0,0 @@
/******************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@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.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.ResUtils;
import com.xuexiang.xui.utils.ThemeUtils;
import com.xuexiang.xui.widget.actionbar.TitleBar;
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.SettingUtils.getServerPath;
import static com.kerwin.wumei.utils.TokenUtils.clearToken;
/**
* 登录页面
*
* @author xuexiang
* @since 2019-11-17 22:15
*/
@Page(anim = CoreAnim.none)
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.iv_code)
ImageView imgVertifyCode;
@BindView(R.id.btn_clear)
RoundButton btnClear;
private String uuid="";
private String token="";
@Override
protected int getLayoutId() {
return R.layout.fragment_login;
}
@Override
protected TitleBar initTitle() {
TitleBar titleBar = super.initTitle()
.setImmersive(true);
titleBar.setBackgroundColor(Color.TRANSPARENT);
titleBar.setTitle("");
titleBar.setLeftImageDrawable(ResUtils.getVectorDrawable(getContext(), R.drawable.ic_login_close));
titleBar.setActionTextColor(ThemeUtils.resolveColor(getContext(), R.attr.colorAccent));
titleBar.addAction(new TitleBar.TextAction(R.string.title_jump_login) {
@Override
public void performAction(View view) {
clearToken();
onLoginSuccess();
}
});
return titleBar;
}
@Override
protected void initViews() {
//隐私政策弹窗
// if (!SettingUtils.isAgreePrivacy()) {
// Utils.showPrivacyDialog(getContext(), (dialog, which) -> {
// dialog.dismiss();
// SettingUtils.setIsAgreePrivacy(true);
// });
// }
getCatpureImage();
getLocalAccount();
}
@SingleClick
@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_clear:
SettingUtils.clearPassword();
etPassword.clear();
break;
case R.id.iv_code:
getCatpureImage();
break;
case R.id.btn_login:
if(etPhoneNumber.getEditValue().length()==0 || etPassword.getEditValue().length()==0 || etVerifyCode.getEditValue().length()==0){
XToastUtils.error("请正确填写账号、密码和验证码");
}else {
loginByVerifyCode(etPhoneNumber.getEditValue(), etPassword.getEditValue(), etVerifyCode.getEditValue());
}
break;
default:
break;
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
}
/**
* 登录成功的处理
*/
private void onLoginSuccess() {
TokenUtils.handleLoginSuccess(token);
popToBack();
ActivityUtils.startActivity(MainActivity.class);
}
/**
* 获取本地存储的账号
*/
private void getLocalAccount(){
etPhoneNumber.setText(SettingUtils.getUserName());
etPassword.setText(SettingUtils.getPassword());
}
/**
* HTTP获取验证码
*/
private void getCatpureImage(){
XHttp.get(getServerPath()+"/captchaImage")
.execute(new CallBackProxy<CaptchaImageApiResult<CaptureImage>, CaptureImage>(new TipRequestCallBack<CaptureImage>() {
@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);
}
@Override
public void onError(ApiException e) {
XToastUtils.error(e.getMessage());
}
}){});
}
/**
* HTTP登录
*
* @param phoneNumber 手机号
* @param verifyCode 验证码
*/
private void loginByVerifyCode(String phoneNumber,String password, String verifyCode) {
XHttp.post(getServerPath()+ "/login")
.upJson("{\"username\":\""+phoneNumber+"\",\"password\":\""+password+"\",\"code\":\""+verifyCode+"\",\"uuid\":\""+uuid+"\"}")
.execute(new CallBackProxy<TokenApiResult<String>, String>(new TipRequestCallBack<String>() {
@Override
public void onSuccess(String tokenResult) throws Throwable {
SettingUtils.setAccount(etPhoneNumber.getEditValue(),etPassword.getEditValue());
token=tokenResult;
onLoginSuccess();
}
@Override
public void onError(ApiException e) {
clearToken();
XToastUtils.error(e.getMessage());
}
}){});
}
}

View File

@@ -1,53 +0,0 @@
/******************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@qq.com
* source:https://github.com/kerwincui/wumei-smart
******************************************************************************/
package com.kerwin.wumei.fragment;
import android.view.View;
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;
import com.xuexiang.xui.widget.grouplist.XUIGroupListView;
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 MessageFragment extends BaseFragment {
@BindView(R.id.titlebar_min)
TitleBar titleBarMin;
@Override
protected int getLayoutId() {
return R.layout.fragment_message;
}
@Override
protected TitleBar initTitle() {
return null;
}
@Override
protected void initViews() {
titleBarMin.setLeftClickListener(v -> popToBack());
}
}

View File

@@ -1,118 +0,0 @@
/******************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@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;
import com.xuexiang.xutil.XUtil;
import butterknife.BindView;
import static com.kerwin.wumei.utils.SettingUtils.getServerPath;
/**
* @author xuexiang
* @since 2019-10-15 22:38
*/
@Page(name = "设置")
public class SettingsFragment extends BaseFragment implements SuperTextView.OnSuperTextViewClickListener {
@BindView(R.id.menu_common)
SuperTextView menuCommon;
@BindView(R.id.menu_privacy)
SuperTextView menuPrivacy;
@BindView(R.id.menu_push)
SuperTextView menuPush;
@BindView(R.id.menu_helper)
SuperTextView menuHelper;
@BindView(R.id.menu_change_account)
SuperTextView menuChangeAccount;
@BindView(R.id.menu_logout)
SuperTextView menuLogout;
@Override
protected int getLayoutId() {
return R.layout.fragment_settings;
}
@Override
protected void initViews() {
menuCommon.setOnSuperTextViewClickListener(this);
menuPrivacy.setOnSuperTextViewClickListener(this);
menuPush.setOnSuperTextViewClickListener(this);
menuHelper.setOnSuperTextViewClickListener(this);
menuChangeAccount.setOnSuperTextViewClickListener(this);
menuLogout.setOnSuperTextViewClickListener(this);
}
/**
* HTTP退出登录
*/
private void logout(){
XHttp.post(getServerPath()+"/logout")
.execute(new CallBackProxy<NoDataApiResult<String>, String>(new TipRequestCallBack<String>() {
@Override
public void onSuccess(String tokenResult) throws Throwable {
XToastUtils.success("登出成功" );
}
@Override
public void onError(ApiException e) {
}
}){});
}
@SingleClick
@Override
public void onClick(SuperTextView superTextView) {
switch (superTextView.getId()) {
case R.id.menu_common:
case R.id.menu_privacy:
case R.id.menu_push:
case R.id.menu_helper:
XToastUtils.toast(superTextView.getLeftString());
break;
case R.id.menu_change_account:
XToastUtils.toast(superTextView.getCenterString());
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;
}
}
}

View File

@@ -1,303 +0,0 @@
/*****************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@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.CheckBox;
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.adapter.entity.EspTouchViewModel;
import com.kerwin.wumei.core.BaseFragment;
import com.xuexiang.xpage.annotation.Page;
import com.king.view.circleprogressview.CircleProgressView;
import com.xuexiang.xui.widget.textview.supertextview.SuperButton;
import java.util.List;
import butterknife.BindView;
import static com.kerwin.wumei.utils.SettingUtils.getWifiPassword;
import static com.kerwin.wumei.utils.SettingUtils.setWifiPassword;
@Page(name = "智能配网")
public class AddDeviceFragment extends BaseFragment {
@BindView(R.id.advance_frame_layout)
FrameLayout advanceFrameLayout;
@BindView(R.id.advance_linear_layout)
LinearLayout advanceLinearLayout;
@BindView(R.id.advance_icon)
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;
@BindView(R.id.chk_remeber)
CheckBox chk_remeber;
@BindView(R.id.circleProgressView)
CircleProgressView circleProgressView;
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
*
* @return
*/
@Override
protected int getLayoutId() {
return R.layout.fragment_add_device;
}
/**
* 初始化控件
*/
@Override
protected void initViews() {
//智能配网
mViewModel = ((AddDeviceActivity)this.getActivity()).GetMViewModel();
mViewModel.apPasswordEdit = findViewById(R.id.wifi_password_txt);
mViewModel.apPasswordEdit.setText(getWifiPassword());
mViewModel.ssidSpinner = findViewById(R.id.ssid_spinner);
mViewModel.packageModeGroup = findViewById(R.id.packageModeGroup);
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();
//存储wifi密码
if(chk_remeber.isChecked()){
setWifiPassword(mViewModel.apPasswordEdit.getText().toString());
}else{
setWifiPassword("");
}
// 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) {
String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION};
requestPermissions(permissions, REQUEST_PERMISSION);
}
MyApp.getInstance().observeBroadcast(this, broadcast -> {
Log.d(TAG, "onCreate: Broadcast=" + broadcast);
((AddDeviceActivity)this.getActivity()).onWifiChanged();
List<String> ssids=((AddDeviceActivity)this.getActivity()).GetSsids();
if(ssids!=null && ssids.size()>0){
Log.e(TAG, "进入数据绑定 " );
mViewModel.ssidSpinner.setItems(ssids);
// ssidSpinner.setOnItemSelectedListener((spinner, position, id, item) -> SnackbarUtils.Long(spinner, "Clicked " + item).show());
// ssidSpinner.setOnNothingSelectedListener(spinner -> SnackbarUtils.Long(spinner, "Nothing selected").show());
String ssid=((AddDeviceActivity)this.getActivity()).GetSelectedSSID();
if(ssid!=null && ssid.length()>0 && ssids.contains(ssid)) {
mViewModel.ssidSpinner.setSelectedItem(ssid);
}
}
});
}
@Override
protected void initListeners() {
//单击高级设置项
advanceFrameLayout.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
int visible=advanceLinearLayout.getVisibility();
if(visible!=0) {
advanceLinearLayout.setVisibility(View.VISIBLE);
advanceIcon.setImageDrawable(getResources().getDrawable((R.drawable.up)));
}else{
advanceLinearLayout.setVisibility(View.GONE);
advanceIcon.setImageDrawable(getResources().getDrawable((R.drawable.down)));
}
}
});
//显示和隐藏密码
wifiPasswordIcon.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view){
if(wifiPasswordIcon.getTag()==null) return;
if(wifiPasswordIcon.getTag().toString().equals("show")){
wifiPasswordIcon.setImageDrawable(getResources().getDrawable((R.drawable.hide)));
wifiPasswordIcon.setTag("hide");
mViewModel.apPasswordEdit.setTransformationMethod(PasswordTransformationMethod.getInstance());
}else{
wifiPasswordIcon.setImageDrawable(getResources().getDrawable((R.drawable.show)));
wifiPasswordIcon.setTag("show");
mViewModel.apPasswordEdit.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
}
}
});
btnConfigCancle.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view){
((AddDeviceActivity)getActivity()).interruptEspTouchTask();
cancleCounter();
}
});
btnReturn.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view){
popToBack();
cancleCounter();
}
});
}
@Override
public void onDestroyView() {
cancleCounter();
super.onDestroyView();
}
/**
* 打开计时器
*/
public void beginCounter(){
mViewModel.confirmBtn.setEnabled(false);
btnConfigCancle.setEnabled(true);
showMessage("配网中...",true);
mHander.post(mCounter);
//显示进度动画,进度,动画时长
circleProgressView.showAnimation(100,3000);
//设置进度改变监听
circleProgressView.setOnChangeListener(new CircleProgressView.OnChangeListener() {
@Override
public void onProgressChanged(float progress, float max) {
if(progress==100){
circleProgressView.setProgress(0);
circleProgressView.showAnimation(100);
}
}
});
}
/**
* 计时器完成
*/
public void completeCounter(){
mCount=0;
mHander.removeCallbacks(mCounter);
progressTextMain.setText("100");
circleProgressView.setOnChangeListener(null);
circleProgressView.showAppendAnimation(100);
}
/**
* 关闭计时器
*/
public void cancleCounter(){
mViewModel.confirmBtn.setEnabled(true);
btnConfigCancle.setEnabled(false);
showMessage("",true);
mCount=0;
mHander.removeCallbacks(mCounter);
progressTextMain.setText("0");
circleProgressView.setOnChangeListener(null);
circleProgressView.showAppendAnimation(0);
}
/**
* 计时器
*/
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);
}
}

View File

@@ -1,74 +0,0 @@
/***************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@qq.com
* source:https://github.com/kerwincui/wumei-smart
***************************************************************************/
package com.kerwin.wumei.fragment.device;
import android.Manifest;
import android.os.Build;
import android.os.Bundle;
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 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.kerwin.wumei.utils.XToastUtils;
import com.xuexiang.xpage.annotation.Page;
import com.xuexiang.xui.widget.spinner.materialspinner.MaterialSpinner;
import java.util.List;
import butterknife.BindView;
@Page(name = "设备信息")
public class AddDeviceTwoFragment extends BaseFragment {
/**
* 布局的资源id
* @return
*/
@Override
protected int getLayoutId() {
return R.layout.fragment_add_device_two;
}
/**
* 初始化控件
*/
@Override
protected void initViews() {
Bundle arguments = getArguments();
String mac = arguments.getString("device_mac");
XToastUtils.toast("设备MAC:" + mac);
}
@Override
protected void initListeners() {
}
}

View File

@@ -1,78 +0,0 @@
/******************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@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<BaseFragment> 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);
}
}

View File

@@ -1,244 +0,0 @@
/******************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@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.xui.widget.toast.XToast;
import com.xuexiang.xutil.net.JsonUtil;
import java.util.List;
import butterknife.BindView;
import butterknife.OnClick;
import static com.kerwin.wumei.utils.SettingUtils.getServerPath;
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;
@BindView(R.id.sp_upgrade)
SuperButton sp_upgrade;
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,R.id.sp_upgrade})
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;
case R.id.sp_upgrade:
XToastUtils.success("固件已经是最新版本");
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(getServerPath()+"/system/status/getStatus/"+deviceNum)
.headers("Authorization","Bearer "+getToken())
.execute(new CallBackProxy<NoDataApiResult<String>, String>(new TipRequestCallBack<String>() {
@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(getServerPath()+"/system/status/new/"+device_id)
.headers("Authorization","Bearer "+getToken())
.execute(new SimpleCallBack<IotDeviceStatus>() {
@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(getServerPath()+"/system/device/"+device_id)
.headers("Authorization","Bearer "+getToken())
.execute(new SimpleCallBack<IotDevice>() {
@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()==null || device.getFirmwareVersion().length()==0? "1.0" : device.getFirmwareVersion()));
txt_create_time.setText(device.getCreateTime());
sp_device_temperature.setText(device.getDeviceTemp()==null?0+"":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(getServerPath()+"/system/device")
.upJson(JsonUtil.toJson(device))
.headers("Authorization","Bearer "+getToken())
.execute(new CallBackProxy<NoDataApiResult<String>, String>(new TipRequestCallBack<String>() {
@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());
}
}
}){});
}
}

View File

@@ -1,307 +0,0 @@
/****************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@qq.com
* source:https://github.com/kerwincui/wumei-smart
****************************************************************************/
package com.kerwin.wumei.fragment.device;
import android.util.Log;
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.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.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 static com.google.android.material.tabs.TabLayout.MODE_SCROLLABLE;
import static com.kerwin.wumei.utils.SettingUtils.getServerPath;
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)
ViewPager2 viewPager;
private boolean mIsShowNavigationView;
private FragmentStateViewPager2Adapter mAdapter;
/**
* @return 返回为 null意为不需要导航栏
*/
@Override
protected TitleBar initTitle() {
// mAdapter.addFragment(2, SimpleTabFragment.newInstance("动态加入"), "动态加入");
// mAdapter.removeFragment(2);
// mAdapter.notifyDataSetChanged();
return null;
}
/**
* 布局的资源id
*
* @return
*/
@Override
protected int getLayoutId() {
return R.layout.fragment_device;
}
/**
* 初始化控件
*/
@Override
protected void initViews() {
//获取分组列表
getGroupList(this);
}
@Override
public void onTabSelected(TabLayout.Tab tab) {
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
/**
* 初始化设备列表
* @param listener
* @param groupList
*/
private void initDeviceListView(@NonNull TabLayout.OnTabSelectedListener listener,List<IotGroup> 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(getServerPath()+"/system/group/list?pageNum=1&pageSize=100")
.headers("Authorization","Bearer "+getToken())
.execute(new CallBackProxy<ListApiResult<List<IotGroup>>, List<IotGroup>>(new TipRequestCallBack<List<IotGroup>>() {
@Override
public void onSuccess(List<IotGroup> list) throws Throwable {
List<IotGroup> 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<IotGroup> groupList=new ArrayList<IotGroup>();
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(getServerPath()+"/system/dict/data/type/iot_trigger_source")
.headers("Authorization","Bearer "+getToken())
.execute(new SimpleCallBack<List<DictData>>() {
@Override
public void onSuccess(List<DictData> 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(getServerPath()+"/system/group/"+groupId)
.headers("Authorization","Bearer "+getToken())
.execute(new SimpleCallBack<IotGroup>(){
@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(getServerPath()+"/system/group")
.upJson(JsonUtil.toJson(group))
.headers("Authorization","Bearer "+getToken())
.execute(new CallBackProxy<NoDataApiResult<String>, String>(new TipRequestCallBack<String>() {
@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(getServerPath()+"/system/group")
.upJson(JsonUtil.toJson(group))
.headers("Authorization","Bearer "+getToken())
.execute(new CallBackProxy<NoDataApiResult<String>, String>(new TipRequestCallBack<String>() {
@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(getServerPath()+"/system/group/"+groupId)
.headers("Authorization","Bearer "+getToken())
.execute(new CallBackProxy<NoDataApiResult<String>, String>(new TipRequestCallBack<String>() {
@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());
}
}
}){});
}
}

View File

@@ -1,269 +0,0 @@
/***************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@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.SettingUtils.getServerPath;
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<DictData> 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<rfFunctionList.size();i++)
{
if(rfFunctionList.get(i).getDictValue()==value){
return i;
}
}
return 0;
}
/**
* HTTP获取遥控按键功能字典列表
*/
private void getRFFunctionDic(){
XHttp.get(getServerPath()+"/system/dict/data/type/rf_function")
.headers("Authorization","Bearer "+getToken())
.execute(new SimpleCallBack<List<DictData>>() {
@Override
public void onSuccess(List<DictData> list) {
//绑定数据
rfFunctionList=list;
rfFunctionStrings=new String[rfFunctionList.size()];
for(int i=0;i<rfFunctionList.size();i++){
rfFunctionStrings[i]=rfFunctionList.get(i).getDictLabel();
}
WidgetUtils.initSpinnerStyle(spinner_rf_func_one, rfFunctionStrings);
WidgetUtils.initSpinnerStyle(spinner_rf_func_two, rfFunctionStrings);
WidgetUtils.initSpinnerStyle(spinner_rf_func_three, rfFunctionStrings);
WidgetUtils.initSpinnerStyle(spinner_rf_func_four, rfFunctionStrings);
//获取设备配置
getDeviceSet(deviceId);
}
@Override
public void onError(ApiException e) {
}
});
}
/**
* HTTP获取设备配置
*/
private void getDeviceSet(Long device_id){
XHttp.get(getServerPath()+"/system/set/new/"+device_id)
.headers("Authorization","Bearer "+getToken())
.execute(new SimpleCallBack<IotDeviceSet>() {
@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(getServerPath()+"/system/set")
.upJson(JsonUtil.toJson(deviceSet))
.headers("Authorization","Bearer "+getToken())
.execute(new CallBackProxy<NoDataApiResult<String>, String>(new TipRequestCallBack<String>() {
@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());
}
}
}){});
}
}

View File

@@ -1,308 +0,0 @@
/*****************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@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.SettingUtils.getServerPath;
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<DictData> 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<lightModeList.size();i++)
{
if(lightModeList.get(i).getDictValue()==value){
return i;
}
}
return 0;
}
/**
* HTTP获取最新设备信息
*/
private void getNewStatusData(){
XHttp.get(getServerPath()+"/system/status/getStatus/"+deviceNum)
.headers("Authorization","Bearer "+getToken())
.execute(new CallBackProxy<NoDataApiResult<String>, String>(new TipRequestCallBack<String>() {
@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(getServerPath()+"/system/dict/data/type/light_mode")
.headers("Authorization","Bearer "+getToken())
.execute(new SimpleCallBack<List<DictData>>() {
@Override
public void onSuccess(List<DictData> list) {
lightModeList=list;
lightModeStrings=new String[lightModeList.size()];
for (int i=0;i<lightModeList.size();i++) {
lightModeStrings[i]=lightModeList.get(i).getDictLabel();
}
WidgetUtils.initSpinnerStyle(spinner_light_mode, lightModeStrings);
//获取设备状态
getDeviceStatus(deviceId);
}
@Override
public void onError(ApiException e) {
}
});
}
/**
* HTTP获取设备状态
*/
private void getDeviceStatus(Long device_id){
XHttp.get(getServerPath()+"/system/status/new/"+device_id)
.headers("Authorization","Bearer "+getToken())
.execute(new SimpleCallBack<IotDeviceStatus>() {
@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(getServerPath()+"/system/status")
.upJson(JsonUtil.toJson(deviceStatus))
.headers("Authorization","Bearer "+getToken())
.execute(new CallBackProxy<NoDataApiResult<String>, String>(new TipRequestCallBack<String>() {
@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());
}
}
}){});
}
}

View File

@@ -1,27 +0,0 @@
package com.kerwin.wumei.fragment.device;
import com.kerwin.wumei.R;
import com.kerwin.wumei.core.BaseFragment;
import com.xuexiang.xpage.annotation.Page;
@Page(name = "分享设备")
public class EditDeviceFragment extends BaseFragment {
/**
* 布局的资源id
*
* @return
*/
@Override
protected int getLayoutId() {
return R.layout.fragment_edit_device;
}
/**
* 初始化控件
*/
@Override
protected void initViews() {
}
}

View File

@@ -1,101 +0,0 @@
/*****************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@qq.com
* source:https://github.com/kerwincui/wumei-smart
*****************************************************************************/
package com.kerwin.wumei.fragment.device;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
/**
* @author xuexiang
* @since 2020/5/21 1:27 AM
*/
public class FragmentStateViewPager2Adapter extends FragmentStateAdapter {
private List<Fragment> mFragmentList = new ArrayList<>();
private List<String> mTitleList = new ArrayList<>();
private List<Long> mIds = new ArrayList<>();
private AtomicLong mAtomicLong = new AtomicLong(0);
public FragmentStateViewPager2Adapter(@NonNull Fragment fragment) {
super(fragment);
}
@NonNull
@Override
public Fragment createFragment(int position) {
return mFragmentList.get(position);
}
public FragmentStateViewPager2Adapter addFragment(Fragment fragment, String title) {
if (fragment != null) {
mFragmentList.add(fragment);
mTitleList.add(title);
mIds.add(getAtomicGeneratedId());
}
return this;
}
public FragmentStateViewPager2Adapter addFragment(int index, Fragment fragment, String title) {
if (fragment != null && index >= 0 && index <= mFragmentList.size()) {
mFragmentList.add(index, fragment);
mTitleList.add(index, title);
mIds.add(index, getAtomicGeneratedId());
}
return this;
}
public FragmentStateViewPager2Adapter removeFragment(int index) {
if (index >= 0 && index < mFragmentList.size()) {
mFragmentList.remove(index);
mTitleList.remove(index);
mIds.remove(index);
}
return this;
}
private long getAtomicGeneratedId() {
return mAtomicLong.incrementAndGet();
}
@Override
public int getItemCount() {
return mFragmentList.size();
}
public void clear() {
mFragmentList.clear();
mTitleList.clear();
mIds.clear();
notifyDataSetChanged();
}
public CharSequence getPageTitle(int position) {
return mTitleList.get(position);
}
@Override
public long getItemId(int position) {
return mIds.get(position);
}
@Override
public boolean containsItem(long itemId) {
return mIds.contains(itemId);
}
}

View File

@@ -1,37 +0,0 @@
/******************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@qq.com
* source:https://github.com/kerwincui/wumei-smart
******************************************************************************/
package com.kerwin.wumei.fragment.device;
import com.kerwin.wumei.R;
import com.kerwin.wumei.core.BaseFragment;
import com.xuexiang.xpage.annotation.Page;
@Page(name = "分组管理")
public class GroupFragment extends BaseFragment {
/**
* 布局的资源id
*
* @return
*/
@Override
protected int getLayoutId() {
return R.layout.fragment_group;
}
/**
* 初始化控件
*/
@Override
protected void initViews() {
}
}

View File

@@ -1,44 +0,0 @@
package com.kerwin.wumei.fragment.device;/*
/**
* @author xuexiang
* @since 2018/12/26 下午11:49
*/
public enum MultiPage {
全部(0),
浇灌(1),
一楼(2),
二楼(3),
三楼(4),
走廊(5);
private final int position;
MultiPage(int pos) {
position = pos;
}
public static MultiPage getPage(int position) {
return MultiPage.values()[position];
}
public static int size() {
return MultiPage.values().length;
}
public static String[] getPageNames() {
MultiPage[] pages = MultiPage.values();
String[] pageNames = new String[pages.length];
for (int i = 0; i < pages.length; i++) {
pageNames[i] = pages[i].name();
}
return pageNames;
}
public int getPosition() {
return position;
}
}

View File

@@ -1,172 +0,0 @@
/******************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@qq.com
* source:https://github.com/kerwincui/wumei-smart
******************************************************************************/
package com.kerwin.wumei.fragment.device;
import android.graphics.Color;
import android.util.Log;
import android.view.View;
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.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.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.getServerAddress;
import static com.kerwin.wumei.utils.SettingUtils.getServerPath;
import static com.kerwin.wumei.utils.SettingUtils.setAccount;
import static com.kerwin.wumei.utils.SettingUtils.setApIp;
import static com.kerwin.wumei.utils.SettingUtils.setServeAddress;
import static com.kerwin.wumei.utils.SettingUtils.setServePath;
import static com.kerwin.wumei.utils.TokenUtils.clearToken;
@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_address;
@BindView(R.id.et_path)
MaterialEditText et_serve_path;
@BindView(R.id.et_ap_address)
MaterialEditText et_ap_address;
/**
* @return 返回为 null意为不需要导航栏
*/
@Override
protected TitleBar initTitle() {
return null;
}
/**
* 布局的资源id
*
* @return
*/
@Override
protected int getLayoutId() {
return R.layout.fragment_scene;
}
/**
* 初始化控件
*/
@Override
protected void initViews() {
et_serve_address.setText(getServerAddress());
et_serve_path.setText(getServerPath());
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_serve_address.getEditValue().length()==0)
{
showMessage("接口地址不能为空",false);
return;
}
switch (view.getId()) {
case R.id.btn_save_serve:
setServeAddress(et_serve_address.getEditValue());
setServePath(et_serve_path.getEditValue());
clearToken();
setAccount("","");
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;
}
}
/**
* HTTP获取验证码(用于连接测试)
*/
private void getCatpureImage(){
String address=et_serve_address.getEditValue();
String path=et_serve_path.getEditValue();
if(path==null || path.length()==0){
Log.d("地址", address.substring(address.length()-1));
if(address.substring(address.length()-1).equals("/")){
address=address.substring(0,address.length()-1);
}
}
String fullPath=address+path;
XHttp.get(fullPath+ "/captchaImage")
.execute(new CallBackProxy<CaptchaImageApiResult<CaptureImage>, CaptureImage>(new TipRequestCallBack<CaptureImage>() {
@Override
public void onSuccess(CaptureImage image) throws Throwable {
String uuid=image.getUuid();
showMessage("服务端连接成功",true);
}
@Override
public void onError(ApiException e) {
showMessage("服务端连接失败\n"+"地址:"+et_serve_address.getEditValue()+et_serve_path.getEditValue()+"\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);
}
}

View File

@@ -1,39 +0,0 @@
/******************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@qq.com
* source:https://github.com/kerwincui/wumei-smart
******************************************************************************/
package com.kerwin.wumei.fragment.device;
import com.kerwin.wumei.R;
import com.kerwin.wumei.core.BaseFragment;
import com.xuexiang.xpage.annotation.Page;
import com.xuexiang.xpage.enums.CoreAnim;
import com.xuexiang.xui.widget.actionbar.TitleBar;
@Page(name = "分享设备")
public class ShareDeviceFragment extends BaseFragment {
/**
* 布局的资源id
*
* @return
*/
@Override
protected int getLayoutId() {
return R.layout.fragment_share_device;
}
/**
* 初始化控件
*/
@Override
protected void initViews() {
}
}

View File

@@ -1,386 +0,0 @@
/******************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@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.Color;
import android.os.Vibrator;
import android.util.Log;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.cardview.widget.CardView;
import androidx.fragment.app.FragmentActivity;
import androidx.recyclerview.widget.RecyclerView;
import com.alibaba.android.vlayout.DelegateAdapter;
import com.alibaba.android.vlayout.VirtualLayoutManager;
import com.alibaba.android.vlayout.layout.StaggeredGridLayoutHelper;
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.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.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.widget.actionbar.TitleBar;
import com.xuexiang.xui.widget.button.SwitchIconView;
import com.xuexiang.xutil.net.JsonUtil;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import me.samlss.broccoli.Broccoli;
import static com.kerwin.wumei.utils.SettingUtils.getServerPath;
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 SimpleTabFragment extends BaseFragment {
private static final String TAG = "SimpleTabFragment";
@BindView(R.id.recyclerView)
RecyclerView recyclerView;
@BindView(R.id.refreshLayout)
SmartRefreshLayout refreshLayout;
private SimpleDelegateAdapter<IotDeviceVo> deviceAdapter;
private List<IotDeviceVo> devices=new ArrayList<IotDeviceVo>() {};
private int pageNum=1;
private int pageSize=10;
private Long groupId=0L;
public static SimpleTabFragment newInstance(Long groupId) {
SimpleTabFragment fragment = new SimpleTabFragment();
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:" + groupId);
}
@Override
public void onDetach() {
super.onDetach();
Log.e(TAG, "onDetach:" + groupId);
}
@Override
public void onResume() {
super.onResume();
Log.e(TAG, "onResume:" + groupId);
}
@Override
public void onStop() {
super.onStop();
Log.e(TAG, "onStop:" + groupId);
}
private void initView() {
VirtualLayoutManager virtualLayoutManager = new VirtualLayoutManager(getContext());
recyclerView.setLayoutManager(virtualLayoutManager);
RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool();
recyclerView.setRecycledViewPool(viewPool);
viewPool.setMaxRecycledViews(0, 10);
// 设备
FragmentActivity activity=this.getActivity();
XPageFragment fragment= this;
deviceAdapter = new BroccoliSimpleDelegateAdapter<IotDeviceVo>(R.layout.adapter_device_card_view_list_item, new StaggeredGridLayoutHelper(2,0), devices) {
@SuppressLint("ResourceType")
@Override
protected void onBindData(RecyclerViewHolder holder, IotDeviceVo device, int position) {
if (device == null) {return;}
//设置item宽度适配屏幕分辨率
// CardView view=holder.findViewById(R.id.device_item_card_view);
// int widthPixels = getScreenWidth(activity);
// int space=dip2px(40); //间隙=左边距+右边距+中间间隔
// 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()==null? 0+"":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);
SwitchIconView lightIconView=holder.findViewById(R.id.device_item_light_button);
radarView.setIconEnabled(device.getIsRadar()!=null && device.getIsRadar()==1 && device.getIsOnline()==1?true:false);
alarmView.setIconEnabled(device.getIsAlarm()!=null && device.getIsAlarm()==1 && device.getIsOnline()==1?true:false);
switchIconView.setIconEnabled(device.getRelayStatus()!=null && device.getRelayStatus()==1 && device.getIsOnline()==1?true:false);
lightIconView.setIconEnabled(device.getLightStatus()!=null && device.getLightStatus()==1 && device.getIsOnline()==1?true:false);
//显示网络信号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.getIsOnline()!=null && device.getRssi()!=null) {
if (device.getIsOnline() == 1 && device.getRssi() >= -55) {
wifiView.setImageDrawable(getResources().getDrawable((R.drawable.wifi_4)));
} else if (device.getIsOnline() == 1 && device.getRssi() >= 70) {
wifiView.setImageDrawable(getResources().getDrawable((R.drawable.wifi_3)));
} else if (device.getIsOnline() == 1 && device.getRssi() >= -85) {
wifiView.setImageDrawable(getResources().getDrawable((R.drawable.wifi_2)));
} else if (device.getIsOnline() == 1 && device.getRssi() >= -100) {
wifiView.setImageDrawable(getResources().getDrawable((R.drawable.wifi_1)));
}
}
//其他文字、标题和图片
FrameLayout flTitle=holder.findViewById(R.id.device_item_fl_title);
if(device.getIsOnline()!=null && device.getIsOnline()==1){
holder.text(R.id.device_item_wifi, "在线");
flTitle.setBackgroundColor(Color.argb(255, 63, 208, 173));
}else{
holder.text(R.id.device_item_wifi, "离线");
flTitle.setBackgroundColor(Color.argb(255, 220, 220, 220));
//显示图标
AppCompatImageView categoryIcon=holder.findViewById(R.id.device_item_category_icon);
AppCompatImageView temp=holder.findViewById(R.id.device_item_temp_icon);
categoryIcon.setColorFilter(Color.parseColor("#909399"));
temp.setColorFilter(Color.parseColor("#909399"));
}
holder.click(R.id.device_item_light_button, v -> {
if(device.getIsOnline()==null || device.getIsOnline()==0) return;
//震动
Vibrator vibrator = (Vibrator) activity.getSystemService(activity.VIBRATOR_SERVICE);
vibrator.vibrate(100);
// 更新灯状态
updateDeviceStatus(
buildDeviceLightStatus(device.getDeviceId(), device.getDeviceNum(),lightIconView.isIconEnabled()==true?0:1)
, lightIconView);
});
holder.click(R.id.device_item_switch_button, v -> {
if(device.getIsOnline()==null || device.getIsOnline()==0) return;
//震动
Vibrator vibrator = (Vibrator) activity.getSystemService(activity.VIBRATOR_SERVICE);
vibrator.vibrate(100);
// 更新继电器状态
updateDeviceStatus(
buildDeviceRelayStatus(device.getDeviceId(),device.getDeviceNum(),switchIconView.isIconEnabled()==true?0:1)
, switchIconView);
});
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); //打开页面进行跳转
});
}
@Override
protected void onBindBroccoli(RecyclerViewHolder holder, Broccoli broccoli) {
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(deviceAdapter);
recyclerView.setAdapter(delegateAdapter);
//下拉刷新
refreshLayout.setOnRefreshListener(refreshLayout -> {
refreshLayout.getLayout().postDelayed(() -> {
pageNum=1;
getDeviceList();
}, 1000);
});
//上拉加载
refreshLayout.setOnLoadMoreListener(refreshLayout -> {
refreshLayout.getLayout().postDelayed(() -> {
pageNum=pageNum+1;
getDeviceList();
}, 1000);
});
// 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,SwitchIconView iconView){
if(!hasToken()) return;
XHttp.put(getServerPath()+"/system/status")
.upJson(JsonUtil.toJson(deviceStatus))
.headers("Authorization","Bearer "+getToken())
.execute(new CallBackProxy<NoDataApiResult<String>, String>(new TipRequestCallBack<String>() {
@Override
public void onSuccess(String response) throws Throwable {
Log.d("response:",response);
iconView.switchState(true);
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(getServerPath()+"/system/device/list?"+"pageNum="+pageNum+"&pageSize="+pageSize+"&groupId="+groupId)
.headers("Authorization","Bearer "+getToken())
.execute(new CallBackProxy<ListApiResult<List<IotDeviceVo>>, List<IotDeviceVo>>(new TipRequestCallBack<List<IotDeviceVo>>() {
@Override
public void onSuccess(List<IotDeviceVo> 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(getServerPath()+"/system/category/list?pageNum=1&pageSize=100")
.headers("Authorization","Bearer "+getToken())
.execute(new CallBackProxy<ListApiResult<List<IotCategory>>, List<IotCategory>>(new TipRequestCallBack<List<IotCategory>>() {
@Override
public void onSuccess(List<IotCategory> list) throws Throwable {
}
@Override
public void onError(ApiException e) {
if(e.getCode()==401){
XToastUtils.info("匿名登录状态,功能受限");
clearToken();
}else{
XToastUtils.error(e.getMessage());
}
}
}){});
}
}

View File

@@ -1,122 +0,0 @@
/******************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@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<NewInfo> 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();//第一次进入触发自动刷新,演示效果
}
}

View File

@@ -1,183 +0,0 @@
/******************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@qq.com
* source:https://github.com/kerwincui/wumei-smart
******************************************************************************/
package com.kerwin.wumei.fragment.news;
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.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.scwang.smartrefresh.layout.SmartRefreshLayout;
import com.kerwin.wumei.R;
import com.kerwin.wumei.utils.DemoDataProvider;
import com.kerwin.wumei.utils.Utils;
import com.kerwin.wumei.utils.XToastUtils;
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 NewsFragment extends BaseFragment {
@BindView(R.id.recyclerView)
RecyclerView recyclerView;
@BindView(R.id.refreshLayout)
SmartRefreshLayout refreshLayout;
private SimpleDelegateAdapter<NewInfo> mNewsAdapter;
/**
* @return 返回为 null意为不需要导航栏
*/
@Override
protected TitleBar initTitle() {
return null;
}
/**
* 布局的资源id
*
* @return
*/
@Override
protected int getLayoutId() {
return R.layout.fragment_news;
}
/**
* 初始化控件
*/
@Override
protected void initViews() {
VirtualLayoutManager virtualLayoutManager = new VirtualLayoutManager(getContext());
recyclerView.setLayoutManager(virtualLayoutManager);
RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool();
recyclerView.setRecycledViewPool(viewPool);
viewPool.setMaxRecycledViews(0, 10);
//轮播条
SingleDelegateAdapter bannerAdapter = new SingleDelegateAdapter(R.layout.include_head_view_banner) {
@Override
public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) {
SimpleImageBanner banner = holder.findViewById(R.id.sib_simple_usage);
banner.setSource(DemoDataProvider.getBannerList())
.setOnItemClickListener((view, item, position1) -> XToastUtils.toast("headBanner position--->" + position1)).startScroll();
}
};
//九宫格菜单
GridLayoutHelper gridLayoutHelper = new GridLayoutHelper(4);
gridLayoutHelper.setPadding(0, 16, 0, 0);
gridLayoutHelper.setVGap(10);
gridLayoutHelper.setHGap(0);
SimpleDelegateAdapter<AdapterItem> commonAdapter = new SimpleDelegateAdapter<AdapterItem>(R.layout.adapter_common_grid_item, gridLayoutHelper, DemoDataProvider.getGridItems(getContext())) {
@Override
protected void bindData(@NonNull RecyclerViewHolder holder, int position, AdapterItem item) {
if (item != null) {
RadiusImageView imageView = holder.findViewById(R.id.riv_item);
imageView.setCircle(true);
ImageLoader.get().loadImage(imageView, item.getIcon());
holder.text(R.id.device_item_title, item.getTitle().toString().substring(0, 1));
holder.text(R.id.tv_sub_title, item.getTitle());
holder.click(R.id.ll_container, v -> XToastUtils.toast("点击了:" + item.getTitle()));
}
}
};
//动态的标题
SingleDelegateAdapter titleAdapter = new SingleDelegateAdapter(R.layout.adapter_title_item) {
@Override
public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) {
holder.text(R.id.device_item_title, "动态");
holder.text(R.id.tv_action, "更多");
holder.click(R.id.tv_action, v -> XToastUtils.toast("更多"));
}
};
// 动态
mNewsAdapter = new BroccoliSimpleDelegateAdapter<NewInfo>(R.layout.adapter_news_card_view_list_item, new LinearLayoutHelper(), DemoDataProvider.getEmptyNewInfo()) {
@Override
protected void onBindData(RecyclerViewHolder holder, NewInfo model, int position) {
if (model != null) {
holder.text(R.id.tv_user_name, model.getUserName());
holder.text(R.id.tv_tag, model.getTag());
holder.text(R.id.device_item_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.tv_user_name),
holder.findView(R.id.tv_tag),
holder.findView(R.id.device_item_title),
holder.findView(R.id.tv_summary),
holder.findView(R.id.tv_praise),
holder.findView(R.id.tv_comment),
holder.findView(R.id.tv_read),
holder.findView(R.id.iv_image)
);
}
};
DelegateAdapter delegateAdapter = new DelegateAdapter(virtualLayoutManager);
delegateAdapter.addAdapter(bannerAdapter);
delegateAdapter.addAdapter(commonAdapter);
delegateAdapter.addAdapter(titleAdapter);
delegateAdapter.addAdapter(mNewsAdapter);
recyclerView.setAdapter(delegateAdapter);
}
@Override
protected void initListeners() {
//下拉刷新
refreshLayout.setOnRefreshListener(refreshLayout -> {
// TODO: 2020-02-25 这里只是模拟了网络请求
refreshLayout.getLayout().postDelayed(() -> {
mNewsAdapter.refresh(DemoDataProvider.getDemoNewInfos());
refreshLayout.finishRefresh();
}, 1000);
});
//上拉加载
refreshLayout.setOnLoadMoreListener(refreshLayout -> {
// TODO: 2020-02-25 这里只是模拟了网络请求
refreshLayout.getLayout().postDelayed(() -> {
mNewsAdapter.loadMore(DemoDataProvider.getDemoNewInfos());
refreshLayout.finishLoadMore();
}, 1000);
});
refreshLayout.autoRefresh();//第一次进入触发自动刷新,演示效果
}
}

View File

@@ -1,130 +0,0 @@
/******************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@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.getServerPath;
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(getServerPath()+"/getInfo")
.headers("Authorization","Bearer "+getToken())
.execute(new CallBackProxy<UserInfoApiResult<User>, User>(new TipRequestCallBack<User>() {
@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());
}
}
}){});
}
}

View File

@@ -1,150 +0,0 @@
/******************************************************************************
* 作者kerwincui
* 时间2021-06-08
* 邮箱164770707@qq.com
* 源码地址https://gitee.com/kerwincui/wumei-smart
* author: kerwincui
* create: 2021-06-08
* email164770707@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;
import static com.kerwin.wumei.utils.SettingUtils.getServerPath;
@Page(anim = CoreAnim.none)
public class ProfileFragment extends BaseFragment implements SuperTextView.OnSuperTextViewClickListener {
@BindView(R.id.riv_head_pic)
RadiusImageView rivHeadPic;
@BindView(R.id.menu_message)
SuperTextView menuMessage;
@BindView(R.id.menu_logout)
SuperTextView menuLogout;
@BindView(R.id.control_list)
XUIGroupListView mControlGroupListView;
@BindView(R.id.tv_copyright)
TextView mCopyrightTextView;
@BindView(R.id.menu_account)
SuperTextView menuAccount;
/**
* @return 返回为 null意为不需要导航栏
*/
@Override
protected TitleBar initTitle() {
return null;
}
/**
* 布局的资源id
*
* @return
*/
@Override
protected int getLayoutId() {
return R.layout.fragment_profile;
}
/**
* 初始化控件
*/
@Override
protected void initViews() {
XUIGroupListView.newSection(getContext())
.addItemView(mControlGroupListView.createItemView(getResources().getString(R.string.about_item_add_qq_group)), v -> AgentWebActivity.goWeb(getContext(), getString(R.string.url_add_qq_group)))
.addItemView(mControlGroupListView.createItemView("应用版本 - V" + AppUtils.getAppVersionName()), v -> XToastUtils.toast("官网下载最新版本"))
.addTo(mControlGroupListView);
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() {
menuMessage.setOnSuperTextViewClickListener(this);
menuLogout.setOnSuperTextViewClickListener(this);
menuAccount.setOnSuperTextViewClickListener(this);
}
/**
* HTTP退出登录
*/
private void logout(){
XHttp.post(getServerPath()+"/logout")
.execute(new CallBackProxy<NoDataApiResult<String>, String>(new TipRequestCallBack<String>() {
@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_message:
openNewPage(MessageFragment.class);
break;
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;
}
}
}

View File

@@ -1,55 +0,0 @@
/*
* 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<T> extends SimpleCallBack<T> {
/**
* 记录一下请求的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);
}
}
}

View File

@@ -1,60 +0,0 @@
/*
* 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<T> extends SimpleCallBack<T> {
/**
* 记录一下请求的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);
}
}
}

Some files were not shown because too many files have changed in this diff Show More