Compare commits

..

162 Commits
dev ... master

Author SHA1 Message Date
xiaoxiao
3013b441a6 1.2.0部分代码 2025-09-09 13:27:34 +08:00
xiaoxiao
e89a5f15ce 1.2.0部分代码 2025-08-27 16:11:20 +08:00
XiuYun CHEN
ca7d1dd379 环境切换 2025-08-19 15:48:01 +08:00
XiuYun CHEN
81aba7fdf6 bug修改 2025-08-19 09:09:46 +08:00
xiaoxiao
662c0ba507 状态栏修改 2025-08-18 16:28:56 +08:00
XiuYun CHEN
ccd4cdf328 选择多张图片 2025-08-18 16:33:10 +08:00
XiuYun CHEN
110512d9cb 选择多张图片 2025-08-18 16:21:56 +08:00
XiuYun CHEN
f1032ddef1 bug优化 2025-08-15 17:35:06 +08:00
xiaoxiao
7035dbcdfb 聊天输入框高度自适应 2025-08-15 17:17:37 +08:00
xiaoxiao
bf8f2c90e6 聊天输入框高度自适应 2025-08-15 17:16:19 +08:00
XiuYun CHEN
b63d268712 关闭网络请求的log 2025-08-15 11:09:46 +08:00
XiuYun CHEN
9e8c96ccd3 bug修改 2025-08-15 11:02:03 +08:00
xiaoxiao
8ce86ba34b 图片上传 2025-08-15 10:36:32 +08:00
xiaoxiao
75f032f853 bug修复 2025-08-15 10:30:15 +08:00
xiaoxiao
e73e2d541f cookie添加 2025-08-14 14:36:34 +08:00
xiaoxiao
38af6d3fd8 上传图片 2025-08-14 13:02:39 +08:00
xiaoxiao
8ab35786fb 上传图片 2025-08-14 11:56:16 +08:00
XiuYun CHEN
b7a08cc1b3 bug修改 2025-08-13 14:27:37 +08:00
xiaoxiao
f5a31e1ffa 聊天气泡背景图 2025-08-12 13:30:54 +08:00
XiuYun CHEN
5212bfee2c bug修改 2025-08-11 15:01:18 +08:00
xiaoxiao
2ae59301fd 消息撤回显示 2025-08-11 13:50:46 +08:00
xiaoxiao
9d235c72f8 消息撤回显示 2025-08-11 13:48:52 +08:00
xiaoxiao
33c3fbea68 消息撤回显示+扫一扫按钮文字 2025-08-11 13:21:54 +08:00
xiaoxiao
5ea18f1468 cookie 2025-08-08 17:03:39 +08:00
xiaoxiao
bf3a456c8f cookie 2025-08-08 16:57:26 +08:00
xiaoxiao
ebeea4da75 cookie 2025-08-08 16:33:07 +08:00
xiaoxiao
691af9e35c cookie 2025-08-08 16:32:59 +08:00
xiaoxiao
58931fcf2e 患者分组代码优化,解决大数据问题 2025-08-08 10:17:47 +08:00
xiaoxiao
8d0f7452b5 患者分组代码提交 2025-08-07 16:07:26 +08:00
xiaoxiao
43663a9656 患者分组代码提交 2025-08-07 14:13:28 +08:00
XiuYun CHEN
e590efbe68 我的患者列表 2025-08-07 14:13:57 +08:00
XiuYun CHEN
69dd55bf27 我的患者列表 2025-08-06 15:38:11 +08:00
XiuYun CHEN
8cb36953d9 群发消息显示 2025-08-06 11:08:48 +08:00
xiaoxiao
c016bc889f 群发bug修复 2025-08-06 09:54:45 +08:00
xiaoxiao
9f37131022 bug修复 2025-08-05 17:01:39 +08:00
xiaoxiao
68c33cf3a5 bug修复 2025-08-05 16:59:58 +08:00
XiuYun CHEN
76b7785d84 角标,小红点,群发消息 2025-08-05 17:02:15 +08:00
XiuYun CHEN
9355959b36 登录和接口请求 2025-08-05 10:52:22 +08:00
XiuYun CHEN
ef0b32cfe4 Merge branch 'master' of https://gitea.igandanyiyuan.com/gdxz/harmony
# Conflicts:
#	features/register/src/main/ets/view/LoginComp.ets
2025-08-05 09:58:30 +08:00
XiuYun CHEN
ad584a9860 登录 2025-08-05 09:56:53 +08:00
xiaoxiao
36455701a5 Merge remote-tracking branch 'origin/master' 2025-08-05 09:46:31 +08:00
xiaoxiao
5ccec3005f 扫一扫 2025-08-05 09:46:18 +08:00
XiuYun CHEN
92b91dd65e 群发消息与页面刷新 2025-08-01 17:18:36 +08:00
xiaoxiao
3f58565a76 bug修复 2025-08-01 10:37:07 +08:00
xiaoxiao
ecee58295a bug修复 2025-08-01 10:34:52 +08:00
xiaoxiao
0253493285 bug修复 2025-08-01 10:18:52 +08:00
XiuYun CHEN
7618c0337d tab切换刷新 2025-07-31 11:58:34 +08:00
xiaoxiao
7d5a604665 request 2025-07-31 11:44:46 +08:00
xiaoxiao
69a4ca17e8 页面刷新 2025-07-30 17:30:56 +08:00
XiuYun CHEN
1e99ff4dfa 出诊计划相关 2025-07-30 16:22:38 +08:00
XiuYun CHEN
0d7ddb5854 Merge branch 'master' of https://gitea.igandanyiyuan.com/gdxz/harmony 2025-07-30 09:15:51 +08:00
XiuYun CHEN
431758516a 出诊计划相关 2025-07-30 09:15:41 +08:00
XiuYun CHEN
f73ed8ccad 出诊计划相关 2025-07-30 09:15:14 +08:00
XiuYun CHEN
b8a894d47d 出诊计划相关 2025-07-30 09:14:13 +08:00
xiaoxiao
8ac8d11256 门诊安排弹窗层级问题 2025-07-29 17:25:09 +08:00
XiuYun CHEN
7c2db724a5 出诊计划 2025-07-25 14:03:18 +08:00
xiaoxiao
67c2c35841 患者相关 2025-07-25 13:44:36 +08:00
xiaoxiao
abbd0540ab 患者相关 2025-07-25 13:38:42 +08:00
XiuYun CHEN
6744eb1a78 出诊计划 2025-07-25 13:32:47 +08:00
XiuYun CHEN
a1fde660d9 出诊计划 2025-07-25 13:30:25 +08:00
XiuYun CHEN
85d23c1504 出诊计划 2025-07-25 13:23:43 +08:00
XiuYun CHEN
75277f5bb5 图片组件跟患者列表 2025-07-21 16:23:36 +08:00
xiaoxiao
1cdb5a3311 患者相关 2025-07-18 17:24:31 +08:00
XiuYun CHEN
cbf50189cc 云信发送消息相关 2025-07-18 17:26:48 +08:00
xiaoxiao
f7408f7cbc HMRouter主入口 2025-07-16 11:16:38 +08:00
xiaoxiao
1bee90d673 HMRouter集成 2025-07-15 17:00:01 +08:00
xiaoxiao
c43fb1905e HMRouter集成 2025-07-15 16:03:09 +08:00
xiaoxiao
17f339216c HMRouter集成 2025-07-15 16:00:39 +08:00
xiaoxiao
46feac9a02 HMRouter集成 2025-07-15 14:24:44 +08:00
xiaoxiao
63b13d7ccd 患者回话列表筛选 2025-07-15 14:16:15 +08:00
XiuYun CHEN
b843007d7a 最近会话有问题 2025-07-15 11:55:02 +08:00
xiaoxiao
c46d9848f0 患者分组 2025-07-14 17:38:11 +08:00
XiuYun CHEN
1121cc3f20 扩展消息部分代码提交 2025-07-14 17:37:45 +08:00
XiuYun CHEN
cf7aa93d6e 更新云信和公益咨询相关代码 2025-07-11 17:34:23 +08:00
XiuYun CHEN
879646296d 更新云信和公益咨询相关代码 2025-07-11 17:33:40 +08:00
xiaoxiao
2da6409a0b 空字符串判断 2025-07-11 17:18:49 +08:00
xiaoxiao
4df444ed0e 患者相关文件 2025-07-11 17:15:50 +08:00
xiaoxiao
971cd1c332 随访二维码 2025-07-10 14:09:00 +08:00
xiaoxiao
4d6af76e47 颜色转换 2025-07-10 09:29:37 +08:00
xiaoxiao
4641e9ecee 首页、患者分组、审核、列表等 2025-07-10 09:27:17 +08:00
XiuYun CHEN
5954f51701 更新云信相关代码 2025-07-10 08:57:32 +08:00
XiuYun CHEN
a297e0452f 审核修改更新 2025-07-08 18:02:09 +08:00
XiuYun CHEN
16b85effa5 审核修改更新 2025-07-07 09:59:05 +08:00
XiuYun CHEN
5a976a6e32 审核修改更新 2025-07-01 15:02:23 +08:00
XiuYun CHEN
cbc0fa3112 bug修改 2025-06-18 17:23:29 +08:00
XiuYun CHEN
4d4a345038 bug修改 2025-06-18 10:29:28 +08:00
XiuYun CHEN
7414611bc5 bug修改 2025-06-17 15:40:04 +08:00
xiaoxiao
57fc7cfdf3 包名修改 2025-06-17 15:22:46 +08:00
xiaoxiao
7e8836fadf 视频阅读量++ 2025-06-17 13:50:34 +08:00
XiuYun CHEN
61a28b9150 bug修改 2025-06-17 13:18:34 +08:00
XiuYun CHEN
7e3a597e92 Merge branch 'master' of https://gitea.igandanyiyuan.com/gdxz/harmony 2025-06-17 13:12:58 +08:00
XiuYun CHEN
1c77820187 bug修改 2025-06-17 13:12:51 +08:00
xiaoxiao
643d464d19 bug修复 2025-06-17 13:05:19 +08:00
XiuYun CHEN
3222c6df05 bug修改 2025-06-17 10:43:41 +08:00
XiuYun CHEN
e16aaa901c bug修改 2025-06-13 17:48:57 +08:00
XiuYun CHEN
2ad7db0c7b Merge remote-tracking branch 'origin/master'
# Conflicts:
#	features/register/src/main/ets/view/PerfectUserDataComp.ets
2025-06-13 17:40:12 +08:00
XiuYun CHEN
a4c1de3955 bug修改 2025-06-13 17:39:58 +08:00
xiaoxiao
c4a3b21499 自定义警告弹窗 2025-06-13 17:32:06 +08:00
xiaoxiao
8300766e5c bug修复 2025-06-13 16:24:54 +08:00
xiaoxiao
f649fd3480 启动图 2025-06-09 09:46:36 +08:00
xiaoxiao
23a7a2ce90 登录删除默认信息 2025-06-09 09:40:29 +08:00
xiaoxiao
cdb3a6af51 我的页 2025-06-09 09:37:54 +08:00
XiuYun CHEN
e03a95ef69 更新 2025-06-05 16:01:58 +08:00
XiuYun CHEN
efcb4be65a 点击tabbar 2025-06-05 14:10:30 +08:00
XiuYun CHEN
ca5ab146b7 更新 2025-06-04 15:24:18 +08:00
XiuYun CHEN
5a59fa16bf 更新空白 2025-06-04 11:26:56 +08:00
XiuYun CHEN
ca68e42541 Merge branch 'master' of https://gitea.igandanyiyuan.com/gdxz/harmony 2025-06-04 11:26:24 +08:00
XiuYun CHEN
3f84f2b918 更新空白 2025-06-04 11:26:13 +08:00
xiaoxiao
195e42f50e 修改bug 2025-06-04 11:19:27 +08:00
XiuYun CHEN
a83890881e 更新 2025-05-30 17:23:47 +08:00
XiuYun CHEN
db44d85747 更新视频跳转逻辑和精选 2025-05-30 17:11:58 +08:00
xiaoxiao
0c2b6c096c 搜索页 2025-05-30 16:57:06 +08:00
xiaoxiao
e0efb15e61 导航栏右侧按钮添加构建函数和其他 2025-05-30 11:45:32 +08:00
xiaoxiao
3cce02a36a 导航栏右侧按钮添加构建函数和其他 2025-05-30 11:45:16 +08:00
xiaoxiao
ce439d4222 导航栏右侧按钮添加构建函数和其他 2025-05-30 11:45:04 +08:00
xiaoxiao
e31432bc3a icon 2025-05-29 17:24:19 +08:00
XiuYun CHEN
a2c63608be Merge remote-tracking branch 'origin/master'
# Conflicts:
#	features/register/src/main/ets/view/LoginComp.ets
2025-05-29 17:23:15 +08:00
XiuYun CHEN
aa6b694ba4 更新注册等相关逻辑 2025-05-29 17:22:54 +08:00
xiaoxiao
fc801e1345 视频详情评论 2025-05-29 17:13:23 +08:00
XiuYun CHEN
5375c26462 肝胆视频 2025-05-27 13:15:22 +08:00
xiaoxiao
3bdbf49577 loading 2025-05-21 16:59:39 +08:00
XiuYun CHEN
12bd6efea9 选择医院 2025-05-21 16:57:48 +08:00
XiuYun CHEN
5aa6de62c7 过往会议 2025-05-20 15:52:50 +08:00
xiaoxiao
f2868c2de3 注册资料 2025-05-20 15:00:32 +08:00
xiaoxiao
86f95a4732 注册资料 2025-05-20 14:55:25 +08:00
xiaoxiao
09a6f13e1d 注册资料 2025-05-20 14:23:03 +08:00
xiaoxiao
e215f73788 注册资料 2025-05-20 14:04:04 +08:00
XiuYun CHEN
f821535e18 会议回放,观看直播与会议 2025-05-19 16:42:50 +08:00
XiuYun CHEN
f44649d8dc 提交网络请求 2025-05-15 15:16:02 +08:00
XiuYun CHEN
7f8c81dc66 提交网络请求 2025-05-15 15:15:40 +08:00
xiaoxiao
15f7f114c4 网络请求封装 2025-05-15 13:12:20 +08:00
XiuYun CHEN
8908fa3cc9 接入保利威视demo 2025-05-15 13:14:18 +08:00
XiuYun CHEN
bed645747d 接入保利威视demo 2025-05-15 13:11:26 +08:00
xiaoxiao
b2bdaeaff3 上传图片 2025-05-14 15:28:00 +08:00
XiuYun CHEN
2c3f44b362 保利威视介入前的代码提交 2025-05-14 15:11:36 +08:00
xiaoxiao
1a0b9e0436 我的页 2025-05-14 13:10:06 +08:00
xiaoxiao
ab1f72ba6c 图片上传 2025-05-13 17:25:26 +08:00
XiuYun CHEN
3d1c988435 肝胆会议UI 2025-05-13 11:52:42 +08:00
XiuYun CHEN
ae3b458c02 上拉加载 2025-05-12 15:39:30 +08:00
xiaoxiao
bc9817efe7 Merge remote-tracking branch 'origin/master' 2025-05-12 15:13:11 +08:00
XiuYun CHEN
338a890d4a gitignore 2025-05-12 15:12:54 +08:00
XiuYun CHEN
468f966a7e Merge remote-tracking branch 'origin/master'
# Conflicts:
#	.hvigor/outputs/build-logs/build.log
2025-05-12 15:11:58 +08:00
XiuYun CHEN
afa8c2d17f 会议提交测试 2025-05-12 15:11:31 +08:00
XiuYun CHEN
8be5369c25 会议提交测试 2025-05-12 15:09:38 +08:00
XiuYun CHEN
da5a1b603c 会议提交测试 2025-05-12 15:04:23 +08:00
xiaoxiao
b11b4b65db 我的页 2025-05-12 14:19:30 +08:00
XiuYun CHEN
c8184e2b32 提交会议页面 2025-05-09 16:26:09 +08:00
xiaoxiao
7de570c9d8 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	.hvigor/outputs/build-logs/build.log
2025-05-09 16:24:12 +08:00
xiaoxiao
80351c6ca2 提交 2025-05-09 16:23:54 +08:00
XiuYun CHEN
ae211c8b35 提交 2025-05-09 16:12:39 +08:00
XiuYun CHEN
d9449ec9fa 更改忽略 2025-05-09 16:09:44 +08:00
XiuYun CHEN
76df9928f4 Merge branch 'master' of https://gitea.igandanyiyuan.com/gdxz/harmony 2025-05-09 16:06:54 +08:00
XiuYun CHEN
8d5973df8d 测试 2025-05-09 16:06:32 +08:00
XiuYun CHEN
e9bb89b90a Merge branch 'master' of https://gitea.igandanyiyuan.com/gdxz/harmony 2025-05-09 16:03:05 +08:00
xiaoxiao
962e4c6725 gnore文件再提交 2025-05-09 16:00:41 +08:00
xiaoxiao
e8c8f73568 gnore文件提交 2025-05-09 15:58:07 +08:00
XiuYun CHEN
bbecb72aec Merge branch 'master' of https://gitea.igandanyiyuan.com/gdxz/harmony 2025-05-09 15:55:34 +08:00
XiuYun CHEN
becf6e12c3 1323 2025-05-09 15:50:44 +08:00
xiaoxiao
f9d7986df0 第一次提交 2025-05-09 15:47:54 +08:00
XiuYun CHEN
b3dae046d1 133 2025-05-09 15:47:35 +08:00
xiaoxiao
25e596b591 122222222 2025-05-09 15:27:29 +08:00
xiaoxiao
eab0c6de60 12 2025-05-09 15:26:07 +08:00
1413 changed files with 137950 additions and 0 deletions

64
.clang-format Normal file
View File

@ -0,0 +1,64 @@
Language: Cpp
# BasedOnStyle: LLVM
ColumnLimit: 120
SortIncludes: CaseSensitive
TabWidth: 4
IndentWidth: 4
UseTab: Never
AccessModifierOffset: -4
ContinuationIndentWidth: 4
IndentCaseBlocks: false
IndentCaseLabels: false
IndentGotoLabels: true
IndentWrappedFunctionNames: false
SortUsingDeclarations: false
NamespaceIndentation: None
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInConditionalStatement: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
AlignTrailingComments: true
AlignAfterOpenBracket: true
AllowShortCaseLabelsOnASingleLine: false
AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
AlwaysBreakTemplateDeclarations: MultiLine
BinPackArguments: true
BinPackParameters: true
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakInheritanceList: BeforeColon
BreakStringLiterals: true
InsertBraces: false
IndentExternBlock: NoIndent
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
ReflowComments: true
MaxEmptyLinesToKeep: 2

38
.gitignore vendored Normal file
View File

@ -0,0 +1,38 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
*.log
oh_modules/
features/Home/build/
.hvigor/
.hvigor/outputs/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/

1
.hvigor/cache/meta.json vendored Normal file
View File

@ -0,0 +1 @@
{"compileSdkVersion":"5.0.2(14)","hvigorVersion":"5.14.3","toolChainsVersion":"5.0.2.123"}

View File

@ -0,0 +1 @@
{"name":"home","version":"1.0.0","description":"Please describe the basic information.","main":"Index.ets","author":"","license":"Apache-2.0","dependencies":{"@itcast/basic":"file:../../commons/basic"}}

View File

@ -0,0 +1 @@
{"name":"@itcast/basic","version":"1.0.0","description":"Please describe the basic information.","main":"Index.ets","author":"","license":"Apache-2.0","dependencies":{}}

View File

@ -0,0 +1 @@
{"name":"expert","version":"1.0.0","description":"Please describe the basic information.","main":"","author":"","license":"","dependencies":{"@itcast/basic":"file:../../commons/basic","utils":"file:../../commons/utils","mypage":"file:../../features/mypage","home":"file:../../features/Home","register":"file:../../features/register"}}

View File

@ -0,0 +1 @@
{"basePath":"D:\\202076work\\hongmeng\\newExpert\\harmony\\.hvigor\\dependencyMap\\dependencyMap.json5","rootDependency":"./oh-package.json5","dependencyMap":{"default":"./default/oh-package.json5","mypage":"./mypage/oh-package.json5","basic":"./basic/oh-package.json5","Home":"./Home/oh-package.json5","register":"./register/oh-package.json5","polyv":"./polyv/oh-package.json5","scene_single_video":"./scene_single_video/oh-package.json5"},"modules":[{"name":"default","srcPath":"..\\..\\..\\products\\expert"},{"name":"mypage","srcPath":"..\\..\\..\\features\\mypage"},{"name":"basic","srcPath":"..\\..\\..\\commons\\basic"},{"name":"Home","srcPath":"..\\..\\..\\features\\Home"},{"name":"register","srcPath":"..\\..\\..\\features\\register"},{"name":"polyv","srcPath":"..\\..\\..\\polyv"},{"name":"scene_single_video","srcPath":"..\\..\\..\\scene_single_video"}]}

View File

@ -0,0 +1 @@
{"name":"mypage","version":"1.0.0","description":"Please describe the basic information.","main":"Index.ets","author":"","license":"Apache-2.0","dependencies":{"@itcast/basic":"file:../../commons/basic"}}

View File

@ -0,0 +1 @@
{"modelVersion":"5.0.2","description":"Please describe the basic information.","dependencies":{"@ohos/crypto-js":"^2.0.4"},"devDependencies":{"@ohos/hypium":"1.0.21","@ohos/hamock":"1.0.0"},"dynamicDependencies":{}}

View File

@ -0,0 +1 @@
{"name":"register","version":"1.0.0","description":"Please describe the basic information.","main":"Index.ets","author":"","license":"Apache-2.0","dependencies":{"@itcast/basic":"file:../../commons/basic"}}

View File

@ -0,0 +1 @@
{"name":"uicomponents","version":"1.0.0","description":"Please describe the basic information.","main":"Index.ets","author":"","license":"Apache-2.0","dependencies":{}}

View File

@ -0,0 +1 @@
{"name":"utils","version":"1.0.0","description":"Please describe the basic information.","main":"Index.ets","author":"","license":"Apache-2.0","dependencies":{"@ohos/crypto-js":"^2.0.4"},"devDependencies":{},"dynamicDependencies":{}}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,718 @@
{
"ohos-module-default": {
"SELECT_TARGET": "default",
"MODULE_BUILD_DIR": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\build",
"DEPENDENCY_INFO": {
"@itcast/basic": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\basic",
"utils": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\utils",
"mypage": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\mypage",
"home": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\Home",
"register": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\register",
"@ohos/crypto-js": "D:\\202076work\\hongmeng\\newExpert\\harmony\\oh_modules\\.ohpm\\@ohos+crypto-js@2.0.4\\oh_modules\\@ohos\\crypto-js"
},
"TARGETS": {
"default": {
"SOURCE_ROOT": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\src\\main",
"RESOURCES_PATH": [
"D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\src\\main\\resources"
],
"BUILD_PATH": {
"OUTPUT_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\build\\default\\outputs\\default",
"INTERMEDIA_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\build\\default\\intermediates",
"JS_ASSETS_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\build\\default\\intermediates\\loader_out\\default",
"JS_LITE_ASSETS_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\build\\default\\intermediates\\loader_out_lite\\default",
"RES_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\build\\default\\intermediates\\res\\default",
"RES_PROFILE_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\build\\default\\intermediates\\res\\default\\resources\\base\\profile",
"ETS_SUPER_VISUAL_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\build\\default\\cache\\default\\default@CompileArkTS\\esmodule",
"JS_SUPER_VISUAL_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\build\\default\\cache\\default\\default@CompileJS\\jsbundle",
"WORKER_LOADER": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\build\\default\\intermediates\\loader\\default\\loader.json",
"MANIFEST_JSON": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\build\\default\\intermediates\\manifest\\default",
"OUTPUT_METADATA_JSON": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\build\\default\\intermediates\\hap_metadata\\default\\output_metadata.json",
"SOURCE_MAP_DIR": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\build\\default\\intermediates\\source_map\\default"
},
"BUILD_OPTION": {
"debuggable": true
}
},
"ohosTest": {
"SOURCE_ROOT": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\src\\ohosTest",
"RESOURCES_PATH": [
"D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\src\\ohosTest\\resources"
],
"BUILD_PATH": {
"OUTPUT_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\build\\default\\outputs\\ohosTest",
"INTERMEDIA_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\build\\default\\intermediates",
"JS_ASSETS_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\build\\default\\intermediates\\loader_out\\ohosTest",
"JS_LITE_ASSETS_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\build\\default\\intermediates\\loader_out_lite\\ohosTest",
"RES_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\build\\default\\intermediates\\res\\ohosTest",
"RES_PROFILE_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\build\\default\\intermediates\\res\\ohosTest\\resources\\base\\profile",
"ETS_SUPER_VISUAL_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\build\\default\\cache\\ohosTest\\ohosTest@OhosTestCompileArkTS\\esmodule",
"JS_SUPER_VISUAL_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\build\\default\\cache\\ohosTest\\ohosTest@OhosTestCompileJS\\jsbundle",
"WORKER_LOADER": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\build\\default\\intermediates\\loader\\ohosTest\\loader.json",
"MANIFEST_JSON": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\build\\default\\intermediates\\manifest\\ohosTest",
"OUTPUT_METADATA_JSON": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\build\\default\\intermediates\\hap_metadata\\ohosTest\\output_metadata.json",
"SOURCE_MAP_DIR": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert\\build\\default\\intermediates\\source_map\\ohosTest"
},
"BUILD_OPTION": {
"debuggable": true
}
}
},
"BUILD_OPTION": {
"default-default": {
"debuggable": true,
"copyFrom": "default",
"strictMode": {
"caseSensitiveCheck": true,
"useNormalizedOHMUrl": true
},
"name": "debug"
}
},
"BUILD_PROFILE_OPT": {
"apiType": "stageMode",
"buildOption": {},
"buildOptionSet": [
{
"name": "release",
"arkOptions": {
"obfuscation": {
"ruleOptions": {
"enable": false,
"files": [
"./obfuscation-rules.txt"
]
}
}
}
},
{
"name": "default"
},
{
"name": "debug"
}
],
"targets": [
{
"name": "default"
},
{
"name": "ohosTest"
}
]
},
"BUILD_CACHE_DIR": ""
},
"ohos-module-uicomponents": {
"SELECT_TARGET": "default",
"MODULE_BUILD_DIR": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\uicomponents\\build",
"DEPENDENCY_INFO": {
"@ohos/crypto-js": "D:\\202076work\\hongmeng\\newExpert\\harmony\\oh_modules\\.ohpm\\@ohos+crypto-js@2.0.4\\oh_modules\\@ohos\\crypto-js"
},
"TARGETS": {
"default": {
"SOURCE_ROOT": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\uicomponents\\src\\main",
"RESOURCES_PATH": [
"D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\uicomponents\\src\\main\\resources"
],
"BUILD_PATH": {
"OUTPUT_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\uicomponents\\build\\default\\outputs\\default",
"INTERMEDIA_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\uicomponents\\build\\default\\intermediates",
"JS_ASSETS_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\uicomponents\\build\\default\\intermediates\\loader_out\\default",
"JS_LITE_ASSETS_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\uicomponents\\build\\default\\intermediates\\loader_out_lite\\default",
"RES_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\uicomponents\\build\\default\\intermediates\\res\\default",
"RES_PROFILE_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\uicomponents\\build\\default\\intermediates\\res\\default\\resources\\base\\profile",
"ETS_SUPER_VISUAL_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\uicomponents\\build\\default\\cache\\default\\default@HarCompileArkTS\\esmodule",
"JS_SUPER_VISUAL_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\uicomponents\\build\\default\\cache\\default\\default@HarCompileJS\\jsbundle",
"WORKER_LOADER": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\uicomponents\\build\\default\\intermediates\\loader\\default\\loader.json",
"MANIFEST_JSON": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\uicomponents\\build\\default\\intermediates\\manifest\\default",
"OUTPUT_METADATA_JSON": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\uicomponents\\build\\default\\intermediates\\hap_metadata\\default\\output_metadata.json",
"SOURCE_MAP_DIR": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\uicomponents\\build\\default\\intermediates\\source_map\\default"
},
"BUILD_OPTION": {
"debuggable": true
}
}
},
"BUILD_OPTION": {
"default-default": {
"debuggable": true,
"copyFrom": "default",
"strictMode": {
"caseSensitiveCheck": true,
"useNormalizedOHMUrl": true
},
"name": "debug"
}
},
"BUILD_PROFILE_OPT": {
"apiType": "stageMode",
"buildOption": {},
"buildOptionSet": [
{
"name": "release",
"arkOptions": {
"obfuscation": {
"ruleOptions": {
"enable": false,
"files": [
"./obfuscation-rules.txt"
]
},
"consumerFiles": [
"./consumer-rules.txt"
]
}
}
},
{
"name": "default"
},
{
"name": "debug"
}
],
"targets": [
{
"name": "default"
},
{
"name": "ohosTest"
}
]
},
"BUILD_CACHE_DIR": ""
},
"ohos-module-utils": {
"SELECT_TARGET": "default",
"MODULE_BUILD_DIR": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\utils\\build",
"DEPENDENCY_INFO": {
"@ohos/crypto-js": "D:\\202076work\\hongmeng\\newExpert\\harmony\\oh_modules\\.ohpm\\@ohos+crypto-js@2.0.4\\oh_modules\\@ohos\\crypto-js"
},
"TARGETS": {
"default": {
"SOURCE_ROOT": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\utils\\src\\main",
"RESOURCES_PATH": [
"D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\utils\\src\\main\\resources"
],
"BUILD_PATH": {
"OUTPUT_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\utils\\build\\default\\outputs\\default",
"INTERMEDIA_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\utils\\build\\default\\intermediates",
"JS_ASSETS_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\utils\\build\\default\\intermediates\\loader_out\\default",
"JS_LITE_ASSETS_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\utils\\build\\default\\intermediates\\loader_out_lite\\default",
"RES_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\utils\\build\\default\\intermediates\\res\\default",
"RES_PROFILE_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\utils\\build\\default\\intermediates\\res\\default\\resources\\base\\profile",
"ETS_SUPER_VISUAL_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\utils\\build\\default\\cache\\default\\default@HarCompileArkTS\\esmodule",
"JS_SUPER_VISUAL_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\utils\\build\\default\\cache\\default\\default@HarCompileJS\\jsbundle",
"WORKER_LOADER": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\utils\\build\\default\\intermediates\\loader\\default\\loader.json",
"MANIFEST_JSON": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\utils\\build\\default\\intermediates\\manifest\\default",
"OUTPUT_METADATA_JSON": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\utils\\build\\default\\intermediates\\hap_metadata\\default\\output_metadata.json",
"SOURCE_MAP_DIR": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\utils\\build\\default\\intermediates\\source_map\\default"
},
"BUILD_OPTION": {
"debuggable": true
}
}
},
"BUILD_OPTION": {
"default-default": {
"debuggable": true,
"copyFrom": "default",
"strictMode": {
"caseSensitiveCheck": true,
"useNormalizedOHMUrl": true
},
"name": "debug"
}
},
"BUILD_PROFILE_OPT": {
"apiType": "stageMode",
"buildOption": {},
"buildOptionSet": [
{
"name": "release",
"arkOptions": {
"obfuscation": {
"ruleOptions": {
"enable": false,
"files": [
"./obfuscation-rules.txt"
]
},
"consumerFiles": [
"./consumer-rules.txt"
]
}
}
},
{
"name": "default"
},
{
"name": "debug"
}
],
"targets": [
{
"name": "default"
},
{
"name": "ohosTest"
}
]
},
"BUILD_CACHE_DIR": ""
},
"ohos-module-mypage": {
"SELECT_TARGET": "default",
"MODULE_BUILD_DIR": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\mypage\\build",
"DEPENDENCY_INFO": {
"@itcast/basic": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\basic",
"@ohos/crypto-js": "D:\\202076work\\hongmeng\\newExpert\\harmony\\oh_modules\\.ohpm\\@ohos+crypto-js@2.0.4\\oh_modules\\@ohos\\crypto-js"
},
"TARGETS": {
"default": {
"SOURCE_ROOT": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\mypage\\src\\main",
"RESOURCES_PATH": [
"D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\mypage\\src\\main\\resources"
],
"BUILD_PATH": {
"OUTPUT_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\mypage\\build\\default\\outputs\\default",
"INTERMEDIA_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\mypage\\build\\default\\intermediates",
"JS_ASSETS_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\mypage\\build\\default\\intermediates\\loader_out\\default",
"JS_LITE_ASSETS_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\mypage\\build\\default\\intermediates\\loader_out_lite\\default",
"RES_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\mypage\\build\\default\\intermediates\\res\\default",
"RES_PROFILE_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\mypage\\build\\default\\intermediates\\res\\default\\resources\\base\\profile",
"ETS_SUPER_VISUAL_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\mypage\\build\\default\\cache\\default\\default@HarCompileArkTS\\esmodule",
"JS_SUPER_VISUAL_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\mypage\\build\\default\\cache\\default\\default@HarCompileJS\\jsbundle",
"WORKER_LOADER": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\mypage\\build\\default\\intermediates\\loader\\default\\loader.json",
"MANIFEST_JSON": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\mypage\\build\\default\\intermediates\\manifest\\default",
"OUTPUT_METADATA_JSON": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\mypage\\build\\default\\intermediates\\hap_metadata\\default\\output_metadata.json",
"SOURCE_MAP_DIR": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\mypage\\build\\default\\intermediates\\source_map\\default"
},
"BUILD_OPTION": {
"debuggable": true
}
}
},
"BUILD_OPTION": {
"default-default": {
"debuggable": true,
"copyFrom": "default",
"strictMode": {
"caseSensitiveCheck": true,
"useNormalizedOHMUrl": true
},
"name": "debug"
}
},
"BUILD_PROFILE_OPT": {
"apiType": "stageMode",
"buildOption": {},
"buildOptionSet": [
{
"name": "release",
"arkOptions": {
"obfuscation": {
"ruleOptions": {
"enable": false,
"files": [
"./obfuscation-rules.txt"
]
},
"consumerFiles": [
"./consumer-rules.txt"
]
}
}
},
{
"name": "default"
},
{
"name": "debug"
}
],
"targets": [
{
"name": "default"
},
{
"name": "ohosTest"
}
]
},
"BUILD_CACHE_DIR": ""
},
"ohos-module-basic": {
"SELECT_TARGET": "default",
"MODULE_BUILD_DIR": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\basic\\build",
"DEPENDENCY_INFO": {
"@ohos/crypto-js": "D:\\202076work\\hongmeng\\newExpert\\harmony\\oh_modules\\.ohpm\\@ohos+crypto-js@2.0.4\\oh_modules\\@ohos\\crypto-js"
},
"TARGETS": {
"default": {
"SOURCE_ROOT": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\basic\\src\\main",
"RESOURCES_PATH": [
"D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\basic\\src\\main\\resources"
],
"BUILD_PATH": {
"OUTPUT_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\basic\\build\\default\\outputs\\default",
"INTERMEDIA_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\basic\\build\\default\\intermediates",
"JS_ASSETS_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\basic\\build\\default\\intermediates\\loader_out\\default",
"JS_LITE_ASSETS_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\basic\\build\\default\\intermediates\\loader_out_lite\\default",
"RES_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\basic\\build\\default\\intermediates\\res\\default",
"RES_PROFILE_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\basic\\build\\default\\intermediates\\res\\default\\resources\\base\\profile",
"ETS_SUPER_VISUAL_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\basic\\build\\default\\cache\\default\\default@HarCompileArkTS\\esmodule",
"JS_SUPER_VISUAL_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\basic\\build\\default\\cache\\default\\default@HarCompileJS\\jsbundle",
"WORKER_LOADER": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\basic\\build\\default\\intermediates\\loader\\default\\loader.json",
"MANIFEST_JSON": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\basic\\build\\default\\intermediates\\manifest\\default",
"OUTPUT_METADATA_JSON": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\basic\\build\\default\\intermediates\\hap_metadata\\default\\output_metadata.json",
"SOURCE_MAP_DIR": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\basic\\build\\default\\intermediates\\source_map\\default"
},
"BUILD_OPTION": {
"debuggable": true
}
}
},
"BUILD_OPTION": {
"default-default": {
"debuggable": true,
"copyFrom": "default",
"strictMode": {
"caseSensitiveCheck": true,
"useNormalizedOHMUrl": true
},
"name": "debug"
}
},
"BUILD_PROFILE_OPT": {
"apiType": "stageMode",
"buildOption": {},
"buildOptionSet": [
{
"name": "release",
"arkOptions": {
"obfuscation": {
"ruleOptions": {
"enable": false,
"files": [
"./obfuscation-rules.txt"
]
},
"consumerFiles": [
"./consumer-rules.txt"
]
}
}
},
{
"name": "default"
},
{
"name": "debug"
}
],
"targets": [
{
"name": "default"
},
{
"name": "ohosTest"
}
]
},
"BUILD_CACHE_DIR": ""
},
"ohos-module-Home": {
"SELECT_TARGET": "default",
"MODULE_BUILD_DIR": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\Home\\build",
"DEPENDENCY_INFO": {
"@itcast/basic": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\basic",
"@ohos/crypto-js": "D:\\202076work\\hongmeng\\newExpert\\harmony\\oh_modules\\.ohpm\\@ohos+crypto-js@2.0.4\\oh_modules\\@ohos\\crypto-js"
},
"TARGETS": {
"default": {
"SOURCE_ROOT": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\Home\\src\\main",
"RESOURCES_PATH": [
"D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\Home\\src\\main\\resources"
],
"BUILD_PATH": {
"OUTPUT_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\Home\\build\\default\\outputs\\default",
"INTERMEDIA_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\Home\\build\\default\\intermediates",
"JS_ASSETS_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\Home\\build\\default\\intermediates\\loader_out\\default",
"JS_LITE_ASSETS_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\Home\\build\\default\\intermediates\\loader_out_lite\\default",
"RES_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\Home\\build\\default\\intermediates\\res\\default",
"RES_PROFILE_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\Home\\build\\default\\intermediates\\res\\default\\resources\\base\\profile",
"ETS_SUPER_VISUAL_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\Home\\build\\default\\cache\\default\\default@HarCompileArkTS\\esmodule",
"JS_SUPER_VISUAL_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\Home\\build\\default\\cache\\default\\default@HarCompileJS\\jsbundle",
"WORKER_LOADER": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\Home\\build\\default\\intermediates\\loader\\default\\loader.json",
"MANIFEST_JSON": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\Home\\build\\default\\intermediates\\manifest\\default",
"OUTPUT_METADATA_JSON": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\Home\\build\\default\\intermediates\\hap_metadata\\default\\output_metadata.json",
"SOURCE_MAP_DIR": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\Home\\build\\default\\intermediates\\source_map\\default"
},
"BUILD_OPTION": {
"debuggable": true
}
}
},
"BUILD_OPTION": {
"default-default": {
"debuggable": true,
"copyFrom": "default",
"strictMode": {
"caseSensitiveCheck": true,
"useNormalizedOHMUrl": true
},
"name": "debug"
}
},
"BUILD_PROFILE_OPT": {
"apiType": "stageMode",
"buildOption": {},
"buildOptionSet": [
{
"name": "release",
"arkOptions": {
"obfuscation": {
"ruleOptions": {
"enable": false,
"files": [
"./obfuscation-rules.txt"
]
},
"consumerFiles": [
"./consumer-rules.txt"
]
}
}
},
{
"name": "default"
},
{
"name": "debug"
}
],
"targets": [
{
"name": "default"
},
{
"name": "ohosTest"
}
]
},
"BUILD_CACHE_DIR": ""
},
"ohos-module-register": {
"SELECT_TARGET": "default",
"MODULE_BUILD_DIR": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\register\\build",
"DEPENDENCY_INFO": {
"@itcast/basic": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\basic",
"@ohos/crypto-js": "D:\\202076work\\hongmeng\\newExpert\\harmony\\oh_modules\\.ohpm\\@ohos+crypto-js@2.0.4\\oh_modules\\@ohos\\crypto-js"
},
"TARGETS": {
"default": {
"SOURCE_ROOT": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\register\\src\\main",
"RESOURCES_PATH": [
"D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\register\\src\\main\\resources"
],
"BUILD_PATH": {
"OUTPUT_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\register\\build\\default\\outputs\\default",
"INTERMEDIA_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\register\\build\\default\\intermediates",
"JS_ASSETS_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\register\\build\\default\\intermediates\\loader_out\\default",
"JS_LITE_ASSETS_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\register\\build\\default\\intermediates\\loader_out_lite\\default",
"RES_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\register\\build\\default\\intermediates\\res\\default",
"RES_PROFILE_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\register\\build\\default\\intermediates\\res\\default\\resources\\base\\profile",
"ETS_SUPER_VISUAL_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\register\\build\\default\\cache\\default\\default@HarCompileArkTS\\esmodule",
"JS_SUPER_VISUAL_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\register\\build\\default\\cache\\default\\default@HarCompileJS\\jsbundle",
"WORKER_LOADER": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\register\\build\\default\\intermediates\\loader\\default\\loader.json",
"MANIFEST_JSON": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\register\\build\\default\\intermediates\\manifest\\default",
"OUTPUT_METADATA_JSON": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\register\\build\\default\\intermediates\\hap_metadata\\default\\output_metadata.json",
"SOURCE_MAP_DIR": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\register\\build\\default\\intermediates\\source_map\\default"
},
"BUILD_OPTION": {
"debuggable": true
}
}
},
"BUILD_OPTION": {
"default-default": {
"debuggable": true,
"copyFrom": "default",
"strictMode": {
"caseSensitiveCheck": true,
"useNormalizedOHMUrl": true
},
"name": "debug"
}
},
"BUILD_PROFILE_OPT": {
"apiType": "stageMode",
"buildOption": {},
"buildOptionSet": [
{
"name": "release",
"arkOptions": {
"obfuscation": {
"ruleOptions": {
"enable": false,
"files": [
"./obfuscation-rules.txt"
]
},
"consumerFiles": [
"./consumer-rules.txt"
]
}
}
},
{
"name": "default"
},
{
"name": "debug"
}
],
"targets": [
{
"name": "default"
},
{
"name": "ohosTest"
}
]
},
"BUILD_CACHE_DIR": ""
},
"ohos-project": {
"SELECT_PRODUCT_NAME": "default",
"MODULE_BUILD_DIR": "D:\\202076work\\hongmeng\\newExpert\\harmony\\build",
"BUNDLE_NAME": "com.example.expert",
"BUILD_PATH": {
"OUTPUT_PATH": "D:\\202076work\\hongmeng\\newExpert\\harmony\\build\\outputs\\default"
},
"MODULES": [
{
"name": "default",
"srcPath": "D:\\202076work\\hongmeng\\newExpert\\harmony\\products\\expert",
"targets": [
{
"name": "default",
"applyToProducts": [
"default"
]
}
],
"belongProjectPath": "D:\\202076work\\hongmeng\\newExpert\\harmony"
},
{
"name": "uicomponents",
"srcPath": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\uicomponents",
"belongProjectPath": "D:\\202076work\\hongmeng\\newExpert\\harmony"
},
{
"name": "utils",
"srcPath": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\utils",
"belongProjectPath": "D:\\202076work\\hongmeng\\newExpert\\harmony"
},
{
"name": "mypage",
"srcPath": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\mypage",
"belongProjectPath": "D:\\202076work\\hongmeng\\newExpert\\harmony"
},
{
"name": "basic",
"srcPath": "D:\\202076work\\hongmeng\\newExpert\\harmony\\commons\\basic",
"belongProjectPath": "D:\\202076work\\hongmeng\\newExpert\\harmony"
},
{
"name": "Home",
"srcPath": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\Home",
"belongProjectPath": "D:\\202076work\\hongmeng\\newExpert\\harmony"
},
{
"name": "register",
"srcPath": "D:\\202076work\\hongmeng\\newExpert\\harmony\\features\\register",
"belongProjectPath": "D:\\202076work\\hongmeng\\newExpert\\harmony"
}
],
"PROFILE_OPT": {
"app": {
"signingConfigs": [],
"products": [
{
"name": "default",
"signingConfig": "default",
"compatibleSdkVersion": "5.0.2(14)",
"runtimeOS": "HarmonyOS",
"buildOption": {
"strictMode": {
"caseSensitiveCheck": true,
"useNormalizedOHMUrl": true
}
}
}
],
"buildModeSet": [
{
"name": "debug"
},
{
"name": "release"
}
]
},
"modules": [
{
"name": "default",
"srcPath": "./products/expert",
"targets": [
{
"name": "default",
"applyToProducts": [
"default"
]
}
]
},
{
"name": "uicomponents",
"srcPath": "./commons/uicomponents"
},
{
"name": "utils",
"srcPath": "./commons/utils"
},
{
"name": "mypage",
"srcPath": "./features/mypage"
},
{
"name": "basic",
"srcPath": "./commons/basic"
},
{
"name": "Home",
"srcPath": "./features/Home"
},
{
"name": "register",
"srcPath": "./features/register"
}
]
},
"CONFIG_PROPERTIES": {
"enableSignTask": true,
"skipNativeIncremental": false,
"hvigor.keepDependency": true
},
"OVERALL_PROJECT_PATHS": [
"D:\\202076work\\hongmeng\\newExpert\\harmony"
],
"BUILD_CACHE_DIR": ""
},
"version": 1
}

10
AppScope/app.json5 Normal file
View File

@ -0,0 +1,10 @@
{
"app": {
"bundleName": "cn.shangyu.gdxzExports",
"vendor": "example",
"versionCode": 1000003,
"versionName": "1.1.0",
"icon": "$media:layered_image",
"label": "$string:app_name"
}
}

View File

@ -0,0 +1,8 @@
{
"string": [
{
"name": "app_name",
"value": "Expert"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

View File

@ -0,0 +1,7 @@
{
"layered-image":
{
"background" : "$media:background",
"foreground" : "$media:foreground"
}
}

View File

@ -0,0 +1,7 @@
2222
3333
5666611

6
RefreshLib/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
/node_modules
/oh_modules
/.preview
/build
/.cxx
/.test

View File

@ -0,0 +1,17 @@
/**
* Use these variables when you tailor your ArkTS code. They must be of the const type.
*/
export const HAR_VERSION = '1.0.0';
export const BUILD_MODE_NAME = 'debug';
export const DEBUG = true;
export const TARGET_NAME = 'default';
/**
* BuildProfile Class is used only for compatibility purposes.
*/
export default class BuildProfile {
static readonly HAR_VERSION = HAR_VERSION;
static readonly BUILD_MODE_NAME = BUILD_MODE_NAME;
static readonly DEBUG = DEBUG;
static readonly TARGET_NAME = TARGET_NAME;
}

5
RefreshLib/CHANGELOG.md Normal file
View File

@ -0,0 +1,5 @@
# 版本更新记录
## [v1.0.0] 2024-09-24
# 首次上传

15
RefreshLib/Index.ets Normal file
View File

@ -0,0 +1,15 @@
export { PullToRefreshLayout } from './src/main/ets/PullToRefreshLayout'
export { RefreshLayout } from './src/main/ets/RefreshLayout'
export { RefreshLayoutConfig } from './src/main/ets/RefreshLayoutConfig'
export { PullDown } from './src/main/ets/PullDown'
export { PullStatus } from './src/main/ets/PullStatus'
export { RefreshLayoutHelper } from './src/main/ets/RefreshLayoutHelper'
export { RefreshController } from './src/main/ets/RefreshController'
export { PullToRefreshConfig } from './src/main/ets/PullToRefreshConfig'

22
RefreshLib/README.md Normal file
View File

@ -0,0 +1,22 @@
PullToRefresh
简介
PullToRefresh 实现垂直列表下拉刷新,上拉加载,横向列表左拉刷新,右拉加载
特点
1.无入侵性,不需要传数据源
2.不限制组件,支持任意布局(List,Grid,Web,Scroll,Text,Row,Column等布局)
3.支持header和footer定制(支持Lottie动画)
4.支持垂直列表和横向列表的刷新和加载
5.支持下拉(或者上拉)打开其他页面
提供了RefreshLayout和PullToRefreshLayout
1.RefreshLayout支持各种定制化
2.PullToRefreshLayout是在RefreshLayout基础上定制的实现常用刷新和加载功能
3.如果没有个性化需求可以直接使用PullToRefreshLayout
详细使用Domehttps://gitee.com/myspace01/refresh-lib

View File

@ -0,0 +1,31 @@
{
"apiType": "stageMode",
"buildOption": {
},
"buildOptionSet": [
{
"name": "release",
"arkOptions": {
"obfuscation": {
"ruleOptions": {
"enable": false,
"files": [
"./obfuscation-rules.txt"
]
},
"consumerFiles": [
"./consumer-rules.txt"
]
}
},
},
],
"targets": [
{
"name": "default"
},
{
"name": "ohosTest"
}
]
}

View File

6
RefreshLib/hvigorfile.ts Normal file
View File

@ -0,0 +1,6 @@
import { harTasks } from '@ohos/hvigor-ohos-plugin';
export default {
system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
}

View File

@ -0,0 +1,23 @@
# Define project specific obfuscation rules here.
# You can include the obfuscation configuration files in the current module's build-profile.json5.
#
# For more details, see
# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5
# Obfuscation options:
# -disable-obfuscation: disable all obfuscations
# -enable-property-obfuscation: obfuscate the property names
# -enable-toplevel-obfuscation: obfuscate the names in the global scope
# -compact: remove unnecessary blank spaces and all line feeds
# -remove-log: remove all console.* statements
# -print-namecache: print the name cache that contains the mapping from the old names to new names
# -apply-namecache: reuse the given cache file
# Keep options:
# -keep-property-name: specifies property names that you want to keep
# -keep-global-name: specifies names that you want to keep in the global scope
-enable-property-obfuscation
-enable-toplevel-obfuscation
-enable-filename-obfuscation
-enable-export-obfuscation

View File

@ -0,0 +1,9 @@
{
"name": "refreshlib",
"version": "1.0.0",
"description": "Please describe the basic information.",
"main": "Index.ets",
"author": "os_space",
"license": "Apache-2.0",
"dependencies": {}
}

View File

@ -0,0 +1,20 @@
import { PullStatus } from './PullStatus'
export interface PullDown {
/*是否是下拉*/
isPullDown: boolean
/*是否是上拉*/
isPullUp: boolean
/*是否触摸*/
isTouch: boolean
/*下拉距离*/
distance: number
/*上拉距离*/
distanceLoad: number
/*headerView高度*/
headerViewSize: number
/*footerView高度*/
footerViewSize: number
/*状态*/
status: PullStatus
}

View File

@ -0,0 +1,34 @@
export enum PullStatus {
/*0默认状态(无下拉距离)*/
DEF,
/***********************************下拉状态*******************************************/
/*1下拉状态*/
PullDown,
/*2下拉至可以刷新的状态(准备刷新)*/
PreRefresh,
/*3刷新中*/
Refresh,
/*4下拉超过刷新高度时准备打开其他页面*/
PreOpenPage,
/*5下拉超过刷新高度时松手打开其他页面*/
OpenPage,
/*6刷新成功*/
RefreshSuccess,
/*7刷新失败*/
RefreshError,
/***********************************上拉状态*******************************************/
/*8上拉状态*/
PullUp,
/*9上拉至可以加载的状态(准备加载)*/
PreLoad,
/*10加载中*/
Load,
/*11上拉超过加载高度时准备打开其他页面*/
PreLoadOpenPage,
/*12上拉超过加载高度时松手打开其他页面*/
LoadOpenPage,
/*13加载成功*/
LoadSuccess,
/*14加载失败*/
LoadError
}

View File

@ -0,0 +1,95 @@
export class PullToRefreshConfig {
/*刷新loading宽度*/
public refreshLoadingWidth: Length = 25
/*刷新loading高度*/
public refreshLoadingHeight: Length = 25
/*刷新loading颜色*/
public refreshLoadingColor: ResourceColor = "#333333"
/*下拉刷新箭头*/
public arrowImage: Resource = $r("app.media.icon_refresh_arrow")
/*下拉刷新箭头颜色*/
public arrowImageColor: ResourceColor = "#333333"
/*下拉刷新箭头宽度*/
public arrowImageWidth: Length = 20
/*下拉刷新箭头高度*/
public arrowImageHeight: Length = 20
/*上拉刷新箭头*/
public arrowLoadImage: Resource = $r("app.media.icon_refresh_arrow")
/*上拉刷新箭头颜色*/
public arrowLoadImageColor: ResourceColor = "#333333"
/*上拉刷新箭头宽度*/
public arrowLoadImageWidth: Length = 20
/*上拉刷新箭头高度*/
public arrowLoadImageHeight: Length = 20
/*暂无更多提示*/
public noMoreTips: string | Resource = $r("app.string.zr_load_no_more")
/*暂无更多提示大小*/
public noMoreTipsSize: number | string | Resource = 13
/*暂无更多提示颜色*/
public noMoreTipsColor: ResourceColor = "#666666"
/*暂无更多提示——横向列表*/
public noMoreTipsHorizontal: string | Resource = $r("app.string.h_zr_load_no_more")
/*是否显示刷新时间*/
public showRefreshTime: boolean = false
/*刷新时间tips大小*/
public refreshTimeTipsSize: number | string | Resource = 11
/*刷新时间tips颜色*/
public refreshTimeTipsColor: ResourceColor = "#999999"
/*下拉刷新提示*/
public pullDownTips: string | Resource = $r("app.string.zr_pull_down_to_refresh")
/*下拉刷新提示——横向列表*/
public pullDownTipsHorizontal: string | Resource = $r("app.string.h_zr_pull_down_to_refresh")
/*下拉刷新提示大小*/
public pullDownTipsSize: number | string | Resource = 13
/*下拉刷新提示颜色*/
public pullDownTipsColor: ResourceColor = "#666666"
/*释放立即刷新tips*/
public releaseRefreshTips: string | Resource = $r("app.string.zr_release_to_refresh")
/*释放立即刷新tips——横向列表*/
public releaseRefreshTipsHorizontal: string | Resource = $r("app.string.h_zr_release_to_refresh")
/*正在刷新tips*/
public refreshTips: string | Resource = $r("app.string.zr_refreshing")
/*正在刷新tips——横向列表*/
public refreshTipsHorizontal: string | Resource = $r("app.string.h_zr_refreshing")
/*刷新成功tips*/
public refreshSuccessTips: string | Resource = $r("app.string.zr_refresh_success")
/*刷新成功tips——横向列表*/
public refreshSuccessTipsHorizontal: string | Resource = $r("app.string.h_zr_refresh_success")
/*刷新失败tips*/
public refreshErrorTips: string | Resource = $r("app.string.zr_refresh_error")
/*刷新失败tips——横向列表*/
public refreshErrorTipsHorizontal: string | Resource = $r("app.string.h_zr_refresh_error")
/*下拉打开其他页面tips*/
public pullOpenPageTips: string | Resource = $r("app.string.zr_release_to_open_age")
/*下拉打开其他页面tips——横向列表*/
public pullOpenPageTipsHorizontal: string | Resource = $r("app.string.h_zr_release_to_open_age")
/*上拉加载提示*/
public pullUpTips: string | Resource = $r("app.string.zr_pull_up_to_load")
/*上拉加载提示——横向列表*/
public pullUpTipsHorizontal: string | Resource = $r("app.string.h_zr_pull_up_to_load")
/*上拉加载提示大小*/
public pullUpTipsSize: number | string | Resource = 13
/*上拉加载提示颜色*/
public pullUpTipsColor: ResourceColor = "#333333"
/*释放立即加载tips*/
public releaseLoadTips: string | Resource = $r("app.string.zr_release_to_load")
/*释放立即加载tips——横向列表*/
public releaseLoadTipsHorizontal: string | Resource = $r("app.string.h_zr_release_to_load")
/*正在加载tips*/
public loadTips: string | Resource = $r("app.string.zr_loading")
/*正在加载tips——横向列表*/
public loadTipsHorizontal: string | Resource = $r("app.string.h_zr_loading")
/*加载成功tips*/
public loadSuccessTips: string | Resource = $r("app.string.zr_load_success")
/*加载成功tips——横向列表*/
public loadSuccessTipsHorizontal: string | Resource = $r("app.string.h_zr_load_success")
/*加载失败tips*/
public loadErrorTips: string | Resource = $r("app.string.zr_load_error")
/*加载失败tips——横向列表*/
public loadErrorTipsHorizontal: string | Resource = $r("app.string.h_zr_load_error")
/*下拉打开其他页面tips*/
public loadOpenPageTips: string | Resource = $r("app.string.zr_release_to_open_age")
}

View File

@ -0,0 +1,806 @@
import { PullDown } from './PullDown';
import { PullStatus } from './PullStatus';
import { RefreshController } from './RefreshController';
import { RefreshLayout } from './RefreshLayout';
import { RefreshLayoutConfig } from './RefreshLayoutConfig';
import { _ContentView } from './RefreshLayoutHelper';
import web from '@ohos.web.webview';
import preferences from '@ohos.data.preferences';
import { PullToRefreshConfig } from './PullToRefreshConfig';
@ComponentV2
export struct PullToRefreshLayout {
/*下拉箭头旋转角度*/
@Local arrowRotate: number = 0;
/*上拉箭头旋转角度*/
@Local arrowRotateLoad: number = 180;
@Local status: PullStatus = PullStatus.DEF
/********************************************************************************************************/
@Param public pullConfig: PullToRefreshConfig = new PullToRefreshConfig()
/*记录组件刷新时间*/
@Param public viewKey: string = ""
@Param public scroller: Scroller | undefined = undefined
@Param public webviewController: web.WebviewController | undefined = undefined
@Param public controller: RefreshController = new RefreshController()
/*是否可以下拉*/
@Param public onCanPullRefresh: () => boolean = () => true
/*是否可以下拉*/
@Param public onCanPullLoad: () => boolean = () => false
/*刷新通知*/
@Param public onRefresh: () => void = () => {
}
/*刷新通知*/
@Param public onLoad: () => void = () => {
}
/*打开页面通知*/
@Param public onOpenPage: () => void = () => {
}
/*打开页面通知*/
@Param public onLoadOpenPage: () => void = () => {
}
/*下拉状态监听*/
@Param public onPullListener: (pullDown: PullDown) => void = () => {
}
//内容视图
@BuilderParam contentView: () => void = _ContentView
//loading视图
@BuilderParam headerLoadIngView?: () => void
//loading视图
@BuilderParam footerLoadIngView?: () => void
/*下拉刷新配置*/
@Param public config: RefreshLayoutConfig = new RefreshLayoutConfig()
//正在加载视图
@BuilderParam viewLoading?: () => void
//空视图
@BuilderParam viewEmpty?: () => void
//加载错误视图
@BuilderParam viewError?: () => void
//无网络视图
@BuilderParam viewNoNetwork?: () => void
/********************************************************************************************************/
aboutToAppear(): void {
this.resetArrowRotate()
this.resetArrowRotateLoad()
}
/*************垂直列表和水平列表feader视图箭头角度**************/
private isPullRotate(): boolean {
if (this.isVerticalLayout()) {
return this.arrowRotate == 0
} else {
return this.arrowRotate == -90
}
}
private isPreRefreshRotate(): boolean {
if (this.isVerticalLayout()) {
return this.arrowRotate == 180
} else {
return this.arrowRotate == 90
}
}
private setPreRefreshRotate() {
if (this.isVerticalLayout()) {
this.arrowRotate = 180
} else {
this.arrowRotate = 90
}
}
private resetArrowRotate() {
if (this.isVerticalLayout()) {
this.arrowRotate = 0
} else {
this.arrowRotate = -90
}
}
/*************垂直列表和水平列表footer视图箭头角度**************/
private isPullLoadRotate(): boolean {
if (this.isVerticalLayout()) {
return this.arrowRotateLoad == 180
} else {
return this.arrowRotateLoad == 90
}
}
private isPreLoadRotate(): boolean {
if (this.isVerticalLayout()) {
return this.arrowRotateLoad == 0
} else {
return this.arrowRotateLoad == -90
}
}
private setPreLoadRotate() {
if (this.isVerticalLayout()) {
this.arrowRotateLoad = 180
} else {
this.arrowRotateLoad = 90
}
}
private resetArrowRotateLoad() {
if (this.isVerticalLayout()) {
this.arrowRotateLoad = 0
} else {
this.arrowRotateLoad = -90
}
}
build() {
RefreshLayout({
scroller: this.scroller,
webviewController: this.webviewController,
controller: this.controller,
config: this.config,
headerView: () => {
if (this.isVerticalLayout()) {
this.defHeaderView()
} else {
this.defHeaderViewHorizontal()
}
},
onCanPullRefresh: () => {
return this.onCanPullRefresh()
},
onCanPullLoad: () => {
return this.onCanPullLoad()
},
onRefresh: () => {
this.onRefresh()
},
onLoad: () => {
this.onLoad()
},
onOpenPage: () => {
this.onOpenPage()
},
onLoadOpenPage: () => {
this.onLoadOpenPage()
},
contentView: () => {
this.contentView()
},
loadView: () => {
if (this.isVerticalLayout()) {
this.defFooterView()
} else {
this.defFooterViewHorizontal()
}
},
noMoreView: () => {
if (this.isVerticalLayout()) {
this.defFooterNoMoreView()
} else {
this.defFooterNoMoreViewHorizontal()
}
},
onPullListener: (pullDown: PullDown) => {
this.status = pullDown.status
this.updateRefreshTime(this.status)
this.onPullListener?.(pullDown)
if (this.config.pullHeaderHeightRefresh <= pullDown.headerViewSize) {
this.config.pullHeaderHeightRefresh = pullDown.headerViewSize * 1.5
}
if (this.config.pullHeaderHeightOpenPage <= this.config.pullHeaderHeightRefresh) {
this.config.pullHeaderHeightOpenPage = pullDown.headerViewSize * 2.6
}
if (this.config.pullFooterHeightLoad <= pullDown.footerViewSize) {
this.config.pullFooterHeightLoad = pullDown.footerViewSize * 1.1
}
if (this.config.pullFooterHeightOpenPage <= this.config.pullFooterHeightLoad) {
this.config.pullFooterHeightOpenPage = pullDown.footerViewSize * 2.6
}
if (this.status == PullStatus.PullDown) {
if (this.isPullRotate()) {
return
}
/*进入下拉状态*/
animateTo({ duration: 10, curve: Curve.Linear }, () => {
this.resetArrowRotate()
})
} else if (this.status == PullStatus.PreRefresh) {
if (this.isPreRefreshRotate()) {
return
}
/*进入释放刷新状态*/
animateTo({ duration: 150, curve: Curve.Linear }, () => {
this.setPreRefreshRotate()
})
} else if (this.status == PullStatus.PullUp) {
if (this.isPullLoadRotate()) {
return
}
/*进入上拉状态*/
animateTo({ duration: 10, curve: Curve.Linear }, () => {
this.setPreLoadRotate()
})
} else if (this.status == PullStatus.PreLoad) {
if (this.isPreLoadRotate()) {
return
}
/*进入释放加载状态*/
animateTo({ duration: 150, curve: Curve.Linear }, () => {
this.resetArrowRotateLoad()
})
}
},
/*正在加载视图*/
viewLoading: this.viewLoading,
/*空数据视图*/
viewEmpty: this.viewEmpty,
/*加载失败视图*/
viewError: this.viewError,
/*无网络视图*/
viewNoNetwork: this.viewNoNetwork
}).clip(true)
}
private isVerticalLayout(): boolean {
return (this.config.isVertical || this.config.horizontalMode == 1 || this.config.horizontalMode == 2)
}
@Local private zrLastUpdate: string = getContext().resourceManager.getStringByNameSync(("zr_last_update"))
@Builder
defHeaderViewHorizontal() {
RelativeContainer() {
Stack() {
Image(this.pullConfig.arrowImage)
.width(this.pullConfig.arrowImageWidth)
.height(this.pullConfig.arrowImageHeight)
.visibility(this.getPullArrowVisibility())
.fillColor(this.pullConfig.arrowImageColor)
.margin({ top: 5 })
.rotate({
x: 0,
y: 0,
z: 1,
angle: this.arrowRotate
})
if (this.headerLoadIngView) {
Stack() {
this.headerLoadIngView()
}
.visibility(this.getRefreshVisibility())
} else {
LoadingProgress()
.color(this.pullConfig.refreshLoadingColor)
.width(this.pullConfig.refreshLoadingWidth)
.height(this.pullConfig.refreshLoadingHeight)
.visibility(this.getRefreshVisibility())
}
}.alignRules({
top: { anchor: "title", align: VerticalAlign.Bottom },
middle: { anchor: "__container__", align: HorizontalAlign.Center }
}).id("arrow")
Row() {
Text(this.getTips())
.fontSize(this.pullConfig.pullDownTipsSize)
.fontColor(this.pullConfig.pullDownTipsColor)
.textAlign(TextAlign.Center)
Text(this.zrLastUpdate)
.fontSize(this.pullConfig.refreshTimeTipsSize)
.fontColor(this.pullConfig.refreshTimeTipsColor)
.margin({ left: 2 })
.visibility(this.pullConfig.showRefreshTime ? this.getTimeTipsVisibility() : Visibility.None)
.textAlign(TextAlign.Center)
}.id("title").alignRules({
middle: { anchor: "__container__", align: HorizontalAlign.Center },
center: { anchor: "__container__", align: VerticalAlign.Center }
}).alignItems(VerticalAlign.Center)
}.width(50).height("100%")
}
@Builder
defHeaderView() {
RelativeContainer() {
Stack() {
Image(this.pullConfig.arrowImage)
.width(this.pullConfig.arrowImageWidth)
.height(this.pullConfig.arrowImageHeight)
.visibility(this.getPullArrowVisibility())
.fillColor(this.pullConfig.arrowImageColor)
.margin({ right: 10 })
.rotate({
x: 0,
y: 0,
z: 1,
angle: this.arrowRotate
})
if (this.headerLoadIngView) {
Stack() {
this.headerLoadIngView()
}
.visibility(this.getRefreshVisibility())
} else {
LoadingProgress()
.color(this.pullConfig.refreshLoadingColor)
.width(this.pullConfig.refreshLoadingWidth)
.height(this.pullConfig.refreshLoadingHeight)
.visibility(this.getRefreshVisibility())
}
}.alignRules({
right: { anchor: "title", align: HorizontalAlign.Start },
center: { anchor: "__container__", align: VerticalAlign.Center }
}).id("arrow")
Column() {
Text(this.getTips()).fontSize(this.pullConfig.pullDownTipsSize)
.fontColor(this.pullConfig.pullDownTipsColor)
Text(this.zrLastUpdate).fontSize(this.pullConfig.refreshTimeTipsSize)
.fontColor(this.pullConfig.refreshTimeTipsColor).margin({ top: 2 })
.visibility(this.pullConfig.showRefreshTime ? this.getTimeTipsVisibility() : Visibility.None)
}.id("title").alignRules({
middle: { anchor: "__container__", align: HorizontalAlign.Center },
center: { anchor: "__container__", align: VerticalAlign.Center }
}).constraintSize({ minWidth: 80 }).alignItems(HorizontalAlign.Center)
}.height(50).width("100%")
}
@Builder
defFooterViewHorizontal() {
RelativeContainer() {
Stack() {
Image(this.pullConfig.arrowLoadImage)
.width(this.pullConfig.arrowLoadImageWidth)
.height(this.pullConfig.arrowLoadImageHeight)
.visibility(this.getPullUpArrowVisibility())
.fillColor(this.pullConfig.arrowLoadImageColor)
.margin({ top: 5 })
.rotate({
x: 0,
y: 0,
z: 1,
angle: this.arrowRotateLoad
})
if (this.footerLoadIngView) {
Stack() {
this.footerLoadIngView()
}
.visibility(this.getLoadVisibility())
} else {
LoadingProgress()
.color(this.pullConfig.refreshLoadingColor)
.width(this.pullConfig.refreshLoadingWidth)
.height(this.pullConfig.refreshLoadingHeight).visibility(this.getLoadVisibility())
}
}.alignRules({
top: { anchor: "title", align: VerticalAlign.Bottom },
middle: { anchor: "__container__", align: HorizontalAlign.Center }
}).id("arrow")
Row() {
Text(this.getLoadTips())
.fontSize(this.pullConfig.pullUpTipsSize)
.fontColor(this.pullConfig.pullUpTipsColor)
.textAlign(TextAlign.Center)
}.id("title").alignRules({
middle: { anchor: "__container__", align: HorizontalAlign.Center },
center: { anchor: "__container__", align: VerticalAlign.Center }
}).alignItems(VerticalAlign.Center)
}.width(50).height("100%")
}
@Builder
defFooterNoMoreViewHorizontal() {
Text(this.pullConfig.noMoreTipsHorizontal)
.textAlign(TextAlign.Center)
.height("100%")
.width(50)
.fontSize(this.pullConfig.noMoreTipsSize)
.fontColor(this.pullConfig.noMoreTipsColor)
}
@Builder
defFooterView() {
RelativeContainer() {
Stack() {
Image(this.pullConfig.arrowLoadImage)
.width(this.pullConfig.arrowLoadImageWidth)
.height(this.pullConfig.arrowLoadImageHeight)
.visibility(this.getPullUpArrowVisibility())
.fillColor(this.pullConfig.arrowLoadImageColor)
.margin({ right: 10 })
.rotate({
x: 0,
y: 0,
z: 1,
angle: this.arrowRotateLoad
})
if (this.footerLoadIngView) {
Stack() {
this.footerLoadIngView()
}
.visibility(this.getLoadVisibility())
} else {
LoadingProgress()
.color(this.pullConfig.refreshLoadingColor)
.width(this.pullConfig.refreshLoadingWidth)
.height(this.pullConfig.refreshLoadingHeight)
.visibility(this.getLoadVisibility())
}
}.alignRules({
right: { anchor: "title", align: HorizontalAlign.Start },
center: { anchor: "__container__", align: VerticalAlign.Center }
}).id("arrow")
Column() {
Text(this.getLoadTips()).fontSize(this.pullConfig.pullUpTipsSize).fontColor(this.pullConfig.pullUpTipsColor)
}.id("title").alignRules({
middle: { anchor: "__container__", align: HorizontalAlign.Center },
center: { anchor: "__container__", align: VerticalAlign.Center }
}).constraintSize({ minWidth: 80 }).alignItems(HorizontalAlign.Center)
}.height(50).width("100%")
}
@Builder
defFooterNoMoreView() {
Text(this.pullConfig.noMoreTips)
.textAlign(TextAlign.Center)
.height(50)
.width("100%")
.fontSize(this.pullConfig.noMoreTipsSize)
.fontColor(this.pullConfig.noMoreTipsColor)
}
private getTips(): Resource | string {
// todo
if (!this.config.isVertical && this.config.horizontalMode != 1 && this.config.horizontalMode != 2) {
switch (this.status) {
case PullStatus.DEF:
case PullStatus.PullDown:
return this.pullConfig.pullDownTipsHorizontal
case PullStatus.PreRefresh:
return this.pullConfig.releaseRefreshTipsHorizontal
case PullStatus.Refresh:
return this.pullConfig.refreshTipsHorizontal
case PullStatus.PreOpenPage:
case PullStatus.OpenPage:
return this.pullConfig.pullOpenPageTipsHorizontal
case PullStatus.RefreshSuccess:
if (this.controller.getConfig().refreshShowSuccess) {
return this.pullConfig.refreshSuccessTipsHorizontal
} else {
/*如果不显示刷新成功的视图*/
return this.pullConfig.refreshTipsHorizontal
}
case PullStatus.RefreshError:
if (this.controller.getConfig().refreshShowError) {
return this.pullConfig.refreshErrorTipsHorizontal
} else {
/*如果不显示刷新失败的视图*/
return this.pullConfig.refreshTipsHorizontal
}
default:
return this.pullConfig.pullDownTipsHorizontal
}
}
switch (this.status) {
case PullStatus.DEF:
case PullStatus.PullDown:
return this.pullConfig.pullDownTips
case PullStatus.PreRefresh:
return this.pullConfig.releaseRefreshTips
case PullStatus.Refresh:
return this.pullConfig.refreshTips
case PullStatus.PreOpenPage:
case PullStatus.OpenPage:
return this.pullConfig.pullOpenPageTips
case PullStatus.RefreshSuccess:
if (this.controller.getConfig().refreshShowSuccess) {
return this.pullConfig.refreshSuccessTips
} else {
/*如果不显示刷新成功的视图*/
return this.pullConfig.refreshTips
}
case PullStatus.RefreshError:
if (this.controller.getConfig().refreshShowError) {
return this.pullConfig.refreshErrorTips
} else {
/*如果不显示刷新失败的视图*/
return this.pullConfig.refreshTips
}
default:
return this.pullConfig.pullDownTips
}
}
private getLoadTips(): Resource | string {
if (!this.config.isVertical && this.config.horizontalMode != 1 && this.config.horizontalMode != 2) {
switch (this.status) {
case PullStatus.DEF:
case PullStatus.PullUp:
return this.pullConfig.pullUpTipsHorizontal
case PullStatus.PreLoad:
return this.pullConfig.releaseLoadTipsHorizontal
case PullStatus.Load:
return this.pullConfig.loadTipsHorizontal
case PullStatus.PreLoadOpenPage:
case PullStatus.LoadOpenPage:
return this.pullConfig.pullOpenPageTipsHorizontal
case PullStatus.LoadSuccess:
if (this.controller.getConfig().loadShowSuccess) {
return this.pullConfig.loadSuccessTipsHorizontal
} else {
/*如果不显示刷新成功的视图*/
return this.pullConfig.loadTipsHorizontal
}
case PullStatus.LoadError:
if (this.controller.getConfig().loadShowError) {
return this.pullConfig.loadErrorTipsHorizontal
} else {
/*如果不显示刷新失败的视图*/
return this.pullConfig.loadTipsHorizontal
}
default:
return this.pullConfig.pullUpTipsHorizontal
}
}
switch (this.status) {
case PullStatus.DEF:
case PullStatus.PullUp:
return this.pullConfig.pullUpTips
case PullStatus.PreLoad:
return this.pullConfig.releaseLoadTips
case PullStatus.Load:
return this.pullConfig.loadTips
case PullStatus.PreLoadOpenPage:
case PullStatus.LoadOpenPage:
return this.pullConfig.loadOpenPageTips
case PullStatus.LoadSuccess:
if (this.controller.getConfig().loadShowSuccess) {
return this.pullConfig.loadSuccessTips
} else {
/*如果不显示刷新成功的视图*/
return this.pullConfig.loadTips
}
case PullStatus.LoadError:
if (this.controller.getConfig().loadShowError) {
return this.pullConfig.loadErrorTips
} else {
/*如果不显示刷新失败的视图*/
return this.pullConfig.loadTips
}
default:
return this.pullConfig.pullUpTips
}
}
/*下拉箭头显示逻辑*/
private getPullArrowVisibility(): Visibility {
switch (this.status) {
case PullStatus.DEF:
case PullStatus.PullDown:
case PullStatus.PreRefresh:
return Visibility.Visible
}
return Visibility.Hidden
}
private getRefreshVisibility(): Visibility {
switch (this.status) {
case PullStatus.Refresh:
return Visibility.Visible
case PullStatus.RefreshSuccess:
if (this.controller.getConfig().refreshShowSuccess) {
return Visibility.Hidden
} else {
/*如果不显示刷新成功的视图*/
return Visibility.Visible
}
case PullStatus.RefreshError:
if (this.controller.getConfig().refreshShowError) {
return Visibility.Hidden
} else {
/*如果不显示刷新失败的视图*/
return Visibility.Visible
}
}
return Visibility.Hidden
}
private getPullUpArrowVisibility(): Visibility {
switch (this.status) {
case PullStatus.DEF:
case PullStatus.PullUp:
case PullStatus.PreLoad:
return Visibility.Visible
}
return Visibility.Hidden
}
private getLoadVisibility(): Visibility {
switch (this.status) {
case PullStatus.Load:
return Visibility.Visible
case PullStatus.LoadSuccess:
if (this.controller.getConfig().loadShowSuccess) {
return Visibility.Hidden
} else {
/*如果不显示刷新成功的视图*/
return Visibility.Visible
}
case PullStatus.LoadError:
if (this.controller.getConfig().loadShowError) {
return Visibility.Hidden
} else {
/*如果不显示刷新失败的视图*/
return Visibility.Visible
}
}
return Visibility.Hidden
}
private getTimeTipsVisibility(): Visibility {
switch (this.status) {
case PullStatus.Refresh:
case PullStatus.PreOpenPage:
case PullStatus.OpenPage:
case PullStatus.RefreshSuccess:
case PullStatus.RefreshError:
return Visibility.None
}
if (this.getLastRefreshTime() <= 0) {
return Visibility.None
}
return Visibility.Visible
}
private sp: preferences.Preferences | undefined = undefined
private lastRefreshTime: number | undefined = undefined
private getLastRefreshTime(): number {
if (!this.sp) {
this.sp = preferences.getPreferencesSync(getContext(), {
name: "PullToRefreshLayoutTime"
})
}
if (this.lastRefreshTime) {
return this.lastRefreshTime
}
let preTime: number = this.sp.getSync("lastRefreshTimeKey" + this.viewKey, 0) as number
this.lastRefreshTime = preTime
return preTime;
}
private saveRefreshTime() {
if (!this.sp) {
this.sp = preferences.getPreferencesSync(getContext(), {
name: "PullToRefreshLayoutTime"
})
}
this.lastRefreshTime = new Date().getTime()
this.sp.put("lastRefreshTimeKey" + this.viewKey, this.lastRefreshTime)
this.sp.flush()
}
private lineBreak(): string {
if (this.isVerticalLayout()) {
return ""
} else {
return "\n"
}
}
private getLastFormatRefreshTime(): string {
const time = this.getLastRefreshTime();
if (time <= 0) {
return ""
}
const currentTime = new Date().getTime()
const timeIntervalSecond = Math.floor(((currentTime - time) / 1000))
let timeFormat: string = ""
if (!this.zr_last_update) {
if (this.isVerticalLayout()) {
this.zr_last_update = getContext().resourceManager.getStringByNameSync(("zr_last_update"))
} else {
this.zr_last_update = "\n" + getContext().resourceManager.getStringByNameSync(("h_zr_last_update"))
}
}
timeFormat = timeFormat + this.zr_last_update
if (timeIntervalSecond < 60) {
timeFormat = timeFormat + this.lineBreak() + timeIntervalSecond;
if (!this.zr_seconds_ago) {
if (this.isVerticalLayout()) {
this.zr_seconds_ago = getContext().resourceManager.getStringByNameSync(("zr_seconds_ago"))
} else {
this.zr_seconds_ago = "\n" + getContext().resourceManager.getStringByNameSync(("h_zr_seconds_ago"))
}
}
timeFormat = timeFormat + this.zr_seconds_ago
} else if (timeIntervalSecond < 3600) {
/*小于一小时*/
timeFormat = timeFormat + this.lineBreak() + Math.floor((timeIntervalSecond / 60));
if (!this.zr_minutes_ago) {
if (this.isVerticalLayout()) {
this.zr_minutes_ago = getContext().resourceManager.getStringByNameSync(("zr_minutes_ago"))
} else {
this.zr_minutes_ago = "\n" + getContext().resourceManager.getStringByNameSync(("h_zr_minutes_ago"))
}
}
timeFormat = timeFormat + this.zr_minutes_ago
} else if (timeIntervalSecond < 86400) {
/*小于一天*/
timeFormat = timeFormat + this.lineBreak() + Math.floor((timeIntervalSecond / 3600));
if (!this.zr_hours_ago) {
if (this.isVerticalLayout()) {
this.zr_hours_ago = getContext().resourceManager.getStringByNameSync(("zr_hours_ago"))
} else {
this.zr_hours_ago = "\n" + getContext().resourceManager.getStringByNameSync(("h_zr_hours_ago"))
}
}
timeFormat = timeFormat + this.zr_hours_ago
} else {
/*大于一天*/
timeFormat = timeFormat + this.lineBreak() + Math.floor((timeIntervalSecond / 86400));
if (!this.zr_days_ago) {
if (this.isVerticalLayout()) {
this.zr_days_ago = getContext().resourceManager.getStringByNameSync(("zr_days_ago"))
} else {
this.zr_days_ago = "\n" + getContext().resourceManager.getStringByNameSync(("h_zr_days_ago"))
}
}
timeFormat = timeFormat + this.zr_days_ago
}
return timeFormat
}
private zr_last_update: string | undefined = undefined
private zr_seconds_ago: string | undefined = undefined
private zr_minutes_ago: string | undefined = undefined
private zr_hours_ago: string | undefined = undefined
private zr_days_ago: string | undefined = undefined
private isUpdateTime = false;
private updateRefreshTime(status: PullStatus) {
if (status == PullStatus.RefreshSuccess) {
this.saveRefreshTime()
}
if (status == PullStatus.PullDown || status == PullStatus.PreRefresh) {
if (this.isUpdateTime) {
return;
}
this.isUpdateTime = true
setTimeout(() => {
this.zrLastUpdate = this.getLastFormatRefreshTime()
this.startUpdateTime();
})
} else {
this.stopUpdateTime();
}
}
private startUpdateTime() {
if (!this.isUpdateTime) {
return
}
setTimeout(() => {
this.zrLastUpdate = this.getLastFormatRefreshTime()
// console.log(this.zrLastUpdate + "=======startUpdateTime=====" + (1000 - new Date().getTime() % 1000));
this.startUpdateTime();
}, 1000 - new Date().getTime() % 1000)
}
private stopUpdateTime() {
this.isUpdateTime = false
}
}

View File

@ -0,0 +1,80 @@
import { PullStatus } from './PullStatus'
import { RefreshLayoutConfig } from './RefreshLayoutConfig'
export enum ViewState{
success=0,
loading,
empty,
error,
noNetwork
}
export class RefreshController {
/*刷新成功*/
refreshSuccess: (ignoreViewTips?:boolean) => void = (ignoreViewTips?:boolean) => {
}
/*刷新失败*/
refreshError: () => void = () => {
}
/*刷新完成true:成功false失败*/
refreshComplete: (isSuccess: boolean,ignoreViewTips?:boolean) => void = (isSuccess: boolean,ignoreViewTips?:boolean) => {
}
/*取消刷新*/
refreshCancel: () => void = () => {
}
/*加载成功*/
loadSuccess: (hasMore?: boolean) => void = (hasMore?: boolean) => {
}
/*加载失败*/
loadError: () => void = () => {
}
/*加载完成true:成功false失败*/
loadComplete: (isSuccess: boolean, hasMore?: boolean) => void = (isSuccess: boolean, hasMore?: boolean) => {
}
/*取消加载*/
loadCancel: () => void = () => {
}
/*显示加载中*/
viewLoading: () => void = () => {
this.viewState=ViewState.loading
}
/*显示空布局*/
viewEmpty: () => void = () => {
this.viewState=ViewState.empty
}
/*显示加载失败布局*/
viewError: () => void = () => {
this.viewState=ViewState.error
}
/*显示无网络布局*/
viewNoNetwork: () => void = () => {
this.viewState=ViewState.noNetwork
}
/**/
/*获取当前状态*/
getStatus: () => PullStatus = () => PullStatus.DEF
/*设置是否还有更多数据*/
hasMore: (hasMore: boolean) => void = (hasMore: boolean) => {
}
/*手动触发下拉刷新*/
refresh: () => void = () => {
}
/*手动触发上拉*/
load: () => void = () => {
}
/*下拉刷新开关是否打开*/
refreshIsEnable: () => boolean = () => true
/*下拉刷新开关是否打开*/
loadIsEnable: () => boolean = () => false
/*设置配置*/
/*由于v2装饰器@Param限制原因setConfig方法在v2版本上不提供*/
/*@Param装饰的变量在子组件中无法进行修改。但当装饰的变量类型为对象时在子组件中修改对象中属性是允许的。*/
// setConfig: (config: RefreshLayoutConfig) => void = () => {}
/*获取配置*/
getConfig: () => RefreshLayoutConfig = () => new RefreshLayoutConfig()
/*webview专用*/
onWebviewScroll: (xOffset: number, yOffset: number) => void = (xOffset: number, yOffset: number) => {
}
private viewState:ViewState=ViewState.success
public getViewState():ViewState{
return this.viewState
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,68 @@
export class RefreshLayoutConfig {
/*是否是垂直列表*/
public isVertical: boolean = true
/*横向模式0正常横向布局1header和footer逆时针旋转90度2header和footer顺时针旋转90度*/
public horizontalMode: number = 0
/*是否打开刷新*/
public pullRefreshEnable: boolean = true
/*是否打开加载更多*/
public pullLoadEnable: boolean = true
/*******************************刷新配置*******************************************/
/*true:释放刷新false下拉到一定距离刷新*/
public releaseRefresh: boolean = true
/*下拉最大距离*/
public pullMaxDistance: number = 500
/*下拉阻力*/
public pullRefreshResistance: number = 0.5
/*下拉距离超过多少时达到刷新条件*/
public pullHeaderHeightRefresh: number = 0
/*下拉打开其他页面开关*/
public pullRefreshOpenPageEnable: boolean = false
/*下拉距离超过多少时达到打开其他页面条件*/
public pullHeaderHeightOpenPage: number = 0
/*释放刷新时回弹至headerView高度的时间*/
public durationToHeader: number = 250
/*头布局刷新结束时回弹的时间*/
public durationCloseHeader: number = 200
/*需要打开其他页面时,头布局的回弹时间*/
public durationCloseForOpenPage: number = 180
/*刷新时是否显示头view*/
public refreshKeepHeader: boolean = true
/*是否显示刷新成功状态的view*/
public refreshShowSuccess: boolean = true;
/*是否显示刷新失败状态的view*/
public refreshShowError: boolean = true;
/*刷新结果view显示持续时间*/
public refreshResultDurationTime: number = 600
/*******************************加载更多配置*******************************************/
/*true:释放加载false下拉到一定距离加载*/
public releaseLoad: boolean = true
/*上拉最大距离*/
public pullLoadMaxDistance: number = 500
/*上拉阻力*/
public pullLoadResistance: number = 0.5
/*上拉距离超过多少时达到刷新条件*/
public pullFooterHeightLoad: number = 0
/*上拉打开其他页面开关*/
public pullLoadOpenPageEnable: boolean = false
/*上拉距离超过多少时达到打开其他页面条件*/
public pullFooterHeightOpenPage: number = 0
/*释放刷新时回弹至footerView高度的时间*/
public durationToFooter: number = 250
/*footer布局刷新结束时回弹的时间*/
public durationCloseFooter: number = 200
/*需要打开其他页面时,头布局的回弹时间*/
public durationCloseLoadForOpenPage: number = 180
/*刷新时是否显示footerView*/
public loadKeepFooter: boolean = true
/*是否显示刷新成功状态的view*/
public loadShowSuccess: boolean = true;
/*是否显示刷新失败状态的view*/
public loadShowError: boolean = true;
/*刷新结果view显示持续时间*/
public loadResultDurationTime: number = 600
}

View File

@ -0,0 +1,67 @@
import { AnimatorOptions } from '@kit.ArkUI';
@Builder
export function _headerView() {
Text("headerView:()=>{your @Builder View}")
}
@Builder
export function _ContentView() {
Text("contentView:()=>{your @Builder View}")
}
@Builder
export function _loadMoreView() {
Text("loadView:()=>{your @Builder View}")
}
@Builder
export function _noMoreView() {
Text("noMoreView:()=>{your @Builder View}")
}
export class RefreshLayoutHelper {
private log(str: string, tag: string = "RefreshLayout") {
console.debug(tag + "==" + str)
}
/*记录列表滑动到底部的偏移量*/
public scrollerOffset: number = 0;
/*下拉刷新*/
public preOffset: number = 0;
public totalOffset: number = 0;
/*上拉加载*/
// public preOffsetLoad: number = 0;
public totalOffsetLoad: number = 0;
public headerSize: number = 0;
public footerSize: number = 0;
public isPressDown: boolean = false
public options: PanGestureOptions = new PanGestureOptions({ direction: PanDirection.Down | PanDirection.Up })
/*不是释放刷新*/
public notReleaseRefresh: boolean = false
/*不是释放加载*/
public notReleaseLoad: boolean = false
public animOptions: AnimatorOptions = {
duration: 250,
easing: "fast-out-linear-in",
delay: 0,
fill: "forwards",
direction: "normal",
iterations: 1,
begin: 0,
end: 1
}
public animLoadOptions: AnimatorOptions = {
duration: 250,
easing: "fast-out-linear-in",
delay: 0,
fill: "forwards",
direction: "normal",
iterations: 1,
begin: 0,
end: 1
}
/*webview滑动偏移量*/
public webViewXOffset: number = 0
public webViewYOffset: number = 0
}

View File

@ -0,0 +1,11 @@
{
"module": {
"name": "refreshlib",
"type": "har",
"deviceTypes": [
"default",
"tablet",
"2in1"
]
}
}

View File

@ -0,0 +1,72 @@
{
"string": [
{
"name": "zr_pull_down_to_refresh",
"value": "下拉刷新"
},
{
"name": "zr_release_to_refresh",
"value": "释放立即刷新"
},
{
"name": "zr_release_to_open_age",
"value": "释放打开其他页面"
},
{
"name": "zr_refreshing",
"value": "正在刷新..."
},
{
"name": "zr_refresh_success",
"value": "刷新完成"
},
{
"name": "zr_refresh_error",
"value": "刷新失败"
},
{
"name": "zr_last_update",
"value": "上次更新:"
},
{
"name": "zr_seconds_ago",
"value": " 秒之前"
},
{
"name": "zr_minutes_ago",
"value": " 分钟之前"
},
{
"name": "zr_hours_ago",
"value": " 小时之前"
},
{
"name": "zr_days_ago",
"value": " 天之前"
},
{
"name": "zr_pull_up_to_load",
"value": "上拉加载"
},
{
"name": "zr_release_to_load",
"value": "释放立即加载"
},
{
"name": "zr_loading",
"value": "正在加载..."
},
{
"name": "zr_load_success",
"value": "加载完成"
},
{
"name": "zr_load_error",
"value": "加载失败"
},
{
"name": "zr_load_no_more",
"value": "暂无更多"
}
]
}

View File

@ -0,0 +1,72 @@
{
"string": [
{
"name": "h_zr_pull_down_to_refresh",
"value": "右\n拉\n刷\n新"
},
{
"name": "h_zr_release_to_refresh",
"value": "释\n放\n立\n即\n刷\n新"
},
{
"name": "h_zr_release_to_open_age",
"value": "释\n放\n打\n开\n其\n他\n页\n面"
},
{
"name": "h_zr_refreshing",
"value": "正\n在\n刷\n新\n..."
},
{
"name": "h_zr_refresh_success",
"value": "刷\n新\n完\n成"
},
{
"name": "h_zr_refresh_error",
"value": "刷\n新\n失\n败"
},
{
"name": "h_zr_last_update",
"value": "上\n次\n更\n新"
},
{
"name": "h_zr_seconds_ago",
"value": "秒\n之\n前"
},
{
"name": "h_zr_minutes_ago",
"value": "分\n钟\n之\n前"
},
{
"name": "h_zr_hours_ago",
"value": "小\n时\n之\n前"
},
{
"name": "h_zr_days_ago",
"value": "天\n之\n前"
},
{
"name": "h_zr_pull_up_to_load",
"value": "左\n拉\n加\n载"
},
{
"name": "h_zr_release_to_load",
"value": "释\n放\n立\n即\n加\n载"
},
{
"name": "h_zr_loading",
"value": "正\n在\n加\n载\n..."
},
{
"name": "h_zr_load_success",
"value": "加\n载\n完\n成"
},
{
"name": "h_zr_load_error",
"value": "加\n载\n失\n败"
},
{
"name": "h_zr_load_no_more",
"value": "暂\n无\n更\n多"
}
]
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="0"
width="64" height="64" >
<path d="M641.774 783.11L382.209 783.11c-26.078 0-47.1785-21.1016-47.1785-47.1785l23.5877-330.373c0-26.078 21.1016-47.1785 47.1795-47.1785L618.183 358.38c26.077 0 47.2205 21.1006 47.2205 47.1785l23.5877 330.373c0 26.077-21.1415 47.1784-47.2184 47.1785Zm-35.3631-471.951L417.61299999 311.159c-19.5678 0-35.4043-15.8357-35.40429999-35.4043L382.208 252.166c0-19.52679999 15.8357-35.40540001 35.4043-35.4054l188.798 0c19.52679999 0 35.3634 15.8796 35.3634 35.4054l0 23.5894c-0.00106066 19.5677-15.8377 35.4034-35.3644 35.4033Zm-11.8155-141.57700001L429.386 169.582c-13.0165 0-23.5882-10.5708-23.5882-23.5882l0-23.6322c0-13.0165 10.5718-23.58820001 23.5882-23.5882l165.208 0c13.0185 0 23.58820001 10.5718 23.5882 23.5882l0 23.63219999c0.00101823 13.0185-10.5697 23.5882-23.5872 23.58820001ZM571.00600001 51.596L453.018 51.596c-13.0594 0-23.6312-10.5728-23.6312-23.5903 0-13.05739999 10.5718-23.62919999 23.6312-23.6292l117.988 0c13.0165 0 23.58820001 10.5718 23.5882 23.6292 0.0010253 13.0165-10.5708 23.5903-23.58819999 23.5903Zm284.687 626.294L537.508 1008.759c-6.92267 7.21328-15.5041 10.8614-25.4967 10.8614-10.03150001 0-18.572-3.64811-25.5366-10.8614L168.29 677.89c-10.0744-10.4868-12.7299-25.0393-7.04851-38.4303 5.68037-13.349 18.0337-21.515 32.5851-21.51499999l636.372-1e-8c14.5504 0 26.8628 8.16701 32.5442 21.515 5.72027 13.39 3.02493001 27.9434-7.04957 38.4303Z"
fill="#333333"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,8 @@
{
"string": [
{
"name": "page_show",
"value": "page from package"
}
]
}

View File

@ -0,0 +1,8 @@
{
"string": [
{
"name": "page_show",
"value": "page from package"
}
]
}

View File

@ -0,0 +1,35 @@
import { hilog } from '@kit.PerformanceAnalysisKit';
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
export default function abilityTest() {
describe('ActsAbilityTest', () => {
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
beforeAll(() => {
// Presets an action, which is performed only once before all test cases of the test suite start.
// This API supports only one parameter: preset action function.
})
beforeEach(() => {
// Presets an action, which is performed before each unit test case starts.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: preset action function.
})
afterEach(() => {
// Presets a clear action, which is performed after each unit test case ends.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: clear action function.
})
afterAll(() => {
// Presets a clear action, which is performed after all test cases of the test suite end.
// This API supports only one parameter: clear action function.
})
it('assertContain', 0, () => {
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
hilog.info(0x0000, 'testTag', '%{public}s', 'it begin');
let a = 'abc';
let b = 'b';
// Defines a variety of assertion methods, which are used to declare expected boolean conditions.
expect(a).assertContain(b);
expect(a).assertEqual(a);
})
})
}

View File

@ -0,0 +1,5 @@
import abilityTest from './Ability.test';
export default function testsuite() {
abilityTest();
}

View File

@ -0,0 +1,13 @@
{
"module": {
"name": "refreshlib",
"type": "feature",
"deviceTypes": [
"default",
"tablet",
"2in1"
],
"deliveryWithInstall": true,
"installationFree": false
}
}

View File

@ -0,0 +1,5 @@
import localUnitTest from './LocalUnit.test';
export default function testsuite() {
localUnitTest();
}

View File

@ -0,0 +1,33 @@
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
export default function localUnitTest() {
describe('localUnitTest', () => {
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
beforeAll(() => {
// Presets an action, which is performed only once before all test cases of the test suite start.
// This API supports only one parameter: preset action function.
});
beforeEach(() => {
// Presets an action, which is performed before each unit test case starts.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: preset action function.
});
afterEach(() => {
// Presets a clear action, which is performed after each unit test case ends.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: clear action function.
});
afterAll(() => {
// Presets a clear action, which is performed after all test cases of the test suite end.
// This API supports only one parameter: clear action function.
});
it('assertContain', 0, () => {
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
let a = 'abc';
let b = 'b';
// Defines a variety of assertion methods, which are used to declare expected boolean conditions.
expect(a).assertContain(b);
expect(a).assertEqual(a);
});
});
}

118
build-profile.json5 Normal file
View File

@ -0,0 +1,118 @@
{
"app": {
"signingConfigs": [
{
"name": "default",
"type": "HarmonyOS",
"material": {
"storeFile": "D:/202076work/gdxzExport.p12",
"storePassword": "00000018C50E504AB8CC43CCB52E64D656B0131573F764452F4F1FED54B55C3ECC0010D2BD946612",
"keyAlias": "gdxz",
"keyPassword": "00000018EB40FA6E3F3E03EBCA9DCC01DFAB5A57692D48BC16DDF2182CD2CD08E1E583F524397C53",
"signAlg": "SHA256withECDSA",
"profile": "D:/202076work/profile测试Debug.p7b",
"certpath": "D:/202076work/鸿蒙专家端测试证书.cer"
// "profile": "D:/202076work/release鸿蒙Release.p7b",
// "certpath": "D:/202076work/鸿蒙专家端发布证书.cer"
}
}
],
"products": [
{
"name": "default",
"signingConfig": "default",
"compatibleSdkVersion": "5.0.2(14)",
"runtimeOS": "HarmonyOS",
"buildOption": {
"strictMode": {
"caseSensitiveCheck": true,
"useNormalizedOHMUrl": true
}
}
}
],
"buildModeSet": [
// {
// "name": "debug"
// },
{
"name": "release"
}
]
},
"modules": [
{
"name": "default",
"srcPath": "./products/expert",
"targets": [
{
"name": "default",
"applyToProducts": [
"default"
]
}
]
},
{
"name": "mypage",
"srcPath": "./features/mypage"
},
{
"name": "basic",
"srcPath": "./commons/basic"
},
{
"name": "Home",
"srcPath": "./features/Home"
},
{
"name": "register",
"srcPath": "./features/register"
},
{
"name": "polyv",
"srcPath": "./polyv"
},
{
"name": "scene_single_video",
"srcPath": "./scene_single_video"
},
{
"name": "patient",
"srcPath": "./features/patient",
},
{
"name": "refreshlib",
"srcPath": "./RefreshLib"
},
{
"name": "corekit",
"srcPath": "./corekit"
},
{
"name": "chatkit",
"srcPath": "./chatkit"
},
{
"name": "chatkit_ui",
"srcPath": "./chatkit_ui"
},
{
"name": "netease",
"srcPath": "./features/netease"
},
{
"name": "conversationkit_ui",
"srcPath": "./conversationkit_ui"
},
{
"name": "common",
"srcPath": "./common"
},
{
"name": "localconversationkit_ui",
"srcPath": "./localconversationkit_ui"
}
]
}

6
chatkit/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
/node_modules
/oh_modules
/.preview
/build
/.cxx
/.test

17
chatkit/BuildProfile.ets Normal file
View File

@ -0,0 +1,17 @@
/**
* Use these variables when you tailor your ArkTS code. They must be of the const type.
*/
export const HAR_VERSION = '10.1.0';
export const BUILD_MODE_NAME = 'release';
export const DEBUG = false;
export const TARGET_NAME = 'default';
/**
* BuildProfile Class is used only for compatibility purposes.
*/
export default class BuildProfile {
static readonly HAR_VERSION = HAR_VERSION;
static readonly BUILD_MODE_NAME = BUILD_MODE_NAME;
static readonly DEBUG = DEBUG;
static readonly TARGET_NAME = TARGET_NAME;
}

78
chatkit/Index.ets Normal file
View File

@ -0,0 +1,78 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
export { ChatKitClient, currentConversationChanged } from './src/main/ets/ChatKitClient'
export { ChatRepo } from './src/main/ets/repo/ChatRepo'
export { ContactRepo } from './src/main/ets/repo/ContactRepo'
export { TeamRepo } from './src/main/ets/repo/TeamRepo'
export { SettingRepo } from './src/main/ets/repo/SettingRepo'
export { StorageRepo } from './src/main/ets/repo/StorageRepo'
export { NEUserWithFriend } from './src/main/ets/model/NEUserWithFriend'
export { NEFriendUserCache } from './src/main/ets/NEFriendUserCache'
export { ConversationRepo } from './src/main/ets/repo/ConversationRepo'
export { LocalConversationRepo } from './src/main/ets/repo/LocalConversationRepo'
export { IsDiscussion } from './src/main/ets/utils/Utils'
export { ErrorUtils } from './src/main/ets/utils/ErrorUtils'
export { TeamMemberWithUser, TeamMemberResult } from './src/main/ets/model/TeamMemberWithUser'
export { PersonSelectParam } from './src/main/ets/model/PersonSelectParam'
export { ConversationSelectParam } from './src/main/ets/model/ConversationSelectParam'
export { ConversationSelectedParam } from './src/main/ets/model/ConversationSelectedParam'
export { CustomMessageUtils } from './src/main/ets/utils/CustomMessageUtils'
export { MergedMessageAttachment,
MergeMessageAbstract,
MessageUploadInfo } from './src/main/ets/model/CustomMessageAttachment'
export { mergedMessageNickKey,
mergedMessageAvatarKey,
multiForwardFileName,
mergedMessageMaxDepth,
mergedMessageLimitCount,
singleMessageLimitCount,
deleteMessagesLimitCount,
mergedMessageCustomType,
mergedMessageCellHeight,
conversationSelectLimitCount,
keyExtensionLastOptType,
keyExtensionAtAll,
typeExtensionAllowAll,
typeExtensionAllowManager,
collectionTypeOffset,
keyReplyMsgKey
} from './src/main/ets/constant/Constant'
export { TeamMemberCache } from './src/main/ets/cache/TeamMemberCache'
export { AitModel, accountAll, aitKey, getAitModelFromJson, YxAitMsg } from './src/main/ets/model/ait/AitModel'
export { AitMessage } from './src/main/ets/model/ait/AitMessage'
export { AitSegment } from './src/main/ets/model/ait/AitSegment'
export { AitAllPermission } from './src/main/ets/model/ait/AitAllPermission'
export { KitLogger as Logger } from './src/main/ets/logger/AppLogger'
export { IMKitConfigCenter } from './src/main/ets/IMKitConfigCenter'
export { TeamSettingParam } from './src/main/ets/model/TeamSettingParam'

View File

@ -0,0 +1,31 @@
{
"apiType": "stageMode",
"buildOption": {
},
"buildOptionSet": [
{
"name": "release",
"arkOptions": {
"obfuscation": {
"ruleOptions": {
"enable": false,
"files": [
"./obfuscation-rules.txt"
]
},
"consumerFiles": [
"./consumer-rules.txt"
]
}
},
},
],
"targets": [
{
"name": "default"
},
{
"name": "ohosTest"
}
]
}

View File

13
chatkit/hvigorfile.ts Normal file
View File

@ -0,0 +1,13 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
import { harTasks } from '@ohos/hvigor-ohos-plugin';
export default {
system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
plugins: [] /* Custom plugin to extend the functionality of Hvigor. */
}

View File

@ -0,0 +1,23 @@
# Define project specific obfuscation rules here.
# You can include the obfuscation configuration files in the current module's build-profile.json5.
#
# For more details, see
# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5
# Obfuscation options:
# -disable-obfuscation: disable all obfuscations
# -enable-property-obfuscation: obfuscate the property names
# -enable-toplevel-obfuscation: obfuscate the names in the global scope
# -compact: remove unnecessary blank spaces and all line feeds
# -remove-log: remove all console.* statements
# -print-namecache: print the name cache that contains the mapping from the old names to new names
# -apply-namecache: reuse the given cache file
# Keep options:
# -keep-property-name: specifies property names that you want to keep
# -keep-global-name: specifies names that you want to keep in the global scope
-enable-property-obfuscation
-enable-toplevel-obfuscation
-enable-filename-obfuscation
-enable-export-obfuscation

View File

@ -0,0 +1,132 @@
{
"meta": {
"stableOrder": true
},
"lockfileVersion": 3,
"ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
"specifiers": {
"@nimkit/corekit@../corekit": "@nimkit/corekit@../corekit",
"@nimsdk/base@../oh_modules/.ohpm/@nimsdk+conversation@10.9.10/oh_modules/@nimsdk/conversation/libs/base.har": "@nimsdk/base@../oh_modules/.ohpm/@nimsdk+nim@10.9.10/oh_modules/@nimsdk/nim/libs/base.har",
"@nimsdk/base@../oh_modules/.ohpm/@nimsdk+friend@10.9.10/oh_modules/@nimsdk/friend/libs/base.har": "@nimsdk/base@../oh_modules/.ohpm/@nimsdk+nim@10.9.10/oh_modules/@nimsdk/nim/libs/base.har",
"@nimsdk/base@../oh_modules/.ohpm/@nimsdk+message@10.9.10/oh_modules/@nimsdk/message/libs/base.har": "@nimsdk/base@../oh_modules/.ohpm/@nimsdk+nim@10.9.10/oh_modules/@nimsdk/nim/libs/base.har",
"@nimsdk/base@../oh_modules/.ohpm/@nimsdk+nim@10.9.10/oh_modules/@nimsdk/nim/libs/base.har": "@nimsdk/base@../oh_modules/.ohpm/@nimsdk+nim@10.9.10/oh_modules/@nimsdk/nim/libs/base.har",
"@nimsdk/base@../oh_modules/.ohpm/@nimsdk+team@10.9.10/oh_modules/@nimsdk/team/libs/base.har": "@nimsdk/base@../oh_modules/.ohpm/@nimsdk+nim@10.9.10/oh_modules/@nimsdk/nim/libs/base.har",
"@nimsdk/base@../oh_modules/.ohpm/@nimsdk+user@10.9.10/oh_modules/@nimsdk/user/libs/base.har": "@nimsdk/base@../oh_modules/.ohpm/@nimsdk+nim@10.9.10/oh_modules/@nimsdk/nim/libs/base.har",
"@nimsdk/base@10.9.10": "@nimsdk/base@../oh_modules/.ohpm/@nimsdk+nim@10.9.10/oh_modules/@nimsdk/nim/libs/base.har",
"@nimsdk/conversation@10.9.10": "@nimsdk/conversation@10.9.10",
"@nimsdk/friend@10.9.10": "@nimsdk/friend@10.9.10",
"@nimsdk/message@10.9.10": "@nimsdk/message@10.9.10",
"@nimsdk/nim@10.9.10": "@nimsdk/nim@10.9.10",
"@nimsdk/team@10.9.10": "@nimsdk/team@10.9.10",
"@nimsdk/user@10.9.10": "@nimsdk/user@10.9.10",
"@nimsdk/vendor@1.0.0": "@nimsdk/vendor@1.0.0",
"class-transformer@^0.5.1": "class-transformer@0.5.1",
"reflect-metadata@^0.1.13": "reflect-metadata@0.2.1"
},
"packages": {
"@nimkit/corekit@../corekit": {
"name": "@nimkit/corekit",
"version": "1.1.0",
"resolved": "../corekit",
"registryType": "local"
},
"@nimsdk/base@../oh_modules/.ohpm/@nimsdk+nim@10.9.10/oh_modules/@nimsdk/nim/libs/base.har": {
"name": "@nimsdk/base",
"version": "10.9.10",
"resolved": "../oh_modules/.ohpm/@nimsdk+nim@10.9.10/oh_modules/@nimsdk/nim/libs/base.har",
"registryType": "local",
"dependencies": {
"@nimsdk/vendor": "1.0.0"
}
},
"@nimsdk/conversation@10.9.10": {
"name": "@nimsdk/conversation",
"version": "10.9.10",
"integrity": "sha512-1HLvs19/GJAHeIOCN0OiKlowkg6dzZwvZK0Jqu7tAcYGcLl4+G/Z3pwsGHhv+E2Tzs8FHZCqbESMgSh+LNyt/g==",
"resolved": "https://repo.harmonyos.com/ohpm/@nimsdk/conversation/-/conversation-10.9.10.har",
"registryType": "ohpm",
"dependencies": {
"@nimsdk/base": "file:./libs/base.har",
"@nimsdk/vendor": "1.0.0"
}
},
"@nimsdk/friend@10.9.10": {
"name": "@nimsdk/friend",
"version": "10.9.10",
"integrity": "sha512-JVACpT8xqLLaN8D26YHmwfsS1dHFQvBnP3Jyk9El89P2trn/2ZFLvnQjxzyBDsqJRUtNFfIrN+TK7Idmud4ACQ==",
"resolved": "https://repo.harmonyos.com/ohpm/@nimsdk/friend/-/friend-10.9.10.har",
"registryType": "ohpm",
"dependencies": {
"@nimsdk/base": "file:./libs/base.har",
"@nimsdk/vendor": "1.0.0"
}
},
"@nimsdk/message@10.9.10": {
"name": "@nimsdk/message",
"version": "10.9.10",
"integrity": "sha512-f59rWiM4SjhhxNftRUt9vg7lIwkGycV/aL8J3omH+Te4SMbUGolwDGErDr7adtZ3tDUThtxxgU8n5tD28TBRtA==",
"resolved": "https://repo.harmonyos.com/ohpm/@nimsdk/message/-/message-10.9.10.har",
"registryType": "ohpm",
"dependencies": {
"@nimsdk/base": "file:./libs/base.har",
"@nimsdk/vendor": "1.0.0"
}
},
"@nimsdk/nim@10.9.10": {
"name": "@nimsdk/nim",
"version": "10.9.10",
"integrity": "sha512-WpT8vBTld92ExtH30Ffsm+xq6BW6/UFj8SuhJrcQaZY3AYf9sg+d+euqx/dFzjZin5cWRxd/yoodBiVcGfsM4w==",
"resolved": "https://repo.harmonyos.com/ohpm/@nimsdk/nim/-/nim-10.9.10.har",
"registryType": "ohpm",
"dependencies": {
"@nimsdk/base": "file:./libs/base.har",
"@nimsdk/vendor": "1.0.0"
}
},
"@nimsdk/team@10.9.10": {
"name": "@nimsdk/team",
"version": "10.9.10",
"integrity": "sha512-T4YSN395VXQr1TDX2B24DmGYuvUgUqE7wndbleR980wEyki9IfhC2VxxJ1yajhxVlVkfmuBjCB/eKWL0zLzu5A==",
"resolved": "https://repo.harmonyos.com/ohpm/@nimsdk/team/-/team-10.9.10.har",
"registryType": "ohpm",
"dependencies": {
"@nimsdk/base": "file:./libs/base.har",
"@nimsdk/vendor": "1.0.0"
}
},
"@nimsdk/user@10.9.10": {
"name": "@nimsdk/user",
"version": "10.9.10",
"integrity": "sha512-KyWVDDPbymj3qoC8Y0mB8umgvLg89Y2cB02tM35oSG8IW95C936v5ogip2Jk7qAfabXxI/XTyy5wQoW1z950JA==",
"resolved": "https://repo.harmonyos.com/ohpm/@nimsdk/user/-/user-10.9.10.har",
"registryType": "ohpm",
"dependencies": {
"@nimsdk/base": "file:./libs/base.har",
"@nimsdk/vendor": "1.0.0"
}
},
"@nimsdk/vendor@1.0.0": {
"name": "@nimsdk/vendor",
"version": "1.0.0",
"integrity": "sha512-q49MJM6PfucNs8jvLP56a2etyqRfZCeJaMa1BT9vO4sIgwt15bin+hpUWZ1qkflBs9YkDb2nMIX5O8zt556muw==",
"resolved": "https://repo.harmonyos.com/ohpm/@nimsdk/vendor/-/vendor-1.0.0.har",
"registryType": "ohpm"
},
"class-transformer@0.5.1": {
"name": "class-transformer",
"version": "0.5.1",
"integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==",
"resolved": "https://repo.harmonyos.com/ohpm/class-transformer/-/class-transformer-0.5.1.tgz",
"shasum": "24147d5dffd2a6cea930a3250a677addf96ab336",
"registryType": "ohpm"
},
"reflect-metadata@0.2.1": {
"name": "reflect-metadata",
"version": "0.2.1",
"integrity": "sha512-i5lLI6iw9AU3Uu4szRNPPEkomnkjRTaVt9hy/bn5g/oSzekBSMeLZblcjP74AW0vBabqERLLIrz+gR8QYR54Tw==",
"resolved": "https://repo.harmonyos.com/ohpm/reflect-metadata/-/reflect-metadata-0.2.1.tgz",
"shasum": "8d5513c0f5ef2b4b9c3865287f3c0940c1f67f74",
"registryType": "ohpm"
}
}
}

22
chatkit/oh-package.json5 Normal file
View File

@ -0,0 +1,22 @@
{
"name": "@nimkit/chatkit",
"version": "10.1.0",
"description": "Please describe the basic information.",
"main": "Index.ets",
"author": "",
"license": "Apache-2.0",
"dependencies": {
"@nimsdk/conversation": "10.9.10",
"@nimsdk/message": "10.9.10",
"@nimsdk/team": "10.9.10",
"@nimsdk/user": "10.9.10",
"@nimsdk/friend": "10.9.10",
"@nimsdk/nim": "10.9.10",
"@nimsdk/base": "10.9.10",
"@nimkit/corekit": "file:../corekit",
"class-transformer": "^0.5.1",
"reflect-metadata": "^0.1.13",
"@itcast/basic": "file:../commons/basic",
// 用于嵌套对象@Type反射
}
}

View File

@ -0,0 +1,250 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
import { CoreKitClient } from '@nimkit/corekit';
import {
IM_SDK_VERSION,
NIM,
NIMInterface,
V2NIMConnectStatus,
V2NIMDataSyncState,
V2NIMDataSyncType,
V2NIMEnableServiceType,
V2NIMError,
V2NIMKickedOfflineDetail,
V2NIMLoginStatus,
V2NIMMessage,
V2NIMMessageRevokeNotification,
V2NIMP2PMessageMuteMode
} from '@nimsdk/base';
import { ContactRepo } from '../../../Index';
import { KitLogger } from './logger/AppLogger';
import { LoggerKitImpl } from './logger/LoggerKitImpl';
import { ChatRepo } from './repo/ChatRepo';
import { saveLocalRevokeMessageFormOther } from './utils/MessageUtils';
import { LengthMetrics, router } from '@kit.ArkUI';
import { HMRouterMgr } from '@hadss/hmrouter';
import { ChangeUtil, NotificationManagementUtil, NotificationUtil } from '@itcast/basic';
import { BusinessError } from '@kit.BasicServicesKit';
import { NotificationBasicOptions } from '@itcast/basic/src/main/ets/pushnotification/NotificationOptions';
export const currentConversationChanged: string = 'CurrentConversationChanged'
export class ChatKitClient {
declare static nim: NIMInterface
static haveSyncedConversation: boolean = false
//是否主动离开群
static selfLeaveTeam = false
static hasInitListener = false
static currentConversationId: string = ''
static networkAvailable: boolean = true
static logger: KitLogger | undefined = undefined
static init(nimSdk: NIMInterface, appKey: string, disableLog?: boolean) {
ChatKitClient.nim = nimSdk
if (disableLog !== true) {
if (nimSdk instanceof NIM) {
let logger = new LoggerKitImpl(nimSdk.context.cacheDir)
ChatKitClient.logger = new KitLogger(logger)
}
}
ChatKitClient.haveSyncedConversation = false
ChatKitClient.initListener()
CoreKitClient.init({
appKey: appKey,
imVersion: IM_SDK_VERSION,
})
}
/**
* 长连接是否断开
* 可用于判断网络是否断开
*/
static connectBroken() {
if(ChatKitClient.nim!=null&&ChatKitClient.nim!=undefined&&ChatKitClient.nim.loginService!=null&&ChatKitClient.nim.loginService!=undefined)
{
return ChatKitClient.nim.loginService.getConnectStatus() !== V2NIMConnectStatus.V2NIM_CONNECT_STATUS_CONNECTED
}
else
return false
}
/**
* 设置当前会话id
* @param conversationId 当前会话id
*/
static setCurrentConversationId(conversationId: string) {
ChatKitClient.currentConversationId = conversationId
getContext().eventHub.emit(currentConversationChanged, conversationId)
}
/**
* 清除当前会话id
*/
static clearCurrentConversationId() {
ChatKitClient.currentConversationId = ''
getContext().eventHub.emit(currentConversationChanged, '')
}
/**
* 获取当前会话id
* @returns 当前会话id
*/
static getCurrentConversationId(): string {
return ChatKitClient.currentConversationId
}
/**
* 是否登录
* @returns
*/
static hasLogin(): boolean {
return ChatKitClient.nim != null && ChatKitClient.nim.loginService.getLoginUser() != null
}
static getLoginUserId(): string {
return ChatKitClient.nim.loginService.getLoginUser()
}
/**
* IM 主数据是否同步完成
* @returns
*/
static isMainDataSynced(): boolean {
let dataSync = ChatKitClient.nim.loginService.getDataSync()
if (dataSync != null) {
for (const item of dataSync) {
if (item.type === V2NIMDataSyncType.V2NIM_DATA_SYNC_TYPE_MAIN &&
item.state === V2NIMDataSyncState.V2NIM_DATA_SYNC_STATE_COMPLETED) {
return true
}
}
}
return false
}
static isLocalConversation(): boolean {
return ChatKitClient.nim.isServiceEnable(V2NIMEnableServiceType.LOCAL_CONVERSATION)
}
/**
* 等待登录后执行
*/
static runAfterLoggedIn(fn: Function) {
if (ChatKitClient.nim.loginService?.getLoginStatus() === V2NIMLoginStatus.V2NIM_LOGIN_STATUS_LOGINED) {
fn()
} else {
const onLoginStatusFunc = (status: V2NIMLoginStatus) => {
if (status === V2NIMLoginStatus.V2NIM_LOGIN_STATUS_LOGINED) {
fn()
ChatKitClient.nim.loginService.off('onLoginStatus', onLoginStatusFunc)
}
}
ChatKitClient.nim.loginService.on('onLoginStatus', onLoginStatusFunc)
}
}
/*
* 销毁 清理监听
*/
static onDestroy() {
ChatKitClient.hasInitListener = false
ChatKitClient.haveSyncedConversation = false
ChatKitClient.selfLeaveTeam = false
ChatKitClient.currentConversationId = ''
ChatRepo.offRevokeMessage(ChatKitClient.onRevokeFun)
ChatKitClient.nim.conversationService?.off('onSyncFinished', ChatKitClient.onSyncFinishedFun)
ChatKitClient.nim.loginService.off('onDataSync', ChatKitClient.dataSyncFun)
ChatKitClient.nim.loginService.off('onKickedOffline', (detail: V2NIMKickedOfflineDetail) => {
})
}
/**
* 初始化监听
*/
private static initListener() {
if (ChatKitClient.hasInitListener) {
return
}
console.info("netease ChatKitClient initListener ");
ChatKitClient.nim.loginService.on("onKickedOffline", async (detail: V2NIMKickedOfflineDetail) => {
// const detail = ChatKitClient.nim.loginService.getKickedOfflineDetail()
// console.log('Response onKickedOffline'+detail.clientType+' 22 '+detail.customClientType)
if(HMRouterMgr.getCurrentPathStack()!=null)
{
HMRouterMgr.removeAll()
}
let phone="ios";
switch(detail.clientType)
{
case 1:
phone="android";
break;
case 2:
phone="ios";
break;
case 16:
phone="web";
break;
default:
phone="其他设备";
break;
}
await ChatKitClient.nim.loginService.logout()
ChangeUtil.Logout(phone)
// router.replaceUrl({
// url: 'pages/LoginPage/LoginPage', // 目标url
// },router.RouterMode.Single)
// router.clear()
})
// 数据同步监听
ChatKitClient.nim.conversationService?.on('onSyncFinished', ChatKitClient.onSyncFinishedFun)
ChatKitClient.nim.loginService.on('onDataSync', ChatKitClient.dataSyncFun)
// 消息撤回监听,消息撤回后,会收到通知
ChatRepo.onRevokeMessage(ChatKitClient.onRevokeFun)
ChatKitClient.hasInitListener = true
let unreadCount=ChatKitClient.nim.localConversationService?ChatKitClient.nim.localConversationService.getTotalUnreadCount():-1
NotificationManagementUtil.setBadgeNumber(unreadCount)
// ChatKitClient.nim.messageService?.on("onReceiveMessages", (messages: V2NIMMessage[]) => {
// for (const message of messages) {
// let basicOptions: NotificationBasicOptions = {
// id: Number(message.messageServerId),
// title: String(message['fromNick']),
// text: String(message.text),
// }
// NotificationUtil.publishBasic(basicOptions).then((id) => {
//
// }).catch((err: BusinessError) => {
// console.error('推送展示失败:', err)
// });
// }
// })
}
private static onSyncFinishedFun = () => {
console.debug(`Performance Test onSyncFinishedFun`)
ChatKitClient.haveSyncedConversation = true
}
private static dataSyncFun = (type: V2NIMDataSyncType, state: V2NIMDataSyncState, error?: V2NIMError) => {
if (state === V2NIMDataSyncState.V2NIM_DATA_SYNC_STATE_COMPLETED) {
ContactRepo.getFriendList()
}
}
private static onRevokeFun = (messages: V2NIMMessageRevokeNotification[]) => {
messages.forEach((msg, index, messages) => {
if (msg.messageRefer.conversationId !== ChatKitClient.currentConversationId) {
saveLocalRevokeMessageFormOther(msg.messageRefer.conversationId, msg, false)
}
})
}
}

View File

@ -0,0 +1,13 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
@ObservedV2
export class IMKitConfigCenter {
// 是否使用本地会话列表
@Trace static enableLocalConversation: boolean = true;
}

View File

@ -0,0 +1,194 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
import { ChatKitClient } from './ChatKitClient';
import { NEUserWithFriend } from './model/NEUserWithFriend';
import { V2NIMFriend, V2NIMUser } from '@nimsdk/base';
import { ContactRepo } from './repo/ContactRepo';
interface updateFriendInfoParams {
user?: V2NIMUser;
friend?: V2NIMFriend;
friendUser?: NEUserWithFriend;
}
/// 好友信息缓存,只缓存好友
@ObservedV2
export class NEFriendUserCache {
@Trace public static mineUserCache?: NEUserWithFriend
// 黑名单账号集合
public blockAccountList: string[] = []
// 好友列表,包括黑名单中好友
public friendCache: Map<string, NEUserWithFriend> = new Map<string, NEUserWithFriend>()
private constructor() {
ContactRepo.addListener()
ContactRepo.getFriendList()
ContactRepo.getUserListFromCloud([ChatKitClient.getLoginUserId()])
ContactRepo.getBlockList()
}
public static getInstance() {
if (!AppStorage.get<NEFriendUserCache>(NEFriendUserCache.name)) {
let instance = new NEFriendUserCache()
AppStorage.setOrCreate(NEFriendUserCache.name, instance);
}
return AppStorage.get<NEFriendUserCache>(NEFriendUserCache.name) as NEFriendUserCache;
}
/// 是否是自己
public static isMe(accountId: string): Boolean {
return NEFriendUserCache.mineUserCache?.user?.accountId === accountId
}
/// 好友缓存是否为空
public isEmpty(): Boolean {
if (this.friendCache == undefined || this.friendCache.size === 0) {
return true
}
return false
}
/// 是否是好友
public isFriend(accountId: string): Boolean {
return this.friendCache.has(accountId) && !this.blockAccountList.includes(accountId)
}
/// 添加(更新)好友信息
public updateFriendInfo(params: updateFriendInfoParams) {
let accountId = ""
if (params.user) {
accountId = params.user.accountId
let friendUser = this.friendCache.get(accountId)
if (friendUser) {
friendUser.user = params.user
} else {
this.friendCache.set(accountId, new NEUserWithFriend({
user: params.user
}))
}
}
if (params.friend) {
accountId = params.friend.accountId
let friendUser = this.friendCache.get(accountId)
if (friendUser) {
friendUser.friend = params.friend
friendUser.user = params.friend.userProfile
} else {
this.friendCache.set(accountId, new NEUserWithFriend({
friend: params.friend
}))
}
}
if (params.friendUser && params.friendUser.user?.accountId) {
accountId = params.friendUser.user.accountId
this.friendCache.set(accountId, params.friendUser)
}
}
/// 使用好友列表初始化缓存
public loadFriendList(friends: V2NIMFriend[]) {
friends.forEach((friend: V2NIMFriend) => {
this.updateFriendInfo({
friend: friend
})
})
ContactRepo.listener.emit('loadFriendCache')
}
/// 获取缓存的好友信息
public getFriendById(accountId: string) {
return this.friendCache.get(accountId)
}
/**
* 通过用户ID列表获取用户信息
* @param accIds
* @returns
*/
public getFriendsByIds(accIds: string[]) {
let result: NEUserWithFriend[] = []
accIds.forEach((accId) => {
let user = this.friendCache.get(accId)
if (user) {
result.push(user)
}
})
return result
}
/// 获取缓存的好友信息列表,包含黑名单中的好友
public getFriendList() {
return Array.from(this.friendCache.values())
}
/// 获取缓存的好友信息列表,不包含黑名单中的好友
public getFriendListNotInBlocklist() {
let friends: Map<string, NEUserWithFriend> = new Map<string, NEUserWithFriend>()
this.friendCache.forEach((value, key) => {
if (!this.blockAccountList.includes(key)) {
friends.set(key, value)
}
})
return Array.from(friends.values())
}
/// 获取缓存的黑名单列表
public getBlocklist(): string[] {
return this.blockAccountList
}
/// 删除好友信息缓存
public removeFriendInfo(accountId: string) {
this.friendCache.delete(accountId)
ContactRepo.listener.emit('removeFriendInfo', accountId)
}
/// 删除所有好友信息缓存
public removeAllFriendInfo() {
this.friendCache.clear()
this.blockAccountList = []
ContactRepo.removeListener()
AppStorage.delete(NEFriendUserCache.name)
}
/// 初始化黑名单
public initBlockAccountSet(blockList: string[]) {
this.blockAccountList = blockList
}
/// 是否是黑名单账号
public isBlockAccount(accountId: string) {
return this.blockAccountList.includes(accountId)
}
/// 更新黑名单
public addBlockAccount(accountId: string) {
if (!this.blockAccountList.includes(accountId)) {
this.blockAccountList.push(accountId)
ContactRepo.listener.emit('addBlockAccount', accountId)
}
}
/// 移除黑名单账号
public removeBlockAccount(accountId: string) {
if (this.blockAccountList.includes(accountId)) {
for (let index = 0; index < this.blockAccountList.length; index++) {
if (this.blockAccountList[index] === accountId) {
this.blockAccountList.splice(index, 1)
ContactRepo.listener.emit('removeBlockAccount', accountId)
break
}
}
}
}
}

View File

@ -0,0 +1,379 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
import {
V2NIMError,
V2NIMFriend,
V2NIMQueryDirection,
V2NIMTeam,
V2NIMTeamMember,
V2NIMTeamMemberRole,
V2NIMTeamType,
V2NIMUser
} from '@nimsdk/base';
import { ChatKitClient } from '../ChatKitClient';
import { TeamMemberWithUser } from '../model/TeamMemberWithUser';
import { TeamRepo } from '../repo/TeamRepo';
@ObservedV2
export class TeamMemberCache {
static logTag = 'TeamMemberCache'
//全成员列表
@Trace membersMap: Map<string, TeamMemberWithUser> = new Map()
//自己的群身份
@Trace mineTeamMember: V2NIMTeamMember | undefined = undefined
//群组Id
teamId: string = ''
//群组
team?: V2NIMTeam = undefined
//下次拉去的token
nextToken = ''
//是否拉完了
isFinish = false
private static instance: TeamMemberCache
private constructor() {
}
public static getInstance(): TeamMemberCache {
if (!TeamMemberCache.instance) {
TeamMemberCache.instance = new TeamMemberCache()
}
return TeamMemberCache.instance
}
/**
* 初始化信息
* @param teamId
* @param team
*/
intTeamInfo(teamId: string, team?: V2NIMTeam) {
if (this.teamId !== teamId) {
this.membersMap.clear()
this.mineTeamMember = undefined
this.teamId = teamId
this.team = team
this.isFinish = false
this.initMemberChangeListener()
}
}
/**
* 是否为空
* @returns
*/
isEmpty(): boolean {
return this.membersMap.size <= 0
}
/**
* 是否需要拉取
* @returns
*/
needFetchMember(): boolean {
if (this.membersMap.size <= 0) {
return true
}
if (this.membersMap.size < 100 && this.isFinish === false) {
return true
}
return false
}
/**
* 好友信息变更
* @param friend
*/
onFriendInfoChanged(friend: V2NIMFriend) {
let member = this.membersMap.get(friend.accountId)
if (member) {
member.friendInfo = friend
this.membersMap.set(friend.accountId, member)
}
}
/**
* 群乘以信息变更
* @param members
*/
onTeamMemberInfoUpdated(members: V2NIMTeamMember[]) {
if (members[0].teamId === this.teamId) {
members.forEach((m) => {
let member = this.membersMap.get(m.accountId)
if (member) {
member.teamMember = m
this.membersMap.set(m.accountId, member)
if (m.accountId === ChatKitClient.getLoginUserId()) {
this.mineTeamMember = m
}
}
})
}
}
/**
* 离开群
* @param members
*/
onTeamMemberLeft(members: V2NIMTeamMember[]) {
if (members[0].teamId === this.teamId) {
let removeIds: string[] = members.map(member => member.accountId)
removeIds.forEach((e) => {
this.membersMap.delete(e)
})
}
}
/**
* 踢人
* @param accId
* @param members
*/
onTeamMemberKicked(accId: string, members: V2NIMTeamMember[]) {
if (members[0].teamId === this.teamId) {
let removeIds: string[] = members.map(member => member.accountId)
removeIds.forEach((e) => {
this.membersMap.delete(e)
})
}
}
/**
* 成员加入
* @param members
*/
onTeamMemberJoined(members: V2NIMTeamMember[]) {
if (members[0].teamId === this.teamId) {
let accIds = members.map(m => m.accountId)
TeamRepo.getTeamMembersByIds(this.teamId, V2NIMTeamType.V2NIM_TEAM_TYPE_NORMAL,
accIds).then((newMembers) => {
newMembers.forEach((m) => {
this.membersMap.set(m.getAccId(), m)
})
})
}
}
/**
* 获取所有成员的accId
* @returns
*/
getAllMemberAccounts(): string[] {
return Array.from(this.membersMap.keys())
}
/**
* 获取所有的成员列表
* @returns
*/
getAllMembers(): TeamMemberWithUser[] {
return Array.from(this.membersMap.values()).sort((a, b) => this.sortTeamMember(a, b))
}
// 群更新
onTeamInfoUpdated = (team: V2NIMTeam) => {
if (team.teamId === this.teamId) {
this.team = team
}
}
/**
* 刷新群信息
*/
onSyncFinished = () => {
if (this.teamId) {
TeamRepo.getTeamInfo(this.teamId, V2NIMTeamType.V2NIM_TEAM_TYPE_NORMAL)
.then((team) => {
this.team = team
})
TeamRepo.getTeamMembersByIds(
this.teamId, V2NIMTeamType.V2NIM_TEAM_TYPE_NORMAL, [ChatKitClient.getLoginUserId()]
)
.then((members: TeamMemberWithUser[]) => {
if (members.length > 0) {
this.mineTeamMember = members[0].teamMember
}
})
}
}
/**
* 用户信息变更
* @param users
*/
onUserProfileChanged(users: V2NIMUser[]) {
users.forEach((user) => {
let member = this.membersMap.get(user.accountId)
if (member) {
member.userInfo = user
this.membersMap.set(user.accountId, member)
}
})
}
/**
* 初始化成员信息变化回调
*/
initMemberChangeListener() {
//用户信息变更
ChatKitClient.nim.userService?.on('onUserProfileChanged', this.onUserProfileChanged.bind(this))
//好友信息变更
ChatKitClient.nim.friendService?.on('onFriendInfoChanged', this.onFriendInfoChanged.bind(this))
//群成员信息变更
ChatKitClient.nim.teamService?.on('onTeamMemberInfoUpdated', this.onTeamMemberInfoUpdated.bind(this))
ChatKitClient.nim.teamService?.on('onTeamMemberLeft', this.onTeamMemberLeft.bind(this))
ChatKitClient.nim.teamService?.on('onTeamMemberKicked', this.onTeamMemberKicked.bind(this))
ChatKitClient.nim.teamService?.on('onTeamMemberJoined', this.onTeamMemberJoined.bind(this))
//群信息变更
ChatKitClient.nim.teamService?.on('onTeamInfoUpdated', this.onTeamInfoUpdated.bind(this))
//断网
ChatKitClient.nim.teamService?.on('onSyncFinished', this.onSyncFinished.bind(this))
}
/**
* 初始化群信息
*/
async getTeam(): Promise<V2NIMTeam | undefined> {
if (!this.team) {
this.team = await TeamRepo.getTeamInfo(this.teamId, V2NIMTeamType.V2NIM_TEAM_TYPE_NORMAL)
}
return this.team
}
/**
* 拉取全量成员
*/
async loadAllTeamMember() {
if (this.team) {
while (!this.isFinish) {
await this.getMemberList()
}
}
}
async getMoreMemberList() {
if (!this.isFinish) {
await this.getMemberList()
}
}
async getMemberList() {
let result = await TeamRepo.getTeamMembers(this.teamId,
V2NIMTeamType.V2NIM_TEAM_TYPE_NORMAL, {
nextToken: this.nextToken,
direction: V2NIMQueryDirection.V2NIM_QUERY_DIRECTION_ASC
}).catch((e: V2NIMError) => {
console.debug(`${TeamMemberCache.logTag} getTeamMembers error code = ${e.code}`)
})
if (result) {
this.isFinish = result.finished
this.nextToken = result.nextToken
result.memberList.forEach((e) => {
this.membersMap.set(e.getAccId(), e)
})
let mineMember = result.memberList.find(member => member.getAccId() === ChatKitClient.getLoginUserId())
if (mineMember) {
this.mineTeamMember = mineMember.teamMember
}
}
}
//群成员排序
sortTeamMember(a: TeamMemberWithUser, b: TeamMemberWithUser): number {
if (a.teamMember.memberRole === b.teamMember.memberRole) {
return a.teamMember.joinTime - b.teamMember.joinTime
}
if (a.teamMember.memberRole === V2NIMTeamMemberRole.V2NIM_TEAM_MEMBER_ROLE_OWNER) {
return -1
}
if (b.teamMember.memberRole === V2NIMTeamMemberRole.V2NIM_TEAM_MEMBER_ROLE_OWNER) {
return 1
}
if (a.teamMember.memberRole === V2NIMTeamMemberRole.V2NIM_TEAM_MEMBER_ROLE_MANAGER) {
return -1
}
if (b.teamMember.memberRole === V2NIMTeamMemberRole.V2NIM_TEAM_MEMBER_ROLE_MANAGER) {
return 1
}
return a.teamMember.joinTime - b.teamMember.joinTime
}
/**
* 获取自己的成员信息
* @returns
*/
async getMineMember(): Promise<V2NIMTeamMember | undefined> {
if (!this.mineTeamMember) {
let mineMember = (await TeamRepo.getTeamMembersByIds(
this.teamId, V2NIMTeamType.V2NIM_TEAM_TYPE_NORMAL, [ChatKitClient.getLoginUserId()]
)
).find(m => m.getAccId() === ChatKitClient.getLoginUserId())
if (mineMember) {
this.membersMap.set(mineMember.getAccId(), mineMember)
this.mineTeamMember = mineMember.teamMember
}
}
return this.mineTeamMember
}
/**
* 根据accId 获取具体的成员
* @param account
* @returns
*/
async getMemberById(account: string): Promise<TeamMemberWithUser | undefined> {
let member = this.membersMap.get(account)
if (member) {
return member
} else {
let result = (await TeamRepo.getTeamMembersByIds(
this.teamId, V2NIMTeamType.V2NIM_TEAM_TYPE_NORMAL, [account]
))
if (result.length > 0) {
const m = result[0]
this.membersMap.set(m.getAccId(), m)
return m
}
}
return undefined
}
clear() {
this.membersMap.clear()
this.mineTeamMember = undefined
this.teamId = ''
this.team = undefined
this.isFinish = false
this.nextToken = ''
//用户信息变更
ChatKitClient.nim.userService?.off('onUserProfileChanged', this.onUserProfileChanged.bind(this))
//好友信息变更
ChatKitClient.nim.friendService?.off('onFriendInfoChanged', this.onFriendInfoChanged.bind(this))
//群成员信息变更
ChatKitClient.nim.teamService?.off('onTeamMemberInfoUpdated', this.onTeamMemberInfoUpdated.bind(this))
ChatKitClient.nim.teamService?.off('onTeamMemberLeft', this.onTeamMemberLeft.bind(this))
ChatKitClient.nim.teamService?.off('onTeamMemberKicked', this.onTeamMemberKicked.bind(this))
ChatKitClient.nim.teamService?.off('onTeamMemberJoined', this.onTeamMemberJoined.bind(this))
//群信息变更
ChatKitClient.nim.teamService?.off('onTeamInfoUpdated', this.onTeamInfoUpdated.bind(this))
ChatKitClient.nim.teamService?.off('onSyncFinished', this.onSyncFinished.bind(this))
}
/**
* 是否已经加载了所有成员
* @returns
*/
haveLoadAllMember(): boolean {
return this.isFinish
}
}

View File

@ -0,0 +1,47 @@
// 用于显示合并后的消息的发送方Nick的key
export const mergedMessageNickKey: string = 'mergedMessageNickKey';
// 用于显示合并后的消息的发送方avatar的key
export const mergedMessageAvatarKey: string = 'mergedMessageAvatarKey';
// 合并转发消息文件名前缀
export const multiForwardFileName = "multiForward"
/// 合并转发消息最大层数(深度): 3
export let mergedMessageMaxDepth = 3
/// 合并转发消息限制条数: 100
export let mergedMessageLimitCount = 100
/// 逐条转发消息限制条数: 10
export let singleMessageLimitCount = 10
/// 批量删除消息限制条数: 50
export let deleteMessagesLimitCount = 50
/// 合并转发自定义消息 type: 101
export let mergedMessageCustomType = 101
/// 合并转发自定义消息 cellHeight: 130
export let mergedMessageCellHeight: number = 130
/// 会话选择器最大选择数量: 9
export let conversationSelectLimitCount: number = 9
// 最新操作的类型
export let keyExtensionLastOptType = "lastOpt"
// 群自定义配置参数,用于是否群中所有人都可以@所有人配置的KEY值
export let keyExtensionAtAll = "yxAllowAt"
// 群自定义配置参数,用于是否群中管理员可以@所有人,允许所有群成员@所有人
export let typeExtensionAllowAll = "all"
// 群自定义配置参数,用于是否群中管理员可以@所有人,只允许管理员@所有人
export let typeExtensionAllowManager = "manager"
/// 收藏类型与消息类型映射(在类型基础上+1000)
export let collectionTypeOffset = 1000
/// 回复消息key, 用于不使用 thread 的消息回复方案
export let keyReplyMsgKey = "yxReplyMsg"

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
import { LogLevel } from '@nimsdk/base'
import { LoggerKitImpl } from './LoggerKitImpl'
export class KitLogger {
private core: LoggerKitImpl
public constructor(core: LoggerKitImpl) {
this.core = core
}
public async debug(label?: string, message?: string, ...args: string[]): Promise<void> {
try {
label = label ? label : 'Debug'
message = message ? message : 'logMessage'
const level = LogLevel.Debug
this.core.write(level, label, message, args)
} catch (e) {
this.core.write(LogLevel.Error, label ?? '', 'debug', ['write error'])
}
}
public async info(label?: string, message?: string, ...args: string[]): Promise<void> {
try {
label = label ? label : 'Info'
message = message ? message : 'logMessage'
const level = LogLevel.Info
this.core.write(level, label, message, args)
} catch (e) {
this.core.write(LogLevel.Error, label ?? '', 'debug', ['write error'])
}
}
public async warn(label?: string, message?: string, ...args: string[]): Promise<void> {
try {
label = label ? label : 'Warn'
message = message ? message : 'logMessage'
const level = LogLevel.Warn
this.core.write(level, label, message, args)
} catch (e) {
this.core.write(LogLevel.Error, label ?? '', 'debug', ['write error'])
}
}
public async error(label?: string, message?: string, ...args: string[]): Promise<void> {
try {
label = label ? label : 'Error'
message = message ? message : 'logMessage'
const level = LogLevel.Error
this.core.write(level, label, message, args)
} catch (e) {
this.core.write(LogLevel.Error, label ?? '', 'debug', ['write error'])
}
}
}

View File

@ -0,0 +1,248 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
import { taskpool } from '@kit.ArkTS';
import { LogLevel, NetWorkingInStance, NIMEStrAnyObj, V2NIMErrorImpl } from '@nimsdk/base';
import fs from '@ohos.file.fs';
@Concurrent
async function writeLogger(filePath: string, level: string, label: string, message: string, state: string,
...args: NIMEStrAnyObj[]) {
// CELLULAR = 0, WIFI = 1, ETHERNET = 3, VPN = 4
const netInfo = NetWorkingInStance.getInstance().getNetInfoSync()
const customInfo = `${state}_${netInfo.netType}_${netInfo.isConnected}`
// date formatter
const date = new Date()
const milliseconds: number = date.getMilliseconds()
const formattedMilliseconds: string = ("00" + milliseconds).slice(-3);
const dateStr = `${date.getMonth() +
1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}:${formattedMilliseconds}`
const prefix = `[${dateStr}]: ${level}: ${customInfo}: ${label}: ${message} `
// args formatter
let tempStr = args.map((item) => {
if (item instanceof V2NIMErrorImpl) {
let desc = `${item.name}\n code: ${item.code}\n message: "${item.message}"\n detail: ${item.detail ?
JSON.stringify(item.detail) : ''}`
if (item?.detail?.rawError) {
desc += `\n rawError: ${item.detail.rawError.message}`
}
return desc
} else if (item instanceof Error) {
return item && item.message ? item.message : item
} else if (typeof item === 'object') {
return JSON.stringify(item).replace(/^\[|\]$/g, "").replace(/^\[|\]$/g, "")
} else {
return item
}
}).join(' ')
tempStr = tempStr.replace(/^"|"$/g, '')
const logMessage = tempStr ? `${prefix + ': ' + tempStr}\n` : `${prefix}\n`
const file: fs.File = fs.openSync(filePath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE | fs.OpenMode.APPEND)
fs.writeSync(file.fd, logMessage)
fs.closeSync(file)
}
const TAG = '[LoggerServiceImpl]'
export class LoggerKitImpl {
// 本地日志,默认保存 15 天
private static readonly LoggerFileEffectivePeriod: number = 15
logDir: string = ''
// core: NIM
sequenceRunner: taskpool.SequenceRunner
logLevel: LogLevel
isOpenConsoleLog: boolean
private currentLogPath: string
public constructor(cacheDir: string, logLevel?: LogLevel, isOpenConsoleLog?: boolean) {
// core.loggerService = this
// this.core = core
this.logDir = cacheDir + '/nim_kit_log'
this.checkLoggerEffectivePeriod(this.logDir)
const formattedDate = this.formattedDate()
this.currentLogPath = this.logDir + `/nim_kit_${formattedDate}.txt`
// this.core.eventBus.on('LoggerServiceImpl/onUploadLogFiles', () => {
// this.uploadZipLogFile(false)
// })
this.sequenceRunner = new taskpool.SequenceRunner()
this.logLevel = logLevel ?? LogLevel.Debug
this.isOpenConsoleLog = isOpenConsoleLog ?? false
}
async write(level: LogLevel, label: string, message: string, ...args: NIMEStrAnyObj[]): Promise<void> {
let state = 'U'
// const isForeground = this.core.settingService?.v2IGetIsForeground()
// if (typeof isForeground !== 'undefined') {
// state = isForeground ? 'F' : 'B'
// }
if (this.isWriteLog(level)) {
const filePath = this.currentLogPath
const task = new taskpool.Task(writeLogger, filePath, level, label, message, state, args)
this.sequenceRunner.execute(task)
}
this.consoleLog(level, label, message, args)
}
isWriteLog(level: LogLevel): boolean {
switch (this.logLevel) {
case LogLevel.Debug:
return true;
case LogLevel.Info:
return level !== LogLevel.Debug;
case LogLevel.Warn:
return level !== LogLevel.Debug && level !== LogLevel.Info;
case LogLevel.Error:
return level === LogLevel.Error;
default:
return true;
}
}
consoleLog(level: LogLevel, label: string, message: string, args: NIMEStrAnyObj[]) {
// console log
message = message.slice(0, 2000)
if (this.isOpenConsoleLog) {
if (level === LogLevel.Debug) {
console.debug(label, message, args[0].length === 0 ? '' : JSON.stringify(args[0]))
} else if (level === LogLevel.Info) {
console.info(label, message, args[0].length === 0 ? '' : JSON.stringify(args[0]))
} else if (level === LogLevel.Error) {
console.error(label, message, args[0].length === 0 ? '' : JSON.stringify(args[0]))
} else if (level === LogLevel.Warn) {
console.warn(label, message, args[0].length === 0 ? '' : JSON.stringify(args[0]))
}
}
}
// async uploadSDKLogs(isActive: boolean): Promise<string> {
// try {
// this.core.logger.info(TAG, 'uploadSDKLogs', isActive)
// return await this.uploadZipLogFile(isActive)
// } catch (e) {
// this.core.logger.error(TAG, 'uploadSDKLogs', isActive, e)
// if (e instanceof V2NIMErrorImpl || e.name === 'V2NIMError') {
// throw e as V2NIMErrorImpl
// } else {
// throw new V2NIMErrorImpl({
// code: V2NIMErrorCode.V2NIM_ERROR_CODE_FILE_UPLOAD_FAILED,
// detail: {
// reason: 'upload log file: error: ' + `${JSON.stringify(e)}`
// }
// })
// }
// }
// }
public getLogDirectory(): string {
return this.logDir
}
public getLogFilePath(): string {
return this.currentLogPath
}
async checkLoggerEffectivePeriod(fileDir: string): Promise<void> {
try {
// 获取log list
if (!fs.accessSync(this.logDir)) {
fs.mkdirSync(this.logDir, true);
}
let fileList: Array<string> = await fs.listFile(fileDir, { recursion: false, listNum: 0 })
// 大于等于 15 时,淘汰最久的
if (fileList.length >= LoggerKitImpl.LoggerFileEffectivePeriod) {
fileList.sort((a, b) => a.localeCompare(b))
let oldestName: string = fileList[0]
let oldestFilePath = `${fileDir} + ${oldestName}`
await fs.unlink(oldestFilePath)
}
} catch (e) {
this.write(LogLevel.Error, 'checkLoggerEffectivePeriod', `fail:${JSON.stringify(e)}, filename ${fileDir}`)
}
}
// async uploadZipLogFile(isActive: boolean): Promise<string> {
// let outFile = this.getOutputZipFilePath()
// try {
// this.core.logger.info(TAG, 'uploadZipLogFile', isActive)
// // zip log file
// const fileList: Array<string> = await fs.listFile(this.logDir, { recursion: false, listNum: 0 })
// const zipList = fileList.map(item => this.logDir + '/' + item)
// await zlib.compressFiles(zipList, outFile, {
// level: zlib.CompressLevel.COMPRESS_LEVEL_DEFAULT_COMPRESSION,
// memLevel: zlib.MemLevel.MEM_LEVEL_MAX,
// strategy: zlib.CompressStrategy.COMPRESS_STRATEGY_HUFFMAN_ONLY
// })
//
// const result: UploadFileResult = await this.core.storageService.uploadFileTask({
// taskId: guid(),
// uploadParams: {
// filePath: outFile,
// sceneName: V2NIMStorageSceneConfig.DEFAULT_SYSTEM().sceneName,
// } as V2NIMUploadFileParams
// })
// // 上传成功删除本地zip 文件
// await this.uploadSendLog(result.url, isActive)
// await fs.unlink(outFile)
// this.core.logger.info(TAG, 'uploadZipLogFile succeed')
// return result.url
// } catch (e) {
// await fs.unlink(outFile)
// this.core.logger.error(TAG, 'uploadZipLogFile', isActive, e)
// if (e instanceof V2NIMErrorImpl || e.name === 'V2NIMError') {
// throw e as V2NIMErrorImpl
// } else {
// throw new V2NIMErrorImpl({
// code: V2NIMErrorCode.V2NIM_ERROR_CODE_FILE_UPLOAD_FAILED,
// detail: {
// reason: 'upload log file: error: ' + `${JSON.stringify(e)}`
// }
// })
// }
// }
// }
// private async uploadSendLog(url: string, isActive: boolean): Promise<void> {
// try {
// this.core.logger.info(TAG, 'uploadSendLog', url, isActive)
// const activeType = isActive ? 1 : 0
// const uploadLogUrlRequest: UploadLogUrlRequest = new UploadLogUrlRequest(
// url,
// new UploadLogUrlParams(activeType)
// )
// await this.core.sendCmd('uploadLogUrl', uploadLogUrlRequest)
// } catch (e) {
// this.core.logger.error(TAG, 'uploadSendLog', url, isActive, e)
// }
// }
private getOutputZipFilePath(): string {
const filepath = this.logDir + `/nim_log.zip`
if (fs.accessSync(filepath)) {
fs.unlinkSync(filepath)
}
return filepath
}
private formattedDate(): string {
const date = new Date()
const formattedDate = Intl.DateTimeFormat("en-US",
{ year: "numeric", month: "numeric", day: "numeric" }
).format(date)
.replace(/\//g, '_');
return formattedDate
}
}

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
/**
* Request params of protocol:
* uploadLogUrl
*/
export class UploadLogUrlRequest {
public url: string
public info: UploadLogUrlParams
public constructor(url: string, info: UploadLogUrlParams) {
this.url = url
this.info = info
}
}
/**
* Params of 'UploadLogUrlRequest'
*/
export class UploadLogUrlParams {
public sdklogUploadType: number
public constructor(sdklogUploadType: number) {
this.sdklogUploadType = sdklogUploadType
}
}

View File

@ -0,0 +1,14 @@
// 转发选择页面数据模型
@ObservedV2
export class ConversationSelectModel {
// 会话id
conversationId?: string
// 会话名称
name?: string
// 会话头像
avatar?: ResourceStr
// 是否已选中
@Trace isSelected: boolean = false
// 会话人数,用于展示群人数(单聊默认为 0群聊为群人数
memberCount: number = 0
}

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
import { ConversationSelectModel } from './ConversationSelectModel';
export class ConversationSelectParam {
filterList?: string[] = [];
selectLimit: number = 200;
onSureButtonClick?: (selectedList: ConversationSelectModel[]) => void = undefined
constructor(filterList: string[] = [],
selectLimit: number = 200,
onSureButtonClick?: (selectedList: ConversationSelectModel[]) => void
) {
this.filterList = filterList
this.selectLimit = selectLimit
this.onSureButtonClick = onSureButtonClick
}
}

View File

@ -0,0 +1,20 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
import { ConversationSelectModel } from './ConversationSelectModel';
export class ConversationSelectedParam {
selectedList?: ConversationSelectModel[] = [];
onRemoveButtonClick?: (item: ConversationSelectModel) => void = undefined // 移除按钮点击事件
constructor(selectedList?: ConversationSelectModel[],
onRemoveButtonClick?: (item: ConversationSelectModel) => void
) {
this.selectedList = selectedList
this.onRemoveButtonClick = onRemoveButtonClick
}
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
// 自定义消息附件
export interface CustomMessageAttachment {
// 自定义消息类型
type?: string;
}
// 合并消息
export interface MergedMessageAttachment extends CustomMessageAttachment {
// 会话id
sessionId?: string;
// 会话名称
sessionName?: string;
// 合并消息上传NOS后的url
url?: string;
// 合并消息文件的md5
md5?: string;
// 合并消息的深度
depth?: number;
// 合并消息的摘要,用于在消息列表展示,默认三条
abstracts?: MergeMessageAbstract[];
// 合并消息的id用于标识合并消息
// 通[NIMMessage.uuid]获取
messageId?: string;
}
// 合并转发消息的缩略
export interface MergeMessageAbstract {
// 消息展示的nick只取fromNick没有就accId
senderNick: string;
// 内容不是Text的显示缩略
content: string;
// 发送方的accId
userAccId: string;
}
// 消息上传后的信息
export interface MessageUploadInfo {
url: string;
md5: string;
}

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
import { V2NIMFriend, V2NIMUser } from '@nimsdk/base';
interface NEUserWithFriendParams {
friend?: V2NIMFriend;
user?: V2NIMUser;
}
@ObservedV2
export class NEUserWithFriend {
@Trace user?: V2NIMUser
@Trace friend?: V2NIMFriend
constructor(params: NEUserWithFriendParams) {
this.friend = params.friend
if (params.user) {
this.user = params.user
} else {
this.user = params.friend?.userProfile
}
}
/// 获取显示名称
/// (备注) > 昵称 > accid
/// - Parameter showAlias: 是否优先显示备注
public showName(showAlias: boolean = true): string {
if (showAlias && this.friend?.alias && this.friend.alias.length > 0) {
return this.friend?.alias
}
if (this.user?.name && this.user.name.length > 0) {
return this.user.name
}
return this.user?.accountId ?? ""
}
/// 获取简称 (尾部截取)
/// - Parameter showAlias: 是否优先显示备注
/// - Parameter count: 尾部截取长度
public shortName(showAlias: boolean = true, count: number = 2): string {
let name = this.showName(showAlias)
if (name) {
const start: number = (name.length - count) > 0 ? name.length - count : 0
const end: number = name.length
return name.substring(start, end)
}
return ""
}
/**
* 获取好友备注
* @returns
*/
public getAlias() {
return this.friend?.alias
}
}

View File

@ -0,0 +1,21 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
import { NEUserWithFriend } from './NEUserWithFriend';
export class PersonSelectParam {
filterList?: string[] = [];
selectLimit: number = 200;
onClickSureButton?: (selectedList: NEUserWithFriend[]) => void = undefined
constructor(onClickSureButton?: (selectedList: NEUserWithFriend[]) => void, filterList: string[] = [],
selectLimit: number = 200) {
this.filterList = filterList
this.selectLimit = selectLimit
this.onClickSureButton = onClickSureButton
}
}

View File

@ -0,0 +1,14 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
export interface RevokeMessageExtension {
revoke_message_local: boolean,
revoke_message_local_time: number,
revoke_message_local_edit: boolean,
revoke_message_local_content: string,
revoke_message_client_id: string,
}

View File

@ -0,0 +1,131 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
import { V2NIMFriend, V2NIMTeamMember, V2NIMTeamMemberRole, V2NIMUser } from '@nimsdk/base'
/**
* 群成员,好友,用户信息的集合
*/
export class TeamMemberWithUser {
//群成员信息
teamMember: V2NIMTeamMember
//好友信息
friendInfo?: V2NIMFriend
//用户信息
userInfo?: V2NIMUser
constructor(teamMember: V2NIMTeamMember,
friendInfo?: V2NIMFriend, userInfo?: V2NIMUser) {
this.teamMember = teamMember
this.friendInfo = friendInfo
this.userInfo = userInfo
}
/**
* 获取头像
* @returns
*/
getAvatar(): string | undefined {
return this.userInfo?.avatar
}
/**
* 获取头像nick
* @returns
*/
getAvatarName(): string {
let avatarName = ''
if (this.friendInfo && this.friendInfo.alias &&
this.friendInfo.alias.length > 0) {
avatarName = this.friendInfo.alias
} else if (this.userInfo && this.userInfo.name && this.userInfo.name.length > 0) {
avatarName = this.userInfo.name
} else {
avatarName = this.teamMember.accountId
}
return avatarName.length > 2 ? avatarName.substring(avatarName.length - 2, avatarName.length) : avatarName
}
/**
* 获取@的名称,不包含好友备注
*/
getAitName(): string {
//群昵称
if (this.teamMember.teamNick &&
this.teamMember.teamNick.length > 0) {
return this.teamMember.teamNick
}
//用户名
if (this.userInfo && this.userInfo.name && this.userInfo.name.length > 0) {
return this.userInfo.name
}
//最后accId
return this.teamMember.accountId
}
/**
* 是否是群主
* @returns
*/
isOwner(): boolean {
return this.teamMember.memberRole === V2NIMTeamMemberRole.V2NIM_TEAM_MEMBER_ROLE_OWNER
}
/**
* 是否是管理员
* @returns
*/
isManager(): boolean {
return this.teamMember.memberRole === V2NIMTeamMemberRole.V2NIM_TEAM_MEMBER_ROLE_MANAGER
}
/**
* 获取昵称
* @returns
*/
getNickname(): string {
//优先好友备注
if (this.friendInfo && this.friendInfo.alias &&
this.friendInfo.alias.length > 0) {
return this.friendInfo.alias
}
//其次群昵称
if (this.teamMember.teamNick &&
this.teamMember.teamNick.length > 0) {
return this.teamMember.teamNick
}
//再次用户名
if (this.userInfo && this.userInfo.name && this.userInfo.name.length > 0) {
return this.userInfo.name
}
//最后accId
return this.teamMember.accountId
}
/**
* 获取群成员Id
* @returns
*/
getAccId(): string {
return this.teamMember.accountId
}
}
/**
* 群成员请求返回结果
*/
export interface TeamMemberResult {
//是否结束
finished: boolean
//下次请求token
nextToken: string
//成员列表
memberList: TeamMemberWithUser[]
}

View File

@ -0,0 +1,4 @@
export interface TeamSettingParam {
teamId: string,
memberIds: string[]
}

View File

@ -0,0 +1,14 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
/**
* @所有人的权限
*/
export interface AitAllPermission {
yxAllowAt: string
lastOpt: string
}

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
import { AitSegment } from './AitSegment'
import { Type } from 'class-transformer'
import 'reflect-metadata'
export class AitMessage {
/**
* 账号
*/
accountId: string = ""
//@的文本
text: string
//@的信息存储,一个文案可能被@多次
@Type(() => AitSegment)
segments: AitSegment[] = []
constructor(text: string, accountId: string) {
this.text = text
this.accountId = accountId
}
addSegment(start: number, end: number, broken?: boolean) {
let segment: AitSegment = {
start: start,
end: end,
broken: broken ?? false
}
this.segments.push(...[segment])
}
removeSegment(start: number, end: number) {
let index = this.segments.findIndex(e => e.start === start && e.end === end)
if (index >= 0) {
this.segments.splice(index, 1)
}
}
valid(): boolean {
if (this.segments.length < 0) {
return false
}
for (let segment of this.segments) {
if (!segment.broken) {
return true
}
}
return false
}
segmentToMap(segment: AitSegment): Map<string, number | boolean> {
let map = new Map<string, number | boolean>()
map.set('start', segment.start)
map.set('end', segment.end)
map.set('broken', segment.broken ?? false)
return map
}
}

View File

@ -0,0 +1,271 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
import { AitMessage } from './AitMessage'
import { plainToClass, Transform, Type } from 'class-transformer'
import 'reflect-metadata'
import { AitSegment } from './AitSegment'
import { JSON } from '@kit.ArkTS'
//@所有人的Account
export const accountAll: string = "ait_all"
//@key
export const aitKey: string = 'yxAitMsg'
/**
* 云信@功能集合
*/
export interface YxAitMsg {
yxAitMsg?: Map<string, AitMessage>
}
export class AitModel {
/**
* key 为AccountID
*/
@Type(() => Map)
@Transform((param) => {
const map = new Map<string, AitMessage>();
if (param.value instanceof Map) {
let params = param.value as Map<string, AitMessage>
params.forEach((
value, key
) => {
map.set(key, value)
})
}
return map;
})
aitBlocks: Map<string, AitMessage> = new Map()
reset() {
this.aitBlocks.clear()
}
/**
* 删除一个@的用户
* @param deletedText 文本
* @param endIndex 删除的文本的光标所在位置
* @param length 删除的文本的长度
* @returns
*/
deleteAitUser(deletedText: string, endIndex: number, length: number): AitMessage | null {
//如果deletedText为空直接返回
if (deletedText.length <= 0) {
return null
}
let len: number = deletedText.length;
//如果aitBlocks 中有Value值和deletedText不匹配则返回
let removedBlack: AitMessage | null = null;
for (let aitMsg of this.aitBlocks.values()) {
for (let segment of aitMsg.segments) {
if (endIndex < segment.start) {
segment.start -= length;
segment.end -= length;
continue;
}
if (len < segment.end + 1 ||
deletedText.substring(segment.start, segment.end + 1) !== aitMsg.text) {
removedBlack = new AitMessage(aitMsg.text, "");
removedBlack.addSegment(segment.start, segment.end);
}
}
}
if (removedBlack !== null) {
this.removeSegment(removedBlack, length);
}
return removedBlack;
}
/**
* 删除文本
* @param endIndex 删除后光标的位置
* @param length 删除的长度
*/
deleteText(endIndex: number, length: number) {
let removedBlack: AitMessage | null = null;
for (let aitMsg of this.aitBlocks.values()) {
let deletedSegment: AitSegment | null = null
for (let segment of aitMsg.segments) {
if (endIndex < segment.start) {
segment.start -= length;
segment.end -= length;
continue;
} else if (endIndex < segment.end) {
deletedSegment = segment
}
}
if (deletedSegment !== null) {
aitMsg.removeSegment(deletedSegment.start, deletedSegment.end)
}
if (aitMsg.segments.length <= 0) {
removedBlack = aitMsg
}
}
if (removedBlack !== null) {
this.removeSegment(removedBlack, length)
}
}
/**
* 删除aitMsg中的segment,如果aitMsg中的segment为空则删除aitMsg
* 同时处理其他aitMsg中的segment的位置
* @param removedBlack
* @param deletedLen 删除的文本的长度,如果为正数则其他后面的前移,如果为负数,则其他不变
*/
removeSegment(removedBlack: AitMessage, deletedLen: number): void {
// 删除aitMsg中的segment,如果aitMsg中的segment为空则删除aitMsg
let aitMsg: AitMessage | undefined = undefined
let removeKey: string = ''
this.aitBlocks.forEach((value, key) => {
if (value.text === removedBlack.text) {
aitMsg = value
removeKey = key
}
})
if (aitMsg) {
//artTs 语法要求,重新拷贝
const aitMessage: AitMessage = aitMsg
const start: number = removedBlack.segments[0].start;
const end: number = removedBlack.segments[0].end;
// 该段文字的长度,加上删除的长度,因为其在前面已经移了deletedLen位
const length = end - start + 1 - deletedLen;
aitMessage.removeSegment(start, end);
if (aitMessage.segments.length === 0) {
this.aitBlocks.delete(removeKey);
}
if (deletedLen > 0) {
for (const aitMsg of this.aitBlocks.values()) {
for (const segment of aitMsg.segments) {
if (end <= segment.start) {
segment.start -= length;
segment.end -= length;
continue;
}
}
}
}
}
}
/**
* 用户是否被@
* @param accId
* @returns
*/
isUserBeenAit(accId: string | null): boolean {
if (accId === null) {
return false;
}
for (let key of this.aitBlocks.keys()) {
if (key === accountAll) {
return true;
}
if (key === accId) {
return true;
}
}
return false;
}
/**
* 拷贝
* @param aitModel
*/
fork(aitModel: AitModel) {
this.aitBlocks.clear()
this.aitBlocks = aitModel.aitBlocks
}
/**
* 根据插入后的Text 文案, segment 移位或者删除。
* @param changedText
* @param endIndex
* @param length
*/
insertText(endIndex: number, length: number): void {
let removedBlack: AitMessage | null = null;
const start: number = endIndex - length;
for (let aitMsg of this.aitBlocks.values()) {
for (let segment of aitMsg.segments) {
if (start <= segment.start) {
segment.start += length;
segment.end += length;
continue;
}
if (endIndex > segment.start && endIndex <= segment.end) {
removedBlack = new AitMessage(aitMsg.text, "");
removedBlack.addSegment(segment.start, segment.end);
continue;
}
}
}
if (removedBlack !== null) {
this.removeSegment(removedBlack, -1);
}
}
/**
* 添加@成员
* @param account
* @param name
* @param start
*/
addAitMember(account: string, name: string, start: number): void {
for (let aitMsg of this.aitBlocks.values()) {
for (let segment of aitMsg.segments) {
if (start <= segment.start) {
segment.start += name.length;
segment.end += name.length;
continue;
}
}
}
let aitBlock: AitMessage | undefined = this.aitBlocks.get(account);
if (aitBlock === undefined) {
aitBlock = new AitMessage(name, account);
this.aitBlocks.set(account, aitBlock);
}
const end: number = start + name.length - 1;
aitBlock.addSegment(start, end);
}
}
/**
* Extension 解析获得AitModel
* @param extension
* @returns
*/
export function getAitModelFromJson(extension?: string): AitModel | undefined {
if (extension) {
try {
const obj: Record<string, Object> = JSON.parse(extension) as Record<string, Object>
for (let key of Object.entries(obj)) {
if (key[0] === aitKey) {
let trans: AitModelTrans = {
aitBlocks: key[1]
}
let aitModel: AitModel = plainToClass(AitModel, trans, { enableImplicitConversion: true })
if (aitModel.aitBlocks.size > 0) {
return aitModel
}
}
}
}catch (e) {
console.error('parse json error', JSON.stringify(e), JSON.stringify(extension))
return undefined
}
}
return undefined
}
interface AitModelTrans {
aitBlocks: object
}

View File

@ -0,0 +1,18 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
/**
* 记录@消息的最小单位
*/
export class AitSegment {
//@消息的起点
start: number = 0;
//@消息的终点位置
end: number = 0;
//是否已经被破坏
broken: boolean = false
}

View File

@ -0,0 +1,514 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
import {
V2NIMAddCollectionParams,
V2NIMCollection,
V2NIMCollectionOption,
V2NIMMessage,
V2NIMMessageDeletedNotification,
V2NIMMessageListOption,
V2NIMMessagePin,
V2NIMMessagePinNotification,
V2NIMMessageRefer,
V2NIMMessageRevokeNotification,
V2NIMMessageRevokeParams,
V2NIMMessageSearchParams,
V2NIMP2PMessageReadReceipt,
V2NIMSendMessageParams,
V2NIMSendMessageResult,
V2NIMTeamMessageReadReceipt,
V2NIMTeamMessageReadReceiptDetail
} from '@nimsdk/base';
import { ChatKitClient } from '../ChatKitClient';
export class ChatRepo {
/**
* 发送消息
* @param sendFn 消息接受处理方法
*/
static onSendMessage(sendFn: (message: V2NIMMessage) => void) {
ChatKitClient.nim.messageService?.on('onSendMessage', sendFn);
}
/**
* 发送消息
* @param receiveFn 消息接受处理方法
*/
static offSendMessage(receiveFn: (message: V2NIMMessage) => void) {
ChatKitClient.nim.messageService?.off('onSendMessage', receiveFn);
}
/**
* 接受消息
* @param receiveFn 消息接受处理方法
*/
static onReceiverMessage(receiveFn: (messageList: V2NIMMessage[]) => void) {
ChatKitClient.nim.messageService?.on('onReceiveMessages', receiveFn);
}
/**
* 接受消息
* @param receiveFn 消息接受处理方法
*/
static offReceiverMessage(receiveFn: (messageList: V2NIMMessage[]) => void) {
ChatKitClient.nim.messageService?.off('onReceiveMessages', receiveFn);
}
/**
* 删除消息
* @param receiveFn 消息接受处理方法
*/
static onDeleteMessage(deleteFn: (messageList: V2NIMMessageDeletedNotification[]) => void) {
ChatKitClient.nim.messageService?.on('onMessageDeletedNotifications', deleteFn);
}
/**
* 删除消息
* @param receiveFn 消息接受处理方法
*/
static offDeleteMessage(deleteFn: (messageList: V2NIMMessageDeletedNotification[]) => void) {
ChatKitClient.nim.messageService?.off('onMessageDeletedNotifications', deleteFn);
}
/**
* 注册撤回消息监听
* @param receiveFn 消息接受处理方法
*/
static onRevokeMessage(revokeFn: (messageList: V2NIMMessageRevokeNotification[]) => void) {
ChatKitClient.nim.messageService?.on('onMessageRevokeNotifications', revokeFn);
}
/**
* 取消注册撤回消息监听
* @param receiveFn 消息接受处理方法
*/
static offRevokeMessage(revokeFn: (messageList: V2NIMMessageRevokeNotification[]) => void) {
ChatKitClient.nim.messageService?.off('onMessageRevokeNotifications', revokeFn);
}
/**
* 注册单聊消息已读回执监听
* @param receiptsFn 单聊消息已读回执处理方法
*/
static onP2PMessageReadReceipts(receiptsFn: (messageList: V2NIMP2PMessageReadReceipt[]) => void) {
ChatKitClient.nim.messageService?.on('onReceiveP2PMessageReadReceipts', receiptsFn);
}
/**
* 取消注册单聊消息已读回执监听
* @param receiptsFn 单聊消息已读回执处理方法
*/
static offP2PMessageReadReceipts(receiptsFn: (messageList: V2NIMP2PMessageReadReceipt[]) => void) {
ChatKitClient.nim.messageService?.off('onReceiveP2PMessageReadReceipts', receiptsFn);
}
/**
* 注册群消息已读回执监听
* @param receiptsFn 群消息已读回执处理方法
*/
static onReceiveTeamMessageReadReceipts(receiptsFn: (messageList: V2NIMTeamMessageReadReceipt[]) => void) {
ChatKitClient.nim.messageService?.on('onReceiveTeamMessageReadReceipts', receiptsFn);
}
/**
* 取消注册群消息已读回执监听
* @param receiptsFn 群消息已读回执处理方法
*/
static offReceiveTeamMessageReadReceipts(receiptsFn: (messageList: V2NIMTeamMessageReadReceipt[]) => void) {
ChatKitClient.nim.messageService?.off('onReceiveTeamMessageReadReceipts', receiptsFn);
}
/**
* 注册PIN消息监听
* @param pinFn PIN消息监听处理方法
*/
static onMessagePinNotification(pinFn: (notification: V2NIMMessagePinNotification) => void) {
ChatKitClient.nim.messageService?.on('onMessagePinNotification', pinFn);
}
/**
* 取消注册PIN消息监听
* @param pinFn PIN消息监听处理方法
*/
static offMessagePinNotification(pinFn: (notification: V2NIMMessagePinNotification) => void) {
ChatKitClient.nim.messageService?.off('onMessagePinNotification', pinFn);
}
/**
* 注册更新消息监听
* @param modifyFn PIN消息监听处理方法
*/
static onReceiveMessagesModified(modifyFn: (messageList: V2NIMMessage[]) => void) {
ChatKitClient.nim.messageService?.on('onReceiveMessagesModified', modifyFn);
}
/**
* 取消更新消息监听
* @param modifyFn PIN消息监听处理方法
*/
static offReceiveMessagesModified(modifyFn: (messageList: V2NIMMessage[]) => void) {
ChatKitClient.nim.messageService?.off('onReceiveMessagesModified', modifyFn);
}
/**
* 撤回消息
* @param receiveFn 消息接受处理方法
*/
static removeAllListeners(revokeFn: (messageList: V2NIMMessageRevokeNotification[]) => void) {
ChatKitClient.nim.messageService?.removeAllListeners('onMessageRevokeNotifications');
}
/**
* 查询消息
* @param option
* @returns
*/
static async getMessageList(option: V2NIMMessageListOption): Promise<V2NIMMessage[]> {
let messageList = await ChatKitClient.nim.messageService!!.getMessageList(option)
return messageList;
}
/**
* 根据 messageRefers 批量查询消息
* @param option
* @returns
*/
static async getMessageListByRefers(messageRefers: V2NIMMessageRefer[]): Promise<V2NIMMessage[]> {
let messageList = await ChatKitClient.nim.messageService!!.getMessageListByRefers(messageRefers)
return messageList ?? [];
}
/**
* 检索云端的消息
*
* @param params 检索参数
*/
static async searchCloudMessages(params: V2NIMMessageSearchParams): Promise<V2NIMMessage[]> {
let messageList = await ChatKitClient.nim.messageService!!.searchCloudMessages(params)
return messageList ?? [];
}
/**
* 发送消息
*
* @param message 消息体, 由 V2NIMMessageCreator 的对应方法创建
* @param conversationId 会话 id
* @param params 发送消息相关配置参数
* @param progress 发送消息进度回调. 作用于需要上传的文件,图片,音视频消息
*/
static async sendMessage(
message: V2NIMMessage,
conversationId: string,
params?: V2NIMSendMessageParams,
progress?: (percentage: number) => void
): Promise<V2NIMSendMessageResult | undefined> {
return ChatKitClient.nim.messageService?.sendMessage(message, conversationId, params, progress);
}
/**
* 回复消息
*
* @param message 需要发送的消息体, 由 V2NIMMessageCreator 的对应方法创建
* @param replyMessage 被回复的消息
* @param params 发送消息相关配置参数
* @param progress 发送消息进度回调. 作用于需要上传的文件,图片,音视频消息
*/
static async replyMessage(message: V2NIMMessage, replyMessage: V2NIMMessage, params?: V2NIMSendMessageParams,
progress?: (percentage: number) => void): Promise<V2NIMSendMessageResult> {
const res = await ChatKitClient.nim.messageService?.replyMessage(message, replyMessage, params, progress);
return res!;
}
/**
* 插入一条本地消息, 该消息不会发送。该消息不会多端同步,只是本端显示
* @param message 需要插入的消息体
* @param conversationId 会话 ID
* @param senderId 消息发送者账号
* @param createTime 指定插入消息时间
* @returns 插入成功的 message
*/
static async insertMessageToLocal(message: V2NIMMessage, conversationId: string, senderId?: string,
createTime?: number): Promise<V2NIMMessage> {
const res = ChatKitClient.nim.messageService?.insertMessageToLocal(message, conversationId, senderId, createTime);
return res!;
}
/**
* 撤回消息
*
* @param message 需要撤回的消息
* @param params 撤回消息相关参数
*/
static async revokeMessage(message: V2NIMMessage, params?: V2NIMMessageRevokeParams): Promise<void> {
const res = await ChatKitClient.nim.messageService?.revokeMessage(message, params);
return res!;
}
/**
* 删除单条消息
*
* 注: 操作成功后, SDK 会抛出事件 {@link V2NIMMessageListener.onMessageDeletedNotifications | V2NIMMessageListener.onMessageDeletedNotifications}
*
* @param message 需要删除的消息
* @param serverExtension 扩展字段
*/
static async deleteMessage(message: V2NIMMessage, serverExtension?: string,
onlyDeleteLocal?: boolean): Promise<void> {
const res = await ChatKitClient.nim.messageService?.deleteMessage(message, serverExtension, onlyDeleteLocal);
return res!;
}
/**
* 批量删除消息
*
* 注: 操作成功后, SDK 会抛出事件 {@link V2NIMMessageListener.onMessageDeletedNotifications | V2NIMMessageListener.onMessageDeletedNotifications} <br/>
* - 所删除的消息必须是同一会话的消息 <br/>
* - 限制一次最多删除 50 条消息
*
* @param messages 需要删除的消息
* @param serverExtension 扩展字段
*/
static async deleteMessages(messages: V2NIMMessage[], serverExtension?: string,
onlyDeleteLocal?: boolean): Promise<void> {
const res = await ChatKitClient.nim.messageService?.deleteMessages(messages, serverExtension, onlyDeleteLocal);
return res!;
}
/**
* pin 一条消息
*
* @param message 需要被 pin 的消息体
* @param serverExtension 扩展字段
*
* 注: 操作成功后, SDK 会抛出事件 {@link V2NIMMessageListener.onMessagePinNotification | V2NIMMessageListener.onMessagePinNotification}
*/
static async pinMessage(message: V2NIMMessage, serverExtension?: string): Promise<void> {
const res = await ChatKitClient.nim.messageService?.pinMessage(message, serverExtension);
return res!;
}
/**
* 取消一条Pin消息
*
* @param messageRefer 需要被取消 pin 的消息摘要
* @param serverExtension 扩展字段
*/
static async unpinMessage(messageRefer: V2NIMMessageRefer, serverExtension?: string): Promise<void> {
const res = await ChatKitClient.nim.messageService?.unpinMessage(messageRefer, serverExtension);
return res!;
}
/**
* 获取 pin 消息列表
*
* @param conversationId 会话 ID
*/
static async getPinnedMessageList(conversationId: string): Promise<V2NIMMessagePin[]> {
const res = ChatKitClient.nim.messageService?.getPinnedMessageList(conversationId);
return res!;
}
/**
* 添加一个收藏
*
* @param params 添加收藏的相关参数
*/
static async addCollection(params: V2NIMAddCollectionParams): Promise<V2NIMCollection> {
const res = await ChatKitClient.nim.messageService?.addCollection(params)
return res!;
}
/**
* 移除相关收藏
*
* @param collections 需要移除的相关收藏
*/
static async removeCollections(collections: V2NIMCollection[]): Promise<number> {
const res = await ChatKitClient.nim.messageService?.removeCollections(collections)
return res!;
}
/**
* 按条件分页获取收藏信息
*
* @param option 查询参数
*/
static async getCollectionListByOption(option: V2NIMCollectionOption): Promise<V2NIMCollection[]> {
const res = ChatKitClient.nim.messageService?.getCollectionListByOption(option)
return res!;
}
/**
* 构造文本消息
*
* @param text 文本内容. 不允许为空字符串
*
* @example
* ```
* const message = nim.V2NIMMessageCreator.createTextMessage('hello world')
* ```
*/
static createTextMessage(text: string): V2NIMMessage {
return ChatKitClient.nim.messageCreator.createTextMessage(text);
}
/**
* 构造图片消息
*
* @param imagePath 图片文件路径
* @param name 文件显示名称
* @param sceneName 场景名
* @param width 图片宽度.
* @param height 图片高度.
*/
static async createImageMessage(imagePath: string, name?: string, sceneName?: string, width?: number,
height?: number): Promise<V2NIMMessage> {
return ChatKitClient.nim.messageCreator.createImageMessage(imagePath, name, sceneName, width, height);
}
/**
* 构造语音消息
*
* @param audioPath 语音文件地址
* @param name 文件显示名称
* @param sceneName 场景名
* @param duration 音频时长
*/
static async createAudioMessage(audioPath: string, name?: string, sceneName?: string,
duration?: number): Promise<V2NIMMessage> {
return ChatKitClient.nim.messageCreator.createAudioMessage(audioPath, name, sceneName, duration);
}
/**
* 构造视频消息
*
* @param videoPath 视频文件地址
* @param name 文件显示名称
* @param sceneName 场景名
* @param duration 视频时长
* @param width 视频宽度
* @param height 视频高度
*/
static async createVideoMessage(videoPath: string, name?: string, sceneName?: string, duration?: number,
width?: number, height?: number): Promise<V2NIMMessage> {
return ChatKitClient.nim.messageCreator.createVideoMessage(videoPath, name, sceneName, duration, width, height);
}
/**
* 构造文件消息
*
* @param filePath 文件地址
* @param name 文件显示名称
* @param sceneName 场景名
*/
static async createFileMessage(filePath: string, name?: string, sceneName?: string): Promise<V2NIMMessage> {
return ChatKitClient.nim.messageCreator.createFileMessage(filePath, name, sceneName);
}
/**
* 构造地理位置消息
*
* @param latitude 纬度
* @param longitude 经度
* @param address 详细位置信息
*/
static createLocationMessage(latitude: number, longitude: number, address: string): V2NIMMessage {
return ChatKitClient.nim.messageCreator.createLocationMessage(latitude, longitude, address);
}
/**
* 构造自定义消息消息
*
* @param text 文本
* @param rawAttachment 自定义的附件内容
*/
static createCustomMessage(text: string, rawAttachment: string): V2NIMMessage {
return ChatKitClient.nim.messageCreator.createCustomMessage(text, rawAttachment);
}
/**
* 构造转发消息,消息内容与原消息一样
*
* https://overmind.hz.netease.com/206/requirement/issues/OMIM-50521
*
* 其它端怕抛 error 导致应用崩溃,所以这里不抛 error而是返回 null
*
* @param message 需要转发的消息体
*/
static createForwardMessage(message: V2NIMMessage): V2NIMMessage | null {
return ChatKitClient.nim.messageCreator.createForwardMessage(message);
}
/**
* 构造提示消息
*
* @param text 提示文本
*/
static createTipsMessage(text: string): V2NIMMessage {
return ChatKitClient.nim.messageCreator.createTipsMessage(text);
}
/**
* 插入一条本地消息, 该消息不会发送。该消息不会多端同步,只是本端显示
* @param message 需要插入的消息体
* @param conversationId 会话 ID
*/
static saveLocalMessage(msg: V2NIMMessage, conversationId: string, senderId: string, createTime: number) {
ChatKitClient.nim.messageService?.insertMessageToLocal(msg, conversationId, senderId, createTime)
}
/**
* 查询点对点消息已读回执
* @param conversationId 会话 id
*/
static async getP2PMessageReceipt(conversationId: string): Promise<V2NIMP2PMessageReadReceipt | undefined> {
return await ChatKitClient.nim.messageService?.getP2PMessageReceipt(conversationId)
}
/**
* 获取群消息已读回执状态详情
*
* @param msg 需要查询已读回执状态的消息
* @param memberAccountIds 查找指定的账号列表已读未读
* 为空表示查询全部
* 同时作用于已读未读账号列表和人数
*/
static getTeamMessageReceiptDetail(msg: V2NIMMessage,
memberAccountIds?: string[]): Promise<V2NIMTeamMessageReadReceiptDetail> {
return ChatKitClient.nim.messageService!!.getTeamMessageReceiptDetail(
msg, memberAccountIds
)
}
/**
* 发送消息已读回执
*
* @param message 点对点会话收到的对方最后一条消息
*/
static async sendP2PMessageReceipt(message: V2NIMMessage): Promise<void> {
return ChatKitClient.nim.messageService?.sendP2PMessageReceipt(message)
}
/**
* 获取群消息已读回执状态
*
* @param messages 获取群消息已读回执状态. 限制一批最多 50 个且所有消息必须属于同一个会话
*/
static async getTeamMessageReceipts(messages: V2NIMMessage[]): Promise<V2NIMTeamMessageReadReceipt[] | undefined> {
return ChatKitClient.nim.messageService?.getTeamMessageReceipts(messages)
}
/**
* 发送群消息已读回执
*
* @param messages 需要发送已读回执的消息列表. 限制一批最多 50 个且所有消息必须属于同一个会话
*/
static async sendTeamMessageReceipt(messages: V2NIMMessage[]): Promise<void> {
return ChatKitClient.nim.messageService?.sendTeamMessageReceipts(messages)
}
}

View File

@ -0,0 +1,338 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
import {
V2NIMCheckFriendResult,
V2NIMFriend,
V2NIMFriendAddApplication,
V2NIMFriendAddApplicationQueryOption,
V2NIMFriendAddApplicationResult,
V2NIMFriendAddParams,
V2NIMFriendDeleteParams,
V2NIMFriendDeletionType,
V2NIMFriendSearchOption,
V2NIMFriendSetParams,
V2NIMLoginStatus,
V2NIMUser,
V2NIMUserSearchOption,
V2NIMUserUpdateParams
} from '@nimsdk/base';
import { ChatKitClient } from '../ChatKitClient';
import { NEUserWithFriend } from '../model/NEUserWithFriend';
import { NEFriendUserCache } from '../NEFriendUserCache';
export class ContactRepo {
public static listener = getContext(this).eventHub
static onBlockListAddedFun = async (user: V2NIMUser) => {
NEFriendUserCache.getInstance().addBlockAccount(user.accountId)
}
static onLoginStatusFun = (status: V2NIMLoginStatus) => {
switch (status) {
case V2NIMLoginStatus.V2NIM_LOGIN_STATUS_LOGOUT:
NEFriendUserCache.getInstance().removeAllFriendInfo()
NEFriendUserCache.mineUserCache = undefined
break;
default:
break;
}
}
static onUserProfileChangedFun = async (users: V2NIMUser[]) => {
users.forEach((user) => {
if (NEFriendUserCache.getInstance().isFriend(user.accountId)) {
NEFriendUserCache.getInstance().updateFriendInfo({
user: user
})
}
if (NEFriendUserCache.isMe(user.accountId) && NEFriendUserCache.mineUserCache) {
NEFriendUserCache.mineUserCache.user = user
}
})
ContactRepo.listener.emit('updateUserInfo', users)
}
static onBlockListRemovedFun = (accountId: string) => {
NEFriendUserCache.getInstance().removeBlockAccount(accountId)
}
static onFriendAddedFun = async (friend: V2NIMFriend) => {
NEFriendUserCache.getInstance().updateFriendInfo({
friend: friend
})
ContactRepo.removeUserFromBlockList(friend.accountId)
ContactRepo.listener.emit('updateFriendInfo', friend)
// 更新 user 信息至最新
ContactRepo.getUserListFromCloud([friend.accountId])
}
static onFriendDeletedFun = (accountId: string, deletionType: V2NIMFriendDeletionType) => {
NEFriendUserCache.getInstance().removeFriendInfo(accountId)
}
static onFriendInfoChangedFun = (friend: V2NIMFriend) => {
NEFriendUserCache.getInstance().updateFriendInfo({
friend: friend
})
ContactRepo.listener.emit('updateFriendInfo', friend)
}
static addListener() {
ChatKitClient.nim.loginService.on('onLoginStatus', ContactRepo.onLoginStatusFun)
ChatKitClient.nim.userService?.on('onUserProfileChanged', ContactRepo.onUserProfileChangedFun)
ChatKitClient.nim.userService?.on('onBlockListAdded', ContactRepo.onBlockListAddedFun)
ChatKitClient.nim.userService?.on('onBlockListRemoved', ContactRepo.onBlockListRemovedFun)
ChatKitClient.nim.friendService?.on('onFriendAdded', ContactRepo.onFriendAddedFun)
ChatKitClient.nim.friendService?.on('onFriendDeleted', ContactRepo.onFriendDeletedFun)
ChatKitClient.nim.friendService?.on('onFriendInfoChanged', ContactRepo.onFriendInfoChangedFun)
}
static removeListener() {
ChatKitClient.nim.loginService.off('onLoginStatus', ContactRepo.onLoginStatusFun)
ChatKitClient.nim.userService?.off('onUserProfileChanged', ContactRepo.onUserProfileChangedFun)
ChatKitClient.nim.userService?.off('onBlockListAdded', ContactRepo.onBlockListAddedFun)
ChatKitClient.nim.userService?.off('onBlockListRemoved', ContactRepo.onBlockListRemovedFun)
ChatKitClient.nim.friendService?.off('onFriendAdded', ContactRepo.onFriendAddedFun)
ChatKitClient.nim.friendService?.off('onFriendDeleted', ContactRepo.onFriendDeletedFun)
ChatKitClient.nim.friendService?.off('onFriendInfoChanged', ContactRepo.onFriendInfoChangedFun)
}
/**
* 根据用户账号列表获取用户资料
*
* @param accountIds 用户 Id 列表。最大为 150 个
*/
static async getUserList(accountIds: string[]): Promise<V2NIMUser[]> {
return await ChatKitClient.nim.userService?.getUserList(accountIds) ?? []
}
/**
* 根据用户账号列表获取用户资料-从云端获取
*
* 注: 其结果会更新本地数据, 建议在需要实时感知用户最新的信息的场景下使用
*
* @param accountIds 用户 Id 列表。最大为 150 个
*/
static async getUserListFromCloud(accountIds: string[]): Promise<V2NIMUser[]> {
const userList = await ChatKitClient.nim.userService?.getUserListFromCloud(accountIds) ?? []
let friendList: V2NIMUser[] = []
userList.forEach((user) => {
const accountId = user.accountId
if (accountId === ChatKitClient.getLoginUserId()) {
NEFriendUserCache.mineUserCache = new NEUserWithFriend({
user: user
})
}
if (NEFriendUserCache.getInstance().isFriend(accountId)) {
friendList.push(user)
NEFriendUserCache.getInstance().updateFriendInfo({
user: user
})
}
})
if (friendList.length > 0) {
ContactRepo.listener.emit('updateUserInfo', friendList)
}
return userList
}
/**
* 更新自己的用户资料。调用该 API 后,会触发 onUserProfileChanged 事件
*
* @param updateParams 更新参数
*/
static async updateSelfUserProfile(updateParams: V2NIMUserUpdateParams): Promise<void> {
await ChatKitClient.nim.userService?.updateSelfUserProfile(updateParams)
}
/**
* 添加用户到黑名单中
*
* @param accountId 用户 Id
*/
static async addUserToBlockList(accountId: string): Promise<void> {
await ChatKitClient.nim.userService?.addUserToBlockList(accountId)
}
/**
* 从黑名单中移除用户
*
* @param accountId 用户 Id
*/
static async removeUserFromBlockList(accountId: string): Promise<void> {
await ChatKitClient.nim.userService?.removeUserFromBlockList(accountId)
}
/**
* 获取黑名单列表
*/
static async getBlockList(): Promise<string[]> {
const blockList = await ChatKitClient.nim.userService?.getBlockList() ?? []
NEFriendUserCache.getInstance().initBlockAccountSet(blockList)
return blockList
}
/**
* 根据关键词搜索用户信息
*
* @param option 搜索选项
*/
static async searchUserByOption(option: V2NIMUserSearchOption): Promise<V2NIMUser[]> {
return await ChatKitClient.nim.userService?.searchUserByOption(option) ?? []
}
/**
* 添加/申请好友
* @param accountId 好友 ID
* @param params 申请相关参数
*/
static async addFriend(accountId: string, params: V2NIMFriendAddParams): Promise<void> {
await ChatKitClient.nim.friendService?.addFriend(accountId, params)
}
/**
* 删除好友
*
* @param accountId 好友 ID
* @param params 删除相关参数
*/
static async deleteFriend(accountId: string, params: V2NIMFriendDeleteParams): Promise<void> {
await ChatKitClient.nim.friendService?.deleteFriend(accountId, params)
}
/**
* 接受好友申请
*
* @param accountId 好友 ID
*/
static async acceptAddApplication(application: V2NIMFriendAddApplication): Promise<void> {
await ChatKitClient.nim.friendService?.acceptAddApplication(application)
}
/**
* 拒绝好友申请
*
* @param accountId 好友 ID
* @param postscript 拒绝时的附言
*/
static async rejectAddApplication(application: V2NIMFriendAddApplication, postscript?: string): Promise<void> {
await ChatKitClient.nim.friendService?.rejectAddApplication(application, postscript)
}
/**
* 清空所有好友申请
*
*/
static async clearAllAddApplication(): Promise<void> {
await ChatKitClient.nim.friendService?.clearAllAddApplication()
}
/**
* 设置好友信息
*
* @param accountId 好友 ID
* @param params 设置好友信息参数
*/
static async setFriendInfo(accountId: string, params: V2NIMFriendSetParams): Promise<void> {
await ChatKitClient.nim.friendService?.setFriendInfo(accountId, params)
}
/**
* 获取好友列表
*/
static async getFriendList(): Promise<V2NIMFriend[]> {
let friendList = await ChatKitClient.nim.friendService?.getFriendList() ?? []
if (AppStorage.get<NEFriendUserCache>(NEFriendUserCache.name)) {
NEFriendUserCache.getInstance().loadFriendList(friendList)
}
return friendList
}
/**
* 根据账号 ID 获取好友信息
*
* @param accountIds 好友 ID 列表
*/
static async getFriendByIds(accountIds: string[]): Promise<V2NIMFriend[]> {
return await ChatKitClient.nim.friendService?.getFriendByIds(accountIds) ?? []
}
/**
* 根据账号 ID 获取用户信息(包含好友信息)
*
* @param accountIds 用户 ID 列表
*/
static async getUserWithFriendByIds(accountIds: string[]): Promise<NEUserWithFriend[]> {
let userWithFriends: NEUserWithFriend[] = []
const users = await ContactRepo.getUserListFromCloud(accountIds)
const friends = await ContactRepo.getFriendByIds(accountIds)
let friendsMap: Map<string, NEUserWithFriend> = new Map<string, NEUserWithFriend>()
for (const friend of friends) {
if (friend.accountId) {
friendsMap.set(friend.accountId, new NEUserWithFriend({
friend: friend
}))
}
}
for (const user of users) {
const friend = friendsMap.get(user.accountId)?.friend
let userWithFriend: NEUserWithFriend = new NEUserWithFriend({
friend: friend,
user: user
})
if (friend) {
NEFriendUserCache.getInstance().updateFriendInfo({
friendUser: userWithFriend
})
}
userWithFriends.push(userWithFriend)
}
return userWithFriends
}
/**
* 根据账号 ID 检查好友状态
* @param accountIds 好友 ID列表
*/
static async checkFriend(accountIds: string[]): Promise<V2NIMCheckFriendResult | undefined> {
return await ChatKitClient.nim.friendService?.checkFriend(accountIds)
}
/**
* 获取申请添加好友列表通知
*/
static async getAddApplicationList(option: V2NIMFriendAddApplicationQueryOption): Promise<V2NIMFriendAddApplicationResult | undefined> {
return await ChatKitClient.nim.friendService?.getAddApplicationList(option)
}
/**
* 设置好友申请已读
*/
static async setAddApplicationRead(): Promise<void> {
await ChatKitClient.nim.friendService?.setAddApplicationRead()
}
/**
* 获取未读的好友申请数量
*/
static async getAddApplicationUnreadCount(): Promise<number> {
return await ChatKitClient.nim.friendService?.getAddApplicationUnreadCount() ?? 0
}
/**
* 根据关键词搜索好友
* @param option 搜索好友的条件
*/
static async searchFriendByOption(option: V2NIMFriendSearchOption): Promise<V2NIMFriend[]> {
return await ChatKitClient.nim.friendService?.searchFriendByOption(option) ?? []
}
}

View File

@ -0,0 +1,282 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
import {
V2NIMConversation,
V2NIMConversationFilter,
V2NIMConversationOperationResult,
V2NIMConversationOption,
V2NIMConversationResult,
V2NIMConversationType,
V2NIMConversationUpdate
} from '@nimsdk/base';
import { ChatKitClient } from '../ChatKitClient';
export class ConversationRepo {
/**
* 获取会话列表
*
* @param offset 分页偏移量. 首页应传 0, 其他页数据使用返回的 offset
* @param limit 分页拉取数量,不建议超过 100
*/
static async getConversationList(offset: number, limit: number): Promise<V2NIMConversationResult | null> {
return await ChatKitClient.nim.conversationService?.getConversationList(offset, limit) ?? null
}
/**
* 置顶会话
*
* 注: 在操作成功且是有效的操作时, 则触发事件 {@link V2NIMConversationListener.onConversationChanged | V2NIMConversationListener.onConversationChanged}
*
* @param conversationId 会话 id
* @param stickTop 是否置顶. true: 置顶, false: 取消置顶.
*/
static async stickTopConversation(conversationId: string, stickTop: boolean): Promise<void> {
return await ChatKitClient.nim.conversationService?.stickTopConversation(conversationId, stickTop)
}
/**
* 删除会话
*
* 注: 在操作成功且是有效的操作时, 会抛出事件 {@link V2NIMConversationListener.onConversationDeleted | V2NIMConversationListener.onConversationCreated}
*
* @param conversationId 会话 id
* @param clearMessage 是否删除会话对应的历史消息. 默认为 false
*/
static async deleteConversation(conversationId: string, clearMessage?: boolean): Promise<void> {
return await ChatKitClient.nim.conversationService?.deleteConversation(conversationId, clearMessage)
}
/**
* 获取会话列表. 可以指定筛选条件,按会话类型,未读等
*
* @param offset 会话标记. 首页应传 0, 其他页数据使用返回的 offset
* @param limit 分页拉取数量, 不建议超过100
* @param option 查询选项
*
*/
static async getConversationListByOption(offset: number, limit: number,
option: V2NIMConversationOption): Promise<V2NIMConversationResult | undefined> {
return await ChatKitClient.nim.conversationService?.getConversationListByOption(offset, limit, option)
}
/**
* 根据会话 id 获取单条会话
*
* @param conversationId 会话 id
*/
static async getConversation(conversationId: string): Promise<V2NIMConversation | undefined> {
return await ChatKitClient.nim.conversationService?.getConversation(conversationId)
}
/**
* 根据会话 id 获取会话列表
*
* @param conversationIds 会话 id 列表
*
*/
static async getConversationListByIds(conversationIds: string[]): Promise<V2NIMConversation[] | undefined> {
return await ChatKitClient.nim.conversationService?.getConversationListByIds(conversationIds)
}
/**
* 创建会话
*
* 注: 在操作成功且是有效的操作时, 会抛出事件 {@link V2NIMConversationListener.onConversationCreated | V2NIMConversationListener.onConversationCreated}
*
* @param conversationId 会话 id
*
*/
static async createConversation(conversationId: string): Promise<V2NIMConversation | undefined> {
return await ChatKitClient.nim.conversationService?.createConversation(conversationId)
}
/**
* 批量删除会话
*
* 注: 在操作成功且是有效的操作时, 会抛出事件 {@link V2NIMConversationListener.onConversationDeleted | V2NIMConversationListener.onConversationDeleted}
*
* @param conversationIds 会话 id 列表
* @param clearMessage 是否删除会话对应的历史消息. 默认为 false
* @returns 返回操作失败的列表,列表的对象包含会话 id 以及错误信息.
*/
static async deleteConversationListByIds(conversationIds: string[],
clearMessage?: boolean): Promise<V2NIMConversationOperationResult[] | undefined> {
return await ChatKitClient.nim.conversationService?.deleteConversationListByIds(conversationIds, clearMessage)
}
/**
* 更新会话
*
* 注: 在操作成功且是有效的操作时, 触发事件 {@link V2NIMConversationListener.onConversationChanged | V2NIMConversationListener.onConversationChanged}
*
* @param conversationId 会话 id
* @param updateInfo 欲更新的信息
*
*/
static async updateConversation(conversationId: string, updateInfo: V2NIMConversationUpdate): Promise<void> {
return await ChatKitClient.nim.conversationService?.updateConversation(conversationId, updateInfo)
}
/**
* 更新会话的本地扩展字段
*
* 注: 在操作成功且是有效的操作时, 触发事件 {@link V2NIMConversationListener.onConversationChanged | V2NIMConversationListener.onConversationChanged}
*
* 注2: 字段只能存在内存里, 不能持久化存储. 登出或者重新初始化后 localExtension 都会再次成为空字符串.
*
* @param conversationId 会话 id
* @param localExtension 本地扩展信息
*
*/
static async updateConversationLocalExtension(conversationId: string, localExtension: string): Promise<void> {
return await ChatKitClient.nim.conversationService?.updateConversationLocalExtension(conversationId, localExtension)
}
/**
* 获取全部会话的总的未读数
*
*/
static getTotalUnreadCount(): number | undefined {
return ChatKitClient.nim.conversationService?.getTotalUnreadCount()
}
/**
* 根据 id 列表获取会话的未读数
*
* @param conversationIds 会话 id 列表
*
*/
static async getUnreadCountByIds(conversationIds: string[]): Promise<number | undefined> {
return await ChatKitClient.nim.conversationService?.getUnreadCountByIds(conversationIds)
}
/**
* 根据过滤参数获取相应的未读信息
*
* @param filter 过滤条件
*/
static async getUnreadCountByFilter(filter: V2NIMConversationFilter): Promise<number | undefined> {
return await ChatKitClient.nim.conversationService?.getUnreadCountByFilter(filter)
}
/**
* 清空所有会话总的未读数
*
* 注: 当该方法调用后SDK 可能给开发者抛出以下的事件
*
* {@link V2NIMConversationListener.onConversationChanged | V2NIMConversationListener.onConversationChanged} <br/>
* {@link V2NIMConversationListener.onTotalUnreadCountChanged | V2NIMConversationListener.onTotalUnreadCountChanged} <br/>
* {@link V2NIMConversationListener.onUnreadCountChangedByFilter | V2NIMConversationListener.onUnreadCountChangedByFilter}
*/
static async clearTotalUnreadCount(): Promise<void> {
return await ChatKitClient.nim.conversationService?.clearTotalUnreadCount()
}
/**
* 根据会话 id 列表清空相应会话的未读数
*
* 注: 当该方法调用后SDK 可能给开发者抛出以下的事件
*
* {@link V2NIMConversationListener.onConversationChanged | V2NIMConversationListener.onConversationChanged} <br/>
* {@link V2NIMConversationListener.onTotalUnreadCountChanged | V2NIMConversationListener.onTotalUnreadCountChanged} <br/>
* {@link V2NIMConversationListener.onUnreadCountChangedByFilter | V2NIMConversationListener.onUnreadCountChangedByFilter}
*
* @param conversationIds 会话 id 列表
* @returns 返回操作失败结果的列表
*/
static async clearUnreadCountByIds(conversationIds: string[]): Promise<V2NIMConversationOperationResult[] | undefined> {
return await ChatKitClient.nim.conversationService?.clearUnreadCountByIds(conversationIds)
}
/**
* 清除对应指定分组下的会话的未读数
*
* 注: 当该方法调用后SDK 可能给开发者抛出以下的事件
*
* {@link V2NIMConversationListener.onConversationChanged | V2NIMConversationListener.onConversationChanged} <br/>
* {@link V2NIMConversationListener.onTotalUnreadCountChanged | V2NIMConversationListener.onTotalUnreadCountChanged} <br/>
* {@link V2NIMConversationListener.onUnreadCountChangedByFilter | V2NIMConversationListener.onUnreadCountChangedByFilter}
*
* @param groupId 指定的会话分组 id
*/
static async clearUnreadCountByGroupId(groupId: string): Promise<void> {
return await ChatKitClient.nim.conversationService?.clearUnreadCountByGroupId(groupId)
}
/**
* 清除对应指定类型下的会话的未读数
*
* 注: 当该方法调用后SDK 可能给开发者抛出以下的事件
*
* {@link V2NIMConversationListener.onConversationChanged | V2NIMConversationListener.onConversationChanged} <br/>
* {@link V2NIMConversationListener.onTotalUnreadCountChanged | V2NIMConversationListener.onTotalUnreadCountChanged} <br/>
* {@link V2NIMConversationListener.onUnreadCountChangedByFilter | V2NIMConversationListener.onUnreadCountChangedByFilter}
*
* @param types 指定的会话类型列表
*/
static async clearUnreadCountByTypes(types: V2NIMConversationType[]): Promise<void> {
return await ChatKitClient.nim.conversationService?.clearUnreadCountByTypes(types)
}
/**
* 订阅指定过滤条件的会话未读数变化
*
* 注1: 当订阅该条件后,该 filter 下的未读数发生变化时, 触发 {@link V2NIMConversationListener.onUnreadCountChangedByFilter | V2NIMConversationListener.onUnreadCountChangedByFilter} 事件
*
* 注2: 同一种 filter 只能被订阅一次, 第二次的调用不会有任何效果
*
* @param filter 过滤条件
*/
static subscribeUnreadCountByFilter(filter: V2NIMConversationFilter) {
return ChatKitClient.nim.conversationService?.subscribeUnreadCountByFilter(filter)
}
/**
* 取消订阅指定过滤条件的会话未读变化
*
* @param filter 过滤条件
*/
static unsubscribeUnreadCountByFilter(filter: V2NIMConversationFilter) {
return ChatKitClient.nim.conversationService?.unsubscribeUnreadCountByFilter(filter)
}
/**
* 标记会话已读时间戳
*
* 注: 当该方法调用后SDK 可能给多端账户抛出以下的事件
*
* {@link V2NIMConversationListener.onConversationReadTimeUpdated | V2NIMConversationListener.onConversationReadTimeUpdated} <br/>
*
*/
static async markConversationRead(conversationId: string): Promise<number | undefined> {
return await ChatKitClient.nim.conversationService?.markConversationRead(conversationId)
}
/**
* 获取会话已读时间戳。该时间包含多端已读时间戳
*/
static async getConversationReadTime(conversationId: string): Promise<number | undefined> {
return await ChatKitClient.nim.conversationService?.getConversationReadTime(conversationId)
}
/**
* 移除会话的所有监听
*/
static removeAllConversationListener() {
//移除
ChatKitClient.nim.conversationService?.removeAllListeners('onSyncFinished')
//会话创建
ChatKitClient.nim.conversationService?.removeAllListeners("onConversationCreated")
//会话删除
ChatKitClient.nim.conversationService?.removeAllListeners("onConversationDeleted")
//会话更新
ChatKitClient.nim.conversationService?.removeAllListeners("onConversationChanged")
}
}

View File

@ -0,0 +1,282 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
import {
V2NIMConversationType,
V2NIMLocalConversation,
V2NIMLocalConversationFilter,
V2NIMLocalConversationOperationResult,
V2NIMLocalConversationOption,
V2NIMLocalConversationResult,
} from '@nimsdk/base';
import { ChatKitClient } from '../ChatKitClient';
export class LocalConversationRepo {
/**
* 获取会话列表
*
* @param offset 分页偏移量. 首页应传 0, 其他页数据使用返回的 offset
* @param limit 分页拉取数量,不建议超过 100
*/
static async getConversationList(offset: number, limit: number): Promise<V2NIMLocalConversationResult | null> {
return await ChatKitClient.nim.localConversationService?.getConversationList(offset, limit) ?? null
}
/**
* 置顶会话
*
* 注: 在操作成功且是有效的操作时, 则触发事件 {@link V2NIMConversationListener.onConversationChanged | V2NIMConversationListener.onConversationChanged}
*
* @param conversationId 会话 id
* @param stickTop 是否置顶. true: 置顶, false: 取消置顶.
*/
static async stickTopConversation(conversationId: string, stickTop: boolean): Promise<void> {
return await ChatKitClient.nim.localConversationService?.stickTopConversation(conversationId, stickTop)
}
/**
* 删除会话
*
* 注: 在操作成功且是有效的操作时, 会抛出事件 {@link V2NIMConversationListener.onConversationDeleted | V2NIMConversationListener.onConversationCreated}
*
* @param conversationId 会话 id
* @param clearMessage 是否删除会话对应的历史消息. 默认为 false
*/
static async deleteConversation(conversationId: string, clearMessage?: boolean): Promise<void> {
return await ChatKitClient.nim.localConversationService?.deleteConversation(conversationId, clearMessage)
}
/**
* 获取会话列表. 可以指定筛选条件,按会话类型,未读等
*
* @param offset 会话标记. 首页应传 0, 其他页数据使用返回的 offset
* @param limit 分页拉取数量, 不建议超过100
* @param option 查询选项
*
*/
static async getConversationListByOption(offset: number, limit: number,
option: V2NIMLocalConversationOption): Promise<V2NIMLocalConversationResult | undefined> {
return await ChatKitClient.nim.localConversationService?.getConversationListByOption(offset, limit, option)
}
/**
* 根据会话 id 获取单条会话
*
* @param conversationId 会话 id
*/
static async getConversation(conversationId: string): Promise<V2NIMLocalConversation | undefined> {
return await ChatKitClient.nim.localConversationService?.getConversation(conversationId)
}
/**
* 根据会话 id 获取会话列表
*
* @param conversationIds 会话 id 列表
*
*/
static async getConversationListByIds(conversationIds: string[]): Promise<V2NIMLocalConversation[] | undefined> {
return await ChatKitClient.nim.localConversationService?.getConversationListByIds(conversationIds)
}
/**
* 创建会话
*
* 注: 在操作成功且是有效的操作时, 会抛出事件 {@link V2NIMConversationListener.onConversationCreated | V2NIMConversationListener.onConversationCreated}
*
* @param conversationId 会话 id
*
*/
static async createConversation(conversationId: string): Promise<V2NIMLocalConversation | undefined> {
return await ChatKitClient.nim.localConversationService?.createConversation(conversationId)
}
/**
* 批量删除会话
*
* 注: 在操作成功且是有效的操作时, 会抛出事件 {@link V2NIMConversationListener.onConversationDeleted | V2NIMConversationListener.onConversationDeleted}
*
* @param conversationIds 会话 id 列表
* @param clearMessage 是否删除会话对应的历史消息. 默认为 false
* @returns 返回操作失败的列表,列表的对象包含会话 id 以及错误信息.
*/
static async deleteConversationListByIds(conversationIds: string[],
clearMessage?: boolean): Promise<V2NIMLocalConversationOperationResult[] | undefined> {
return await ChatKitClient.nim.localConversationService?.deleteConversationListByIds(conversationIds, clearMessage)
}
/**
* 更新会话
*
* 注: 在操作成功且是有效的操作时, 触发事件 {@link V2NIMConversationListener.onConversationChanged | V2NIMConversationListener.onConversationChanged}
*
* @param conversationId 会话 id
* @param updateInfo 欲更新的信息
*
*/
// static async updateConversation(conversationId: string, updateInfo: V2NIMLocalConversationUpdate): Promise<void> {
// return await ChatKitClient.nim.localConversationService?.updateConversation(conversationId, updateInfo)
// }
/**
* 更新会话的本地扩展字段
*
* 注: 在操作成功且是有效的操作时, 触发事件 {@link V2NIMConversationListener.onConversationChanged | V2NIMConversationListener.onConversationChanged}
*
* 注2: 字段只能存在内存里, 不能持久化存储. 登出或者重新初始化后 localExtension 都会再次成为空字符串.
*
* @param conversationId 会话 id
* @param localExtension 本地扩展信息
*
*/
static async updateConversationLocalExtension(conversationId: string, localExtension: string): Promise<void> {
return await ChatKitClient.nim.localConversationService?.updateConversationLocalExtension(conversationId,
localExtension)
}
/**
* 获取全部会话的总的未读数
*
*/
static getTotalUnreadCount(): number | undefined {
return ChatKitClient.nim.localConversationService?.getTotalUnreadCount()
}
/**
* 根据 id 列表获取会话的未读数
*
* @param conversationIds 会话 id 列表
*
*/
static async getUnreadCountByIds(conversationIds: string[]): Promise<number | undefined> {
return await ChatKitClient.nim.localConversationService?.getUnreadCountByIds(conversationIds)
}
/**
* 根据过滤参数获取相应的未读信息
*
* @param filter 过滤条件
*/
static async getUnreadCountByFilter(filter: V2NIMLocalConversationFilter): Promise<number | undefined> {
return await ChatKitClient.nim.localConversationService?.getUnreadCountByFilter(filter)
}
/**
* 清空所有会话总的未读数
*
* 注: 当该方法调用后SDK 可能给开发者抛出以下的事件
*
* {@link V2NIMConversationListener.onConversationChanged | V2NIMConversationListener.onConversationChanged} <br/>
* {@link V2NIMConversationListener.onTotalUnreadCountChanged | V2NIMConversationListener.onTotalUnreadCountChanged} <br/>
* {@link V2NIMConversationListener.onUnreadCountChangedByFilter | V2NIMConversationListener.onUnreadCountChangedByFilter}
*/
static async clearTotalUnreadCount(): Promise<void> {
return await ChatKitClient.nim.localConversationService?.clearTotalUnreadCount()
}
/**
* 根据会话 id 列表清空相应会话的未读数
*
* 注: 当该方法调用后SDK 可能给开发者抛出以下的事件
*
* {@link V2NIMConversationListener.onConversationChanged | V2NIMConversationListener.onConversationChanged} <br/>
* {@link V2NIMConversationListener.onTotalUnreadCountChanged | V2NIMConversationListener.onTotalUnreadCountChanged} <br/>
* {@link V2NIMConversationListener.onUnreadCountChangedByFilter | V2NIMConversationListener.onUnreadCountChangedByFilter}
*
* @param conversationIds 会话 id 列表
* @returns 返回操作失败结果的列表
*/
static async clearUnreadCountByIds(conversationIds: string[]): Promise<V2NIMLocalConversationOperationResult[] | undefined> {
return await ChatKitClient.nim.localConversationService?.clearUnreadCountByIds(conversationIds)
}
/**
* 清除对应指定分组下的会话的未读数
*
* 注: 当该方法调用后SDK 可能给开发者抛出以下的事件
*
* {@link V2NIMConversationListener.onConversationChanged | V2NIMConversationListener.onConversationChanged} <br/>
* {@link V2NIMConversationListener.onTotalUnreadCountChanged | V2NIMConversationListener.onTotalUnreadCountChanged} <br/>
* {@link V2NIMConversationListener.onUnreadCountChangedByFilter | V2NIMConversationListener.onUnreadCountChangedByFilter}
*
* @param groupId 指定的会话分组 id
*/
// static async clearUnreadCountByGroupId(groupId: string): Promise<void> {
// return await ChatKitClient.nim.localConversationService?.clearUnreadCountByGroupId(groupId)
// }
/**
* 清除对应指定类型下的会话的未读数
*
* 注: 当该方法调用后SDK 可能给开发者抛出以下的事件
*
* {@link V2NIMConversationListener.onConversationChanged | V2NIMConversationListener.onConversationChanged} <br/>
* {@link V2NIMConversationListener.onTotalUnreadCountChanged | V2NIMConversationListener.onTotalUnreadCountChanged} <br/>
* {@link V2NIMConversationListener.onUnreadCountChangedByFilter | V2NIMConversationListener.onUnreadCountChangedByFilter}
*
* @param types 指定的会话类型列表
*/
static async clearUnreadCountByTypes(types: V2NIMConversationType[]): Promise<void> {
return await ChatKitClient.nim.localConversationService?.clearUnreadCountByTypes(types)
}
/**
* 订阅指定过滤条件的会话未读数变化
*
* 注1: 当订阅该条件后,该 filter 下的未读数发生变化时, 触发 {@link V2NIMConversationListener.onUnreadCountChangedByFilter | V2NIMConversationListener.onUnreadCountChangedByFilter} 事件
*
* 注2: 同一种 filter 只能被订阅一次, 第二次的调用不会有任何效果
*
* @param filter 过滤条件
*/
static subscribeUnreadCountByFilter(filter: V2NIMLocalConversationFilter) {
return ChatKitClient.nim.localConversationService?.subscribeUnreadCountByFilter(filter)
}
/**
* 取消订阅指定过滤条件的会话未读变化
*
* @param filter 过滤条件
*/
static unsubscribeUnreadCountByFilter(filter: V2NIMLocalConversationFilter) {
return ChatKitClient.nim.localConversationService?.unsubscribeUnreadCountByFilter(filter)
}
/**
* 标记会话已读时间戳
*
* 注: 当该方法调用后SDK 可能给多端账户抛出以下的事件
*
* {@link V2NIMConversationListener.onConversationReadTimeUpdated | V2NIMConversationListener.onConversationReadTimeUpdated} <br/>
*
*/
static async markConversationRead(conversationId: string): Promise<number | undefined> {
return await ChatKitClient.nim.localConversationService?.markConversationRead(conversationId)
}
/**
* 获取会话已读时间戳。该时间包含多端已读时间戳
*/
static async getConversationReadTime(conversationId: string): Promise<number | undefined> {
return await ChatKitClient.nim.localConversationService?.getConversationReadTime(conversationId)
}
/**
* 移除会话的所有监听
*/
static removeAllConversationListener() {
//移除
ChatKitClient.nim.localConversationService?.removeAllListeners('onSyncFinished')
//会话创建
ChatKitClient.nim.localConversationService?.removeAllListeners("onConversationCreated")
//会话删除
ChatKitClient.nim.localConversationService?.removeAllListeners("onConversationDeleted")
//会话更新
ChatKitClient.nim.localConversationService?.removeAllListeners("onConversationChanged")
}
}

View File

@ -0,0 +1,103 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
import { V2NIMDndConfig, V2NIMP2PMessageMuteMode, V2NIMTeamMessageMuteMode, V2NIMTeamType } from '@nimsdk/base';
import { ChatKitClient } from '../ChatKitClient';
export class SettingRepo {
/**
* 获取会话消息免打扰状态
*
* 注: 若会话类型为群, 则群消息免打扰模式为 {@link V2NIMTeamMessageMuteMode.V2NIM_TEAM_MESSAGE_MUTE_MODE_OFF | V2NIMTeamMessageMuteMode.V2NIM_TEAM_MESSAGE_MUTE_MODE_OFF} 返回为false. 其他的返回 true.
*
* @param conversationId 会话 id
* @return mute 是否被免打扰
*/
static async getConversationMuteStatus(conversationId: string): Promise<boolean | undefined> {
return await ChatKitClient.nim.settingService?.getConversationMuteStatus(conversationId)
}
/**
* 设置群消息免打扰模式
*
* @param teamId 群组ID
* @param teamType 群组类型
* @param muteMode 群消息免打扰模式
*/
static async setTeamMessageMuteMode(teamId: string, teamType: V2NIMTeamType,
muteMode: V2NIMTeamMessageMuteMode): Promise<void> {
await ChatKitClient.nim.settingService?.setTeamMessageMuteMode(teamId, teamType, muteMode)
}
/**
* 获取群消息免打扰模式
*
* @param teamId 群组ID
* @param teamType 群组类型
* @return muteMode 群消息免打扰模式
*/
static async getTeamMessageMuteMode(teamId: string,
teamType: V2NIMTeamType): Promise<V2NIMTeamMessageMuteMode | undefined> {
return await ChatKitClient.nim.settingService?.getTeamMessageMuteMode(teamId, teamType)
}
/**
* 设置点对点消息免打扰模式
*
* @param accountId 目标账号 ID
* @param muteMode 设置用户的免打扰模式
*/
static async setP2PMessageMuteMode(accountId: string, muteMode: V2NIMP2PMessageMuteMode): Promise<void> {
await ChatKitClient.nim.settingService?.setP2PMessageMuteMode(accountId, muteMode)
}
/**
* 获取用户消息免打扰模式
*
* @param accountId 目标账号 ID
* @return muteMode p2p 类型消息免打扰模式
*/
static async getP2PMessageMuteMode(accountId: string): Promise<V2NIMP2PMessageMuteMode | undefined> {
return await ChatKitClient.nim.settingService?.getP2PMessageMuteMode(accountId)
}
/**
* 获取点对点消息免打扰列表。
*
* 返回 V2NIMP2PMessageMuteMode 为 V2NIM_P2P_MESSAGE_MUTE_MODE_ON 的 accountId 列表。
*/
static async getP2PMessageMuteList(): Promise<string[]> {
return await ChatKitClient.nim.settingService?.getP2PMessageMuteList() ?? []
}
/**
* 设置当桌面端在线时,移动端是否需要推送
*
* @param need 桌面端在线时,移动端是否需要推送
*/
static async setPushMobileOnDesktopOnline(need: boolean): Promise<void> {
await ChatKitClient.nim.settingService?.setPushMobileOnDesktopOnline(need)
}
/**
* 设置Apns免打扰与详情显示
*
* @param config 免打扰与详情配置参数
*/
static async setDndConfig(config: V2NIMDndConfig): Promise<void> {
await ChatKitClient.nim.settingService?.setDndConfig(config)
}
/**
* 获取Apns免打扰与详情显示
*
* @return 免打扰与详情配置参数
*/
static async getDndConfig(): Promise<V2NIMDndConfig | undefined> {
return await ChatKitClient.nim.settingService?.getDndConfig()
}
}

View File

@ -0,0 +1,104 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
import {
V2NIMGetMediaResourceInfoResult,
V2NIMMessageAttachment,
V2NIMProgressCallback,
V2NIMSize,
V2NIMStorageScene,
V2NIMUploadFileParams,
V2NIMUploadFileTask
} from '@nimsdk/base';
import { ChatKitClient } from '../ChatKitClient';
export class StorageRepo {
/**
* 设置自定义场景
*
* @param sceneName 自定义的场景名
* @param expireTime 文件过期时间. 单位秒. 数值要求大于等于 86400 秒, 即 1 天.
*/
static addCustomStorageScene(sceneName: string, expireTime: number): V2NIMStorageScene | undefined {
return ChatKitClient.nim.storageService?.addCustomStorageScene(sceneName, expireTime)
}
/**
* 查询存储场景列表
*/
static getStorageSceneList(): V2NIMStorageScene[] {
return ChatKitClient.nim.storageService?.getStorageSceneList() ?? []
}
/**
* 创建文件上传任务
*
* @param fileParams 上传文件参数
* @returns 上传任务
*/
static createUploadFileTask(fileParams: V2NIMUploadFileParams): V2NIMUploadFileTask | null {
return ChatKitClient.nim.storageService?.createUploadFileTask(fileParams) ?? null
}
/**
* 上传文件
*
* @param fileTask 上传任务createUploadTask 函数返回值
* @returns 文件的 url
*/
static async uploadFile(fileTask: V2NIMUploadFileTask, progress: V2NIMProgressCallback): Promise<string | undefined> {
return await ChatKitClient.nim.storageService?.uploadFile(fileTask, progress)
}
/**
* 取消文件上传
*
* @param fileTask 上传任务createUploadTask 函数返回值
*/
static async cancelUploadFile(fileTask: V2NIMUploadFileTask): Promise<void> {
return await ChatKitClient.nim.storageService?.cancelUploadFile(fileTask)
}
/**
* 下载文件
*
* @param url 下载文件 url
* @param filePath 文件下载存放的本地路径
* @returns 文件的 url
*/
static async downloadFile(url: string, filePath: string,
progress: V2NIMProgressCallback): Promise<string | undefined> {
return await ChatKitClient.nim.storageService?.downloadFile(url, filePath, progress)
}
/**
* 取消文件下载
*
* @param url 下载文件 url
* @returns
*/
static async cancelDownloadFile(url: string): Promise<void> {
return await ChatKitClient.nim.storageService?.cancelDownloadFile(url)
}
/**
* 短链接转长链接
*
* @param url 文件远程地址
* @returns 文件的 url
*/
static async shortUrlToLong(url: string): Promise<string | undefined> {
return await ChatKitClient.nim.storageService?.shortUrlToLong(url)
}
/**
* 生成图片缩略链接
*/
static async getImageThumbUrl(attachment: V2NIMMessageAttachment, thumbSize: V2NIMSize): Promise<V2NIMGetMediaResourceInfoResult | undefined> {
return await ChatKitClient.nim.storageService?.getImageThumbUrl(attachment, thumbSize)
}
}

View File

@ -0,0 +1,649 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
import {
V2NIMAntispamConfig,
V2NIMCreateTeamParams,
V2NIMCreateTeamResult,
V2NIMTeam,
V2NIMTeamAgreeMode,
V2NIMTeamChatBannedMode,
V2NIMTeamInviteMode,
V2NIMTeamJoinActionInfo,
V2NIMTeamJoinActionInfoQueryOption,
V2NIMTeamJoinActionInfoResult,
V2NIMTeamJoinMode,
V2NIMTeamMember,
V2NIMTeamMemberListResult,
V2NIMTeamMemberQueryOption,
V2NIMTeamMemberRole,
V2NIMTeamMemberSearchOption,
V2NIMTeamMemberSearchResult,
V2NIMTeamType,
V2NIMTeamUpdateExtensionMode,
V2NIMTeamUpdateInfoMode,
V2NIMUpdateSelfMemberInfoParams,
V2NIMUpdateTeamInfoParams,
V2NIMUser
} from '@nimsdk/base'
import { ChatKitClient } from '../ChatKitClient'
import { TeamMemberResult, TeamMemberWithUser } from '../model/TeamMemberWithUser'
import { NEFriendUserCache } from '../NEFriendUserCache'
import { ContactRepo } from './ContactRepo'
interface TeamExtension {
im_ui_kit_group: boolean
}
export class TeamRepo {
//默认群头像
public static teamDefaultIcons = [
"https://s.netease.im/safe/ABg8YjWQWvcqO6sAAAAAAAAAAAA?_im_url=1",
"https://s.netease.im/safe/ABg8YjmQWvcqO6sAAAAAAAABAAA?_im_url=1",
"https://s.netease.im/safe/ABg8YjyQWvcqO6sAAAAAAAABAAA?_im_url=1",
"https://s.netease.im/safe/ABg8YkCQWvcqO6sAAAAAAAABAAA?_im_url=1",
"https://s.netease.im/safe/ABg8YkSQWvcqO6sAAAAAAAABAAA?_im_url=1"
]
/**
* 创建讨论组
* @param inviteeAccountIds
* @param postscript
* @param antispamConfig
* @returns
*/
static async createGroupTeam(
inviteeAccountIds?: string[],
postscript?: string,
antispamConfig?: V2NIMAntispamConfig): Promise<V2NIMCreateTeamResult | undefined> {
let createParams: V2NIMCreateTeamParams = {
name: TeamRepo.getTeamNameByMemberId(inviteeAccountIds),
teamType: V2NIMTeamType.V2NIM_TEAM_TYPE_NORMAL,
joinMode: V2NIMTeamJoinMode.V2NIM_TEAM_JOIN_MODE_FREE,
inviteMode: V2NIMTeamInviteMode.V2NIM_TEAM_INVITE_MODE_ALL,
agreeMode: V2NIMTeamAgreeMode.V2NIM_TEAM_AGREE_MODE_NO_AUTH,
updateInfoMode: V2NIMTeamUpdateInfoMode.V2NIM_TEAM_UPDATE_INFO_MODE_ALL,
updateExtensionMode: V2NIMTeamUpdateExtensionMode.V2NIM_TEAM_UPDATE_EXTENSION_MODE_ALL,
serverExtension: JSON.stringify({ 'im_ui_kit_group': true }),
avatar: TeamRepo.teamDefaultIcons[Math.floor(Math.random() * 5)]
}
return TeamRepo.createTeam(createParams,
inviteeAccountIds, postscript, antispamConfig)
}
/**
* 判断是否为讨论组
* @param team
* @returns
*/
static isGroupTeam(team: V2NIMTeam) {
if (team.serverExtension && team.serverExtension.length > 0) {
try {
let obj = JSON.parse(team.serverExtension) as object | undefined
if (obj && obj['im_ui_kit_group'] === true) {
return true
}
} catch (e) {
console.error('TeamRepo isGroupTeam json parse error')
}
}
return false
}
/**
* 创建高级群
* @param inviteeAccountIds
* @param postscript
* @param antispamConfig
* @returns
*/
static async createAdvanceTeam(
inviteeAccountIds?: string[],
postscript?: string,
antispamConfig?: V2NIMAntispamConfig): Promise<V2NIMCreateTeamResult | undefined> {
let createParams: V2NIMCreateTeamParams = {
name: TeamRepo.getTeamNameByMemberId(inviteeAccountIds),
teamType: V2NIMTeamType.V2NIM_TEAM_TYPE_NORMAL,
joinMode: V2NIMTeamJoinMode.V2NIM_TEAM_JOIN_MODE_FREE,
inviteMode: V2NIMTeamInviteMode.V2NIM_TEAM_INVITE_MODE_MANAGER,
agreeMode: V2NIMTeamAgreeMode.V2NIM_TEAM_AGREE_MODE_NO_AUTH,
updateInfoMode: V2NIMTeamUpdateInfoMode.V2NIM_TEAM_UPDATE_INFO_MODE_MANAGER,
updateExtensionMode: V2NIMTeamUpdateExtensionMode.V2NIM_TEAM_UPDATE_EXTENSION_MODE_MANAGER,
avatar: TeamRepo.teamDefaultIcons[Math.floor(Math.random() * 5)]
}
return TeamRepo.createTeam(createParams,
inviteeAccountIds, postscript, antispamConfig)
}
/**
* 创建一个群组
*
* 注: 操作成功后, 触发事件的规则如下:
* - 操作者端(群主), SDK 抛出: {@link V2NIMTeamListener.onTeamCreated | V2NIMTeamListener.onTeamCreated}
* - agreeMode 需要被邀请者同意
* - 被操作者端, SDK会抛出: {@link V2NIMTeamListener.onReceiveTeamJoinActionInfo | V2NIMTeamListener.onReceiveTeamJoinActionInfo}
* - agreeMode 不需被邀请者同意
* - 被操作者端, SDK会抛出: {@link V2NIMTeamListener.onTeamJoined | V2NIMTeamListener.onTeamJoined}
* - 其他成员端, SDK会抛出: {@link V2NIMTeamListener.onTeamMemberJoined | V2NIMTeamListener.onTeamMemberJoined}
*
* @param createTeamParams 创建群组参数
* @param invitorAccountIds 群组创建时,同时邀请加入群的成员列表
* @param postscript 群组创建时,邀请入群的附言
* @param antispamConfig 反垃圾参数. 如果开启了安全通,默认采用安全通,该配置不需要配置.
* 如果有审核需求,且直接对接易盾,则需要传入该配置
*/
static async createTeam(createTeamParams: V2NIMCreateTeamParams,
inviteeAccountIds?: string[],
postscript?: string,
antispamConfig?: V2NIMAntispamConfig): Promise<V2NIMCreateTeamResult | undefined> {
return await ChatKitClient.nim.teamService?.createTeam(createTeamParams, inviteeAccountIds, postscript,
antispamConfig)
}
/**
* 修改群组信息
*
* 注: 操作成功后, 触发事件的规则如下:
* - 全员用户端SDK会抛出: {@link V2NIMTeamListener.onTeamInfoUpdated | V2NIMTeamListener.onTeamInfoUpdated}
*
* @param teamId 群组id
* @param teamType 群组类型
* @param updateTeamInfoParams 更新群组信息参数
* @param antispamConfig 反垃圾参数. 如果开启了安全通,默认采用安全通,该配置不需要配置.
* 如果有审核需求,且直接对接易盾,则需要传入该配置
*/
static async updateTeamInfo(teamId: string,
teamType: V2NIMTeamType,
updateTeamInfoParams: V2NIMUpdateTeamInfoParams,
antispamConfig?: V2NIMAntispamConfig): Promise<void> {
await ChatKitClient.nim.teamService?.updateTeamInfo(teamId, teamType, updateTeamInfoParams, antispamConfig)
}
/**
* 退出群组
*
* 注: 操作成功后, 触发事件的规则如下:
* - 操作者自己本端SDK会抛出: {@link V2NIMTeamListener.onTeamLeft | V2NIMTeamListener.onTeamLeft}
* - 群内其它用户端, SDK会抛出: {@link V2NIMTeamListener.onTeamMemberLeft | V2NIMTeamListener.onTeamMemberLeft}
*
* @param teamId 群组id
* @param teamType 群组类型
*/
static async leaveTeam(teamId: string, teamType: V2NIMTeamType): Promise<void> {
await ChatKitClient.nim.teamService?.leaveTeam(teamId, teamType)
}
/**
* 获取群组信息
*
* @param teamId 群组id
* @param teamType 群组类型
*/
static async getTeamInfo(teamId: string, teamType: V2NIMTeamType): Promise<V2NIMTeam | undefined> {
return await ChatKitClient.nim.teamService?.getTeamInfo(teamId, teamType)
}
/**
* 获取当前已经加入的群组列表
*
* 注: 群组有效且自己在群中
*
* @param teamTypes 群类型列表. 若不传入这个字段, 代表这个过滤条件不生效, 则查询所有群组
*/
static async getJoinedTeamList(teamTypes?: V2NIMTeamType[]): Promise<V2NIMTeam[]> {
return await ChatKitClient.nim.teamService?.getJoinedTeamList(teamTypes) ?? []
}
/**
* 获取当前已经加入的群组数量
*
* 注: 群组有效且自己在群中
*
* @param teamTypes 群类型列表. 若不传入这个字段, 代表这个过滤条件不生效, 则查询所有群组
*/
static async getJoinedTeamCount(teamTypes?: V2NIMTeamType[]): Promise<number | undefined> {
return await ChatKitClient.nim.teamService?.getJoinedTeamCount(teamTypes)
}
/**
* 根据群组ID获取群组信息
*
* 每次最多100个群组ID. 先查本地数据,本地缺失再查询云端
*
* @param teamIds 群组ID列表
* @param teamType 群组类型
*/
static async getTeamInfoByIds(teamIds: string[],
teamType: V2NIMTeamType): Promise<V2NIMTeam[]> {
return await ChatKitClient.nim.teamService?.getTeamInfoByIds(teamIds, teamType) ?? []
}
/**
* 解散群组
*
* 注: 操作成功后, 触发事件的规则如下:
* - 全员, SDK会抛出: {@link V2NIMTeamListener.onTeamDismissed | V2NIMTeamListener.onTeamDismissed}
*
* @param teamId 群组id
* @param teamType 群组类型
*/
static async dismissTeam(teamId: string, teamType: V2NIMTeamType): Promise<void> {
await ChatKitClient.nim.teamService?.dismissTeam(teamId, teamType)
}
/**
* 邀请成员加入群
*
* 注: 操作成功后, 触发事件的规则如下:
* - agreeMode 需要被邀请者同意
* - 被操作者端, SDK会抛出: {@link V2NIMTeamListener.onReceiveTeamJoinActionInfo | V2NIMTeamListener.onReceiveTeamJoinActionInfo}
* - agreeMode 不需要被邀请者同意
* - 被操作者端, SDK会抛出: {@link V2NIMTeamListener.onTeamJoined | V2NIMTeamListener.onTeamJoined}
* - 其他成员端, SDK会抛出: {@link V2NIMTeamListener.onTeamMemberJoined | V2NIMTeamListener.onTeamMemberJoined}
*
* @param teamId 群组id
* @param teamType 群组类型
* @param inviteeAccountIds 邀请加入群的成员账号列表
* @param postscript 邀请入群的附言
* @returns 邀请失败的账号列表
*/
static async inviteMember(teamId: string,
teamType: V2NIMTeamType,
inviteeAccountIds: string[],
postscript?: string): Promise<string[]> {
return await ChatKitClient.nim.teamService?.inviteMember(teamId, teamType, inviteeAccountIds, postscript) ?? []
}
/**
* 接受邀请入群
*
* 注: 操作成功后, 触发事件的规则如下:
* - 操作者(既接受邀请用户)端, SDK会抛出: {@link V2NIMTeamListener.onTeamJoined | V2NIMTeamListener.onTeamJoined}
* - 其他成员端, SDK会抛出: {@link V2NIMTeamListener.onTeamMemberJoined | V2NIMTeamListener.onTeamMemberJoined}
*
* @param invitationInfo 邀请入群的信息
*/
static async acceptInvitation(invitationInfo: V2NIMTeamJoinActionInfo): Promise<V2NIMTeam | undefined> {
return await ChatKitClient.nim.teamService?.acceptInvitation(invitationInfo)
}
/**
* 拒绝邀请入群
*
* 注: 操作成功后, 触发事件的规则如下:
* - 群主或管理员端, SDK会抛出: {@link V2NIMTeamListener.onReceiveTeamJoinActionInfo | V2NIMTeamListener.onReceiveTeamJoinActionInfo}
*
* @param invitationInfo 邀请入群的信息
*/
static async rejectInvitation(invitationInfo: V2NIMTeamJoinActionInfo, postscript?: string): Promise<void> {
await ChatKitClient.nim.teamService?.rejectInvitation(invitationInfo)
}
/**
* 踢出群组成员
*
* 注1: 只有群主有权限操作改接口
*
* 注2: 操作成功后, 触发事件的规则如下:
* - 被操作者既被踢用户SDK会抛出: {@link V2NIMTeamListener.onTeamLeft | V2NIMTeamListener.onTeamLeft}
* - 其他成员端SDK会抛出: {@link V2NIMTeamListener.onTeamMemberKicked | V2NIMTeamListener.onTeamMemberKicked}
*
* @param teamId 群组id
* @param teamType 群组类型
* @param memberAccountIds 踢出群组的成员账号列表
*/
static async kickMember(teamId: string, teamType: V2NIMTeamType, memberAccountIds: string[]): Promise<void> {
await ChatKitClient.nim.teamService?.kickMember(teamId, teamType, memberAccountIds)
}
/**
* (用户)申请加入群组
*
* 注: 操作成功后, 触发事件的规则如下:
* - joinMode 自由加入
* - 操作者端SDK 会抛出: {@link V2NIMTeamListener.onTeamJoined | V2NIMTeamListener.onTeamJoined}
* - 其他成员端, SDK 会抛出: {@link V2NIMTeamListener.onTeamMemberJoined | V2NIMTeamListener.onTeamMemberJoined}
* - joinMode 群主管理员同意
* - 群主或管理员端SDK 会抛出 {@link V2NIMTeamListener.onReceiveTeamJoinActionInfo | V2NIMTeamListener.onReceiveTeamJoinActionInfo}
*
* @param teamId 群组id
* @param teamType 群组类型
* @param postscript 申请附言
* @returns 对应的群信息
*/
static async applyJoinTeam(teamId: string,
teamType: V2NIMTeamType,
postscript?: string): Promise<V2NIMTeam | undefined> {
return await ChatKitClient.nim.teamService?.applyJoinTeam(teamId, teamType, postscript)
}
/**
* (管理员)接受(用户的)入群申请
*
* 注: 操作成功后, 触发事件的规则如下:
* - 被操作者既被同意用户SDK会抛出: {@link V2NIMTeamListener.onTeamJoined | V2NIMTeamListener.onTeamJoined}
* - 其他成员, SDK会抛出: {@link V2NIMTeamListener.onTeamMemberJoined | V2NIMTeamListener.onTeamMemberJoined}
*
* @param applicationInfo 该申请的相关信息
*/
static async acceptJoinApplication(applicationInfo: V2NIMTeamJoinActionInfo): Promise<void> {
await ChatKitClient.nim.teamService?.acceptJoinApplication(applicationInfo)
}
/**
* (管理员)拒绝(用户的)入群申请
*
* 注: 操作成功后, 触发事件的规则如下:
* - 被操作用户(既被拒绝用户), SDK会抛出: {@link V2NIMTeamListener.onReceiveTeamJoinActionInfo | V2NIMTeamListener.onReceiveTeamJoinActionInfo}
*
* @param applicationInfo 该申请的相关信息
*/
static async rejectJoinApplication(applicationInfo: V2NIMTeamJoinActionInfo, postscript?: string): Promise<void> {
await ChatKitClient.nim.teamService?.rejectJoinApplication(applicationInfo, postscript)
}
/**
* 设置成员角色
*
* 注1: 本操作只有群主可操作, 且只能在普通成员与管理员直接角色切换, 如果成员设置角色与当前角色一致,默认请求成功
*
* 注2: 操作成功后, 触发事件的规则如下:
* - 所有成员SDK会抛出: @link V2NIMTeamListener.onTeamMemberInfoUpdated | V2NIMTeamListener.onTeamMemberInfoUpdated}
*
* @param teamId 群组id
* @param teamType 群组类型
* @param memberAccountIds 待操作的群组的成员账号列表
* @param memberRole 新的角色类型
*/
static async updateTeamMemberRole(teamId: string,
teamType: V2NIMTeamType,
memberAccountIds: string[],
memberRole: V2NIMTeamMemberRole): Promise<void> {
await ChatKitClient.nim.teamService?.updateTeamMemberRole(teamId, teamType, memberAccountIds, memberRole)
}
/**
* 移交群主
*
* 注1: 本操作只有群主可操作
*
* 注2: 操作成功后, 触发事件的规则如下:
* - 所有成员SDK会抛出: {@link V2NIMTeamListener.onTeamInfoUpdated | V2NIMTeamListener.onTeamInfoUpdated}
* - 若入参 leave 为 true:
* - 操作者, SDK会抛出:onTeamLeft
* - 其它成员, SDK会抛出:onTeamMemberLeft
*
* @param teamId 群组id
* @param teamType 群组类型
* @param accountId 新群主的账号 ID
* @param leave 转让群主后, 操作者是否同时退出该群. 默认为 false
* @returns 该操作的时间戳
*/
static async transferTeamOwner(teamId: string,
teamType: V2NIMTeamType,
accountId: string,
leave?: boolean): Promise<void> {
await ChatKitClient.nim.teamService?.transferTeamOwner(teamId, teamType, accountId, leave)
}
/**
* 修改自己的群成员信息
*
* 注: 操作成功后, 触发事件的规则如下:
* - 所有成员, SDK会抛出: {@link V2NIMTeamListener.onTeamMemberInfoUpdated | V2NIMTeamListener.onTeamMemberInfoUpdated}
*
* @param teamId 群组id
* @param teamType 群组类型
* @param memberInfoParams 被修改的字段
*/
static async updateSelfTeamMemberInfo(teamId: string,
teamType: V2NIMTeamType,
memberInfoParams: V2NIMUpdateSelfMemberInfoParams): Promise<void> {
await ChatKitClient.nim.teamService?.updateSelfTeamMemberInfo(teamId, teamType, memberInfoParams)
}
/**
* 修改群成员昵称
*
* 注: 只有群主和管理员拥有此权限可操作
*
* 注: 操作成功后, 触发事件的规则如下:
* - 所有成员SDK会抛出: {@link V2NIMTeamListener.onTeamMemberInfoUpdated | V2NIMTeamListener.onTeamMemberInfoUpdated}
*
* @param teamId 群组id
* @param teamType 群组类型
* @param accountId 新群主的账号 ID
* @param nick 昵称
*/
static async updateTeamMemberNick(teamId: string,
teamType: V2NIMTeamType,
accountId: string,
nick: string): Promise<void> {
await ChatKitClient.nim.teamService?.updateTeamMemberNick(teamId, teamType, accountId, nick)
}
/**
* 设置群组禁言模式
*
* 注: 操作成功后, 触发事件的规则如下:
* - 所有成员SDK会抛出: {@link V2NIMTeamListener.onTeamInfoUpdated | V2NIMTeamListener.onTeamInfoUpdated}
*
* @param teamId 群组id
* @param teamType 群组类型
* @param chatBannedMode 禁言模式
*/
static async setTeamChatBannedMode(teamId: string,
teamType: V2NIMTeamType,
chatBannedMode: V2NIMTeamChatBannedMode): Promise<void> {
await ChatKitClient.nim.teamService?.setTeamChatBannedMode(teamId, teamType, chatBannedMode)
}
/**
* 设置群组成员聊天禁言状态
*
* 注: 操作成功后, 触发事件的规则如下:
* - 所有成员, SDK会抛出: {@link V2NIMTeamListener.onTeamMemberInfoUpdated | V2NIMTeamListener.onTeamMemberInfoUpdated}
*
* @param teamId 群组id
* @param teamType 群组类型
* @param accountId 被修改成员的账号
* @param chatBanned 群组中聊天是否被禁言
*/
static async setTeamMemberChatBannedStatus(teamId: string, teamType: V2NIMTeamType, accountId: string,
chatBanned: boolean): Promise<void> {
await ChatKitClient.nim.teamService?.setTeamMemberChatBannedStatus(teamId, teamType, accountId, chatBanned)
}
/**
* 获取群成员列表
*
* @param teamId 群组id
* @param teamType 群组类型
* @param memberRoles 成员角色
* @returns 查询结果
*/
static async getTeamMemberList(teamId: string,
teamType: V2NIMTeamType,
queryOption: V2NIMTeamMemberQueryOption): Promise<V2NIMTeamMemberListResult | undefined> {
return await ChatKitClient.nim.teamService?.getTeamMemberList(teamId, teamType, queryOption)
}
/**
* 根据账号 ID 列表获取群组成员列表
*
* @param teamId 群组id
* @param teamType 群组类型
* @param accountIds 成员的账号 ID 列表
* @returns 成员列表
*/
static async getTeamMemberListByIds(teamId: string,
teamType: V2NIMTeamType,
accountIds: string[]): Promise<V2NIMTeamMember[]> {
return await ChatKitClient.nim.teamService?.getTeamMemberListByIds(teamId, teamType, accountIds) ?? []
}
/**
* 获取群加入相关信息
*
* @param option 查询参数
*/
static async getTeamJoinActionInfoList(option: V2NIMTeamJoinActionInfoQueryOption): Promise<V2NIMTeamJoinActionInfoResult | undefined> {
return await ChatKitClient.nim.teamService?.getTeamJoinActionInfoList(option)
}
/**
* 根据关键字搜索群信息
* - 混合搜索高级群和超大群like匹配
* - 只搜索群名称
*/
static async searchTeamByKeyword(keyword: string): Promise<V2NIMTeam[]> {
// TODO: 等待SDK实现
// return await ChatKitClient.nim.teamService?.searchTeamByKeyword(keyword) ?? []
return []
}
/**
* 根据关键字搜索群成员
*
* @param searchOption 搜索参数
* @param success 成功回调
* @param failure 失败回调
*/
static async searchTeamMembers(searchOption: V2NIMTeamMemberSearchOption): Promise<V2NIMTeamMemberSearchResult | undefined> {
// TODO: 等待SDK实现
// return await ChatKitClient.nim.teamService?.searchTeamMembers(searchOption)
return undefined
}
/**
* 分页获取群成员列表,包含用户和好友信息
* @param teamId
* @param teamType
* @param limit
* @param nextToken
* @returns
*/
static async getTeamMembers(teamId: string,
teamType: V2NIMTeamType, queryOption: V2NIMTeamMemberQueryOption): Promise<TeamMemberResult | undefined> {
let teamMemberResult = await TeamRepo.getTeamMemberList(
teamId,
teamType,
queryOption
)
let teamMembers: TeamMemberWithUser[] | undefined = teamMemberResult?.memberList.map((teamMember) => {
return new TeamMemberWithUser(teamMember,
NEFriendUserCache.getInstance().getFriendById(teamMember.accountId)?.friend,
NEFriendUserCache.getInstance().getFriendById(teamMember.accountId)?.user)
})
let noUserAccIdList = teamMembers?.filter((member) => {
return !member.userInfo
}).map((teamMember) => {
return teamMember.teamMember.accountId
})
if (noUserAccIdList && noUserAccIdList.length > 0) {
let userList = await ContactRepo.getUserList(noUserAccIdList)
let userMap = userList.reduce((acc, cur, _index) => {
acc.set(cur.accountId, cur)
return acc
}, new Map<string, V2NIMUser>())
teamMembers?.forEach((member) => {
if (!member.userInfo) {
member.userInfo = userMap.get(member.teamMember.accountId)
}
})
}
if (teamMemberResult) {
let result: TeamMemberResult = {
finished: teamMemberResult?.finished,
nextToken: teamMemberResult?.nextToken,
memberList: teamMembers ?? []
}
return result
}
return
}
/**
* 根据成员id查询群成员的信息
* @param teamId
* @param teamType
* @param accountIds
* @returns
*/
static async getTeamMembersByIds(teamId: string,
teamType: V2NIMTeamType, accountIds: string[]): Promise<TeamMemberWithUser[]> {
let teamMemberList: V2NIMTeamMember[] = []
try {
teamMemberList = await TeamRepo.getTeamMemberListByIds(
teamId,
teamType,
accountIds
)
console.debug(`TeamRepo getTeamMembersByIds result = ${teamMemberList.length} `);
} catch (e) {
console.error(`TeamRepo getTeamMembersByIds ${e}`);
}
let teamMembers: TeamMemberWithUser[] = teamMemberList.map((teamMember) => {
return new TeamMemberWithUser(teamMember,
NEFriendUserCache.getInstance().getFriendById(teamMember.accountId)?.friend,
NEFriendUserCache.getInstance().getFriendById(teamMember.accountId)?.user)
})
let noUserAccIdList = teamMembers?.filter((member) => {
return !member.userInfo
}).map((teamMember) => {
return teamMember.teamMember.accountId
})
if (noUserAccIdList && noUserAccIdList.length > 0) {
let userList = await ContactRepo.getUserList(noUserAccIdList)
let userMap = userList.reduce((acc, cur, _index) => {
acc.set(cur.accountId, cur)
return acc
}, new Map<string, V2NIMUser>())
teamMembers?.forEach((member) => {
if (!member.userInfo) {
member.userInfo = userMap.get(member.teamMember.accountId)
}
})
}
return teamMembers
}
/**
* 根据群成员生成群名
* @param inviteeAccountIds
* @returns
*/
private static getTeamNameByMemberId(inviteeAccountIds?: string[]): string {
if (inviteeAccountIds) {
let inviteeUser = NEFriendUserCache.getInstance().getFriendsByIds(inviteeAccountIds)
let inviteeNames = inviteeUser.map(user => user.user?.name ?? user.user?.accountId)
let teamName = inviteeNames.slice(0, Math.min(inviteeNames.length, 30)).join('、')
let mineName = NEFriendUserCache.mineUserCache?.showName(false)
teamName = mineName + '、' + teamName
return teamName.slice(0, Math.min(teamName.length, 30))
}
return ''
}
}

View File

@ -0,0 +1,57 @@
import { V2NIMMessageAttachment } from '@nimsdk/base';
import { mergedMessageCustomType } from '../constant/Constant';
import { MergedMessageAttachment } from '../model/CustomMessageAttachment';
export class CustomMessageUtils {
public static attachmentOfCustomMessage(attachment: V2NIMMessageAttachment) {
if (attachment.raw) {
try {
let attachmentObject = JSON.parse(attachment.raw) as object
return attachmentObject
} catch (err) {
console.error(err)
return undefined
}
}
return undefined
}
public static typeOfCustomMessage(attachment: V2NIMMessageAttachment) {
let customAttachment = CustomMessageUtils.attachmentOfCustomMessage(attachment)
if (customAttachment) {
return customAttachment["type"] as number
}
return undefined
}
public static dataOfCustomMessage(attachment: V2NIMMessageAttachment) {
let customAttachment = CustomMessageUtils.attachmentOfCustomMessage(attachment)
let type = CustomMessageUtils.typeOfCustomMessage(attachment)
if (type === mergedMessageCustomType) {
return customAttachment?.["data"] as MergedMessageAttachment
}
return customAttachment?.["data"] as object
}
public static heightOfCustomMessage(attachment: V2NIMMessageAttachment) {
let customAttachment = CustomMessageUtils.attachmentOfCustomMessage(attachment)
if (customAttachment) {
return customAttachment["customHeight"] as number
}
return undefined
}
/// 是否是【未知消息】
public static isUnknownMessage(attachment?: V2NIMMessageAttachment) {
if (attachment) {
const customType = CustomMessageUtils.typeOfCustomMessage(attachment)
switch (customType) {
case mergedMessageCustomType:
return false
default:
return true
}
}
return false
}
}

View File

@ -0,0 +1,54 @@
import { promptAction } from '@kit.ArkUI';
import { V2NIMErrorCode } from '@nimsdk/base';
import { ChatKitClient } from '../ChatKitClient';
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
export class ErrorUtils {
static handleErrorToast(errorCode: number) {
let msg: ResourceStr = $r('app.string.unknown_error');
switch (errorCode) {
case V2NIMErrorCode.V2NIM_ERROR_CODE_PIN_LIMIT:
msg = $r('app.string.chat_pin_limit_error_tips')
break
case V2NIMErrorCode.V2NIM_ERROR_CODE_COLLECTION_LIMIT:
msg = $r('app.string.chat_collection_limit_error_tips')
break
case V2NIMErrorCode.V2NIM_ERROR_CODE_ILLEGAL_STATE:
msg = $r('app.string.chat_network_error_tips')
break
}
try {
promptAction.showToast({
message: msg,
alignment: Alignment.Bottom
})
} catch (error) {
console.error(`showToast args error code is ${error.code}, message is ${error.message}`);
}
}
static checkNetworkAndToast(): boolean {
if (ChatKitClient.connectBroken()) {
ErrorUtils.showToast($r('app.string.chat_network_error_tips'))
}
return !ChatKitClient.connectBroken()
}
private static showToast(msg: ResourceStr) {
try {
promptAction.showToast({
message: msg,
alignment: Alignment.Bottom
})
} catch (error) {
console.error(`showToast args error code is ${error.code}, message is ${error.message}`);
}
}
}

View File

@ -0,0 +1,25 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
export class EventHubUtil {
private eventhub = getContext(this).eventHub
/// 订阅事件
public on(eventName: string, callback: Function) {
this.eventhub.on(eventName, callback)
}
/// 取消订阅事件
public off(eventName: string, callback?: Function) {
this.eventhub.off(eventName, callback)
}
/// 触发事件
public emit(eventName: string, params: Object) {
this.eventhub.emit(eventName, params)
}
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
import { systemDateTime } from '@kit.BasicServicesKit';
import { V2NIMMessage, V2NIMMessageRevokeNotification } from '@nimsdk/base';
import { ChatKitClient } from '../ChatKitClient';
import { RevokeMessageExtension } from '../model/RevokeMessageExtension';
import { ChatRepo } from '../repo/ChatRepo';
// 保存撤回消息到本地
export function saveLocalRevokeMessage(conversationId: string, msg: V2NIMMessage, edit: boolean) {
let currentTime = systemDateTime.getTime()
// let revokeText = getContext().resourceManager.getStringByNameSync('chat_msg_undo_tips');
let revokeText = '你撤回一条消息';
let revokeMsg = ChatKitClient.nim.messageCreator.createTextMessage(revokeText)
revokeMsg.serverExtension = msg.serverExtension
revokeMsg.threadReply = msg.threadReply
revokeMsg.messageType = 10
let localExtension = {
revoke_message_local: true,
revoke_message_local_time: currentTime,
revoke_message_client_id: msg.messageClientId,
revoke_message_local_edit: edit,
revoke_message_local_content: msg.text ?? ''
} as RevokeMessageExtension
revokeMsg.localExtension = JSON.stringify(localExtension)
let createTime = msg.createTime + 10
console.debug('netease saveLocalRevokeMessage:', revokeMsg.localExtension)
ChatRepo.saveLocalMessage(revokeMsg, conversationId, ChatKitClient.getLoginUserId(), createTime)
}
// 保存他人撤回消息到本地
export function saveLocalRevokeMessageFormOther(conversationId: string, msgNotify: V2NIMMessageRevokeNotification,
edit: boolean) {
let currentTime = systemDateTime.getTime()
// let revokeText = getContext().resourceManager.getStringByNameSync('chat_msg_undo_tips');
let revokeText = '对方撤回一条消息';
let revokeMsg = ChatKitClient.nim.messageCreator.createTextMessage(revokeText)
revokeMsg.messageType = 10
let localExtension = {
revoke_message_local: false,
revoke_message_local_time: currentTime,
revoke_message_client_id: msgNotify.messageRefer.messageClientId,
revoke_message_local_edit: edit,
revoke_message_local_content: ''
} as RevokeMessageExtension
revokeMsg.localExtension = JSON.stringify(localExtension)
console.debug('netease saveLocalRevokeMessageFormOther:', revokeMsg.localExtension)
let createTime = msgNotify.messageRefer.createTime + 10;
ChatRepo.saveLocalMessage(revokeMsg, conversationId, msgNotify.revokeAccountId, createTime)
}

View File

@ -0,0 +1,18 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
import { V2NIMTeam } from '@nimsdk/base';
const discussTeamKey = "im_ui_kit_group" // 讨论组识别关键字
/// 判断是否是讨论组
export function IsDiscussion(team?: V2NIMTeam) {
if (team?.serverExtension && team.serverExtension.includes(discussTeamKey)) {
return true
}
return false
}

View File

@ -0,0 +1,11 @@
{
"module": {
"name": "chatkit",
"type": "har",
"deviceTypes": [
"default",
"tablet",
"2in1"
]
}
}

View File

@ -0,0 +1,76 @@
{
"string": [
{
"name": "unknown_error",
"value": "未知错误"
},
{
"name": "chat_network_error_tips",
"value": "当前网络不可用,请检查你的网络设置。"
},
{
"name": "chat_pin_limit_error_tips",
"value": "PIN消息已达最大限制"
},
{
"name": "chat_collection_limit_error_tips",
"value": "收藏数已达到限制值"
},
{
"name": "chatMessageNonsupportType",
"value": "[当前版本暂不支持该消息体]"
},
{
"name": "audioMessageType",
"value": "[语音消息]"
},
{
"name": "imageMessageType",
"value": "[图片消息]"
},
{
"name": "videoMessageType",
"value": "[视频消息]"
},
{
"name": "locationMessageType",
"value": "[地理位置]"
},
{
"name": "fileMessageType",
"value": "[文件消息]"
},
{
"name": "notificationMessageType",
"value": "[通知消息]"
},
{
"name": "tipMessageType",
"value": "[提醒消息]"
},
{
"name": "chatHistoryBrief",
"value": "聊天记录"
},
{
"name": "msg_type_rtc_video",
"value": "[视频通话]"
},
{
"name": "msg_type_rtc_audio",
"value": "[语音通话]"
},
{
"name": "msg_send_failed_in_block",
"value": "对方已将你拉黑,发送消息失败"
},
{
"name": "msg_send_failed_no_friend",
"value": "双方好友关系已解除,如需沟通,请申请"
},
{
"name": "msg_send_failed_friend_application",
"value": "好友验证"
}
]
}

View File

@ -0,0 +1,76 @@
{
"string": [
{
"name": "unknown_error",
"value": "Unknown error"
},
{
"name": "chat_network_error_tips",
"value": "network error"
},
{
"name": "chat_pin_limit_error_tips",
"value": "PIN Message Limit reached"
},
{
"name": "chat_collection_limit_error_tips",
"value": "Collection Message Limit reached"
},
{
"name": "chatMessageNonsupportType",
"value": "[Nonsupport Message]"
},
{
"name": "audioMessageType",
"value": "[Audio Message]"
},
{
"name": "imageMessageType",
"value": "[Image Message]"
},
{
"name": "videoMessageType",
"value": "[Video Message]"
},
{
"name": "locationMessageType",
"value": "[Location Message]"
},
{
"name": "fileMessageType",
"value": "[File Message]"
},
{
"name": "notificationMessageType",
"value": "[Notification Message]"
},
{
"name": "tipMessageType",
"value": "[Tip Message]"
},
{
"name": "chatHistoryBrief",
"value": "Chat History"
},
{
"name": "msg_type_rtc_video",
"value": "[Video Chat]"
},
{
"name": "msg_type_rtc_audio",
"value": "[Audio Chat]"
},
{
"name": "msg_send_failed_in_block",
"value": "The other party has blocked you, message sending failed"
},
{
"name": "msg_send_failed_no_friend",
"value": "The relationship between both parties has been terminated, please "
},
{
"name": "msg_send_failed_friend_application",
"value": "reapply for contact"
}
]
}

View File

@ -0,0 +1,76 @@
{
"string": [
{
"name": "unknown_error",
"value": "未知错误"
},
{
"name": "chat_network_error_tips",
"value": "当前网络不可用,请检查你的网络设置。"
},
{
"name": "chat_pin_limit_error_tips",
"value": "PIN消息已达最大限制"
},
{
"name": "chat_collection_limit_error_tips",
"value": "收藏数已达到限制值"
},
{
"name": "chatMessageNonsupportType",
"value": "[当前版本暂不支持该消息体]"
},
{
"name": "audioMessageType",
"value": "[语音消息]"
},
{
"name": "imageMessageType",
"value": "[图片消息]"
},
{
"name": "videoMessageType",
"value": "[视频消息]"
},
{
"name": "locationMessageType",
"value": "[地理位置]"
},
{
"name": "fileMessageType",
"value": "[文件消息]"
},
{
"name": "notificationMessageType",
"value": "[通知消息]"
},
{
"name": "tipMessageType",
"value": "[提醒消息]"
},
{
"name": "chatHistoryBrief",
"value": "聊天记录"
},
{
"name": "msg_type_rtc_video",
"value": "[视频通话]"
},
{
"name": "msg_type_rtc_audio",
"value": "[语音通话]"
},
{
"name": "msg_send_failed_in_block",
"value": "对方已将你拉黑,发送消息失败"
},
{
"name": "msg_send_failed_no_friend",
"value": "双方好友关系已解除,如需沟通,请申请"
},
{
"name": "msg_send_failed_friend_application",
"value": "好友验证"
}
]
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
import { hilog } from '@kit.PerformanceAnalysisKit';
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from '@ohos/hypium';
export default function abilityTest() {
describe('ActsAbilityTest', () => {
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
beforeAll(() => {
// Presets an action, which is performed only once before all test cases of the test suite start.
// This API supports only one parameter: preset action function.
})
beforeEach(() => {
// Presets an action, which is performed before each unit test case starts.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: preset action function.
})
afterEach(() => {
// Presets a clear action, which is performed after each unit test case ends.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: clear action function.
})
afterAll(() => {
// Presets a clear action, which is performed after all test cases of the test suite end.
// This API supports only one parameter: clear action function.
})
it('assertContain', 0, () => {
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
hilog.info(0x0000, 'testTag', '%{public}s', 'it begin');
let a = 'abc';
let b = 'b';
// Defines a variety of assertion methods, which are used to declare expected boolean conditions.
expect(a).assertContain(b);
expect(a).assertEqual(a);
})
})
}

View File

@ -0,0 +1,12 @@
/*
* Copyright (c) 2022 NetEase, Inc. All rights reserved.
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
*
*/
import abilityTest from './Ability.test';
export default function testsuite() {
abilityTest();
}

View File

@ -0,0 +1,13 @@
{
"module": {
"name": "chatkit_test",
"type": "feature",
"deviceTypes": [
"default",
"tablet",
"2in1"
],
"deliveryWithInstall": true,
"installationFree": false
}
}

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