diff --git a/IntentsKitNewsUpdate/Application/.gitignore b/IntentsKitNewsUpdate/Application/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..d2ff20141ceed86d87c0ea5d99481973005bab2b --- /dev/null +++ b/IntentsKitNewsUpdate/Application/.gitignore @@ -0,0 +1,12 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test +/.appanalyzer \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/AppScope/app.json5 b/IntentsKitNewsUpdate/Application/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..67d6d976d35277eb9022b6138e3b1c6247cfcff7 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/AppScope/app.json5 @@ -0,0 +1,10 @@ +{ + "app": { + "bundleName": "com.example.intentnewsrecommend", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:layered_image", + "label": "$string:app_name" + } +} diff --git a/IntentsKitNewsUpdate/Application/AppScope/resources/base/element/string.json b/IntentsKitNewsUpdate/Application/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..790f340fbcb94873023ab2456311569869a70c08 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "IntentKitNewsDemo" + } + ] +} diff --git a/IntentsKitNewsUpdate/Application/AppScope/resources/base/media/background.png b/IntentsKitNewsUpdate/Application/AppScope/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f Binary files /dev/null and b/IntentsKitNewsUpdate/Application/AppScope/resources/base/media/background.png differ diff --git a/IntentsKitNewsUpdate/Application/AppScope/resources/base/media/foreground.png b/IntentsKitNewsUpdate/Application/AppScope/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..97014d3e10e5ff511409c378cd4255713aecd85f Binary files /dev/null and b/IntentsKitNewsUpdate/Application/AppScope/resources/base/media/foreground.png differ diff --git a/IntentsKitNewsUpdate/Application/AppScope/resources/base/media/layered_image.json b/IntentsKitNewsUpdate/Application/AppScope/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/IntentsKitNewsUpdate/Application/AppScope/resources/base/media/layered_image.json @@ -0,0 +1,7 @@ +{ + "layered-image": + { + "background" : "$media:background", + "foreground" : "$media:foreground" + } +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/AppScope/resources/rawfile/schema.json b/IntentsKitNewsUpdate/Application/AppScope/resources/rawfile/schema.json new file mode 100644 index 0000000000000000000000000000000000000000..3d8d48f5a669eaa15e8a3fa0315aec494cd13118 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/AppScope/resources/rawfile/schema.json @@ -0,0 +1,145 @@ +{ + "schemaVersion":3, + "objectTypes":[ + { + "objectTypeName":"News", + "fields":[ + { + "fieldName":"newsId", + "fieldType":"LongAutoIncrement", + "belongPrimaryKey":true, + "notNull":true, + "isNeedEncrypt":false, + "isSensitive":false + }, + { + "fieldName":"title", + "fieldType":"String", + "belongPrimaryKey":false, + "notNull":true, + "isNeedEncrypt":false, + "isSensitive":false, + "defaultValue":"" + }, + { + "fieldName":"content", + "fieldType":"Text", + "belongPrimaryKey":false, + "notNull":true, + "isNeedEncrypt":false, + "isSensitive":false, + "defaultValue":"" + }, + { + "fieldName":"newsType", + "fieldType":"String", + "belongPrimaryKey":false, + "notNull":true, + "isNeedEncrypt":false, + "isSensitive":false, + "defaultValue":"图文" + }, + { + "fieldName":"pubUserName", + "fieldType":"String", + "belongPrimaryKey":false, + "notNull":false, + "isNeedEncrypt":false, + "isSensitive":false + }, + { + "fieldName":"pubUserAvatar", + "fieldType":"String", + "belongPrimaryKey":false, + "notNull":false, + "isNeedEncrypt":false, + "isSensitive":false + }, + { + "fieldName":"pubDate", + "fieldType":"Date", + "belongPrimaryKey":false, + "notNull":false, + "isNeedEncrypt":false, + "isSensitive":false + }, + { + "fieldName":"viewCount", + "fieldType":"Integer", + "belongPrimaryKey":false, + "notNull":false, + "isNeedEncrypt":false, + "isSensitive":false + } + ], + "indexes":[ + { + "indexName":"view_count_index", + "indexList":[ + { + "fieldName":"viewCount", + "sortType":"DESC" + } + ] + }, + { + "indexName":"news_id_index", + "indexList":[ + { + "fieldName":"newsId", + "sortType":"ASC" + } + ] + }, + { + "indexName":"pub_date_index", + "indexList":[ + { + "fieldName":"pubDate", + "sortType":"DESC" + } + ] + } + ] + } + ], + "permissions":[ + { + "objectTypeName":"News", + "permissions":[ + { + "role":"World", + "rights":[ + "Read", + "Upsert", + "Delete" + ] + }, + { + "role":"Authenticated", + "rights":[ + "Read", + "Upsert", + "Delete" + ] + }, + { + "role":"Creator", + "rights":[ + "Read", + "Upsert", + "Delete" + ] + }, + { + "role":"Administrator", + "rights":[ + "Read", + "Upsert", + "Delete" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/build-profile.json5 b/IntentsKitNewsUpdate/Application/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..59bb60f29216721afbddbbb925bba0fb4356309a --- /dev/null +++ b/IntentsKitNewsUpdate/Application/build-profile.json5 @@ -0,0 +1,46 @@ +{ + "app": { + "signingConfigs": [], + "products": [ + { + "name": "default", + "signingConfig": "default", + "targetSdkVersion": "5.0.5(17)", + "compatibleSdkVersion": "5.0.5(17)", + "runtimeOS": "HarmonyOS", + "buildOption": { + "strictMode": { + "caseSensitiveCheck": true, + "useNormalizedOHMUrl": true + } + } + } + ], + "buildModeSet": [ + { + "name": "debug", + }, + { + "name": "release" + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + }, + { + "name": "cloud_objects", + "srcPath": "./cloud_objects" + } + ] +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/cloud_objects/BuildProfile.ets b/IntentsKitNewsUpdate/Application/cloud_objects/BuildProfile.ets new file mode 100644 index 0000000000000000000000000000000000000000..6033e79a01b85a7b72e746eb3c8eba704e312bd5 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/cloud_objects/BuildProfile.ets @@ -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 = '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; +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/cloud_objects/Index.ets b/IntentsKitNewsUpdate/Application/cloud_objects/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..2b0040ba8508c6ebfd470a2f7b865be59c6567c6 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/cloud_objects/Index.ets @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { importObject } from './src/main/ets/ImportObject'; +export { IdGenerator } from './src/main/ets/id-generator/IdGenerator'; +export { NewsService } from './src/main/ets/news-service/NewsService'; \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/cloud_objects/build-profile.json5 b/IntentsKitNewsUpdate/Application/cloud_objects/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..29eaaf26bcc4aca8ab02a27e2e546cf3f02928d4 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/cloud_objects/build-profile.json5 @@ -0,0 +1,12 @@ +{ + "apiType": "stageMode", + "buildOption": { + }, + "buildOptionSet": [ + ], + "targets": [ + { + "name": "default" + } + ] +} diff --git a/IntentsKitNewsUpdate/Application/cloud_objects/hvigorfile.ts b/IntentsKitNewsUpdate/Application/cloud_objects/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..42187071482d292588ad40babeda74f7b8d97a23 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/cloud_objects/hvigorfile.ts @@ -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. */ +} diff --git a/IntentsKitNewsUpdate/Application/cloud_objects/oh-package.json5 b/IntentsKitNewsUpdate/Application/cloud_objects/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..8d9045a5df27af47826e627e10b3dd0fe6a89ae8 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/cloud_objects/oh-package.json5 @@ -0,0 +1,9 @@ +{ + "name": "cloud_objects", + "version": "1.0.0", + "description": "This module is generated when the '[CloudDev]Empty ability' template is created. When a cloud object performs the 'Generate Invoke Interface' action, the invoked interface is generated in this module by default. For details, see https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/agc-harmonyos-clouddev-invokecloudobj-V5#section1143116149286.", + "author": "", + "main": "Index.ets", + "license": "Apache-2.0", + "dependencies": {} +} diff --git a/IntentsKitNewsUpdate/Application/cloud_objects/src/main/ets/ImportObject.ts b/IntentsKitNewsUpdate/Application/cloud_objects/src/main/ets/ImportObject.ts new file mode 100644 index 0000000000000000000000000000000000000000..f577fabeb368e5cb06c057d160baf143cd23f8be --- /dev/null +++ b/IntentsKitNewsUpdate/Application/cloud_objects/src/main/ets/ImportObject.ts @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { BusinessError } from '@kit.BasicServicesKit'; +import { cloudFunction } from '@kit.CloudFoundationKit'; + +export interface CloudObjectLikely { + name: string; +} + +function mockMethod(target: T, version: string, + prop: string | symbol): (...args: unknown[]) => Promise { + return async (...args: unknown[]) => new Promise((resolve, reject) => { + cloudFunction.call({ + name: target.name, + version: version, + data: { + method: prop, + params: args + } + }).then((value: cloudFunction.FunctionResult) => { + resolve(value.result); + }).catch((err: BusinessError) => { + reject(err); + }); + }); +} + +export function importObject(tClass: new () => T, version = '$latest'): T { + return new Proxy(new tClass(), { + get(target, prop): (...args: unknown[]) => Promise { + return mockMethod(target, version, prop); + } + }); +} diff --git a/IntentsKitNewsUpdate/Application/cloud_objects/src/main/ets/id-generator/IdGenerator.ts b/IntentsKitNewsUpdate/Application/cloud_objects/src/main/ets/id-generator/IdGenerator.ts new file mode 100644 index 0000000000000000000000000000000000000000..d3d2c05b258dddb563c527f8ba81c19ed116e98f --- /dev/null +++ b/IntentsKitNewsUpdate/Application/cloud_objects/src/main/ets/id-generator/IdGenerator.ts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { CloudObjectLikely } from '../ImportObject'; + +export class IdGenerator implements CloudObjectLikely { + public name = 'id-generator'; + public async randomUUID(): Promise<{ + uuid: `${string}-${string}-${string}-${string}-${string}`; + }> { + return Promise.reject(new Error('Method not implemented.')); + } +} + diff --git a/IntentsKitNewsUpdate/Application/cloud_objects/src/main/ets/news-service/NewsService.ts b/IntentsKitNewsUpdate/Application/cloud_objects/src/main/ets/news-service/NewsService.ts new file mode 100644 index 0000000000000000000000000000000000000000..001e552e978ea0e0bf3594e9453aaf158dcf6b3f --- /dev/null +++ b/IntentsKitNewsUpdate/Application/cloud_objects/src/main/ets/news-service/NewsService.ts @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { CloudObjectLikely } from '../ImportObject'; + +export class NewsService implements CloudObjectLikely { + public name = 'news-service'; + public async shareIntent(): Promise<{ + intentName: string; + intentVersion: string; + identifier: `${string}-${string}-${string}-${string}-${string}`; + intentEntityInfo: { + entityName: string; + entityId: string; + eventImage: string; + columnTitle: string; + blogTitle: string; + availableBeginTime: string; + availableEndTime: string; + }; + }> { + return Promise.reject(new Error('Method not implemented.')); + } +} + diff --git a/IntentsKitNewsUpdate/Application/cloud_objects/src/main/module.json5 b/IntentsKitNewsUpdate/Application/cloud_objects/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..08c995ec9ce1ff1f146df45827a3cb4324ecbfcb --- /dev/null +++ b/IntentsKitNewsUpdate/Application/cloud_objects/src/main/module.json5 @@ -0,0 +1,11 @@ +{ + "module": { + "name": "cloud_objects", + "type": "har", + "deviceTypes": [ + "default", + "tablet", + "2in1" + ] + } +} diff --git a/IntentsKitNewsUpdate/Application/code-linter.json5 b/IntentsKitNewsUpdate/Application/code-linter.json5 new file mode 100644 index 0000000000000000000000000000000000000000..073990fa45394e1f8e85d85418ee60a8953f9b99 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/code-linter.json5 @@ -0,0 +1,32 @@ +{ + "files": [ + "**/*.ets" + ], + "ignore": [ + "**/src/ohosTest/**/*", + "**/src/test/**/*", + "**/src/mock/**/*", + "**/node_modules/**/*", + "**/oh_modules/**/*", + "**/build/**/*", + "**/.preview/**/*" + ], + "ruleSet": [ + "plugin:@performance/recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + "@security/no-unsafe-aes": "error", + "@security/no-unsafe-hash": "error", + "@security/no-unsafe-mac": "warn", + "@security/no-unsafe-dh": "error", + "@security/no-unsafe-dsa": "error", + "@security/no-unsafe-ecdsa": "error", + "@security/no-unsafe-rsa-encrypt": "error", + "@security/no-unsafe-rsa-sign": "error", + "@security/no-unsafe-rsa-key": "error", + "@security/no-unsafe-dsa-key": "error", + "@security/no-unsafe-dh-key": "error", + "@security/no-unsafe-3des": "error" + } +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/.gitignore b/IntentsKitNewsUpdate/Application/entry/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/.gitignore @@ -0,0 +1,6 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/build-profile.json5 b/IntentsKitNewsUpdate/Application/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..4d611879c7913fb0610c686e2399258ab3a6dad1 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/build-profile.json5 @@ -0,0 +1,28 @@ +{ + "apiType": "stageMode", + "buildOption": { + }, + "buildOptionSet": [ + { + "name": "release", + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": false, + "files": [ + "./obfuscation-rules.txt" + ] + } + } + } + }, + ], + "targets": [ + { + "name": "default" + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/hvigorfile.ts b/IntentsKitNewsUpdate/Application/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..c6edcd90486dd5a853cf7d34c8647f08414ca7a3 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/hvigorfile.ts @@ -0,0 +1,6 @@ +import { hapTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/IntentsKitNewsUpdate/Application/entry/obfuscation-rules.txt b/IntentsKitNewsUpdate/Application/entry/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..62b2522b2882ad3a00a9268511c0a305a53efe49 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/obfuscation-rules.txt @@ -0,0 +1,26 @@ +# 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 + +-keep +XXX/oh_modules/@hw-agconnect/auth \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/oh-package-lock.json5 b/IntentsKitNewsUpdate/Application/entry/oh-package-lock.json5 new file mode 100644 index 0000000000000000000000000000000000000000..f74e8c3ee3ddd587e9c6a562a795d63f6bbc5b45 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/oh-package-lock.json5 @@ -0,0 +1,18 @@ +{ + "meta": { + "stableOrder": true + }, + "lockfileVersion": 3, + "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", + "specifiers": { + "cloud_objects@../cloud_objects": "cloud_objects@../cloud_objects" + }, + "packages": { + "cloud_objects@../cloud_objects": { + "name": "cloud_objects", + "version": "1.0.0", + "resolved": "../cloud_objects", + "registryType": "local" + } + } +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/oh-package.json5 b/IntentsKitNewsUpdate/Application/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..c6aed1c8bae97f6562e9fd5555b111394365145a --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/oh-package.json5 @@ -0,0 +1,12 @@ +{ + "license": "", + "devDependencies": {}, + "author": "", + "name": "entry", + "description": "Please describe the basic information.", + "main": "", + "version": "1.0.0", + "dependencies": { + "cloud_objects": "file:../cloud_objects" + } +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/ets/clouddb/news/News.ts b/IntentsKitNewsUpdate/Application/entry/src/main/ets/clouddb/news/News.ts new file mode 100644 index 0000000000000000000000000000000000000000..7e3b43193a232fe0cd7314175267ef55708ea23f --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/src/main/ets/clouddb/news/News.ts @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { cloudDatabase } from '@kit.CloudFoundationKit'; + +class News extends cloudDatabase.DatabaseObject { + public newsId: number; + public title = ''; + public content = ''; + public newsType = '图文'; + public pubUserName: string; + public pubUserAvatar: string; + public pubDate: Date; + public viewCount: number; + + public naturalbase_ClassName(): string { + return 'News'; + } +} + +export { News }; \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/ets/clouddb/news/NewsDb.ets b/IntentsKitNewsUpdate/Application/entry/src/main/ets/clouddb/news/NewsDb.ets new file mode 100644 index 0000000000000000000000000000000000000000..75065a770ae78ab19d9989cd47f12b6f9cce9f11 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/src/main/ets/clouddb/news/NewsDb.ets @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { cloudDatabase } from '@kit.CloudFoundationKit'; +import CloudDatabaseConstants from '../../common/constants/CloudDatabaseConstants'; +import Logger from '../../common/utils/Logger'; +import { News } from './News'; + +const TAG = '[NewsDB]'; +const agcDataBase: cloudDatabase.DatabaseZone = cloudDatabase.zone(CloudDatabaseConstants.DEFAULT_ZONE); + +class NewsDB { + + private allRecords: News[] = []; + + getNewsList() { + return this.queryRecord(new cloudDatabase.DatabaseQuery(News).orderByDesc('pubDate')); + } + + getNewsByNewsId(newsId: string) { + if (!newsId) { + return Promise.resolve(null); + } + return this.queryRecord(new cloudDatabase.DatabaseQuery(News).equalTo("newsId", Number(newsId))); + } + + getNewsByNewsType(newsType: string) { + return this.queryRecord(new cloudDatabase.DatabaseQuery(News).orderByDesc('pubDate').equalTo("newsType", newsType)); + } + + orderByViewCount() { + return this.queryRecord(new cloudDatabase.DatabaseQuery(News).orderByDesc('viewCount')); + } + + private queryRecord(condition: cloudDatabase.DatabaseQuery): Promise { + return new Promise((resolve, reject) => { + agcDataBase.query(condition).then(result => { + Logger.showInfo(TAG, 'query success : %{public}s', JSON.stringify(result)); + this.allRecords = result; + resolve(result); + }).catch((err: Error) => { + Logger.showError(TAG, 'queryRecord err %{public}s', JSON.stringify(err)); + reject([]); + }); + }) + + } + + updateNewsViewCount(item: News) { + let viewCount: number = item.viewCount; + viewCount++; + item.viewCount = viewCount; + + agcDataBase.upsert(item).then(() => { + this.allRecords = this.allRecords.map((record: News) => { + if (record.newsId === item.newsId) { + Logger.showInfo(TAG, 'record: %{public}s', JSON.stringify(record)); + record.viewCount = item.viewCount; + } + return record; + }); + }).catch((err: Error) => { + Logger.showError(TAG, 'upsert err %{public}s', JSON.stringify(err)); + }); + } +} + +let db = new NewsDB(); +export default db; \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/ets/common/constants/CloudDatabaseConstants.ets b/IntentsKitNewsUpdate/Application/entry/src/main/ets/common/constants/CloudDatabaseConstants.ets new file mode 100644 index 0000000000000000000000000000000000000000..005b6e752a0cb0b411f7d015048896fb653932a4 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/src/main/ets/common/constants/CloudDatabaseConstants.ets @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export default class CloudDatabaseConstants { + static readonly DEFAULT_ZONE = "News" +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/ets/common/constants/CommonConstants.ets b/IntentsKitNewsUpdate/Application/entry/src/main/ets/common/constants/CommonConstants.ets new file mode 100644 index 0000000000000000000000000000000000000000..02397a094585e76f9c681185f430ef51b657d6e2 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/src/main/ets/common/constants/CommonConstants.ets @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export default class CommonConstants { + /** + * intent execute event name + */ + static readonly VIEW_NEWS_EVENT: string = 'viewNewsEvent'; + /** + * intent execute event name + */ + static readonly STORAGE_KEY: string = 'entityId'; + /** + * route path + */ + static readonly NEWS_DETAIL_PATH_NAME = "NewsDetail"; +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/ets/common/utils/Logger.ets b/IntentsKitNewsUpdate/Application/entry/src/main/ets/common/utils/Logger.ets new file mode 100644 index 0000000000000000000000000000000000000000..3aa2c7130adc1d78dae113ed1154c4360451a220 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/src/main/ets/common/utils/Logger.ets @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import hilog from '@ohos.hilog'; + +const TAG = 'IntentsKitNews'; + +const DOMAIN = 0x001A; +const SYMBOL = " --> "; + +export default class Log { + /** + * Outputs info-level logs. + * + * @param tag Identifies the log tag. + * @param format Indicates the log format string. + * @param args Indicates the log parameters. + * @since 7 + */ + static showInfo(tag: string, format: string, ...args: string[]) { + if (Log.isLoggable(tag, hilog.LogLevel.INFO)) { + hilog.info(DOMAIN, TAG, tag + SYMBOL + format, args); + } + } + + /** + * Outputs debug-level logs. + * + * @param tag Identifies the log tag. + * @param format Indicates the log format string. + * @param args Indicates the log parameters. + * @since 7 + */ + static showDebug(tag: string, format: string, ...args: string[]) { + if (Log.isLoggable(tag, hilog.LogLevel.DEBUG)) { + hilog.debug(DOMAIN, TAG, tag + SYMBOL + format, args); + } + } + + /** + * Outputs warning-level logs. + * + * @param tag Identifies the log tag. + * @param format Indicates the log format string. + * @param args Indicates the log parameters. + * @since 7 + */ + static showWarn(tag: string, format: string, ...args: string[]) { + if (Log.isLoggable(tag, hilog.LogLevel.WARN)) { + hilog.warn(DOMAIN, TAG, tag + SYMBOL + format, args); + } + } + + /** + * Outputs error-level logs. + * + * @param tag Identifies the log tag. + * @param format Indicates the log format string. + * @param args Indicates the log parameters. + * @since 7 + */ + static showError(tag: string, format: string, ...args: string[]) { + if (Log.isLoggable(tag, hilog.LogLevel.ERROR)) { + hilog.error(DOMAIN, TAG, tag + SYMBOL + format, args); + } + } + + /** + * Outputs fatal-level logs. + * + * @param tag Identifies the log tag. + * @param format Indicates the log format string. + * @param args Indicates the log parameters. + * @since 7 + */ + static showFatal(tag: string, format: string, ...args: string[]) { + if (Log.isLoggable(tag, hilog.LogLevel.FATAL)) { + hilog.fatal(DOMAIN, TAG, tag + SYMBOL + format, args); + } + } + + /** + * Checks whether logs of the specified tag, and level can be printed. + * + * @param tag Identifies the log tag. + * @param level log level + * @since 7 + */ + private static isLoggable(tag:string, level: hilog.LogLevel): boolean { + return hilog.isLoggable(DOMAIN, tag, level); + } +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/ets/common/utils/Utils.ets b/IntentsKitNewsUpdate/Application/entry/src/main/ets/common/utils/Utils.ets new file mode 100644 index 0000000000000000000000000000000000000000..ec3b1de82f3f04a8ed2783a101bfdaada9cf811a --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/src/main/ets/common/utils/Utils.ets @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { i18n } from '@kit.LocalizationKit'; + +export function formatRelativeTime(timestamp: number): string { + const now = Date.now(); + const diffInSeconds = Math.floor((now - timestamp) / 1000); + const isEn = i18n.System.getSystemLanguage() === "en-Latn-US"; + + // Define the unit of time and its corresponding number of seconds + const units: Array = [ + { + name: isEn ? 'year' : '年', + plural: isEn ? 'years' : '年', + seconds: 31536000 + }, + { + name: isEn ? 'month' : '个月', + plural: isEn ? 'months' : '个月', + seconds: 2592000 + }, + { + name: isEn ? 'day' : '天', + plural: isEn ? 'days' : '天', + seconds: 86400 + }, + { + name: isEn ? 'hour' : '小时', + plural: isEn ? 'hours' : '小时', + seconds: 3600 + }, + { + name: isEn ? 'minute' : '分钟', + plural: isEn ? 'minutes' : '分钟', + seconds: 60 + }, + { + name: isEn ? 'second' : '秒', + plural: isEn ? 'seconds' : '秒', + seconds: 1, + threshold: 10 + } + ]; + + // Special case: future time + if (diffInSeconds < 0) { + return isEn ? 'just now' : '刚刚'; + } + + // Find the most suitable time unit + for (const unit of units) { + const value = Math.floor(diffInSeconds / unit.seconds); + + if (value >= 1) { + // If there is a threshold and the difference is less than the threshold + if (unit.threshold !== undefined && diffInSeconds < unit.threshold) { + return isEn ? 'just now' : '刚刚'; + } + return isEn + ? `${value} ${value > 1 ? unit.plural : unit.name} ago` + : `${value}${unit.name}前`; + } + } + + // default return just now + return isEn ? 'just now' : '刚刚'; +} + +interface TimeUnit { + name: string; + plural: string; + seconds: number; + threshold?: number; +} + +/** + * Pad a number with leading zero to make it two digits + * @param num - Number to pad + * @returns Two-digit string + */ +function padZero(num: number): string { + return num.toString().padStart(2, '0'); +} + +/** + * Format Date object to "YYYY-MM-DD HH:mm:ss" string + * @param date - Date object to format + * @returns Formatted datetime string + * @throws {Error} When invalid Date object is provided + */ +export function formatDateTime(date: Date): string { + if (!(date instanceof Date) || isNaN(date.getTime())) { + throw new Error('Invalid Date object'); + } + + const year = date.getFullYear(); + const month = padZero(date.getMonth() + 1); + const day = padZero(date.getDate()); + const hours = padZero(date.getHours()); + const minutes = padZero(date.getMinutes()); + const seconds = padZero(date.getSeconds()); + + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/ets/entryability/EntryAbility.ets b/IntentsKitNewsUpdate/Application/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..b8174c0d8228b58cd9585332249085fa360f102e --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { window } from '@kit.ArkUI'; +import CommonConstants from '../common/constants/CommonConstants'; + +const HILOG_DOMAIN = 0x0000; +const TAG = '[EntryAbility]'; +let para: Record = { 'entityId': '' }; + +export default class EntryAbility extends UIAbility { + storage: LocalStorage = new LocalStorage(para); + + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { + this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); + if (launchParam.launchReason === AbilityConstant.LaunchReason.INSIGHT_INTENT && want && want.parameters) { + this.storage.setOrCreate(CommonConstants.STORAGE_KEY, + (want.parameters?.['ohos.insightIntent.executeParam.param'] as Record)?.entityId); + } + hilog.info(HILOG_DOMAIN, TAG, '%{public}s', 'Ability onCreate'); + } + + onDestroy(): void { + hilog.info(HILOG_DOMAIN, TAG, '%{public}s', 'Ability onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage): void { + // Main window is created, set main page for this ability + hilog.info(HILOG_DOMAIN, TAG, '%{public}s', 'Ability onWindowStageCreate'); + + windowStage.loadContent('pages/Index', this.storage, (err) => { + if (err.code) { + hilog.error(HILOG_DOMAIN, TAG, 'Failed to load the content. Cause: %{public}s', JSON.stringify(err)); + return; + } + hilog.info(HILOG_DOMAIN, TAG, 'Succeeded in loading the content.'); + }); + } + + onWindowStageDestroy(): void { + // Main window is destroyed, release UI related resources + hilog.info(HILOG_DOMAIN, TAG, '%{public}s', 'Ability onWindowStageDestroy'); + } + + onForeground(): void { + // Ability has brought to foreground + hilog.info(HILOG_DOMAIN, TAG, '%{public}s', 'Ability onForeground'); + } + + onBackground(): void { + // Ability has back to background + hilog.info(HILOG_DOMAIN, TAG, '%{public}s', 'Ability onBackground'); + } +} diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/ets/insightintents/IntentExecutorImpl.ets b/IntentsKitNewsUpdate/Application/entry/src/main/ets/insightintents/IntentExecutorImpl.ets new file mode 100644 index 0000000000000000000000000000000000000000..534bc9e75025245abe493ce9a791fd8cfbdbb28f --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/src/main/ets/insightintents/IntentExecutorImpl.ets @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { InsightIntentExecutor, insightIntent } from '@kit.AbilityKit'; +import { window } from '@kit.ArkUI'; +import { BusinessError } from '@kit.BasicServicesKit'; +import CommonConstants from '../common/constants/CommonConstants'; +import Logger from '../common/utils/Logger'; + +const TAG = `IntentExecutorImpl`; +/** + * Entry for insight intent execution. + */ +export default class IntentExecutorImpl extends InsightIntentExecutor { + + /** + * Called when a UIAbility executes the insight intent in the foreground. + * @param { string } intentName - Indicates the insight intent name. + * @param { Record } intentParam - Indicates the insight intent parameters. + * @param { window.WindowStage } pageLoader - Indicates the page loader. + * @returns { Promise } The result of insight intent execution. + */ + async onExecuteInUIAbilityForegroundMode(intentName: string, intentParam: Record, + pageLoader: window.WindowStage): Promise { + const result: insightIntent.ExecuteResult = { + code: 0 + }; + Logger.showInfo(TAG, `onExecuteInUIAbilityForegroundMode, intentName => ${intentName}, intentParam => ${JSON.stringify(intentParam)}`); + pageLoader.getMainWindow().then((windowClass: window.Window) => { + // emit intent execute event and entityId (game id) + windowClass.getUIContext().getHostContext()?.eventHub.emit(CommonConstants.VIEW_NEWS_EVENT, intentParam.entityId); + }).catch((err: BusinessError) => { + Logger.showError('intent executor', 'Failed to obtain the main window. Cause: ' + JSON.stringify(err)); + }) + return Promise.resolve(result); + } + + /** + * Called when a UIAbility executes the insight intent in the background. + * @param { string } intentName - Indicates the insight intent name. + * @param { Record } intentParam - Indicates the insight intent parameters. + * @returns { Promise } The result of insight intent execution. + */ + async onExecuteInUIAbilityBackgroundMode(intentName: string, intentParam: Record): + Promise { + Logger.showInfo(TAG, `onExecuteInUIAbilityForegroundMode, intentName => ${intentName}, intentParam => ${JSON.stringify(intentParam)}`); + const result: insightIntent.ExecuteResult = { + code: 0 + }; + return Promise.resolve(result); + } +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/ets/pages/Index.ets b/IntentsKitNewsUpdate/Application/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..ee00abd39636d76f955f0cb11e0fc5a2e45f4f58 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { common } from '@kit.AbilityKit'; +import { News } from '../clouddb/news/News'; +import newsDb from '../clouddb/news/NewsDb'; +import Logger from '../common/utils/Logger'; +import { formatRelativeTime } from '../common/utils/Utils'; +import CommonConstants from '../common/constants/CommonConstants'; +import { importObject, NewsService } from 'cloud_objects'; +import { insightIntent } from '@kit.IntentsKit'; +import { BusinessError } from '@kit.BasicServicesKit'; + +const TAG = "Home"; + +@Entry +@Component +struct Home { + pathStack: NavPathStack = new NavPathStack(); + private storage: LocalStorage | undefined = this.getUIContext().getSharedLocalStorage(); + private abilityContext: common.UIAbilityContext | undefined = + this.getUIContext().getHostContext() as common.UIAbilityContext; + @State currentTabIndex: number = 0; + @State newsTab: Resource[] = + [$r("app.string.home_tabs_one"), $r("app.string.home_tabs_two"), $r("app.string.home_tabs_three"), + $r("app.string.home_tabs_four"), $r("app.string.home_tabs_five")]; + private tabsController: TabsController = new TabsController(); + @State newsList: News[] = []; + + aboutToAppear(): void { + + // listen intent execute event + this.abilityContext?.eventHub.on(CommonConstants.VIEW_NEWS_EVENT, (entityId: string) => { + this.gotoViewNews(entityId) + }) + const newsType = this.getUIContext() + .getHostContext()?.resourceManager.getStringSync(this.newsTab[this.currentTabIndex].id) as string; + newsDb.getNewsByNewsType(newsType).then((ret) => { + this.newsList = ret; + }); + // cold start + if (this.storage?.get('entityId')) { + this.gotoViewNews(this.storage?.get('entityId') as string); + } + } + + build() { + Navigation(this.pathStack) { + Column() { + List({ space: 8 }) { + ForEach(this.newsTab, (item: string, index: number) => { + this.tabBuilder(item, index); + }, (item: string) => item) + }.height(56).width("100%").listDirection(Axis.Horizontal).scrollBar(BarState.Off) + + Tabs({ index: this.currentTabIndex, controller: this.tabsController }) { + ForEach(this.newsTab, (item: string, idx: number) => { + TabContent() { + List() { + if (this.newsList.length > 0) { + ForEach(this.newsList, (item: News) => { + ListItem() { + RelativeContainer() { + Column() { + Text(item.title) + .fontSize(16) + .fontWeight(FontWeight.Medium) + .lineHeight(23) + .textAlign(TextAlign.Start) + .maxLines(2) + .width("100%") + + Row() { + Text(`${item.pubUserName} ${formatRelativeTime(item.pubDate.getTime())}`) + .fontSize(12) + .fontColor('rgba(0,0,0,0.4)') + .fontWeight(FontWeight.Normal) + .lineHeight(16) + .textAlign(TextAlign.Start) + Text(":") + .textAlign(TextAlign.End) + .fontSize(12) + .lineHeight(14) + .fontColor('rgba(0,0,0,0.4)') + }.width("100%").justifyContent(FlexAlign.SpaceBetween) + } + .justifyContent(FlexAlign.SpaceBetween) + .height("100%") + .id("id_news_left_group") + .alignRules({ + top: { anchor: "__container__", align: VerticalAlign.Top }, + left: { anchor: "__container__", align: HorizontalAlign.Start }, + right: { anchor: "id_news_right_logo", align: HorizontalAlign.Start }, + bottom: { anchor: "__container__", align: VerticalAlign.Bottom } + }) + .margin({ right: 8 }) + + Image($r("app.media.sm_img")) + .width(108) + .height("100%") + .objectFit(ImageFit.Cover) + .borderRadius(4) + .id("id_news_right_logo") + .alignRules({ + top: { anchor: "__container__", align: VerticalAlign.Top }, + right: { anchor: "__container__", align: HorizontalAlign.End }, + bottom: { anchor: "__container__", align: VerticalAlign.Bottom } + }) + }.width("100%").height(81) + }.height(105) + .onClick(() => { + this.pathStack.pushPath({ name: "NewsDetail", param: item }); + }) + }, (item: News) => item.newsId.toString()) + } else { + ListItem() { + Text($r("app.string.home_no_content")) + .fontColor("rgba(0,0,0,0.6)") + .fontSize(15) + .fontWeight(FontWeight.Medium) + .margin({ top: 24 }) + .textAlign(TextAlign.Center) + .width("100%") + } + } + + }.width("100%").height("100%").listDirection(Axis.Vertical) + .margin({ top: 12 }) + } + }, (item: string) => item) + } + .barHeight(0) + .onChange((index: number) => { + this.currentTabIndex = index; + }) + } + .width("100%").height("100%") + .padding({ + top: 8, + bottom: 8, + left: 16, + right: 16 + }) + } + .title({ builder: this.titleBuilder(), height: 56 }) + } + + @Builder + titleBuilder() { + Column() { + Text($r("app.string.home_title")) + .fontSize(30) + .fontWeight(FontWeight.Bold) + .lineHeight(40) + .fontColor("rgba(0,0,0,0.9)") + .margin({ + left: 16, + right: 16, + top: 8, + bottom: 8 + }) + } + .height("100%") + } + + @Builder + tabBuilder(text: string, index: number) { + Column() { + Text(text) + .fontSize(14) + .lineHeight(19) + .fontWeight(FontWeight.Medium) + .fontColor(this.currentTabIndex === index ? '#FFFFFF' : 'rgba(0,0,0,0.9)') + .textAlign(TextAlign.Center) + .width(60) + .height(40) + .backgroundColor(this.currentTabIndex === index ? 'rgb(10,89,247)' : 'rgba(0,0,0,0.05)') + .borderRadius(20) + .onClick(() => { + this.tabsController.changeIndex(index); + const newsType = + this.getUIContext().getHostContext()?.resourceManager.getStringSync(this.newsTab[index].id) as string; + Logger.showInfo(TAG, `tab => ${JSON.stringify(newsType)}`); + newsDb.getNewsByNewsType(newsType).then((ret) => { + this.newsList = ret; + }); + }) + }.height("100%").justifyContent(FlexAlign.Center) + } + + gotoViewNews(entityId: string) { + if (entityId) { + newsDb.getNewsByNewsId(entityId).then((ret: null | News[]) => { + if (!ret) { + return; + } + this.pathStack.replacePathByName(CommonConstants.NEWS_DETAIL_PATH_NAME, (ret as News[])[0]); + }) + } + } + + private shareIntent() { + const newsService = importObject(NewsService); + newsService.shareIntent().then(result => { + const intent: ESObject = { + intentName: result.intentName, + intentVersion: result.intentVersion, + identifier: result.identifier, + intentEntityInfo: { + entityName: result.intentEntityInfo.entityName, + entityId: result.intentEntityInfo.entityId, + eventImage: result.intentEntityInfo.eventImage, + columnTitle: result.intentEntityInfo.columnTitle, + blogTitle: result.intentEntityInfo.blogTitle, + blogType: "图文", + blogPublishTime: new Date().getTime(), + availableBeginTime: result.intentEntityInfo.availableBeginTime, + availableEndTime: result.intentEntityInfo.availableEndTime, + } as insightIntent.IntentEntityInfo, + } + Logger.showInfo(TAG, `intent => ${JSON.stringify(intent)}`); + insightIntent.shareIntent(this.getUIContext().getHostContext(), [intent]).then(() => { + Logger.showInfo(TAG, `shareIntent succeed`); + }).catch((err: BusinessError) => { + Logger.showError(TAG, `error.code: ${err?.code}, failed because ${err.message}`); + }); + }).catch((err: BusinessError) => { + Logger.showError(TAG, 'call id-generator exception, ErrCode: %{public}d ErrMessage: %{public}s', + err.code.toString(), err.message); + }); + } +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/ets/pages/NewsDetail.ets b/IntentsKitNewsUpdate/Application/entry/src/main/ets/pages/NewsDetail.ets new file mode 100644 index 0000000000000000000000000000000000000000..0af24ef155dc1529dd58da3e8818954ec13740d4 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/src/main/ets/pages/NewsDetail.ets @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { insightIntent } from "@kit.IntentsKit"; +import { BusinessError } from "@kit.BasicServicesKit"; +import { IdGenerator, importObject } from 'cloud_objects'; +import { News } from "../clouddb/news/News"; +import { formatDateTime } from "../common/utils/Utils"; +import Logger from "../common/utils/Logger"; + +@Builder +export function NewsDetailBuilder() { + NewsDetail() +} + +const TAG = 'NewsDetail'; + +@Preview +@Component +export struct NewsDetail { + pathStack: NavPathStack = new NavPathStack(); + @State currentNews: News | undefined = undefined; + + build() { + NavDestination() { + Row() { + Text(this.currentNews?.title) + .fontSize(24) + .fontWeight(700) + .lineHeight(32) + .letterSpacing(0.2) + .textAlign(TextAlign.Start) + .maxLines(2) + .width("100%") + }.width("100%").height(64) + .padding({ left: 16, right: 16 }) + .margin({ top: 8}) + + Row() { + Row() { + // avatar + Image($r("app.media.avatar")) + .aspectRatio(1) + .size({ width: 32, height: 32}) + .border({ + width: 0.22, + color: 'rgba(0, 0, 0, 0.05)', + style: BorderStyle.Solid, + radius: 20 + }).margin({ top: 12, bottom: 12, right: 10}) + + Flex({ justifyContent: FlexAlign.SpaceBetween, direction: FlexDirection.Column}) { + Text(this.currentNews?.pubUserName) + .fontColor(Color.Black) + .fontSize(14) + .fontWeight(FontWeight.Medium) + .lineHeight(19) + .letterSpacing(0) + .textAlign(TextAlign.Start) + .align(Alignment.Start) + Text(`${formatDateTime(this.currentNews?.pubDate)} - ${this.currentNews?.pubUserName}官方帐号`) + .fontColor('rgba(0, 0, 0, 0.4)') + .fontSize(10) + .lineHeight(14) + .letterSpacing(0) + .textAlign(TextAlign.Start).margin({top: 0.5}) + }.height(33.5) + } + + Button({ stateEffect: true}) { + Row() { + SymbolGlyph($r("sys.symbol.plus")) + .fontSize(9) + .width(9).height(9) + .fontWeight(FontWeight.Medium) + .fontColor(["rgb(10, 89, 247)"]) + .margin({ right: 3.5}) + Text("关注") + .fontColor("rgb(10, 89, 247)") + .fontSize(12) + .fontWeight(FontWeight.Medium) + .lineHeight(16) + .letterSpacing(0) + .textAlign(TextAlign.Center) + }.alignItems(VerticalAlign.Center) + }.width(64).height(28).borderRadius(14).backgroundColor("rgba(0, 0, 0, 0.05)") + .margin({ top: 14, bottom: 14}) + }.justifyContent(FlexAlign.SpaceBetween) + .width("100%").height(56) + .padding({ left: 16, right: 16 }) + .margin({ top: 8}) + + Column(){ + Text(undefined) { + Span(this.currentNews?.content) + ImageSpan($r("app.media.sm_img")) + .width('100%') + .objectFit(ImageFit.Contain) + .verticalAlign(ImageSpanAlignment.BOTTOM) + .margin({top: 24}).borderRadius(8) + } + .width("100%") + .fontSize(17) + .fontWeight(FontWeight.Normal) + .lineHeight(25.6) + .textAlign(TextAlign.Start) + }.margin({ top: 8}) + .width("100%").height("100%") + .padding({ left: 16, right: 16}) + } + .title({ builder: this.navigationTitle($r("app.string.news_detail_title")), height: 56}) + .onReady(async (context: NavDestinationContext) => { + this.pathStack = context.pathStack; + this.currentNews = this.pathStack.getParamByIndex(0) as News; + await this.shareIntent(this.currentNews); + }) + } + + @Builder + navigationTitle(content: ResourceStr) { + Text(content) + .fontColor("rgba(0,0,0,0.9)") + .fontSize(20) + .fontWeight(FontWeight.Bold) + .lineHeight(27) + .margin({ top: 14.5, left: 8, bottom: 14.5 }) + } + + async shareIntent(news: News) { + // share Intent + const uuid = await this.callIdGenerator(); + const date = new Date(); + let readNewsIntent: insightIntent.InsightIntent = { + intentName: "ViewBlog", + intentVersion: "1.0.1", + identifier: uuid, + intentActionInfo: { + actionMode: "EXECUTED", + executedTimeSlots: { + "executedStartTime": date.getTime(), + "executedEndTime": date.getTime() + 3000 + } + }, + intentEntityInfo: { + entityName: "Blog", + entityId: news.newsId.toString(), + displayName: news.title, + description: "这里是新闻的描述", + logoURL: "https://gitee.com/gorit/IntentsKitVideoContinue/blob/master/entry/src/main/resources/base/media/startIcon.png", + blogTitle: news.title, + blogType: "图文", + blogCategory: news.newsType, + categoryDisplayName: news.newsType + "资讯", + blogAuthor: news.pubUserName + } + } + + Logger.showInfo(TAG, `${JSON.stringify(readNewsIntent)}`); + insightIntent.shareIntent(this.getUIContext().getHostContext(), [readNewsIntent]).then(() => { + Logger.showInfo(TAG, `shareIntent succeed`); + }).catch((err: BusinessError) => { + Logger.showError(TAG, `error.code: ${err?.code}, failed because ${ err.message}`); + }); + + } + + private callIdGenerator(): Promise { + const idGenerator = importObject(IdGenerator); + return new Promise((resolve, reject) => { + idGenerator.randomUUID().then(result => { + resolve(result.uuid); + }).catch((err: BusinessError) => { + Logger.showError(TAG, 'call id-generator exception, ErrCode: %{public}d ErrMessage: %{public}s', + err.code.toString(), err.message); + reject(''); + }); + }); + } +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/module.json5 b/IntentsKitNewsUpdate/Application/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..1ac0db9a170a647cc3faccf8300577f2ff8d00db --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/src/main/module.json5 @@ -0,0 +1,42 @@ +{ + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "routerMap": "$profile:route_map", + "deviceTypes": [ + "phone" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "abilities": [ + { + "name": "EntryAbility", + "srcEntry": "./ets/entryability/EntryAbility.ets", + "description": "$string:entryability_desc", + "icon": "$media:layered_image", + "label": "$string:entryability_label", + "startWindowIcon": "$media:startIcon", + "startWindowBackground": "$color:white", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ], + "requestPermissions": [ + { + "name": "ohos.permission.INTERNET" + } + ] + } +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/element/color.json b/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..ba71337c0bf51cf1b475ca76aa622902cbbe5522 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/element/color.json @@ -0,0 +1,44 @@ +{ + "color": [ + { + "name": "white", + "value": "#ffffff" + }, + { + "name": "start_window_background", + "value": "#ffffff" + }, + { + "name": "action_button_background", + "value": "#169cd5" + }, + { + "name": "dialog_cancel_background", + "value": "#D9001B" + }, + { + "name": "black", + "value": "#000000" + }, + { + "name": "body_color", + "value": "#333333" + }, + { + "name": "placeholder_background", + "value": "#eeeeee" + }, + { + "name": "disabled_button_background", + "value": "#C2C2C2" + }, + { + "name": "border_color", + "value": "#FF9B9B9B" + }, + { + "name": "login_button", + "value": "#007DFF" + } + ] +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/element/float.json b/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/element/float.json new file mode 100644 index 0000000000000000000000000000000000000000..430d3249c5a5cbc9358d4f422602f03284dc9c70 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/element/float.json @@ -0,0 +1,88 @@ +{ + "float": [ + { + "name": "main_title_font_size", + "value": "25fp" + }, + { + "name": "navigation_font_size", + "value": "20fp" + }, + { + "name": "body_font_size", + "value": "15fp" + }, + { + "name": "list_item_font_size", + "value": "12fp" + }, + { + "name": "number_0", + "value": "0" + }, + { + "name": "number_1", + "value": "1" + }, + { + "name": "number_2", + "value": "2" + }, + { + "name": "number_5", + "value": "5" + }, + { + "name": "number_10", + "value": "10" + }, + { + "name": "number_15", + "value": "15" + }, + { + "name": "number_20", + "value": "20" + }, + { + "name": "number_75", + "value": "75" + }, + { + "name": "number_70", + "value": "70" + }, + { + "name": "number_25", + "value": "25" + }, + { + "name": "number_100", + "value": "100" + }, + { + "name": "number_40", + "value": "40" + }, + { + "name": "number_250", + "value": "250" + }, + { + "name": "number_30", + "value": "30" + }, + { + "name": "number_3", + "value": "3" + }, + { + "name": "number_0_5", + "value": "0.5" + }, + { + "name": "page_text_font_size", + "value": "50fp" + } + ] +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/element/string.json b/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..f7ed9e4d69d1af73f216d53930f61bf7eb1a644a --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/element/string.json @@ -0,0 +1,48 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "entryability_desc", + "value": "description" + }, + { + "name": "entryability_label", + "value": "IntentsKitNewsUpdate" + }, + { + "name": "home_title", + "value": "Home" + }, + { + "name": "home_no_content", + "value": "No Content" + }, + { + "name": "home_tabs_one", + "value": "Recd" + }, + { + "name": "home_tabs_two", + "value": "Sports" + }, + { + "name": "home_tabs_three", + "value": "Fin" + }, + { + "name": "home_tabs_four", + "value": "Tech" + }, + { + "name": "home_tabs_five", + "value": "Fiction" + }, + { + "name": "news_detail_title", + "value": "News detail" + } + ] +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/media/avatar.png b/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/media/avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..1ed0f6dbba731816486f05590c0277a71e4ce804 Binary files /dev/null and b/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/media/avatar.png differ diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/media/background.png b/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..f939c9fa8cc8914832e602198745f592a0dfa34d Binary files /dev/null and b/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/media/background.png differ diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/media/foreground.png b/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..4483ddad1f079e1089d685bd204ee1cfe1d01902 Binary files /dev/null and b/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/media/foreground.png differ diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/media/layered_image.json b/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/media/layered_image.json @@ -0,0 +1,7 @@ +{ + "layered-image": + { + "background" : "$media:background", + "foreground" : "$media:foreground" + } +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/media/sm_img.png b/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/media/sm_img.png new file mode 100644 index 0000000000000000000000000000000000000000..35fe759f7876704cfb6d91add134227a63c41e3c Binary files /dev/null and b/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/media/sm_img.png differ diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/media/startIcon.png b/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/media/startIcon.png differ diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/profile/insight_intent.json b/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/profile/insight_intent.json new file mode 100644 index 0000000000000000000000000000000000000000..441527a419222d52007c8f53ebe260c06e49bcbe --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/profile/insight_intent.json @@ -0,0 +1,28 @@ +{ + "insightIntents": [ + { + "domain": "NewsDomain", + "intentName": "ViewBlog", + "intentVersion": "1.0.1", + "srcEntry": "./ets/insightintents/IntentExecutorImpl.ets", + "uiAbility": { + "ability": "EntryAbility", + "executeMode": [ + "foreground" + ] + } + }, + { + "domain": "NewsDomain", + "intentName": "ViewColumnUpdate", + "intentVersion": "1.0.1", + "srcEntry": "./ets/insightintents/IntentExecutorImpl.ets", + "uiAbility": { + "ability": "EntryAbility", + "executeMode": [ + "foreground" + ] + } + } + ] +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/profile/main_pages.json b/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..55c3f007f87b7ce5206d325f968cc56f2f79441f --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,5 @@ +{ + "src": [ + "pages/Index" + ] +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/profile/route_map.json b/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/profile/route_map.json new file mode 100644 index 0000000000000000000000000000000000000000..a983ece627a61e5507b56ad7f922c37783ce5a83 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/profile/route_map.json @@ -0,0 +1,9 @@ +{ + "routerMap": [ + { + "name": "NewsDetail", + "pageSourceFile": "src/main/ets/pages/NewsDetail.ets", + "buildFunction": "NewsDetailBuilder" + } + ] +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/resources/dark/element/color.json b/IntentsKitNewsUpdate/Application/entry/src/main/resources/dark/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..6c7fd038cde7931dc6bbc3a8331042fbc8254c14 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/src/main/resources/dark/element/color.json @@ -0,0 +1,44 @@ +{ + "color": [ + { + "name": "white", + "value": "#ffffff" + }, + { + "name": "start_window_background", + "value": "#000000" + }, + { + "name": "action_button_background", + "value": "#169cd5" + }, + { + "name": "dialog_cancel_background", + "value": "#D9001B" + }, + { + "name": "black", + "value": "#000000" + }, + { + "name": "body_color", + "value": "#FFF5F1F1" + }, + { + "name": "placeholder_background", + "value": "#eeeeee" + }, + { + "name": "disabled_button_background", + "value": "#C2C2C2" + }, + { + "name": "border_color", + "value": "#FF9B9B9B" + }, + { + "name": "login_button", + "value": "#007DFF" + } + ] +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/resources/dark/element/float.json b/IntentsKitNewsUpdate/Application/entry/src/main/resources/dark/element/float.json new file mode 100644 index 0000000000000000000000000000000000000000..dfa4ba1b2e421a2f68b9695e2e5f485a86d56f99 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/src/main/resources/dark/element/float.json @@ -0,0 +1,84 @@ +{ + "float": [ + { + "name": "main_title_font_size", + "value": "25fp" + }, + { + "name": "navigation_font_size", + "value": "20fp" + }, + { + "name": "body_font_size", + "value": "15fp" + }, + { + "name": "list_item_font_size", + "value": "12fp" + }, + { + "name": "number_0", + "value": "0" + }, + { + "name": "number_1", + "value": "1" + }, + { + "name": "number_2", + "value": "2" + }, + { + "name": "number_5", + "value": "5" + }, + { + "name": "number_10", + "value": "10" + }, + { + "name": "number_15", + "value": "15" + }, + { + "name": "number_20", + "value": "20" + }, + { + "name": "number_75", + "value": "75" + }, + { + "name": "number_70", + "value": "70" + }, + { + "name": "number_25", + "value": "25" + }, + { + "name": "number_100", + "value": "100" + }, + { + "name": "number_40", + "value": "40" + }, + { + "name": "number_250", + "value": "250" + }, + { + "name": "number_30", + "value": "30" + }, + { + "name": "number_3", + "value": "3" + }, + { + "name": "number_0_5", + "value": "0.5" + } + ] +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/resources/dark/element/string.json b/IntentsKitNewsUpdate/Application/entry/src/main/resources/dark/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..43230fbfbe0937287185bbc49092ed2b6bc2e66c --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/src/main/resources/dark/element/string.json @@ -0,0 +1,252 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "entryability_desc", + "value": "description" + }, + { + "name": "entryability_label", + "value": "AGC Demo" + }, + { + "name": "cloudDB_label", + "value": "Cloud Database" + }, + { + "name": "tips_label", + "value": "Tips:" + }, + { + "name": "data_label", + "value": "Data:" + }, + { + "name": "publishButton_label", + "value": "Publish" + }, + { + "name": "popUpDesc_label", + "value": "Are you sure you want to delete?" + }, + { + "name": "deleteButton_label", + "value": "Delete" + }, + { + "name": "cloudStorage_label", + "value": "Cloud Storage" + }, + { + "name": "cancelButton_label", + "value": "Cancel" + }, + { + "name": "confirmButton_label", + "value": "Confirm" + }, + { + "name": "no_photo", + "value": "You don't have any images on your phone." + }, + { + "name": "cloudStorage_description_title", + "value": "Tips:" + }, + { + "name": "cloudStorage_uploadButton", + "value": "Upload Image" + }, + { + "name": "list_left_title", + "value": "My Posts" + }, + { + "name": "list_right_title", + "value": "Release Time" + }, + { + "name": "main_page_title", + "value": "Cloud Development" + }, + { + "name": "auth_service_title", + "value": "Auth Service" + }, + { + "name": "auth_result_name", + "value": "nickname" + }, + { + "name": "auth_service_description", + "value": "Secure and reliable user authentication system." + }, + { + "name": "auth_service_login_button_text", + "value": "Login" + }, + { + "name": "auth_service_logout_button_text", + "value": "Log out" + }, + { + "name": "auth_service_delete_user_button_text", + "value": "Delete User" + }, + { + "name": "auth_dialog_title", + "value": "Mobile verification code login" + }, + { + "name": "auth_dialog_number_placeholder", + "value": "phone number" + }, + { + "name": "auth_dialog_code_placeholder", + "value": "code" + }, + { + "name": "auth_dialog_get_code_button_text", + "value": "Get code" + }, + { + "name": "auth_dialog_auth_button_text", + "value": "Authorize" + }, + { + "name": "auth_result_user_id", + "value": "user id" + }, + { + "name": "auth_result_mobile_number", + "value": "mobile number" + }, + { + "name": "auth_result_avatar", + "value": "avatar" + }, + { + "name": "auth_result_registered", + "value": "registered" + }, + { + "name": "auth_result_last_login", + "value": "last login" + }, + { + "name": "cloud_function_title", + "value": "Cloud Functions" + }, + { + "name": "cloud_function_description_main", + "value": "Easy to run code without managing servers." + }, + { + "name": "cloud_function_description", + "value": "Tap to generate a global unique Cloud ID. Generated Cloud ID will be printed after tapping the button below." + }, + { + "name": "cloud_function_button_text", + "value": "Generate Global Unique ID" + }, + { + "name": "cloud_db_description_main", + "value": "Secure and trusted data management services." + }, + { + "name": "login_warning_title", + "value": "Auth Error" + }, + { + "name": "login_warning_message", + "value": "You must login to use this service" + }, + { + "name": "cloudDB_Publications", + "value": "New Posts" + }, + { + "name": "cloudDB_HighestHit", + "value": "Most Liked" + }, + { + "name": "cloudDB_SeeOnly", + "value": "My Posts" + }, + { + "name": "cloudDB_new_record", + "value": "New" + }, + { + "name": "dialog_success_title", + "value": "Success" + }, + { + "name": "dialog_success_message", + "value": "Added new record successfully" + }, + { + "name": "global_var_description", + "value": "Insert as global record" + }, + { + "name": "cloudStorage_description", + "value": "Upload an image to cloud storage. Click the button below to get a file link with high speed, low cost from the cloud storage." + }, + { + "name": "cloudStorage_accessAddressLabel", + "value": "Access URL: " + }, + { + "name": "cloudStorage_publicAccessAddressLabel", + "value": "Public URL: " + }, + { + "name": "image_upload_label", + "value": "image uploading:" + }, + { + "name": "cloudStorage_link1", + "value": "copy" + }, + { + "name": "cloudStorage_link2", + "value": "copy" + }, + { + "name": "db_option_edit", + "value": "Edit" + }, + { + "name": "cloud_storage_description_main", + "value": "Efficient cloud storage. High speed, low cost file upload and download services." + }, + { + "name": "cloudStorage_progressLabel", + "value": "Image uploading " + }, + { + "name": "media_permission_reason", + "value": "App needs media permission to display Cloud Storage Features." + }, + { + "name": "cloudStorage_link_copy", + "value": "Copy" + }, + { + "name": "common_prompt", + "value": "Warn" + }, + { + "name": "common_login_fail", + "value": "Fail to login" + }, + { + "name": "common_check_size", + "value": "The image size cannot exceed 2 MB." + } + ] +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/resources/en_US/element/string.json b/IntentsKitNewsUpdate/Application/entry/src/main/resources/en_US/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..f7ed9e4d69d1af73f216d53930f61bf7eb1a644a --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/src/main/resources/en_US/element/string.json @@ -0,0 +1,48 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "entryability_desc", + "value": "description" + }, + { + "name": "entryability_label", + "value": "IntentsKitNewsUpdate" + }, + { + "name": "home_title", + "value": "Home" + }, + { + "name": "home_no_content", + "value": "No Content" + }, + { + "name": "home_tabs_one", + "value": "Recd" + }, + { + "name": "home_tabs_two", + "value": "Sports" + }, + { + "name": "home_tabs_three", + "value": "Fin" + }, + { + "name": "home_tabs_four", + "value": "Tech" + }, + { + "name": "home_tabs_five", + "value": "Fiction" + }, + { + "name": "news_detail_title", + "value": "News detail" + } + ] +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/resources/light/element/color.json b/IntentsKitNewsUpdate/Application/entry/src/main/resources/light/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..ba71337c0bf51cf1b475ca76aa622902cbbe5522 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/src/main/resources/light/element/color.json @@ -0,0 +1,44 @@ +{ + "color": [ + { + "name": "white", + "value": "#ffffff" + }, + { + "name": "start_window_background", + "value": "#ffffff" + }, + { + "name": "action_button_background", + "value": "#169cd5" + }, + { + "name": "dialog_cancel_background", + "value": "#D9001B" + }, + { + "name": "black", + "value": "#000000" + }, + { + "name": "body_color", + "value": "#333333" + }, + { + "name": "placeholder_background", + "value": "#eeeeee" + }, + { + "name": "disabled_button_background", + "value": "#C2C2C2" + }, + { + "name": "border_color", + "value": "#FF9B9B9B" + }, + { + "name": "login_button", + "value": "#007DFF" + } + ] +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/resources/light/element/float.json b/IntentsKitNewsUpdate/Application/entry/src/main/resources/light/element/float.json new file mode 100644 index 0000000000000000000000000000000000000000..dfa4ba1b2e421a2f68b9695e2e5f485a86d56f99 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/src/main/resources/light/element/float.json @@ -0,0 +1,84 @@ +{ + "float": [ + { + "name": "main_title_font_size", + "value": "25fp" + }, + { + "name": "navigation_font_size", + "value": "20fp" + }, + { + "name": "body_font_size", + "value": "15fp" + }, + { + "name": "list_item_font_size", + "value": "12fp" + }, + { + "name": "number_0", + "value": "0" + }, + { + "name": "number_1", + "value": "1" + }, + { + "name": "number_2", + "value": "2" + }, + { + "name": "number_5", + "value": "5" + }, + { + "name": "number_10", + "value": "10" + }, + { + "name": "number_15", + "value": "15" + }, + { + "name": "number_20", + "value": "20" + }, + { + "name": "number_75", + "value": "75" + }, + { + "name": "number_70", + "value": "70" + }, + { + "name": "number_25", + "value": "25" + }, + { + "name": "number_100", + "value": "100" + }, + { + "name": "number_40", + "value": "40" + }, + { + "name": "number_250", + "value": "250" + }, + { + "name": "number_30", + "value": "30" + }, + { + "name": "number_3", + "value": "3" + }, + { + "name": "number_0_5", + "value": "0.5" + } + ] +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/resources/light/element/string.json b/IntentsKitNewsUpdate/Application/entry/src/main/resources/light/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..43230fbfbe0937287185bbc49092ed2b6bc2e66c --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/src/main/resources/light/element/string.json @@ -0,0 +1,252 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "entryability_desc", + "value": "description" + }, + { + "name": "entryability_label", + "value": "AGC Demo" + }, + { + "name": "cloudDB_label", + "value": "Cloud Database" + }, + { + "name": "tips_label", + "value": "Tips:" + }, + { + "name": "data_label", + "value": "Data:" + }, + { + "name": "publishButton_label", + "value": "Publish" + }, + { + "name": "popUpDesc_label", + "value": "Are you sure you want to delete?" + }, + { + "name": "deleteButton_label", + "value": "Delete" + }, + { + "name": "cloudStorage_label", + "value": "Cloud Storage" + }, + { + "name": "cancelButton_label", + "value": "Cancel" + }, + { + "name": "confirmButton_label", + "value": "Confirm" + }, + { + "name": "no_photo", + "value": "You don't have any images on your phone." + }, + { + "name": "cloudStorage_description_title", + "value": "Tips:" + }, + { + "name": "cloudStorage_uploadButton", + "value": "Upload Image" + }, + { + "name": "list_left_title", + "value": "My Posts" + }, + { + "name": "list_right_title", + "value": "Release Time" + }, + { + "name": "main_page_title", + "value": "Cloud Development" + }, + { + "name": "auth_service_title", + "value": "Auth Service" + }, + { + "name": "auth_result_name", + "value": "nickname" + }, + { + "name": "auth_service_description", + "value": "Secure and reliable user authentication system." + }, + { + "name": "auth_service_login_button_text", + "value": "Login" + }, + { + "name": "auth_service_logout_button_text", + "value": "Log out" + }, + { + "name": "auth_service_delete_user_button_text", + "value": "Delete User" + }, + { + "name": "auth_dialog_title", + "value": "Mobile verification code login" + }, + { + "name": "auth_dialog_number_placeholder", + "value": "phone number" + }, + { + "name": "auth_dialog_code_placeholder", + "value": "code" + }, + { + "name": "auth_dialog_get_code_button_text", + "value": "Get code" + }, + { + "name": "auth_dialog_auth_button_text", + "value": "Authorize" + }, + { + "name": "auth_result_user_id", + "value": "user id" + }, + { + "name": "auth_result_mobile_number", + "value": "mobile number" + }, + { + "name": "auth_result_avatar", + "value": "avatar" + }, + { + "name": "auth_result_registered", + "value": "registered" + }, + { + "name": "auth_result_last_login", + "value": "last login" + }, + { + "name": "cloud_function_title", + "value": "Cloud Functions" + }, + { + "name": "cloud_function_description_main", + "value": "Easy to run code without managing servers." + }, + { + "name": "cloud_function_description", + "value": "Tap to generate a global unique Cloud ID. Generated Cloud ID will be printed after tapping the button below." + }, + { + "name": "cloud_function_button_text", + "value": "Generate Global Unique ID" + }, + { + "name": "cloud_db_description_main", + "value": "Secure and trusted data management services." + }, + { + "name": "login_warning_title", + "value": "Auth Error" + }, + { + "name": "login_warning_message", + "value": "You must login to use this service" + }, + { + "name": "cloudDB_Publications", + "value": "New Posts" + }, + { + "name": "cloudDB_HighestHit", + "value": "Most Liked" + }, + { + "name": "cloudDB_SeeOnly", + "value": "My Posts" + }, + { + "name": "cloudDB_new_record", + "value": "New" + }, + { + "name": "dialog_success_title", + "value": "Success" + }, + { + "name": "dialog_success_message", + "value": "Added new record successfully" + }, + { + "name": "global_var_description", + "value": "Insert as global record" + }, + { + "name": "cloudStorage_description", + "value": "Upload an image to cloud storage. Click the button below to get a file link with high speed, low cost from the cloud storage." + }, + { + "name": "cloudStorage_accessAddressLabel", + "value": "Access URL: " + }, + { + "name": "cloudStorage_publicAccessAddressLabel", + "value": "Public URL: " + }, + { + "name": "image_upload_label", + "value": "image uploading:" + }, + { + "name": "cloudStorage_link1", + "value": "copy" + }, + { + "name": "cloudStorage_link2", + "value": "copy" + }, + { + "name": "db_option_edit", + "value": "Edit" + }, + { + "name": "cloud_storage_description_main", + "value": "Efficient cloud storage. High speed, low cost file upload and download services." + }, + { + "name": "cloudStorage_progressLabel", + "value": "Image uploading " + }, + { + "name": "media_permission_reason", + "value": "App needs media permission to display Cloud Storage Features." + }, + { + "name": "cloudStorage_link_copy", + "value": "Copy" + }, + { + "name": "common_prompt", + "value": "Warn" + }, + { + "name": "common_login_fail", + "value": "Fail to login" + }, + { + "name": "common_check_size", + "value": "The image size cannot exceed 2 MB." + } + ] +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/entry/src/main/resources/zh_CN/element/string.json b/IntentsKitNewsUpdate/Application/entry/src/main/resources/zh_CN/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..469eb83cadfb39ad1eb5ed69589a476b5418a0ed --- /dev/null +++ b/IntentsKitNewsUpdate/Application/entry/src/main/resources/zh_CN/element/string.json @@ -0,0 +1,48 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "entryability_desc", + "value": "description" + }, + { + "name": "entryability_label", + "value": "意图新闻推新" + }, + { + "name": "home_title", + "value": "首页" + }, + { + "name": "home_no_content", + "value": "当前没有内容了~" + }, + { + "name": "home_tabs_one", + "value": "推荐" + }, + { + "name": "home_tabs_two", + "value": "体育" + }, + { + "name": "home_tabs_three", + "value": "财经" + }, + { + "name": "home_tabs_four", + "value": "科技" + }, + { + "name": "home_tabs_five", + "value": "小说" + }, + { + "name": "news_detail_title", + "value": "新闻详情" + } + ] +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/hvigor/hvigor-config.json5 b/IntentsKitNewsUpdate/Application/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..5bebc9755447385d82ce4138f54d991b1f85f348 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/hvigor/hvigor-config.json5 @@ -0,0 +1,22 @@ +{ + "modelVersion": "5.0.5", + "dependencies": { + }, + "execution": { + // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | false ]. Default: "normal" */ + // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */ + // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */ + // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */ + // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */ + }, + "logging": { + // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */ + }, + "debugging": { + // "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */ + }, + "nodeOptions": { + // "maxOldSpaceSize": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/ + // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/ + } +} diff --git a/IntentsKitNewsUpdate/Application/hvigorfile.ts b/IntentsKitNewsUpdate/Application/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..f3cb9f1a87a81687554a76283af8df27d8bda775 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/hvigorfile.ts @@ -0,0 +1,6 @@ +import { appTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/IntentsKitNewsUpdate/Application/oh-package-lock.json5 b/IntentsKitNewsUpdate/Application/oh-package-lock.json5 new file mode 100644 index 0000000000000000000000000000000000000000..6c2400b20303214fd620c18130a90d4dfae61279 --- /dev/null +++ b/IntentsKitNewsUpdate/Application/oh-package-lock.json5 @@ -0,0 +1,35 @@ +{ + "meta": { + "stableOrder": true + }, + "lockfileVersion": 3, + "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", + "specifiers": { + "@hw-agconnect/auth@^1.0.4": "@hw-agconnect/auth@1.0.4", + "@ohos/hamock@1.0.0": "@ohos/hamock@1.0.0", + "@ohos/hypium@1.0.21": "@ohos/hypium@1.0.21" + }, + "packages": { + "@hw-agconnect/auth@1.0.4": { + "name": "@hw-agconnect/auth", + "version": "1.0.4", + "integrity": "sha512-LavuqjXEWjJTGCYy3eK03F980/4wRaIX70fEcWzxlXhXeacyQflkR4W3lq69tcCvEDZAX/heu1SZFsetYvRRGA==", + "resolved": "https://repo.harmonyos.com/ohpm/@hw-agconnect/auth/-/auth-1.0.4.har", + "registryType": "ohpm" + }, + "@ohos/hamock@1.0.0": { + "name": "@ohos/hamock", + "version": "1.0.0", + "integrity": "sha512-K6lDPYc6VkKe6ZBNQa9aoG+ZZMiwqfcR/7yAVFSUGIuOAhPvCJAo9+t1fZnpe0dBRBPxj2bxPPbKh69VuyAtDg==", + "resolved": "https://repo.harmonyos.com/ohpm/@ohos/hamock/-/hamock-1.0.0.har", + "registryType": "ohpm" + }, + "@ohos/hypium@1.0.21": { + "name": "@ohos/hypium", + "version": "1.0.21", + "integrity": "sha512-iyKGMXxE+9PpCkqEwu0VykN/7hNpb+QOeIuHwkmZnxOpI+dFZt6yhPB7k89EgV1MiSK/ieV/hMjr5Z2mWwRfMQ==", + "resolved": "https://repo.harmonyos.com/ohpm/@ohos/hypium/-/hypium-1.0.21.har", + "registryType": "ohpm" + } + } +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/Application/oh-package.json5 b/IntentsKitNewsUpdate/Application/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..803c38c4ad1b12d8241f164dfa126ba1ee471b4c --- /dev/null +++ b/IntentsKitNewsUpdate/Application/oh-package.json5 @@ -0,0 +1,12 @@ +{ + "modelVersion": "5.0.5", + "description": "Please describe the basic information.", + "dependencies": { + "@hw-agconnect/auth": "^1.0.4" + }, + "devDependencies": { + "@ohos/hypium": "1.0.21", + "@ohos/hamock": "1.0.0" + }, + "dynamicDependencies": {} +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/CloudProgram/.gitignore b/IntentsKitNewsUpdate/CloudProgram/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..74504fdc13b9ffde0a04fa3cb1ca1db3f02d10b5 --- /dev/null +++ b/IntentsKitNewsUpdate/CloudProgram/.gitignore @@ -0,0 +1,17 @@ +build/ +*.iml +out/ +.idea/ +node_modules/ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test +/.hvigor +/.idea + +local.properties +package-lock.json +/.clang-format \ No newline at end of file diff --git a/IntentsKitNewsUpdate/CloudProgram/cloud-config.json b/IntentsKitNewsUpdate/CloudProgram/cloud-config.json new file mode 100644 index 0000000000000000000000000000000000000000..abe3ab1fb98d962293630a21ec034faa1264bb47 --- /dev/null +++ b/IntentsKitNewsUpdate/CloudProgram/cloud-config.json @@ -0,0 +1,18 @@ +{ + "appSelected": { + "appId": "6917577979570431044", + "appName": "意图框架习惯推荐常用推新", + "deviceTypes": [ + { + "deviceType": 4 + } + ], + "enableSites": "CN", + "installationFree": 0, + "packageType": 7, + "projectId": "461323198430090695", + "projectName": "意图推荐", + "siteId": "CN" + }, + "teamId": "80086000302418208" +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/CloudProgram/clouddb/dataentry/d_News.json b/IntentsKitNewsUpdate/CloudProgram/clouddb/dataentry/d_News.json new file mode 100644 index 0000000000000000000000000000000000000000..4c550d17a109164205ed3c7cf79e8a79109597af --- /dev/null +++ b/IntentsKitNewsUpdate/CloudProgram/clouddb/dataentry/d_News.json @@ -0,0 +1,26 @@ +{ + "cloudDBZoneName": "News", + "objectTypeName": "News", + "objects": [ + { + "newsId": 1, + "title": "新闻一", + "content": "我是新闻一的内容", + "newsType": "体育", + "pubUserName": "新闻频道", + "pubUserAvatar": "string1", + "pubDate": 1752737926206, + "viewCount": 10 + }, + { + "newsId": 2, + "title": "新闻二", + "content": "我是新闻二的内容", + "newsType": "财经", + "pubUserName": "新闻频道", + "pubUserAvatar": "string2", + "pubDate": 1752737926206, + "viewCount": 20 + } + ] +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/CloudProgram/clouddb/db-config.json b/IntentsKitNewsUpdate/CloudProgram/clouddb/db-config.json new file mode 100644 index 0000000000000000000000000000000000000000..fa1ca662a88c73408ac335a38dae20859fdec6ac --- /dev/null +++ b/IntentsKitNewsUpdate/CloudProgram/clouddb/db-config.json @@ -0,0 +1,4 @@ +{ + "defaultCloudDBZoneName": "default", + "defaultDataStorageLocation": "CN" +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/CloudProgram/clouddb/objecttype/News.json b/IntentsKitNewsUpdate/CloudProgram/clouddb/objecttype/News.json new file mode 100644 index 0000000000000000000000000000000000000000..fab089049259774a95a14d1fa36ff20bb883aaeb --- /dev/null +++ b/IntentsKitNewsUpdate/CloudProgram/clouddb/objecttype/News.json @@ -0,0 +1,135 @@ +{ + "objectTypeName":"News", + "permissions":[ + { + "role":"World", + "rights":[ + "Read", + "Upsert", + "Delete" + ] + }, + { + "role":"Authenticated", + "rights":[ + "Read", + "Upsert", + "Delete" + ] + }, + { + "role":"Creator", + "rights":[ + "Read", + "Upsert", + "Delete" + ] + }, + { + "role":"Administrator", + "rights":[ + "Read", + "Upsert", + "Delete" + ] + } + ], + "indexes":[ + { + "indexName":"view_count_index", + "indexList":[ + { + "fieldName":"viewCount", + "sortType":"DESC" + } + ] + }, + { + "indexName":"news_id_index", + "indexList":[ + { + "fieldName":"newsId", + "sortType":"ASC" + } + ] + }, + { + "indexName":"pub_date_index", + "indexList":[ + { + "fieldName":"pubDate", + "sortType":"DESC" + } + ] + } + ], + "fields":[ + { + "fieldName":"newsId", + "fieldType":"LongAutoIncrement", + "belongPrimaryKey":true, + "notNull":true, + "isNeedEncrypt":false, + "isSensitive":false + }, + { + "fieldName":"title", + "fieldType":"String", + "belongPrimaryKey":false, + "notNull":true, + "isNeedEncrypt":false, + "isSensitive":false, + "defaultValue":"" + }, + { + "fieldName":"content", + "fieldType":"Text", + "belongPrimaryKey":false, + "notNull":true, + "isNeedEncrypt":false, + "isSensitive":false, + "defaultValue":"" + }, + { + "fieldName":"newsType", + "fieldType":"String", + "belongPrimaryKey":false, + "notNull":true, + "isNeedEncrypt":false, + "isSensitive":false, + "defaultValue":"图文" + }, + { + "fieldName":"pubUserName", + "fieldType":"String", + "belongPrimaryKey":false, + "notNull":false, + "isNeedEncrypt":false, + "isSensitive":false + }, + { + "fieldName":"pubUserAvatar", + "fieldType":"String", + "belongPrimaryKey":false, + "notNull":false, + "isNeedEncrypt":false, + "isSensitive":false + }, + { + "fieldName":"pubDate", + "fieldType":"Date", + "belongPrimaryKey":false, + "notNull":false, + "isNeedEncrypt":false, + "isSensitive":false + }, + { + "fieldName":"viewCount", + "fieldType":"Integer", + "belongPrimaryKey":false, + "notNull":false, + "isNeedEncrypt":false, + "isSensitive":false + } + ] +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/id-generator/function-config.json b/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/id-generator/function-config.json new file mode 100644 index 0000000000000000000000000000000000000000..0924643494ffba1bb7d098ed898e78ccbfb84b98 --- /dev/null +++ b/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/id-generator/function-config.json @@ -0,0 +1,15 @@ +{ + "handler": "idGenerator.IdGenerator", + "functionType": 1, + "triggers": [ + { + "type": "http", + "properties": { + "enableUrlDecode": true, + "authFlag": "true", + "authAlgor": "HDA-SYSTEM", + "authType": "apigw-client" + } + } + ] +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/id-generator/idGenerator.ts b/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/id-generator/idGenerator.ts new file mode 100644 index 0000000000000000000000000000000000000000..dd44006aa41bc78c61465776ecb4b5b80b30e515 --- /dev/null +++ b/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/id-generator/idGenerator.ts @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as crypto from 'crypto'; + +export class IdGenerator { + randomUUID() { + const uuid = crypto.randomUUID(); + console.info(`Generate random UUID: ${uuid}`); + return { "uuid": uuid }; + } +} diff --git a/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/id-generator/package.json b/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/id-generator/package.json new file mode 100644 index 0000000000000000000000000000000000000000..8c597645ab92ac0b46590af9efc4fadb786b4a26 --- /dev/null +++ b/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/id-generator/package.json @@ -0,0 +1,12 @@ +{ + "name": "id-generator", + "version": "1.0.0", + "description": "", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + } +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/id-generator/tsconfig.json b/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/id-generator/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..b5e3145419e9983c2b1dfce206082d3ad93e9d3b --- /dev/null +++ b/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/id-generator/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "module": "commonjs", + "checkJs": false, + "sourceMap": true, + "noEmitOnError": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": false, + "skipLibCheck": true + } +} diff --git a/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/news-service/CloudDBZoneWrapper.ts b/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/news-service/CloudDBZoneWrapper.ts new file mode 100644 index 0000000000000000000000000000000000000000..c6ae4f27019c4ef43b54e71f17391196c6413030 --- /dev/null +++ b/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/news-service/CloudDBZoneWrapper.ts @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import { cloud, CloudDBCollection } from '@hw-agconnect/cloud-server'; +import { News } from './News'; + +// database zone +const ZONE_NAME = "News"; + +export class CloudDbZoneWrapper { + collection: CloudDBCollection; + + constructor() { + this.collection = cloud.database({ zoneName: ZONE_NAME }).collection(News); + } + + // query data + async queryNews() { + let query = this.baseQuery().orderByDesc("pubDate"); + return await query.get(); + } + + async queryLatestNews() { + let query = this.baseQuery().orderByDesc("pubDate").limit(1, 0); + return await query.get(); + } + + private baseQuery() { + return this.collection.query(); + } + + // update data + async upsertNews(records: News[]) { + return await this.collection.upsert(records); + } + + + // delete data + async deleteNews(records: News[]) { + return await this.collection.delete(records); + } +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/news-service/News.ts b/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/news-service/News.ts new file mode 100644 index 0000000000000000000000000000000000000000..2359b6a545bd0949e72a5de4db9b59d9a46737e9 --- /dev/null +++ b/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/news-service/News.ts @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class News { + newsId: number; + title: string = ''; + content: string = ''; + newsType: string = '图文'; + pubUserName: string; + pubUserAvatar: string; + pubDate: Date; + viewCount: number; + + constructor() { + } + + getFieldTypeMap(): Map { + let fieldTypeMap = new Map(); + fieldTypeMap.set('newsId', 'LongAutoIncrement'); + fieldTypeMap.set('title', 'String'); + fieldTypeMap.set('content', 'Text'); + fieldTypeMap.set('newsType', 'String'); + fieldTypeMap.set('pubUserName', 'String'); + fieldTypeMap.set('pubUserAvatar', 'String'); + fieldTypeMap.set('pubDate', 'Date'); + fieldTypeMap.set('viewCount', 'Integer'); + return fieldTypeMap; + } + + getClassName(): string { + return 'News'; + } + + getPrimaryKeyList(): string[] { + let primaryKeyList: string[] = []; + primaryKeyList.push('newsId'); + return primaryKeyList; + } + + getIndexList(): string[] { + let indexList: string[] = []; + indexList.push('viewCount'); + indexList.push('newsId'); + indexList.push('pubDate'); + return indexList; + } + + getEncryptedFieldList(): string[] { + let encryptedFieldList: string[] = []; + return encryptedFieldList; + } + + setNewsId(newsId: number): void { + this.newsId = newsId; + } + + getNewsId(): number { + return this.newsId; + } + + setTitle(title: string): void { + this.title = title; + } + + getTitle(): string { + return this.title; + } + + setContent(content: string): void { + this.content = content; + } + + getContent(): string { + return this.content; + } + + setNewsType(newsType: string): void { + this.newsType = newsType; + } + + getNewsType(): string { + return this.newsType; + } + + setPubUserName(pubUserName: string): void { + this.pubUserName = pubUserName; + } + + getPubUserName(): string { + return this.pubUserName; + } + + setPubUserAvatar(pubUserAvatar: string): void { + this.pubUserAvatar = pubUserAvatar; + } + + getPubUserAvatar(): string { + return this.pubUserAvatar; + } + + setPubDate(pubDate: Date): void { + this.pubDate = pubDate; + } + + getPubDate(): Date { + return this.pubDate; + } + + setViewCount(viewCount: number): void { + this.viewCount = viewCount; + } + + getViewCount(): number { + return this.viewCount; + } + + static parseFrom(inputObject: any): News { + let result = new News(); + if (!inputObject) { + return result; + } + if (inputObject.newsId) { + result.newsId = inputObject.newsId; + } + if (inputObject.title) { + result.title = inputObject.title; + } + if (inputObject.content) { + result.content = inputObject.content; + } + if (inputObject.newsType) { + result.newsType = inputObject.newsType; + } + if (inputObject.pubUserName) { + result.pubUserName = inputObject.pubUserName; + } + if (inputObject.pubUserAvatar) { + result.pubUserAvatar = inputObject.pubUserAvatar; + } + if (inputObject.pubDate) { + result.pubDate = new Date(inputObject.pubDate); + } + if (inputObject.viewCount) { + result.viewCount = inputObject.viewCount; + } + return result; + } +} + +export { News }; \ No newline at end of file diff --git a/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/news-service/function-config.json b/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/news-service/function-config.json new file mode 100644 index 0000000000000000000000000000000000000000..c42ead92ae187d825b9c73ab51d344f1f9ec5524 --- /dev/null +++ b/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/news-service/function-config.json @@ -0,0 +1,15 @@ +{ + "handler": "newsService.NewsService", + "functionType": 1, + "triggers": [ + { + "type": "http", + "properties": { + "enableUrlDecode": true, + "authFlag": "true", + "authAlgor": "HDA-SYSTEM", + "authType": "apigw-client" + } + } + ] +} \ No newline at end of file diff --git a/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/news-service/newsService.ts b/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/news-service/newsService.ts new file mode 100644 index 0000000000000000000000000000000000000000..94513ed29eeda28702cb19cb4aac6a9dfdb63c4f --- /dev/null +++ b/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/news-service/newsService.ts @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import { CloudDbZoneWrapper } from './CloudDBZoneWrapper'; +import * as crypto from 'crypto'; +import { News } from './News'; + +export class NewsService { + async shareIntent() { + const news = (await new CloudDbZoneWrapper().queryLatestNews() as Array)[0]; + + const now = new Date(); + const oneHourLater = new Date(now.getTime() + 7200000); + + // 统一的格式化函数 + function formatDateWithLocalTimezone(date) { + const pad = n => String(n).padStart(2, '0'); + + const year = date.getFullYear(); + const month = pad(date.getMonth() + 1); + const day = pad(date.getDate()); + const hours = pad(date.getHours()); + const minutes = pad(date.getMinutes()); + const seconds = pad(date.getSeconds()); + + const offset = date.getTimezoneOffset(); + const timezoneSign = offset <= 0 ? '+' : '-'; + const timezoneHours = pad(Math.abs(Math.floor(offset / 60))); + const timezoneMinutes = pad(Math.abs(offset % 60)); + const timezone = `${timezoneSign}${timezoneHours}:${timezoneMinutes}`; + + return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}${timezone}`; + } + + const ret1 = formatDateWithLocalTimezone(now); + const ret2 = formatDateWithLocalTimezone(oneHourLater); + + const intent = { + intentName: "ViewColumnUpdate", + intentVersion: "1.0.1", + identifier: crypto.randomUUID(), + intentEntityInfo: { + entityName: "ColumnUpdate", + entityId: news.newsId.toString(), + eventImage: "https://gitee.com/gorit/intent-kit-news-demo/blob/main/IntentsKitNewsUpdate/Application/entry/src/main/resources/base/media/sm_img.jpg", + columnTitle: news.newsType, + blogTitle: news.title, + availableBeginTime: ret1, + availableEndTime: ret2 // one hour later + } + } + // do something here + return intent; + } +} diff --git a/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/news-service/package.json b/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/news-service/package.json new file mode 100644 index 0000000000000000000000000000000000000000..b56d1c35bddf6b6acc3b00e5ee5c4a37a912acb2 --- /dev/null +++ b/IntentsKitNewsUpdate/CloudProgram/cloudfunctions/news-service/package.json @@ -0,0 +1,13 @@ +{ + "name": "news-service", + "version": "1.0.0", + "description": "", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "@hw-agconnect/cloud-server": "^1.0.3" + } +} diff --git a/IntentsKitNewsUpdate/CloudProgram/package.json b/IntentsKitNewsUpdate/CloudProgram/package.json new file mode 100644 index 0000000000000000000000000000000000000000..ddaaf70634c582f148e89c84c571e23dc72bbda8 --- /dev/null +++ b/IntentsKitNewsUpdate/CloudProgram/package.json @@ -0,0 +1,15 @@ +{ + "name": "cloud-program", + "version": "1.0.0", + "private": true, + "description": "add shared dependencies for cloud functions", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "devDependencies": { + "@types/node": "^18.11.11", + "typescript": "^5.4.2" + } +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..18795a48d6b12fcdc1aa7bac9a9cb99f83815267 --- /dev/null +++ b/LICENSE @@ -0,0 +1,78 @@ + Copyright (c) 2025 Huawei Device Co., Ltd. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +Apache License, Version 2.0 +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: +1.You must give any other recipients of the Work or Derivative Works a copy of this License; and +2.You must cause any modified files to carry prominent notices stating that You changed the files; and +3.You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and +4.If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/README.md b/README.md index adb53f5af60103a753c12c240e8bc87b0fe6414f..c3765883d12e488f68b83a6ff784c3edc7e09ee2 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,90 @@ -# IntentsKitNewsUpdate +# 基于意图框架推荐能力实现新闻推新 -#### 介绍 -{**以下是 Gitee 平台说明,您可以替换此简介** -Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台 -无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)} +## 介绍 +本示例基于意图框架,使用@kit.IntentsKit实现意图共享,使用@kit.AbilityKit的InsightIntentExecutor 实现意图调用。配合端云一体化提供的云函数,云数据库根据意图调用的参数实现新闻推新。 -#### 软件架构 -软件架构说明 +## 效果预览 +| 新闻首页 | 新闻详情页 | 小艺卡片展示共享意图 | 点击意图卡片实现复访 | +|-------------------------------------------------------|-----------------------------------------------------|----------------------------------------------------------------|---------------------------------------------------------------------| +| ![新闻首页](screenshots/device/screenshot_001.png "新闻首页") | ![新闻详情页](screenshots/device/screenshot_002.png "新闻详情页") | ![小艺卡片展示共享意图](screenshots/device/screenshot_003.png "小艺卡片展示共享意图") | ![点击意图卡片实现复访](screenshots/device/screenshot_004.png "点击意图卡片实现复访") | -#### 安装教程 +使用说明:TODO -1. xxxx -2. xxxx -3. xxxx -#### 使用说明 +## 工程目录 +``` +├──IntentsKitNewsUpdate +│ ├──Application // 客户端工程文件 +│ │ ├──cloud_objects // 云对象 module +│ │ │ └──src/main/ets/ +│ │ │ └──main +│ │ │ └──ets +│ │ │ ├──id-generator +│ │ │ │ └──IdGenerator.ts // 云函数-云对象自动生成的函数接口类型 +│ │ │ └──ImportObject.ts // 云函数-云对象自动生成的接口工具类 +│ │ └──entry +│ │ └──src +│ │ └──main +│ │ ├──ets +│ │ │ ├──clouddb +│ │ │ │ └──news +│ │ │ │ ├──News.ts // 云数据库新闻实体 +│ │ │ │ └──NewsDb.ets // 云数据库操作工具类 +│ │ │ ├──common +│ │ │ │ ├──constants +│ │ │ │ │ ├──CloudDatabaseConstants.ets // 云数据库静态配置类 +│ │ │ │ │ └──CommonConstants.ets // 公共静态配置类 +│ │ │ │ └──utils +│ │ │ │ ├──Logger.ets // 日志工具类 +│ │ │ │ └──Utils.ts // 通用工具类 +│ │ │ ├──entryability +│ │ │ │ └──EntryAbility.ets // 入口 Ability +│ │ │ ├──insightintents +│ │ │ │ └──IntentExecutorImpl.ets // 意图调用类 +│ │ │ └──pages +│ │ │ ├──Index.ets // 新闻首页 +│ │ │ └──NewsDetail.ets // 新闻详情页 +│ │ └──resources +│ │ └──base +│ │ └──profile +│ │ ├──insight_intent.json // 意图注册配置 +│ │ ├──route_map.json // Navigation 组件路由配置 +│ │ └──main_pages.json // 应用界面列表 +│ └──CloudProgram // 服务端工程文件 +│ ├──clouddb // 云数据库相关配置 +│ └──cloudfunvtions // 云函数相关配置 +├──README.md // 项目说明文档 +├──SETUP.md // 基于意图框架推荐能力实现新闻推新端云一体化搭建指导文档 +└──screenshots +``` -1. xxxx -2. xxxx -3. xxxx +- 本示例使用前,需完成端云一体化配置,要求客户端工程与服务端工程协同配置,具体配置过程请参见第[SETUP.md](./SETUP.md)1-5章。 +- 本示例完成端云一体化配置后,数据请求使用的是AGC云函数,运行安装时请保证AGC服务端和客户端的配置信息是与bundleName一一对应的,否则会导致网络请求失败。 -#### 参与贡献 +## 具体实现 +意图共享代码参考 NewsDetail.ets 中的 shareIntent 方法,意图调用源码参考IntentExecutorImpl.ets中的onExecuteInUiAbilityForegroundMode方法。 +- 首页:从服务端api读取新闻列表信息,ForEach生成新闻列表,列表的onClick事件中通过 pathStack.replacePathByName跳转到内容详情页面。 +- 内容页:内容详情页根据新闻id,通过服务端api获取新闻详细内容进行展示。 +- 意图共享:内容页获取到新闻详情数据后,根据意图模型填充意图数据,然后调用insightIntent.shareIntent API实现意图数据共享。 +- 意图调用(云侧):意图管理云侧会在合适的时机调用业务侧服务端API获取栏目最新新闻,推送数据给端侧小艺建议,生成新闻卡片。 +- 意图调用(端侧):在onExecuteInUIAbilityForegroundMode方法中,使用eventHub.emit广播事件,传递entityId新闻id参数。 +index.ets中通过eventHub.on监听事件,通过 pathStack.replacePathByName 触发跳转到内容页面。 +- 意图调用热启动时通过eventHub传递参数给首页,冷启动时通过onCreate方法借助localStorage对象将want特定参数传递给首页。 +- 本示例意图调用没有过多介入业务逻辑和UI逻辑,只是通过不同渠道把相关参数传递给业务,将页面跳转主动权交给业务本身。 +onExecuteInUIAbilityForegroundMode接口也提供了WindowStage实例,可以使用windowStage.loadContent加载特定页面,应用根据实际选择合适的方式。 -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request +## 相关权限 +- 网络权限:ohos.permission.INTERNET。 +## 依赖 +1. 本示例依赖@ohos/hvigor-ohos-plugin。 +2. 使用DevEco Studio版本大于本示例推荐版本,请根据 DevEco Studio 提示更新 hvigor 插件版本。 +3. 需联网登录华为账号并同意小艺建议的用户协议和隐私政策。 -#### 特技 - -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) +## 约束与限制 +1. 意图共享和意图调用的测试,当前无法由开发者独立完成,请根据Intents Kit接入流程,通过邮箱向华为意图框架接口人提交验收申请,由接口人配合开发者一同完成测试验收。 +2. 本示例仅支持标准系统上运行,支持设备:华为手机。 +3. HarmonyOS系统:HarmonyOS 5.0.5 Release及以上。 +4. DevEco Studio版本:DevEco Studio 5.0.5 Release及以上。 +5. HarmonyOS SDK版本:HarmonyOS 5.0.5 Release SDK及以上。 \ No newline at end of file diff --git a/SETUP.md b/SETUP.md new file mode 100644 index 0000000000000000000000000000000000000000..f8daad560774b89a3449ff1653a279ebc7769cf5 --- /dev/null +++ b/SETUP.md @@ -0,0 +1,188 @@ +# 基于意图推荐新闻推新端云一体化搭建 + +### 1.简介 + +基于意图推荐新闻推新涉及端云一体化开发,[开源代码](https://gitee.com/harmonyos_samples/IntentsKitNewsUpdate)包含客户端工程(Application文件)和服务端工程(CloudProgram文件)两部分,需要进行端云一体化配置从而体验完整的基于意图推荐新闻推新的功能,本文章将讲述基于意图推荐新闻推新端云一体化配置过程。 + +### 2.项目准备 + +1. 注册华为账号 + + 基于意图推荐新闻推新端云一体化搭建依托于[AppGallery Connect(AGC)](https://developer.huawei.com/consumer/cn/service/josp/agc/index.html#/)平台,使用AGC平台需要前往[华为开发者联盟官网](https://developer.huawei.com/consumer/cn/)进行华为账号注册,并完成实名认证,具体请参见[注册账号](https://developer.huawei.com/consumer/cn/doc/start/registration-and-verification-0000001053628148)。如果您已经拥有华为账号,并已完成实名认证,可跳过本步骤。 + +2. 项目打开 + + 使用[DevEco Studio](https://developer.huawei.com/consumer/cn/deveco-studio/),选择File > Open,选择“IntentsKitNewsRecommend”,点击“OK”打开项目。请注意,HMOSWorld目录下客户端工程(Application文件)可以作为单独项目打开,但是会编译失败;服务端工程(CloudProgram文件)仅可以通过打开HMOSWorld整个项目打开。建议您直接选择打开“HMOSWorld”文件,同时打开客户端工程(Application文件)和服务端工程(CloudProgram文件),而不是只打开客户端工程(Application文件)。 + + ![image](screenshots/client/open_objects.PNG) + +### 3.AGC基本环境搭建 + +基于意图推荐新闻推新端云一体化配置,首先需要在[AGC](https://developer.huawei.com/consumer/cn/service/josp/agc/index.html#/)中创建本应用,完成AGC配置,为服务端工程在云端实现提供基础。操作步骤如下: + +1. 登录[AGC](https://developer.huawei.com/consumer/cn/service/josp/agc/index.html#/)平台,点击“我的项目”,在项目页面中点击“添加项目”。 + + ![image](screenshots/cloud/add_project.PNG) +2. 在“创建项目”页面中输入项目名称后,本文章项目名称以“意图框架为例”为例,点击“创建并继续”。 + + ![image](screenshots/cloud/create_project.PNG) + +3. 完成项目创建后,点击左侧导航栏的“项目设置”中的“添加应用”即可进行后续操作。 + + ![image](screenshots/cloud/add_apply1.PNG) + +4. 进入“添加应用”页面后选择“APP(HarmonyOS)”,会提示前往证书、APP ID和Profile的APP ID页面,点击“APP ID”。 + + ![image](screenshots/cloud/add_apply2.PNG) + +5. 进入“设置应用开发基础信息”页面,填写应用基础信息: + + - “应用类型”选择“HarmonyOS应用”; + + - “应用名称”以“基于意图推荐新闻推新”为例; + + - “应用包名”以“com.example.intentnewsrecommend”为例,因为应用包名唯一,创建相同包名应用会创建失败,所以配置时请修改为其他应用包名。此处的应用包名必须与客户端工程中配置的Bundle name一致,在后文客户端工程配置时会详细说明,具体命名规范参照[软件包规范](https://developer.huawei.com/consumer/cn/doc/app/agc-help-createharmonyapp-0000001945392297); + + - “应用分类”选择“应用”。 + + - 点击“下一步”。 + + ![image](screenshots/cloud/add_apply3.PNG) + +6. 选择“应用所属项目”为当前项目“基于意图推荐新闻推新”。并点击“确认”。 + + ![image](screenshots/cloud/add_apply4.PNG) + +7. 点击“确认”后,页面下会出现多个API的开放能力,根据项目实际需要选择对应的能力,再点击最下方的“确认”。 + + ![image](screenshots/cloud/add_apply5.PNG) + +8. 如果未开启以上开放能力,并已点击“确认”完成应用创建,可前往“我的项目”,在左侧导航栏选择“项目设置”,进入“项目设置”页面,点击“开放能力管理”打开对应开放能力。如果您已在第8步完成“定位服务”、“位置服务”、“地图服务”和“推送服务”开放能力打开,请跳过第8步,进行第10步及以后配置。 + + ![image](screenshots/cloud/open_capabilities.PNG) + +9. 点击AGC平台“我的项目”,在左侧导航栏选择“云开发(Serverless)”,并开通“云函数”和“云数据库”服务。 + + ![image](screenshots/cloud/cloud_serverless.PNG) + + 在首次开通服务时,需设置“数据处理位置”,选择“中国”并将其设为“默认”。 + + ![image](screenshots/cloud/data_position.PNG) + + +至此,已完成基于意图推荐新闻推新AGC基本环境搭建。 + +### 4.客户端适配 + +基于意图推荐新闻推新端云一体化配置,需要修改客户端项目中的部分配置,为端云一体化搭建提供基础。操作步骤如下: + +1. 修改客户端Bundle name,打开客户端代码AppScope > app.json5,修改Bundle name为包名,与第3章第5步的包名保持一致,以“com.example.intentnewsrecommend”为例。 + + ![image](screenshots/client/bundle_name.PNG) + +2. 在DevEco Studio中,依次点击主菜单栏的File > Project Structure > Project > Signing Configs,勾选“Automatically generate signature”选项,随后点击“Sign in”登录华为账号,最后点击“OK”完成自动签名配置。请注意,操作过程中需确保设备已连接。 + + ![image](screenshots/client/auto_signature.jpg) + +至此,已完成基于意图推荐新闻推新客户端适配。 + +### 5.服务端项目配置 + +基于意图推荐新闻推新端云一体化配置,服务端需要配置信息与[AGC平台](https://developer.huawei.com/consumer/cn/service/josp/agc/index.html#/)链接。操作步骤如下: + +1. 修改配置文件CloudProgram > cloud-config.json。 + + 修改cloud-config.json中的appId、projectId和teamId为[AGC平台](https://developer.huawei.com/consumer/cn/service/josp/agc/index.html#/)创建基于意图推荐新闻推新“项目设置”中的对应信息。 + + ![image](screenshots/cloud/cloud_config.PNG) + +2. 登录[AGC平台](https://developer.huawei.com/consumer/cn/service/josp/agc/index.html#/),依次选择“我的项目” > “云数据库” > “存储区”,然后点击“新增”。在设置“存储区名称”时,请填写“News”。由于第3步上传的数据已关联此存储区名称,建议不要更改为其他名称。 + + ![image](screenshots/cloud/cloud_data.PNG) + +3. 在项目中选中CloudProgram,右击选择Deploy Cloud Program,即可上传云数据库和云函数,请确保上传完成并成功。 + + ![image](screenshots/client/cloud_program.PNG) + + 如果上传超时,请检查是否登录DevEco Studio;如果仍然上传超时或显示teamId报错,可重启DevEco Studio后再次上传。 + + ![image](screenshots/client/check_signature.jpg) + +至此,已完成基于意图推荐新闻推新服务端适配,可以体验新闻服务的基本功能。 + +### 6.特殊功能配置 + +#### 6.1手动签名 + +为确保端云一体化项目能够正常运行,客户端工程需进行手动签名。新闻服务在完成手动签名后重新卸载安装应用即可使用。步骤如下: + +1. 生成密钥(.p12文件),详见[手动签名](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-signing-V5#section297715173233)。 + + - 在DevEco Studio主菜单栏点击Build > Generate Key and CSR。单击Choose Existing选择已有的密钥库文件(存储有密钥的.p12文件);如果没有密钥库文件,单击New进行创建。 + + ![image](screenshots/client/create_key_store1.jpg) + + - 在Create Key Store窗口中,选择并填入密钥(.p12文件)存储位置,建议在客户端工程(Application文件)下新建signature文件作为存储位置,以“signature\IntentsKitNewsUpdate.p12”为例,设置完Password后单击OK,请记住设置的Password,Password将被用于第5步完成手动签名。 + + ![image](screenshots/client/create_key_store2.jpg) + +2. 生成证书请求文件(.csr文件),详见[手动签名](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-signing-V5#section297715173233)。 + + - 此时,在Generate Key and CSR界面中,继续填写Alias,以“IntentsKitNewsUpdate”为例,单击Next。 + + ![image](screenshots/client/generate_key_and_CSR1.jpg) + + - 设置CSR文件存储路径和CSR文件名,建议在客户端工程(Application文件)下新建signature文件作为存储位置,以“signature/IntentsKitNewsUpdate.csr”为例,Key password与Key store password保持一致,无需手动输入。单击Finish,创建CSR文件成功。 + + ![image](screenshots/client/generate_key_and_CSR2.jpg) + + - 可以在存储路径下获取生成的密钥库文件(.p12)、证书请求文件(.csr)和material文件夹(存放签名方案相关材料,如密码、证书等),请妥善保存,建议统一存放在客户端工程的signature文件中。 + +3. 使用密钥(.p12文件)和证书请求文件(.csr文件)申请发布证书(.cer文件),详见[申请发布证书](https://developer.huawei.com/consumer/cn/doc/app/agc-help-add-releasecert-0000001946273961)。 + + - 登录[AGC](https://developer.huawei.com/consumer/cn/service/josp/agc/index.html#/),选择“证书、APP ID和Profile”,在左侧导航栏选择“证书”,点击“新增证书”。 + + ![image](screenshots/cloud/certificate1.jpg) + + - 填写“证书名称”,以“IntentsKitNewsUpdate”为例,选择“证书类型”为“调试证书”,选取在第2步中生成的证书请求文件(.csr文件)。 + + ![image](screenshots/cloud/certificate2.jpg) + + - 下载生成的发布证书(.cer文件),建议在客户端工程(Application文件)下新建signature文件作为存储位置。 + +4. 使用发布证书(.cer文件)申请发布Profile(.p7b文件),详见[申请发布Profile](https://developer.huawei.com/consumer/cn/doc/app/agc-help-add-releaseprofile-0000001914714796)。 + + 申请发布Profile(.p7b文件)前,请确认在左边栏“设备”中存在注册设备,若未拥有设备,需要添加设备,详见[注册调试设备](https://developer.huawei.com/consumer/cn/doc/app/agc-help-add-device-0000001946142249)。 + + - 登录[AGC](https://developer.huawei.com/consumer/cn/service/josp/agc/index.html#/),选择“证书、APP ID和Profile”,在左侧导航栏选择“Profile”,点击“添加”。 +e + ![image](screenshots/cloud/profile1.jpg) + + - “应用名称”选择“基于意图推荐新闻推新”,填写“Profile名称”,以“基于意图推荐新闻推新”为例,“类型”选择调试,“选择证书”为刚刚生成的发布证书(.cer文件)。 + + ![image](screenshots/cloud/profile2.jpg) + + - 下载生成的发布Profile(.p7b文件),建议在客户端工程(Application文件)下新建signature文件作为存储位置。 + +5. 使用密钥(.p12文件),发布证书(.cer文件)和Profile(.p7b文件)完成手动签名,建议将全部文件放于客户端代码中的signature文件,详见[手动配置签名信息](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-signing-V5#section112371245115818)。 + + - 在DevEco Studio主菜单栏File > Project Structure > Project > Signing Configs窗口中,取消勾选“Automatically generate signature”,然后配置工程的签名信息。此处输入的两处密码为第1步和第2步设置的Key password与Key store password,且两密码默认为第1步中设置的Password。 + + ![image](screenshots/client/signature.jpg) + +6. 登录[AGC平台](https://developer.huawei.com/consumer/cn/service/josp/agc/index.html#/),选择“项目设置”,并点击“添加公钥指纹 (HarmonyOS API 9及以上)”,选择在第4步申请的调试证书“IntentsKitNewsUpdate”。 + + ![image](screenshots/cloud/fingerprint.jpg) + +7. 重新安装客户端应用。 + + +### 7.服务端日志查询 + +1. [AGC](https://developer.huawei.com/consumer/cn/service/josp/agc/index.html#/)平台提供了在线查询服务端日志的功能,您可以登录[AGC平台](https://developer.huawei.com/consumer/cn/service/josp/agc/index.html#/),选择“我的项目”后,在左侧边栏选择“质量”下的“云监控”中的“日志服务”进行查看。 + + ![image](screenshots/cloud/log_service1.JPG) + +2. 如需查看特定云函数的日志,请点击“增加过滤条件”,依次选择“function_name” > “等于”,并输入目标云函数的名称。例如,若需查看云函数“push-message”的日志,请在输入框中填写“push-message”,如下图所示。 + + ![image](screenshots/cloud/log_service2.JPG) diff --git a/screenshots/client/auto_signature.jpg b/screenshots/client/auto_signature.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0282b8c5eb74d4248bc13abaa03e19f7217793ad Binary files /dev/null and b/screenshots/client/auto_signature.jpg differ diff --git a/screenshots/client/bundle_name.PNG b/screenshots/client/bundle_name.PNG new file mode 100644 index 0000000000000000000000000000000000000000..6dfe9f28a02f90dd5a59c703e61b0b7a6c20b64a Binary files /dev/null and b/screenshots/client/bundle_name.PNG differ diff --git a/screenshots/client/check_signature.jpg b/screenshots/client/check_signature.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bb4dbbdb96bc1c43a86e3fe3a8b52410cf694084 Binary files /dev/null and b/screenshots/client/check_signature.jpg differ diff --git a/screenshots/client/cloud_program.PNG b/screenshots/client/cloud_program.PNG new file mode 100644 index 0000000000000000000000000000000000000000..bc3f65d21ab9a87c40d374de771585a422ed3fb2 Binary files /dev/null and b/screenshots/client/cloud_program.PNG differ diff --git a/screenshots/client/create_key_store1.jpg b/screenshots/client/create_key_store1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b630a8b2546c4218338e8a28f2aeb7d56ec5df64 Binary files /dev/null and b/screenshots/client/create_key_store1.jpg differ diff --git a/screenshots/client/create_key_store2.jpg b/screenshots/client/create_key_store2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2e7b4b464a2b769b4ec94a47143b3ee47229c3df Binary files /dev/null and b/screenshots/client/create_key_store2.jpg differ diff --git a/screenshots/client/generate_key_and_CSR1.jpg b/screenshots/client/generate_key_and_CSR1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e592de3bca29e802fa960babe70b4439252f3cd1 Binary files /dev/null and b/screenshots/client/generate_key_and_CSR1.jpg differ diff --git a/screenshots/client/generate_key_and_CSR2.jpg b/screenshots/client/generate_key_and_CSR2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9c77ba5862f9cf2077fe9134f4100faf7bb2d219 Binary files /dev/null and b/screenshots/client/generate_key_and_CSR2.jpg differ diff --git a/screenshots/client/open_objects.PNG b/screenshots/client/open_objects.PNG new file mode 100644 index 0000000000000000000000000000000000000000..6715e29929873aa1a0d247868153f3d84ff3aeea Binary files /dev/null and b/screenshots/client/open_objects.PNG differ diff --git a/screenshots/client/signature.jpg b/screenshots/client/signature.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cdc7c8245d2e647208504114bc63707fe7fc6fd5 Binary files /dev/null and b/screenshots/client/signature.jpg differ diff --git a/screenshots/cloud/add_apply1.PNG b/screenshots/cloud/add_apply1.PNG new file mode 100644 index 0000000000000000000000000000000000000000..b918304c84750fc801e963bcd3dd02ac243088fb Binary files /dev/null and b/screenshots/cloud/add_apply1.PNG differ diff --git a/screenshots/cloud/add_apply2.PNG b/screenshots/cloud/add_apply2.PNG new file mode 100644 index 0000000000000000000000000000000000000000..79239e9d7f9a48abb77c15b2e3f63f64e1d27181 Binary files /dev/null and b/screenshots/cloud/add_apply2.PNG differ diff --git a/screenshots/cloud/add_apply3.PNG b/screenshots/cloud/add_apply3.PNG new file mode 100644 index 0000000000000000000000000000000000000000..b0ad6cad420396bfdb691f92f034cd6603961fe8 Binary files /dev/null and b/screenshots/cloud/add_apply3.PNG differ diff --git a/screenshots/cloud/add_apply4.PNG b/screenshots/cloud/add_apply4.PNG new file mode 100644 index 0000000000000000000000000000000000000000..42fbc80147dc66e096625cd222b26799d20a3d9d Binary files /dev/null and b/screenshots/cloud/add_apply4.PNG differ diff --git a/screenshots/cloud/add_apply5.PNG b/screenshots/cloud/add_apply5.PNG new file mode 100644 index 0000000000000000000000000000000000000000..cdd26fe3155e877bd4cdfa6fea4d398420abe6f9 Binary files /dev/null and b/screenshots/cloud/add_apply5.PNG differ diff --git a/screenshots/cloud/add_project.PNG b/screenshots/cloud/add_project.PNG new file mode 100644 index 0000000000000000000000000000000000000000..21d99b4cd70a544e19607aef86a7da807465a3ac Binary files /dev/null and b/screenshots/cloud/add_project.PNG differ diff --git a/screenshots/cloud/certificate1.jpg b/screenshots/cloud/certificate1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..44830c018938968ddd1ff63d72a33e26038d865a Binary files /dev/null and b/screenshots/cloud/certificate1.jpg differ diff --git a/screenshots/cloud/certificate2.jpg b/screenshots/cloud/certificate2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cff5db39eb6be92025d260370de1619a0471bfe6 Binary files /dev/null and b/screenshots/cloud/certificate2.jpg differ diff --git a/screenshots/cloud/cloud_config.PNG b/screenshots/cloud/cloud_config.PNG new file mode 100644 index 0000000000000000000000000000000000000000..344eb1261b1ced48f8073cd93e6e052802ee287d Binary files /dev/null and b/screenshots/cloud/cloud_config.PNG differ diff --git a/screenshots/cloud/cloud_data.PNG b/screenshots/cloud/cloud_data.PNG new file mode 100644 index 0000000000000000000000000000000000000000..204b21240575e289403316bf8215b04b47acdd7b Binary files /dev/null and b/screenshots/cloud/cloud_data.PNG differ diff --git a/screenshots/cloud/cloud_serverless.PNG b/screenshots/cloud/cloud_serverless.PNG new file mode 100644 index 0000000000000000000000000000000000000000..c1f69c83d65d6e6d84ecb9f40ba5a93bbfcaa6af Binary files /dev/null and b/screenshots/cloud/cloud_serverless.PNG differ diff --git a/screenshots/cloud/create_project.PNG b/screenshots/cloud/create_project.PNG new file mode 100644 index 0000000000000000000000000000000000000000..f64513ae51e3c58df682e0631db4ed50d7c6d5d8 Binary files /dev/null and b/screenshots/cloud/create_project.PNG differ diff --git a/screenshots/cloud/data_position.PNG b/screenshots/cloud/data_position.PNG new file mode 100644 index 0000000000000000000000000000000000000000..a1257d0f1763d7dc39ec6a4f25f002eba43e0b4f Binary files /dev/null and b/screenshots/cloud/data_position.PNG differ diff --git a/screenshots/cloud/fingerprint.jpg b/screenshots/cloud/fingerprint.jpg new file mode 100644 index 0000000000000000000000000000000000000000..043fcd9a11382638d7589c3f6084bd60ef15d3f6 Binary files /dev/null and b/screenshots/cloud/fingerprint.jpg differ diff --git a/screenshots/cloud/log_service1.JPG b/screenshots/cloud/log_service1.JPG new file mode 100644 index 0000000000000000000000000000000000000000..666be1acf01c4f587f51d89c40083cae162d70a2 Binary files /dev/null and b/screenshots/cloud/log_service1.JPG differ diff --git a/screenshots/cloud/log_service2.JPG b/screenshots/cloud/log_service2.JPG new file mode 100644 index 0000000000000000000000000000000000000000..5db5c02a27e0385371647224f6c8aec210e3807f Binary files /dev/null and b/screenshots/cloud/log_service2.JPG differ diff --git a/screenshots/cloud/open_capabilities.PNG b/screenshots/cloud/open_capabilities.PNG new file mode 100644 index 0000000000000000000000000000000000000000..cf11ef9debbd9529df2ede3e8aef38f078955a34 Binary files /dev/null and b/screenshots/cloud/open_capabilities.PNG differ diff --git a/screenshots/cloud/profile1.jpg b/screenshots/cloud/profile1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ad42a91e70072b9b63084c7165771f62d424fd92 Binary files /dev/null and b/screenshots/cloud/profile1.jpg differ diff --git a/screenshots/cloud/profile2.jpg b/screenshots/cloud/profile2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bdfd804d45a90b5f8c9ae7dde7684bdfed9b2d95 Binary files /dev/null and b/screenshots/cloud/profile2.jpg differ diff --git a/screenshots/device/screenshot_001.png b/screenshots/device/screenshot_001.png new file mode 100644 index 0000000000000000000000000000000000000000..0a7e5e64588bfc6914ced1a6e18ed6c043d8b3ec Binary files /dev/null and b/screenshots/device/screenshot_001.png differ diff --git a/screenshots/device/screenshot_002.png b/screenshots/device/screenshot_002.png new file mode 100644 index 0000000000000000000000000000000000000000..c03b8c9d437ee694e1293c44447ecaf39434e66e Binary files /dev/null and b/screenshots/device/screenshot_002.png differ diff --git a/screenshots/device/screenshot_003.png b/screenshots/device/screenshot_003.png new file mode 100644 index 0000000000000000000000000000000000000000..8d2c9b1be6caed75de3b3b16e5e05b72ea720f71 Binary files /dev/null and b/screenshots/device/screenshot_003.png differ diff --git a/screenshots/device/screenshot_004.png b/screenshots/device/screenshot_004.png new file mode 100644 index 0000000000000000000000000000000000000000..c03b8c9d437ee694e1293c44447ecaf39434e66e Binary files /dev/null and b/screenshots/device/screenshot_004.png differ