From 4174e02d140daecc4a3b9aa23e2f2b62e637227b Mon Sep 17 00:00:00 2001 From: zhao-zhiqiang-zzq Date: Wed, 14 Jul 2021 11:49:08 +0800 Subject: [PATCH] sync launcher code Signed-off-by: zhao-zhiqiang-zzq --- .gitattributes | 4 + OAT.xml | 57 ++ README.md | 2 +- README_zh.md | 2 +- launcher/src/main/config.json | 8 +- launcher/src/main/js/default/app.js | 20 +- .../common/cache/AppListInfoCacheManager.js | 67 ++ .../common/cache/AppResourceCacheManager.js | 105 +++ .../js/default/common/cache/DiskLruCache.js | 107 +++ .../main/js/default/common/cache/LruCache.js | 77 ++ .../main/js/default/common/colors/Colors.js | 5 +- .../common/component/AppIcon/AppIcon.css | 3 +- .../common/component/AppIcon/AppIcon.hml | 4 +- .../common/component/AppIcon/AppIcon.js | 30 +- .../common/component/GridName/GridName.css | 7 +- .../common/component/GridName/GridName.js | 40 +- .../common/component/ListName/AppName.js | 40 +- .../common/configs/DefaultLayoutConfig.js | 10 +- .../common/configs/GridLayoutConfigs.js | 28 +- .../common/configs/SystemApplication.js | 5 +- .../common/constants/EventConstants.js | 25 + .../common/constants/LayoutConstants.js | 7 +- .../js/default/common/constants/PageData.js | 5 +- .../js/default/common/css/CommonPageStyle.css | 6 +- .../main/js/default/common/model/AppModel.js | 397 ++++++--- .../js/default/common/model/ILayoutConfig.js | 95 +++ .../common/model/LayoutConfigManager.js | 5 + .../default/common/model/MMIEventManager.js | 56 ++ .../main/js/default/common/model/MMIModel.js | 42 + .../default/common/model/ResourceManager.js | 108 ++- .../js/default/common/model/SettingsModel.js | 84 +- .../common/model/StorageLayoutConfig.js | 83 +- .../js/default/common/pics/img_return.png | Bin 0 -> 255 bytes .../js/default/common/pics/img_to_detail.png | Bin 0 -> 391 bytes .../js/default/common/utils/CheckArray.js | 40 + .../default/common/utils/CheckEmptyUtils.js | 48 ++ .../main/js/default/common/utils/FileUtils.js | 213 +++++ .../js/default/common/utils/RouterUtil.js | 54 +- launcher/src/main/js/default/i18n/en-US.json | 8 +- launcher/src/main/js/default/i18n/zh-CN.json | 8 +- .../default/pages/AppGridView/AppGridView.css | 21 +- .../default/pages/AppGridView/AppGridView.hml | 78 +- .../default/pages/AppGridView/AppGridView.js | 625 +++++++++++++-- .../default/pages/AppListView/AppListView.css | 3 +- .../default/pages/AppListView/AppListView.hml | 7 +- .../default/pages/AppListView/AppListView.js | 183 ++++- .../js/default/pages/EntryView/EntryView.css | 1 - .../js/default/pages/EntryView/EntryView.hml | 2 +- .../js/default/pages/EntryView/EntryView.js | 34 +- .../pages/SettingsView/SettingsView.css | 119 --- .../pages/SettingsView/SettingsView.hml | 88 -- .../pages/SettingsView/SettingsView.js | 98 --- .../default/presenter/app/AppGridPresenter.js | 755 ++++++++++++++++-- .../default/presenter/app/AppListPresenter.js | 23 +- .../presenter/app/base/BaseAppPresenter.js | 265 +++++- .../default/presenter/entry/EntryPresenter.js | 9 +- .../main/js/default/resources/res-hdpi.json | 8 + .../main/js/default/resources/res-ldpi.json | 8 + .../main/js/default/resources/res-mdpi.json | 8 + .../main/js/default/resources/res-xhdpi.json | 8 + .../main/js/default/resources/res-xxhdpi.json | 8 + .../js/default/resources/res-xxxhdpi.json | 8 + .../main/resources/rawfile/layoutInfo.json | 9 + recents/src/main/config.json | 4 +- recents/src/main/js/default/app.js | 4 + .../common/component/AppIcon/AppIcon.js | 32 +- .../common/component/AppName/AppName.js | 30 +- .../js/default/common/model/RecentsModel.js | 172 ++-- .../default/common/model/ResourceManager.js | 48 +- .../js/default/common/pics/icon_default.png | Bin 0 -> 5979 bytes recents/src/main/js/default/i18n/en-US.json | 1 + recents/src/main/js/default/i18n/zh-CN.json | 1 + .../main/js/default/pages/recent/recent.css | 17 +- .../main/js/default/pages/recent/recent.hml | 17 +- .../main/js/default/pages/recent/recent.js | 46 +- .../presenter/recent/RecentsPresenter.js | 33 +- .../main/js/default/resources/res-hdpi.json | 8 + .../main/js/default/resources/res-ldpi.json | 8 + .../main/js/default/resources/res-mdpi.json | 8 + .../main/js/default/resources/res-xhdpi.json | 8 + .../main/js/default/resources/res-xxhdpi.json | 8 + .../js/default/resources/res-xxxhdpi.json | 8 + settings.gradle | 2 +- settings/build.gradle | 22 + settings/package.json | 1 + settings/src/main/config.json | 53 ++ settings/src/main/js/default/app.js | 30 + .../common/configs/DefaultLayoutConfig.js | 23 + .../common/configs/GridLayoutConfigs.js | 41 + .../common/constants/LayoutConstants.js | 21 + .../js/default/common/constants/PageData.js | 21 + .../js/default/common/model/ILayoutConfig.js | 115 +++ .../common/model/LayoutConfigManager.js | 24 + .../js/default/common/model/SettingsModel.js | 102 +++ .../common/model/StorageLayoutConfig.js | 108 +++ .../js/default/common/pics/img_return.png | Bin 0 -> 255 bytes .../js/default/common/pics/img_to_detail.png | Bin 0 -> 391 bytes settings/src/main/js/default/i18n/en-US.json | 22 + settings/src/main/js/default/i18n/zh-CN.json | 22 + .../js/default/pages/settings/settings.css | 192 +++++ .../js/default/pages/settings/settings.hml | 136 ++++ .../js/default/pages/settings/settings.js | 227 ++++++ .../presenter/settings/SettingsPresenter.js | 70 +- .../main/js/default/resources/res-hdpi.json | 6 + .../main/js/default/resources/res-ldpi.json | 6 + .../main/js/default/resources/res-mdpi.json | 6 + .../main/js/default/resources/res-xhdpi.json | 6 + .../main/js/default/resources/res-xxhdpi.json | 6 + .../js/default/resources/res-xxxhdpi.json | 6 + .../main/resources/base/element/string.json | 12 + .../src/main/resources/base/media/icon.png | Bin 0 -> 6790 bytes 111 files changed, 5067 insertions(+), 939 deletions(-) create mode 100644 OAT.xml create mode 100644 launcher/src/main/js/default/common/cache/AppListInfoCacheManager.js create mode 100644 launcher/src/main/js/default/common/cache/AppResourceCacheManager.js create mode 100644 launcher/src/main/js/default/common/cache/DiskLruCache.js create mode 100644 launcher/src/main/js/default/common/cache/LruCache.js create mode 100644 launcher/src/main/js/default/common/constants/EventConstants.js create mode 100644 launcher/src/main/js/default/common/model/MMIEventManager.js create mode 100644 launcher/src/main/js/default/common/model/MMIModel.js create mode 100644 launcher/src/main/js/default/common/pics/img_return.png create mode 100644 launcher/src/main/js/default/common/pics/img_to_detail.png create mode 100644 launcher/src/main/js/default/common/utils/CheckArray.js create mode 100644 launcher/src/main/js/default/common/utils/CheckEmptyUtils.js create mode 100644 launcher/src/main/js/default/common/utils/FileUtils.js delete mode 100755 launcher/src/main/js/default/pages/SettingsView/SettingsView.css delete mode 100644 launcher/src/main/js/default/pages/SettingsView/SettingsView.hml delete mode 100644 launcher/src/main/js/default/pages/SettingsView/SettingsView.js create mode 100644 launcher/src/main/js/default/resources/res-hdpi.json create mode 100644 launcher/src/main/js/default/resources/res-ldpi.json create mode 100644 launcher/src/main/js/default/resources/res-mdpi.json create mode 100644 launcher/src/main/js/default/resources/res-xhdpi.json create mode 100644 launcher/src/main/js/default/resources/res-xxhdpi.json create mode 100644 launcher/src/main/js/default/resources/res-xxxhdpi.json create mode 100644 launcher/src/main/resources/rawfile/layoutInfo.json create mode 100644 recents/src/main/js/default/common/pics/icon_default.png create mode 100644 recents/src/main/js/default/resources/res-hdpi.json create mode 100644 recents/src/main/js/default/resources/res-ldpi.json create mode 100644 recents/src/main/js/default/resources/res-mdpi.json create mode 100644 recents/src/main/js/default/resources/res-xhdpi.json create mode 100644 recents/src/main/js/default/resources/res-xxhdpi.json create mode 100644 recents/src/main/js/default/resources/res-xxxhdpi.json create mode 100644 settings/build.gradle create mode 100644 settings/package.json create mode 100644 settings/src/main/config.json create mode 100644 settings/src/main/js/default/app.js create mode 100644 settings/src/main/js/default/common/configs/DefaultLayoutConfig.js create mode 100644 settings/src/main/js/default/common/configs/GridLayoutConfigs.js create mode 100644 settings/src/main/js/default/common/constants/LayoutConstants.js create mode 100644 settings/src/main/js/default/common/constants/PageData.js create mode 100644 settings/src/main/js/default/common/model/ILayoutConfig.js create mode 100644 settings/src/main/js/default/common/model/LayoutConfigManager.js create mode 100644 settings/src/main/js/default/common/model/SettingsModel.js create mode 100644 settings/src/main/js/default/common/model/StorageLayoutConfig.js create mode 100644 settings/src/main/js/default/common/pics/img_return.png create mode 100644 settings/src/main/js/default/common/pics/img_to_detail.png create mode 100644 settings/src/main/js/default/i18n/en-US.json create mode 100644 settings/src/main/js/default/i18n/zh-CN.json create mode 100644 settings/src/main/js/default/pages/settings/settings.css create mode 100644 settings/src/main/js/default/pages/settings/settings.hml create mode 100644 settings/src/main/js/default/pages/settings/settings.js rename {launcher => settings}/src/main/js/default/presenter/settings/SettingsPresenter.js (58%) create mode 100644 settings/src/main/js/default/resources/res-hdpi.json create mode 100644 settings/src/main/js/default/resources/res-ldpi.json create mode 100644 settings/src/main/js/default/resources/res-mdpi.json create mode 100644 settings/src/main/js/default/resources/res-xhdpi.json create mode 100644 settings/src/main/js/default/resources/res-xxhdpi.json create mode 100644 settings/src/main/js/default/resources/res-xxxhdpi.json create mode 100644 settings/src/main/resources/base/element/string.json create mode 100644 settings/src/main/resources/base/media/icon.png diff --git a/.gitattributes b/.gitattributes index 51c63e29..6e4add21 100644 --- a/.gitattributes +++ b/.gitattributes @@ -13,3 +13,7 @@ *.so filter=lfs diff=lfs merge=lfs -text *.bin filter=lfs diff=lfs merge=lfs -text *.dll filter=lfs diff=lfs merge=lfs -text +*.dat filter=lfs diff=lfs merge=lfs -text +*.bz2 filter=lfs diff=lfs merge=lfs -text +*.bz filter=lfs diff=lfs merge=lfs -text +*.gif filter=lfs diff=lfs merge=lfs -text diff --git a/OAT.xml b/OAT.xml new file mode 100644 index 00000000..de3b034c --- /dev/null +++ b/OAT.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + diff --git a/README.md b/README.md index 71a9881a..b0fce4a9 100755 --- a/README.md +++ b/README.md @@ -39,5 +39,5 @@ The home screen launcher provides a main entry to human-machine interactions. It System apps -**applications\_launcher** +**applications\_standard\_launcher** diff --git a/README_zh.md b/README_zh.md index a3c67ceb..8ab6c759 100755 --- a/README_zh.md +++ b/README_zh.md @@ -39,4 +39,4 @@ 系统应用 -**applications\_launcher** +**applications\_standard\_launcher** diff --git a/launcher/src/main/config.json b/launcher/src/main/config.json index fb38740b..df83fe1e 100644 --- a/launcher/src/main/config.json +++ b/launcher/src/main/config.json @@ -3,7 +3,7 @@ "bundleName": "com.ohos.launcher", "vendor": "ohos", "version": { - "code": 1, + "code": 1000000, "name": "1.0" }, "apiVersion": { @@ -21,7 +21,8 @@ "distro": { "deliveryWithInstall": true, "moduleName": "launcher", - "moduleType": "entry" + "moduleType": "entry", + "installationFree": true }, "abilities": [ { @@ -57,8 +58,7 @@ "pages": [ "pages/EntryView/EntryView", "pages/AppGridView/AppGridView", - "pages/AppListView/AppListView", - "pages/SettingsView/SettingsView" + "pages/AppListView/AppListView" ], "name": "default", "window": { diff --git a/launcher/src/main/js/default/app.js b/launcher/src/main/js/default/app.js index d2f36d8f..ac0fffc2 100644 --- a/launcher/src/main/js/default/app.js +++ b/launcher/src/main/js/default/app.js @@ -15,18 +15,30 @@ import AppModel from './common/model/AppModel.js' import SettingsModel from './common/model/SettingsModel.js' +import MMIModel from './common/model/MMIModel.js' +import ResourceManager from './common/model/ResourceManager.js' +import AppListInfoCacheManager from './common/cache/AppListInfoCacheManager.js' export default { - data: { + data:{ appModel: new AppModel(), - settingsModel: new SettingsModel() + settingsModel: new SettingsModel(), + mmiModel: new MMIModel(), + resourceManager: new ResourceManager(), + appListInfoCacheManager: new AppListInfoCacheManager(), + screenHeight: 0, + screenWidth: 0 }, onCreate() { - console.info("Application onCreate"); + console.info("Launcher app Application onCreate"); + this.data.appModel.registerAppListEvent(); }, onDestroy() { - console.info("Application onDestroy"); + console.info("Launcher app Application onDestroy"); + this.data.resourceManager.clearCache(); + this.data.appListInfoCacheManager.clearCache(); + this.data.appModel.unregisterAppListEvent(); } }; diff --git a/launcher/src/main/js/default/common/cache/AppListInfoCacheManager.js b/launcher/src/main/js/default/common/cache/AppListInfoCacheManager.js new file mode 100644 index 00000000..7d0b899c --- /dev/null +++ b/launcher/src/main/js/default/common/cache/AppListInfoCacheManager.js @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2021 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 LruCache from './LruCache.js'; +import DiskLruCache from './DiskLruCache.js'; + +/** + * A Manager class that provides get/set/clear cache methods for app list data. + */ +export default class AppListInfoCacheManager { + #lruCache; + #diskLruCache; + + constructor() { + this.#lruCache = new LruCache(); + this.#diskLruCache = new DiskLruCache(); + } + + /** + * Get cache from disk or memory. + * + * @param {string} key - key of the cache map + * @return {object} - cache get from the memory or disk + */ + getCache(key) { + console.info("Launcher AppListInfoCacheManager getCache key = " + key); + let cache = this.#lruCache.getCache(key); + if (cache == undefined || cache == null || cache == '' || cache == -1) { + return this.#diskLruCache.getCache(key); + } else { + return cache; + } + } + + /** + * Set cache to disk or memory. + * + * @param {string} key - key of the cache map + * @param {object} value - value of the cache map + */ + setCache(key, value) { + console.info("Launcher AppListInfoCacheManager setCache key = " + key + " value = " + value); + this.#lruCache.putCache(key, value); + this.#diskLruCache.putCache(key, value); + } + + /** + * Clear cache of both disk and memory. + */ + clearCache() { + console.info("Launcher AppListInfoCacheManager clearCache"); + this.#lruCache.clear(); + this.#diskLruCache.clear(); + } +} \ No newline at end of file diff --git a/launcher/src/main/js/default/common/cache/AppResourceCacheManager.js b/launcher/src/main/js/default/common/cache/AppResourceCacheManager.js new file mode 100644 index 00000000..84151611 --- /dev/null +++ b/launcher/src/main/js/default/common/cache/AppResourceCacheManager.js @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2021 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 LruCache from './LruCache.js' +import DiskLruCache from './DiskLruCache.js' + +const KEY_ICON = "icon"; +const DISK_CACHE_MISS = -1; + +/** + * A Manager class that provides get/set/clear cache methods for app image data. + */ +export default class AppResourceCacheManager { + #memoryCache; + #diskCache; + + constructor() { + this.#memoryCache = new LruCache(); + this.#diskCache = new DiskLruCache(); + } + + /** + * Get cache from disk or memory. + * + * @param {string} key - key of the cache map + * @return {object} - cache get from memory or disk + */ + getCache(bundleName, key) { + console.info("Launcher AppResourceCacheManager getCache bundleName = " + bundleName + " key = " + key); + let cache = this.#getCacheFromMemory(bundleName, key); + if (cache == undefined || cache == null || cache == '') { + if (key === KEY_ICON) { + return this.#getCacheFromDisk(bundleName); + } + return null; + } else { + return cache; + } + } + + /** + * Set cache to disk or memory. + * + * @param {string} key - key of the cache map + * @param {object} value - value of the cache map + */ + setCache(bundleName, key, value) { + console.info("Launcher AppResourceCacheManager setCache bundleName = " + bundleName + " key = " + key); + this.#setCacheToMemory(bundleName, key, value); + if (key === KEY_ICON) { + this.#setCacheToDisk(bundleName, key, value); + } + } + + /** + * Clear cache of both disk and memory. + */ + clearCache() { + console.info("Launcher AppResourceCacheManager clearCache"); + this.#memoryCache.clear(); + } + + #getCacheFromMemory = (bundleName, key) => { + let cache = this.#memoryCache.getCache(bundleName); + if (cache == undefined || cache == null || cache == '' || cache === -1) { + return null; + } else if (cache[key] == undefined || cache[key] == null || cache[key] == '') { + return null; + } else { + return cache[key]; + } + } + + #setCacheToMemory = (bundleName, key, value) => { + let cache = this.#memoryCache.getCache(bundleName); + if (cache == undefined || cache == null || cache == '' || cache === -1) { + cache = {}; + cache[key] = value; + } else { + cache[key] = value; + } + this.#memoryCache.putCache(bundleName, cache); + } + + #getCacheFromDisk = (bundleName, key) => { + let data = this.#diskCache.getCache(bundleName); + return data !== DISK_CACHE_MISS ? data : null; + } + + #setCacheToDisk = (bundleName, key, value) => { + this.#diskCache.putCache(bundleName, value); + } +} \ No newline at end of file diff --git a/launcher/src/main/js/default/common/cache/DiskLruCache.js b/launcher/src/main/js/default/common/cache/DiskLruCache.js new file mode 100644 index 00000000..9aa62611 --- /dev/null +++ b/launcher/src/main/js/default/common/cache/DiskLruCache.js @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2021 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 FileUtils from "../utils/FileUtils.js"; + +/** + * A class provides persistent operation for memory cache. + */ +export default class DiskLruCache { + constructor(capacity = 100) { + this.cache = new Map(); + this.capacity = capacity; + this.initMap(); //read cache from local + } + + /** + * Init the cache whether the file has data. + */ + initMap() { + console.info("Launcher DiskLruCache initMap start execution"); + try { + let arr = FileUtils.readJournal().split("\n").reverse(); + let len = arr.length >= this.capacity ? this.capacity : arr.length; + for (let i = 0;i < len; i++) { + this.cache.set(arr[i], arr[i]); + } + } catch (e) { + console.error("Launcher DiskLruCache initMap e " + e); + } + } + + /** + * Get cache from disk. + * + * @param {string} key - key of the cache map + * @return {object} - target cache object + */ + getCache(key) { + if (this.cache.has(key)) { + // exist and update + let temp = this.cache.get(key); + //delete the old cache + this.cache.delete(key); + //update the cache to recent use + this.cache.set(key, temp); + //update local cache to recent use + FileUtils.writeJournal(key); + return FileUtils.readJsonObj(key)[key]; + } + return -1; + } + + /** + * Put cache to disk. + * + * @param {string} key - key of the cache map + * @param {object} value - value of the cache map + */ + putCache(key, value) { + if (this.cache.has(key)) { + // exist and update + this.cache.delete(key); + } else if (this.cache.size >= this.capacity) { + // if size > capacity ,remove the old + this.remove(this.cache.keys().next().value); + } + //update the cache to recent use + this.cache.set(key, value); + //update local cache to recent use + FileUtils.writeJournal(key); + FileUtils.writeJsonObj({ + [key] : value + }, key); + } + + /** + * Remove cache of corresponding key. + * + * @param {string} key - key of the cache map + */ + remove(key) { + this.cache.delete(key); + FileUtils.removeFile(key); + } + + /** + * Clear cache of disk. + */ + clear() { + this.cache.forEach(function (value, key) { + FileUtils.removeFile(key); + }); + this.cache.clear(); + } +} \ No newline at end of file diff --git a/launcher/src/main/js/default/common/cache/LruCache.js b/launcher/src/main/js/default/common/cache/LruCache.js new file mode 100644 index 00000000..c92da9b4 --- /dev/null +++ b/launcher/src/main/js/default/common/cache/LruCache.js @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * A class provides memory cache operation. + */ +export default class LruCache { + constructor(capacity = 100) { + this.cache = new Map(); + this.capacity = capacity; //the capacity of cache + } + + /** + * Get cache from memory. + * + * @param {string} key - key of the cache map + * @return {object} - cache from memory + */ + getCache(key) { + if (this.cache.has(key)) { + // exist and update + let temp = this.cache.get(key); + //delete the old cache + this.cache.delete(key); + //update the cache to recent use + this.cache.set(key, temp); + return temp; + } + return -1; + } + + /** + * Put cache to disk. + * + * @param {string} key - key of the cache map + * @param {object} value - value of the cache map + */ + putCache(key, value) { + if (this.cache.has(key)) { + // exist and update + this.cache.delete(key); + } else if (this.cache.size >= this.capacity) { + // if size > capacity ,remove the old + this.cache.delete(this.cache.keys().next().value); + } + //update the cache to recent use + this.cache.set(key, value); + } + + /** + * Remove cache of corresponding key. + * + * @param {string} key - key of the cache map + */ + remove(key) { + this.cache.delete(key); + } + + /** + * Clear cache of memory. + */ + clear() { + this.cache.clear(); + } +} \ No newline at end of file diff --git a/launcher/src/main/js/default/common/colors/Colors.js b/launcher/src/main/js/default/common/colors/Colors.js index ec86b9d8..759da5f0 100644 --- a/launcher/src/main/js/default/common/colors/Colors.js +++ b/launcher/src/main/js/default/common/colors/Colors.js @@ -13,7 +13,10 @@ * limitations under the License. */ -var Colors = { +/** + * Description: Color data. + */ +const Colors = { bgSelectedColor: "#FF008000", bgUnselectedColor: "white", fontSelectedColor: "white", diff --git a/launcher/src/main/js/default/common/component/AppIcon/AppIcon.css b/launcher/src/main/js/default/common/component/AppIcon/AppIcon.css index bdda70d4..42e3252e 100644 --- a/launcher/src/main/js/default/common/component/AppIcon/AppIcon.css +++ b/launcher/src/main/js/default/common/component/AppIcon/AppIcon.css @@ -14,9 +14,8 @@ */ @import '../../css/CommonPageStyle.css'; + .image-box{ - height: 110px; - width: 110px; display: flex; align-items: center; justify-content: center; diff --git a/launcher/src/main/js/default/common/component/AppIcon/AppIcon.hml b/launcher/src/main/js/default/common/component/AppIcon/AppIcon.hml index ee550af1..6a4c3100 100644 --- a/launcher/src/main/js/default/common/component/AppIcon/AppIcon.hml +++ b/launcher/src/main/js/default/common/component/AppIcon/AppIcon.hml @@ -15,6 +15,6 @@ */ --> -
- +
+
\ No newline at end of file diff --git a/launcher/src/main/js/default/common/component/AppIcon/AppIcon.js b/launcher/src/main/js/default/common/component/AppIcon/AppIcon.js index f9db09e2..93ac5806 100644 --- a/launcher/src/main/js/default/common/component/AppIcon/AppIcon.js +++ b/launcher/src/main/js/default/common/component/AppIcon/AppIcon.js @@ -13,10 +13,12 @@ * limitations under the License. */ -import ResourceManager from '../../model/ResourceManager.js'; - -var mResourceManager; +let mResourceManager; +let mDefaultAppIcon; +/** + * A page element that display app icon. + */ export default { props: ['itemAppId', 'itemAppIcon', 'itemBundleName'], @@ -30,23 +32,35 @@ export default { onInit() { this.$watch('itemBundleName','appIconWatcher'); - mResourceManager = new ResourceManager(); - mResourceManager.getAppIcon(this.itemAppIcon, this.itemBundleName, this.iconLoadCallback); - }, - - onShow() { + mDefaultAppIcon = globalThis.$globalR('image.icon_default'); + mResourceManager = this.$app.$def.data.resourceManager; + mResourceManager.getAppIcon(this.itemAppIcon, this.itemBundleName, this.iconLoadCallback, mDefaultAppIcon); }, + /** + * Watch the value of appIcon, called when the value changed. + * + * @param {object} newV - New value of appIcon + * @param {object} oldV - Old value of appIcon + */ appIconWatcher(newV, oldV) { if (newV != null && newV != undefined) { mResourceManager.getAppIcon(this.itemAppIcon, this.itemBundleName, this.iconLoadCallback); } }, + /** + * Callback function when appIcon loaded from the resource manager. + * + * @param {string} image - App icon base64. + */ iconLoadCallback(image) { this.appIcon = image; }, + /** + * Reload the app icon base64 from resource manager. + */ updateIcon() { console.info("Launcher AppIcon updateIcon in bundleName = " + this.itemBundleName); mResourceManager.getAppIcon(this.itemAppIcon, this.itemBundleName, this.iconLoadCallback); diff --git a/launcher/src/main/js/default/common/component/GridName/GridName.css b/launcher/src/main/js/default/common/component/GridName/GridName.css index 2d150204..367dda90 100644 --- a/launcher/src/main/js/default/common/component/GridName/GridName.css +++ b/launcher/src/main/js/default/common/component/GridName/GridName.css @@ -17,8 +17,11 @@ .app-name { text-align: center; - width: 110px; - height: 60px; + width: 100%; + height: 40px; + line-height: 27px; color: white; font-size: 27px; + max-lines: 1; + text-overflow: ellipsis; } diff --git a/launcher/src/main/js/default/common/component/GridName/GridName.js b/launcher/src/main/js/default/common/component/GridName/GridName.js index 6dbb4bfb..14e2572a 100644 --- a/launcher/src/main/js/default/common/component/GridName/GridName.js +++ b/launcher/src/main/js/default/common/component/GridName/GridName.js @@ -13,10 +13,11 @@ * limitations under the License. */ -import ResourceManager from '../../model/ResourceManager.js'; - -var mResourceManager; +let mResourceManager; +/** + * A page element that display app name in GridView. + */ export default { props: ['itemAppId', 'itemLabelId', 'itemBundleName', 'itemAppName'], @@ -30,26 +31,37 @@ export default { }, onInit() { - this.$watch('itemBundleName','appIconWatcher'); - mResourceManager = new ResourceManager(); - mResourceManager.getAppName(this.itemLabelId, this.itemBundleName, this.itemAppName, this.iconLoadCallback); + this.$watch('itemBundleName','appNameWatcher'); + mResourceManager = this.$app.$def.data.resourceManager; + mResourceManager.getAppName(this.itemLabelId, this.itemBundleName, this.itemAppName, this.appNameLoadCallback); }, - onShow() { - }, - - appIconWatcher(newV, oldV) { + /** + * Watch the value of appName, called when the value changed. + * + * @param {object} newV - New value of appName. + * @param {object} oldV - Old value of appName. + */ + appNameWatcher(newV, oldV) { if (newV != null && newV != undefined) { - mResourceManager.getAppName(this.itemLabelId, this.itemBundleName, this.itemAppName, this.iconLoadCallback); + mResourceManager.getAppName(this.itemLabelId, this.itemBundleName, this.itemAppName, this.appNameLoadCallback); } }, - iconLoadCallback(name) { + /** + * Callback function when appName loaded from the resource manager. + * + * @param {string} name - App name. + */ + appNameLoadCallback(name) { this.appName = name; }, + /** + * Reload the app name from resource manager. + */ updateName() { - console.info("Launcher AppIcon updateIcon in bundleName = " + this.itemBundleName); - mResourceManager.getAppName(this.itemLabelId, this.itemBundleName, this.itemAppName, this.iconLoadCallback); + console.info("Launcher GridName updateName in bundleName = " + this.itemBundleName); + mResourceManager.getAppName(this.itemLabelId, this.itemBundleName, this.itemAppName, this.appNameLoadCallback); } } \ No newline at end of file diff --git a/launcher/src/main/js/default/common/component/ListName/AppName.js b/launcher/src/main/js/default/common/component/ListName/AppName.js index 6dbb4bfb..0b658b4c 100644 --- a/launcher/src/main/js/default/common/component/ListName/AppName.js +++ b/launcher/src/main/js/default/common/component/ListName/AppName.js @@ -13,10 +13,11 @@ * limitations under the License. */ -import ResourceManager from '../../model/ResourceManager.js'; - -var mResourceManager; +let mResourceManager; +/** + * A page element that display app name in ListView. + */ export default { props: ['itemAppId', 'itemLabelId', 'itemBundleName', 'itemAppName'], @@ -30,26 +31,37 @@ export default { }, onInit() { - this.$watch('itemBundleName','appIconWatcher'); - mResourceManager = new ResourceManager(); - mResourceManager.getAppName(this.itemLabelId, this.itemBundleName, this.itemAppName, this.iconLoadCallback); + this.$watch('itemBundleName','appNameWatcher'); + mResourceManager = this.$app.$def.data.resourceManager; + mResourceManager.getAppName(this.itemLabelId, this.itemBundleName, this.itemAppName, this.appNameLoadCallback); }, - onShow() { - }, - - appIconWatcher(newV, oldV) { + /** + * Watch the value of appName, called when the value changed. + * + * @param {object} newV - New value of appName + * @param {object} oldV - Old value of appName + */ + appNameWatcher(newV, oldV) { if (newV != null && newV != undefined) { - mResourceManager.getAppName(this.itemLabelId, this.itemBundleName, this.itemAppName, this.iconLoadCallback); + mResourceManager.getAppName(this.itemLabelId, this.itemBundleName, this.itemAppName, this.appNameLoadCallback); } }, - iconLoadCallback(name) { + /** + * Callback function when appName loaded from the resource manager. + * + * @param {string} name - App name. + */ + appNameLoadCallback(name) { this.appName = name; }, + /** + * Reload the app name from resource manager. + */ updateName() { - console.info("Launcher AppIcon updateIcon in bundleName = " + this.itemBundleName); - mResourceManager.getAppName(this.itemLabelId, this.itemBundleName, this.itemAppName, this.iconLoadCallback); + console.info("Launcher AppName updateName in bundleName = " + this.itemBundleName); + mResourceManager.getAppName(this.itemLabelId, this.itemBundleName, this.itemAppName, this.appNameLoadCallback); } } \ No newline at end of file diff --git a/launcher/src/main/js/default/common/configs/DefaultLayoutConfig.js b/launcher/src/main/js/default/common/configs/DefaultLayoutConfig.js index 8ea39543..3c67455d 100644 --- a/launcher/src/main/js/default/common/configs/DefaultLayoutConfig.js +++ b/launcher/src/main/js/default/common/configs/DefaultLayoutConfig.js @@ -13,10 +13,14 @@ * limitations under the License. */ -var DefaultLayoutConfig = { +/** + * Default configuration of page layout and recent. + */ +const DefaultLayoutConfig = { DefaultAppPageStartConfig: 'Grid', - DefaultGridConfig: 0, - DefaultRecentProcessLimit: 6 + DefaultGridConfig: 1, + DefaultRecentProcessLimit: 20, + DefaultRecentProcessLimitArray: [5,10,15,20], } export default DefaultLayoutConfig; \ No newline at end of file diff --git a/launcher/src/main/js/default/common/configs/GridLayoutConfigs.js b/launcher/src/main/js/default/common/configs/GridLayoutConfigs.js index c69d5cc2..436a6b68 100644 --- a/launcher/src/main/js/default/common/configs/GridLayoutConfigs.js +++ b/launcher/src/main/js/default/common/configs/GridLayoutConfigs.js @@ -13,11 +13,31 @@ * limitations under the License. */ -var GridLayoutConfigs = { +/** + * Configuration of different layouts. + */ +const GridLayoutConfigs = { GridLayoutTable: [ - {id:0, layout:'5X4', row:5, column:4}, - {id:1, layout:'4X4', row:4, column:4}, - {id:2, layout:'6X4', row:6, column:4}, + { + id: 0, + layout: '4X4', + row: 4, + column: 4 + }, + + { + id: 1, + layout: '5X4', + row: 5, + column: 4 + }, + + { + id: 2, + layout: '6X4', + row: 6, + column: 4 + }, ] } diff --git a/launcher/src/main/js/default/common/configs/SystemApplication.js b/launcher/src/main/js/default/common/configs/SystemApplication.js index 01435a08..d07e7e58 100644 --- a/launcher/src/main/js/default/common/configs/SystemApplication.js +++ b/launcher/src/main/js/default/common/configs/SystemApplication.js @@ -13,7 +13,10 @@ * limitations under the License. */ -var SystemApplication = { +/** + * Records the system app that will not be displayed in Launcher. + */ +const SystemApplication = { SystemApplicationName: 'com.ohos.launcher,com.ohos.systemui' } diff --git a/launcher/src/main/js/default/common/constants/EventConstants.js b/launcher/src/main/js/default/common/constants/EventConstants.js new file mode 100644 index 00000000..73db7756 --- /dev/null +++ b/launcher/src/main/js/default/common/constants/EventConstants.js @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2021 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. + */ + +/** + * Constants of events that will be registered to system. + */ +const EventConstants = { + EVENT_PACKAGE_ADDED : "usual.event.PACKAGE_ADDED", + EVENT_PACKAGE_CHANGED : "usual.event.PACKAGE_CHANGED", + EVENT_PACKAGE_REMOVED : "usual.event.PACKAGE_REMOVED" +} + +export default EventConstants; \ No newline at end of file diff --git a/launcher/src/main/js/default/common/constants/LayoutConstants.js b/launcher/src/main/js/default/common/constants/LayoutConstants.js index dcf94f39..d86c75d8 100644 --- a/launcher/src/main/js/default/common/constants/LayoutConstants.js +++ b/launcher/src/main/js/default/common/constants/LayoutConstants.js @@ -13,9 +13,12 @@ * limitations under the License. */ -var LayoutContants = { +/** + * A Constant class includes layout type Strings. + */ +const LayoutConstants = { Grid: "Grid", List: "List" } -export default LayoutContants; \ No newline at end of file +export default LayoutConstants; \ No newline at end of file diff --git a/launcher/src/main/js/default/common/constants/PageData.js b/launcher/src/main/js/default/common/constants/PageData.js index 8c6664a7..b94d704c 100644 --- a/launcher/src/main/js/default/common/constants/PageData.js +++ b/launcher/src/main/js/default/common/constants/PageData.js @@ -13,7 +13,10 @@ * limitations under the License. */ -var PageData = { +/** + * Pages' uri that will be used as a param of RouterUtil. + */ +const PageData = { GRID_APP_PAGE: 'pages/AppGridView/AppGridView', LIST_APP_PAGE: 'pages/AppListView/AppListView' } diff --git a/launcher/src/main/js/default/common/css/CommonPageStyle.css b/launcher/src/main/js/default/common/css/CommonPageStyle.css index 72045c17..0dfb8b23 100644 --- a/launcher/src/main/js/default/common/css/CommonPageStyle.css +++ b/launcher/src/main/js/default/common/css/CommonPageStyle.css @@ -22,17 +22,17 @@ justify-content: center; } -.app-icon-img{ +.app-icon-img { border-radius: 20px; width: 110px; height: 110px; } -.app-icon-img:active{ +.app-icon-img:active { width: 105px; height: 105px; } -.app-name{ +.app-name { color: black; } \ No newline at end of file diff --git a/launcher/src/main/js/default/common/model/AppModel.js b/launcher/src/main/js/default/common/model/AppModel.js index 749f6a53..b7bc5ee7 100644 --- a/launcher/src/main/js/default/common/model/AppModel.js +++ b/launcher/src/main/js/default/common/model/AppModel.js @@ -13,187 +13,336 @@ * limitations under the License. */ -import bundle_mgr from '@ohos.bundle_mgr'; -import feature_ability from '@ohos.feature_ability'; +import BundleMgr from '@ohos.bundle'; +import FeatureAbility from '@ohos.ability.featureability'; import Subscriber from '@ohos.commonevent'; import SystemApplication from '../../common/configs/SystemApplication.js'; +import EventConstants from '../../common/constants/EventConstants.js'; +import CheckEmptyUtils from '../../common/utils/CheckEmptyUtils.js'; -var mBundleInfoList = []; -var mGridBootAppList = []; -const DEFAULT_ICON_URL = 'common/pics/icon_default.png'; -var mAppUninstallListener = null; -var mAppInstallListeners = []; -var gridListCallback; -var systemApplicationName = SystemApplication.SystemApplicationName; -var mCommonEventSubscriber = null; -var mCommonEventSubscribeInfo = { - events: ["usual.event.PACKAGE_ADDED", "usual.event.PACKAGE_CHANGED", "usual.event.PACKAGE_REMOVED"] +const UNINSTALL_SUCCESS = "UNINSTALL_SUCCESS"; +const UNINSTALL_FAILED = "UNINSTALL_FAILED"; +const IF_GET_ABILITY = 1; + +let mBundleInfoList = []; +let mAppListInstallListener = []; +let mAppListUninstallListener = []; +let mAppListChangeListener = []; +let installCallback; +let systemApplicationName = SystemApplication.SystemApplicationName; +let mCommonEventSubscriber = null; +let mCommonEventSubscribeInfo = { + events: [EventConstants.EVENT_PACKAGE_ADDED, + EventConstants.EVENT_PACKAGE_CHANGED, + EventConstants.EVENT_PACKAGE_REMOVED] }; +/** + * Model class, get data from system API. + */ export default class AppModel { + /** + * Get app information list from system by @ohos.bundle + * + * @param {object} callback - callback from presenter + */ getAppList(callback) { mBundleInfoList = []; - console.info('Launcher getAppIcon getAppList'); - bundle_mgr.getApplicationInfos().then((data) => { - console.info('Launcher getApplicationInfos >' + JSON.stringify(data)); - for (var i = 0; i < data.length; i++) { - if (systemApplicationName.indexOf(data[i].bundleName) > -1) { + console.info('Launcher AppModel getAppIcon getAppList'); + BundleMgr.getBundleInfos(IF_GET_ABILITY).then((data) => { + if (CheckEmptyUtils.isEmpty(data)) { + console.error("Launcher AppModel getAppList getBundleInfos ERROR"); + } + console.info('Launcher AppModel getBundleInfos >' + JSON.stringify(data)); + for (let i = 0; i < data.length; i++) { + if (systemApplicationName.indexOf(data[i].name) > -1) { } else { mBundleInfoList.push( { - System: data[i].isSystemApp, - AppName: data[i].label, - AppId: data[i].name, - AppIcon: data[i].iconId, - bundleName: data[i].bundleName, - labelId: data[i].labelId, + System:data[i].appInfo.systemApp, + AppName: data[i].appInfo.label, + AppId: data[i].appId, + AppIcon: data[i].appInfo.iconId, + bundleName:data[i].name, + labelId :data[i].appInfo.labelId, + abilityName: data[i].abilityInfos[0].name, } ) } - } + }; let appArrayLength = mBundleInfoList.length; - for (let i = 0; i < appArrayLength; i++) { - var iconUrl = mBundleInfoList[i].AppIcon; - if (iconUrl == null || iconUrl == "" || iconUrl == "undefined") { - mBundleInfoList[i].AppIcon = DEFAULT_ICON_URL; - } - } - console.info('Launcher mBundleInfoList' + JSON.stringify(mBundleInfoList)); + console.info('Launcher AppModel mBundleInfoList' + JSON.stringify(mBundleInfoList)); callback(mBundleInfoList); }); } installApp() { + } - uninstallApp(appId, callback) { - console.info('Launcher uninstallApp appId' + appId); - var result = bundle_mgr.uninstall(appId).then((data) => { - console.info("Launcher uninstall data [" + data + "]"); - callback(true); - }).catch(error => - console.info("Launcher uninstall err " + error)); - } - - getGridBootAppList() { - return mGridBootAppList; - } - - getGridPagesAppList(callback) { - gridListCallback = callback; - this.getAppList(this.getGridlist.bind(this)); - } - - getGridlist(list) { - gridListCallback(this.dealList(list)); - } - - dealList(appList) { - var gridPagesList = []; - var bootListLength = mGridBootAppList.length; - var appArrayLength = appList.length; - for (var i = 0; i < appArrayLength; i++) { - gridPagesList.push(appList[i]); - for (var j = 0; j < bootListLength; j++) { - if (appList[i].AppName === mGridBootAppList[j].AppName) { - gridPagesList.pop(); + /** + * Uninstall app by @ohos.bundle. + * + * @param {string} uninstallBundleName - bundleName of the bundle that will be uninstall + * @param {object} callback - callback from presenter + */ + uninstallApp(uninstallBundleName, callback) { + console.info('Launcher AppModel uninstallApp appId' + uninstallBundleName); + installCallback = callback; + let result = BundleMgr.getBundleInstaller().then((data) => { + if (CheckEmptyUtils.isEmpty(data)) { + console.error("Launcher AppModel uninstallApp getBundleInstaller ERROR"); + } + data.uninstall(uninstallBundleName, { + param: { + userId: 0, + isKeepData: false } - } + }, this.#OnReceiveinstallEvent); + }).catch(error => + console.info("Launcher AppModel uninstall err " + error)); + } + + /** + * Callback method after uninstall. + * + * @param {object} data - uninstall result data + */ + #OnReceiveinstallEvent = (data) => { + console.info('Launcher AppModel OnReceiveinstallEvent ' + data); + if (data.statusMessage == "SUCCESS") { + installCallback(UNINSTALL_SUCCESS); + } else { + installCallback(UNINSTALL_FAILED); } - return gridPagesList; + console.info('Launcher AppModel OnReceiveinstallEvent '); } - openApplication(bundleName) { - this.getAbilityName(bundleName, this.startApplication) - } - - getAbilityName(bundleName, callback) { - console.info('Launcher getAbilityName bundleName' + bundleName); - bundle_mgr.getBundleInfo(bundleName).then(data => { - console.info('Launcher getBundleInfo ' + data); - callback(data.abilityInfos[0].name, bundleName); - }); - } - - startApplication(abilityname, bundleName) { + /** + * Start app by bundle name and ability name. + * + * @param {string} abilityName - ability name of target app + * @param {string} bundleName - bundle name of target app + */ + startApplication(abilityName, bundleName) { let paramBundleName = bundleName; - let paramAbilityname = abilityname; + let paramAbilityName = abilityName; // promise - console.info('Launcher startApplication abilityname' + abilityname); - var result = feature_ability.startAbility({ - bundleName: paramBundleName, - abilityName: paramAbilityname, - requestCode: 1, - abilityType: "PageAbility", + console.info('Launcher AppModel startApplication abilityName ==> ' + abilityName + " bundleName ==> " + bundleName); + let result = FeatureAbility.startAbility({ want: { - action: "action1", - entities: ["entity1"], - type: "PageAbility", - flags: 2, - elementName: { - deviceId: "deviceId", - bundleName: paramBundleName, - abilityName: paramAbilityname, - }, - }, - syncOption: 1, + bundleName: paramBundleName, + abilityName: paramAbilityName + } }).then(data => - console.info("Launcher promise::then : " + JSON.stringify(data)) + console.info("Launcher AppModel startApplication promise::then : " + JSON.stringify(data)) ).catch(error => - console.info("Launcher promise::catch : " + JSON.stringify(error)) + console.info("Launcher AppModel startApplication promise::catch : " + JSON.stringify(error)) ); - console.info("Launcher AceApplication : startAbility : " + result); + console.info("Launcher AppModel startApplication AceApplication : startAbility : " + result); } - reportAppInstallEvent() { - console.info("Launcher AppModel reportAppInstallEvent"); - for (let i = 0; i < mAppInstallListeners.length; i++) { - let listener = mAppInstallListeners[i]; + /** + * Start app by bundle name and ability name with result. + * + * @param {string} abilityName - ability name of target app + * @param {string} bundleName - bundle name of target app + * @param {number} requestCode - result after start app + */ + startApplicationForResult(abilityName, bundleName, requestCode) { + let paramBundleName = bundleName; + let paramAbilityName = abilityName; + // promise + console.info('Launcher AppModel startApplicationForResult abilityName' + abilityName); + let result = FeatureAbility.startAbilityForResult({ + want: { + bundleName: paramBundleName, + abilityName: paramAbilityName + }, + requestCode: requestCode, + }, + (err, data) => { + console.log("Launcher AppModel startAbilityForResult asyncCallback StartAbilityResult: " + + err.code + " data: " + data) + }).then(data => + console.info("Launcher AppModel startApplicationForResult promise::then : " + JSON.stringify(data)) + ).catch(error => + console.info("Launcher AppModel startApplicationForResult promise::catch : " + JSON.stringify(error)) + ); + console.info("Launcher AppModel startApplicationForResult AceApplication : startAbility : " + result); + } + + /** + * Dispatch event to corresponding listeners. + * + * @param {string} event: callback event + * @param {object} bundleInfo: data from callback + */ + #reportAppInstallEvent = (event, bundleInfo) => { + console.info("Launcher AppModel reportAppInstallEvent + " + event); + switch (event) { + case EventConstants.EVENT_PACKAGE_ADDED: + this.#notifyEventListener(mAppListInstallListener, bundleInfo); + break; + case EventConstants.EVENT_PACKAGE_CHANGED: + this.#notifyEventListener(mAppListChangeListener, bundleInfo); + break; + case EventConstants.EVENT_PACKAGE_REMOVED: + this.#notifyEventListener(mAppListUninstallListener, bundleInfo); + break; + default: + break; + } + } + + /** + * Call the callback method which comes from presenter. + * + * @param {object} eventListener - different listeners for different event + * @param {object} bundleInfo - callback data + */ + #notifyEventListener = (eventListener, bundleInfo) => { + for (let i = 0; i < eventListener.length; i++) { + let listener = eventListener[i]; if (listener != undefined && listener != null) { - listener(); + console.info("Launcher AppModel notifyEventListener " + JSON.stringify(bundleInfo)); + listener(bundleInfo); } } } - reportAppUninstallEvent(appId) { - if (mAppUninstallListener != null) { - mAppUninstallListener(appId); + /** + * Register install listener. + * + * @param {object} listener - install listener + */ + registerAppListInstallListener(listener) { + if (mAppListInstallListener.indexOf(listener) == -1) { + mAppListInstallListener.push(listener); } } - registerAppUninstallListener(listener) { - mAppUninstallListener = listener; + /** + * Unregister install listener. + * + * @param {object} listener - install listener + */ + unregisterAppListInstallListener(listener) { + let index = mAppListInstallListener.indexOf(listener); + if (index != -1) { + mAppListInstallListener.splice(index, 1); + } } - registerAppInstallListener(listener) { - console.info("Launcher AppModel registerAppInstallListener"); - if (mAppInstallListeners.indexOf(listener) == -1) { - mAppInstallListeners.push(listener); + /** + * Register uninstall listener. + * + * @param {object} listener - uninstall listener + */ + registerAppListUninstallListener(listener) { + if (mAppListUninstallListener.indexOf(listener) == -1) { + mAppListUninstallListener.push(listener); } + } + + /** + * Unregister uninstall listener. + * + * @param {object} listener - uninstall listener + */ + unregisterAppListUninstallListener(listener) { + let index = mAppListUninstallListener.indexOf(listener); + if (index != -1) { + mAppListUninstallListener.splice(index, 1); + } + } + + /** + * Register change listener. + * + * @param {object} listener - uninstall listener + */ + registerAppListChangeListener(listener) { + if (mAppListChangeListener.indexOf(listener) == -1) { + mAppListChangeListener.push(listener); + } + } + + /** + * Unregister change listener. + * + * @param {object} listener - change listener + */ + unregisterAppListChangeListener(listener) { + let index = mAppListChangeListener.indexOf(listener); + if (index != -1) { + mAppListChangeListener.splice(index, 1); + } + } + + /** + * Called in app.js, create subscriber for app install/uninstall/update events. + */ + registerAppListEvent() { Subscriber.createSubscriber( mCommonEventSubscribeInfo, - this.createInstallationSubscriberCallBack.bind(this) + this.#createInstallationSubscriberCallBack.bind(this) ); } - unregisterAppInstallListener(listener) { + /** + * Called in app.js, unregister app install/uninstall/update events. + */ + unregisterAppListEvent() { Subscriber.unsubscribe(mCommonEventSubscriber, () => { - console.info("Launcher AppModel unsubscribe app install listener"); - let index = mAppInstallListeners.indexOf(listener); - if (index != -1) { - mAppInstallListeners.splice(index, 1); - } + console.info("Launcher AppModel unregisterAppListEvent"); }); } - createInstallationSubscriberCallBack(err, data) { + /** + * Create subscriber for install/uninstall/update event + * + * @param {object} err - error message of callback + * @param {object} data - callback data + */ + #createInstallationSubscriberCallBack = (err, data) => { console.info("Launcher AppModel createInstallationSubscriberCallBack"); mCommonEventSubscriber = data; - Subscriber.subscribe(mCommonEventSubscriber, this.installationSubscriberCallBack.bind(this)); + Subscriber.subscribe(mCommonEventSubscriber, this.#installationSubscriberCallBack.bind(this)); } - installationSubscriberCallBack(err, data) { - console.info("Launcher AppModel installationSubscriberCallBack"); - this.reportAppInstallEvent(); + /** + * callback after install/uninstall/update events, reorganize callback data. + * + * @param {object} err - error returns from the caller + * @param {object} data - data returns from the caller + */ + #installationSubscriberCallBack = (err, data) => { + if (err.code == 0) { + if (CheckEmptyUtils.isEmpty(data)) { + console.error("Launcher AppModel installationSubscriberCallBack ERROR! data is empty"); + } + console.info("Launcher AppModel installationSubscriberCallBack data = " + JSON.stringify(data)); + let callbackData = data; + if (callbackData.event == EventConstants.EVENT_PACKAGE_REMOVED) { + this.#reportAppInstallEvent(callbackData.event, callbackData); + return; + } + BundleMgr.getBundleInfo(callbackData.bundleName, IF_GET_ABILITY).then(data => { + console.info('Launcher AppModel installation subscriber getBundleInfo ' + JSON.stringify(data)); + let bundleInfo = { + System:data.appInfo.systemApp, + AppName: data.appInfo.label, + AppId: data.appId, + AppIcon: data.appInfo.iconId, + bundleName:data.name, + labelId :data.appInfo.labelId, + abilityName: data.abilityInfos[0].name, + }; + this.#reportAppInstallEvent(callbackData.event, bundleInfo); + }); + } else { + console.error("Launcher AppModel app list change failed --- err = " + JSON.stringify(err)); + } } } \ No newline at end of file diff --git a/launcher/src/main/js/default/common/model/ILayoutConfig.js b/launcher/src/main/js/default/common/model/ILayoutConfig.js index ccac07fb..7735593a 100644 --- a/launcher/src/main/js/default/common/model/ILayoutConfig.js +++ b/launcher/src/main/js/default/common/model/ILayoutConfig.js @@ -13,49 +13,144 @@ * limitations under the License. */ +/** + * An abstract class contains methods that can store layout data. + */ export default class ILayoutConfig { constructor() { } + /** + * Get the layout view type. + * + * @return {string} Layout view type, should one of 'Grid' or 'List' which is stored in LayoutConstants class. + */ getAppPageStartConfig() { return this.loadAppPageStartConfig(); } + /** + * Set the layout view type. + * + * @param {string} type - Layout view type, should one of 'Grid' or 'List' which is stored in LayoutConstants class. + */ setAppPageStartConfig(type) { this.saveAppPageStartConfig(type); } + /** + * Get grid layout config id. + * + * @return {number} grid layout config id. + */ getGridConfig() { return this.loadGridConfig(); } + /** + * Set grid layout config id. + * + * @param {number} id - layout config id. + */ setGridConfig(id) { this.saveGridConfig(id); } + /** + * Get recent process max limit. + * + * @return {number} recent process max limit. + */ getRecentProcessLimit() { return this.loadRecentProcessLimit(); } + /** + * Set recent process max limit. + * + * @param {number} num - Recent process max limit. + */ setRecentProcessLimit(num) { this.saveRecentProcessLimit(num); } + /** + * Get layout information of grid view. + * + * @return {object} layout information. + */ + getGridLayoutInfo() { + return this.loadGridLayoutInfo(); + } + + /** + * Set layout information of grid view. + */ + setGridLayoutInfo(layoutInfo) { + this.saveGridLayoutInfo(layoutInfo); + } + + /** + * Remove layout information of grid view. + */ + deleteGridLayoutInfo() { + this.removeGridLayoutInfo(); + } + + /** + * Should overridden by sub-classes , load the launcher layout view type. + */ loadAppPageStartConfig() { } + /** + * Should overridden by sub-classes , save the launcher layout view type. + */ saveAppPageStartConfig(type) { } + /** + * Should overridden by sub-classes , load the launcher grid view layout config id. + */ loadGridConfig() { } + /** + * Should overridden by sub-classes , save the launcher grid view layout config id. + */ saveGridConfig(id) { } + /** + * Should overridden by sub-classes , load the recent process max limit. + */ loadRecentProcessLimit() { } + /** + * Should overridden by sub-classes , save the recent process max limit. + */ saveRecentProcessLimit(num) { } + + /** + * Should overridden by sub-classes , load the layout information of grid view. + */ + loadGridLayoutInfo() { + + } + + /** + * Should overridden by sub-classes , save the layout information of grid view. + */ + saveGridLayoutInfo(layoutInfo) { + + } + + /** + * Should overridden by sub-classes , remove layout information of grid view. + */ + removeGridLayoutInfo() { + + } } \ No newline at end of file diff --git a/launcher/src/main/js/default/common/model/LayoutConfigManager.js b/launcher/src/main/js/default/common/model/LayoutConfigManager.js index 35b0003e..1d8623cf 100644 --- a/launcher/src/main/js/default/common/model/LayoutConfigManager.js +++ b/launcher/src/main/js/default/common/model/LayoutConfigManager.js @@ -15,6 +15,11 @@ import StorageLayoutConfig from './StorageLayoutConfig.js' +/** + * The factory function of producing the class to operate layout config. + * + * @return {object} The class to operate layout config. + */ export function getLayoutConfig() { return new StorageLayoutConfig(); } diff --git a/launcher/src/main/js/default/common/model/MMIEventManager.js b/launcher/src/main/js/default/common/model/MMIEventManager.js new file mode 100644 index 00000000..b27e2e10 --- /dev/null +++ b/launcher/src/main/js/default/common/model/MMIEventManager.js @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021 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. + */ + +let mCallbacks = []; + +/** + * A manager class support Multi-Mode input events. + */ +export default class MMIEventManager { + + /** + * Register the multi mode event callback function. + * + * @param {object} callback - callback function to be registered. + */ + registerEventCallback(callback) { + mCallbacks.push(callback); + } + + /** + * Unregister the multi mode event callback function. + * + * @param {object} callback - callback function to be unregistered. + */ + unregisterEventCallback(callback) { + for (let idx = 0; idx < mCallbacks.length; idx++) { + if (mCallbacks[idx] == callback) { + mCallbacks.splice(idx, 1); + break; + } + } + } + + /** + * Called when the multi mode event occur. + */ + onMMIEvent() { + for (let callback of mCallbacks) { + if (callback != undefined) { + callback(); + } + } + } +} \ No newline at end of file diff --git a/launcher/src/main/js/default/common/model/MMIModel.js b/launcher/src/main/js/default/common/model/MMIModel.js new file mode 100644 index 00000000..6fbf7425 --- /dev/null +++ b/launcher/src/main/js/default/common/model/MMIModel.js @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021 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 MMIEventManager from './MMIEventManager.js'; + +let mMMIEventManager = new MMIEventManager(); + +/** + * A model class provide Multi-Mode input functionality. + */ +export default class MMIModel { + + /** + * Register the multi mode event callback function. + * + * @param {object} callback - callback function to be registered. + */ + registerEventCallback(callback) { + mMMIEventManager.registerEventCallback(callback); + } + + /** + * Unregister the multi mode event callback function. + * + * @param {object} callback - callback function to be unregistered. + */ + unregisterEventCallback(callback) { + mMMIEventManager.unregisterEventCallback(callback); + } +} \ No newline at end of file diff --git a/launcher/src/main/js/default/common/model/ResourceManager.js b/launcher/src/main/js/default/common/model/ResourceManager.js index 8e8a2548..9b4ac31d 100644 --- a/launcher/src/main/js/default/common/model/ResourceManager.js +++ b/launcher/src/main/js/default/common/model/ResourceManager.js @@ -13,45 +13,109 @@ * limitations under the License. */ -import resmgr from '@ohos.resmgr'; +import Resmgr from '@ohos.resmgr'; +import AppResourceCacheManager from '../cache/AppResourceCacheManager.js' +import CheckEmptyUtils from '../../common/utils/CheckEmptyUtils.js'; -const DEFAULT_ICON_URL = 'common/pics/icon_default.png'; +const KEY_ICON = "icon"; +const KEY_NAME = "name"; +/** + * A manager class provide app icon and name from cache or system API. + */ export default class ResourceManager { - ResourceManager() { + #appResourceCacheManager; + constructor() { + this.#appResourceCacheManager = new AppResourceCacheManager(); } - getAppIcon(path, bundleName, callback) { + /** + * Get icon image of specific app. + * + * @param {string} path - path of target file + * @param {string} bundleName - bundle name of the app + * @param {object} callback - callback method + */ + getAppIcon(path, bundleName, callback, defaultAppIcon) { if (path == null || path == undefined || path == "" || path <= 0) { - console.info('Launcher getAppIcon iconid > ' + DEFAULT_ICON_URL); - callback(DEFAULT_ICON_URL); + console.info('Launcher ResourceManager getAppIcon iconId > ' + defaultAppIcon); + callback(defaultAppIcon); } else { - resmgr.getResourceManager(bundleName).then(item => { - console.info('Launcher getResourceManager data>' + item); - item.getMediaBase64(path, (error, value) => { - console.info('Launcher getMediaBase64 value>' + value); - if (value != null) { - callback(value); + let iconBase64 = this.#appResourceCacheManager.getCache(bundleName, KEY_ICON); + if (iconBase64 == undefined || iconBase64 == null || iconBase64 == '') { + Resmgr.getResourceManager(bundleName).then(item => { + if (CheckEmptyUtils.isEmpty(item)) { + console.error("Launcher ResourceManager getAppIcon getResourceManager ERROR! item is empty"); } + console.info('Launcher ResourceManager getAppIcon data>' + item); + item.getMediaBase64(path, (error, value) => { + console.info('Launcher ResourceManager getAppIcon getMediaBase64 value>' + value); + if (value != null) { + this.#appResourceCacheManager.setCache(bundleName, KEY_ICON, value); + callback(value); + } + }); + }).catch(e => { + console.error("Launcher ResourceManager getAppIcon error ") + callback(defaultAppIcon); }); - }); + } else { + callback(iconBase64); + } } } + /** + * Get app name of specific app. + * + * @param {string} labelId - label id of target app + * @param {string} bundleName - bundle name of the app + * @param {string} appName - app name + * @param {object} callback - callback method + */ getAppName(labelId, bundleName, appName, callback) { if (labelId == null || labelId == undefined || labelId == "" || labelId <= 0) { - console.info('Launcher getAppName callback ' + appName); + console.info('Launcher ResourceManager getAppName callback ' + appName); callback(appName); } else { - resmgr.getResourceManager(bundleName).then(item => { - console.info('Launcher getResourceManager labelId' + labelId); - item.getString(labelId, (error, value) => { - console.info('Launcher getString value>' + value); - if (value != null) { - callback(value); - } + let name = this.#appResourceCacheManager.getCache(bundleName, KEY_NAME); + if (name == undefined || name == null || name == '') { + Resmgr.getResourceManager(bundleName).then(item => { + console.info('Launcher ResourceManager getAppName getResourceManager labelId' + labelId); + item.getString(labelId, (error, value) => { + if (CheckEmptyUtils.checkStrIsEmpty(value)) { + console.error("Launcher AppModel getAppName getString ERROR! value is empty"); + } + console.info('Launcher ResourceManager getAppName getString value>' + value); + if (value != null) { + this.#appResourceCacheManager.setCache(bundleName, KEY_NAME, value); + callback(value); + } + }); + }).catch(e => { + console.error("Launcher ResourceManager getAppName error ") + callback(appName); }); - }); + } else { + callback(name); + } } } + + /** + * Get app resource cache. + * + * @param {string} bundleName - bundleName of target file + * @param {string} key - key of the cache + */ + getAppResourceCache(bundleName, key) { + return this.#appResourceCacheManager.getCache(bundleName, key); + } + + /** + * Clear resource cache + */ + clearCache() { + this.#appResourceCacheManager.clearCache(); + } } \ No newline at end of file diff --git a/launcher/src/main/js/default/common/model/SettingsModel.js b/launcher/src/main/js/default/common/model/SettingsModel.js index 264221e4..747cf790 100644 --- a/launcher/src/main/js/default/common/model/SettingsModel.js +++ b/launcher/src/main/js/default/common/model/SettingsModel.js @@ -15,38 +15,112 @@ import GridLayoutConfigs from '../../common/configs/GridLayoutConfigs.js'; import {getLayoutConfig} from './LayoutConfigManager.js'; +import FileUtils from "../../common/utils/FileUtils.js" -var mLayoutConfig = getLayoutConfig(); -var mGridConfig = 0; -var gridLayoutTable = GridLayoutConfigs.GridLayoutTable; +const defaultLayoutInfoFilePath = "/data/accounts/account_0/applications/com.ohos.launcher/com.ohos.launcher/assets/launcher/resources/rawfile/layoutInfo.json"; +let mLayoutConfig = getLayoutConfig(); +let mGridConfig = 0; +let mGridLayoutTable = GridLayoutConfigs.GridLayoutTable; + +/** + * A class that manage configuration data of layout and recent task. + */ export default class SettingsModel { + + /** + * Get the grid view presetting collection of layout config information table. + * + * @return {object} Grid view presetting collection object. + */ getGridLayoutTable() { - return gridLayoutTable; + return mGridLayoutTable; } + /** + * Get default layout information of grid view. + * + * @return {object} Default layout information of grid view. + */ + getDefaultLayoutInfo() { + return FileUtils.readJsonFile(defaultLayoutInfoFilePath); + } + + /** + * Get layout config of grid view. + * + * @return {object} Layout config of grid view. + */ getGridConfig() { mGridConfig = mLayoutConfig.getGridConfig(); - return gridLayoutTable[mGridConfig]; + return mGridLayoutTable[mGridConfig]; } + /** + * Set layout config id of grid view. + * + * @param {string} id - Layout config id of grid view. + */ setGridConfig(id) { mLayoutConfig.setGridConfig(id); } + /** + * Get recent process max limit. + * + * @return {number} recent process max limit. + */ getRecentProcessLimit() { return mLayoutConfig.getRecentProcessLimit(); } + /** + * Set recent process max limit. + * + * @param {number} num - Recent process max limit. + */ setRecentProcessLimit(num) { mLayoutConfig.setRecentProcessLimit(num); } + /** + * Get the layout view type. + * + * @return {string} Layout view type, should one of 'Grid' or 'List' which is stored in LayoutConstants class. + */ getAppPageStartConfig() { return mLayoutConfig.getAppPageStartConfig(); } + /** + * Set the layout view type. + * + * @param {string} type - Layout view type, should one of 'Grid' or 'List' which is stored in LayoutConstants class. + */ setAppPageStartConfig(type) { mLayoutConfig.setAppPageStartConfig(type); } + + /** + * Get layout information of grid view. + * + * @return {object} layout information. + */ + getLayoutInfo() { + return mLayoutConfig.getGridLayoutInfo(); + } + + /** + * Set layout information of grid view. + */ + setLayoutInfo(layoutInfo) { + mLayoutConfig.setGridLayoutInfo(layoutInfo); + } + + /** + * Remove layout information of grid view. + */ + deleteLayoutInfo() { + mLayoutConfig.deleteGridLayoutInfo(); + } } \ No newline at end of file diff --git a/launcher/src/main/js/default/common/model/StorageLayoutConfig.js b/launcher/src/main/js/default/common/model/StorageLayoutConfig.js index 63f6dc3b..cc7b8b47 100755 --- a/launcher/src/main/js/default/common/model/StorageLayoutConfig.js +++ b/launcher/src/main/js/default/common/model/StorageLayoutConfig.js @@ -15,26 +15,42 @@ import ILayoutConfig from './ILayoutConfig.js'; import DefaultLayoutConfig from '../../common/configs/DefaultLayoutConfig.js'; -import storage from '@ohos.data.storage'; +import Storage from '@ohos.data.storage'; const APP_PAGE_START_CONFIG = 'AppStartPageType'; const GRID_CONFIG = "GridConfig"; const RECENT_PROCESS_LIMIT = "RecentProcessLimit"; +const GRID_LAYOUT_INFO = "GridLayoutInfo"; const PREFERENCES_PATH = '/data/accounts/account_0/appdata/com.ohos.launcher/sharedPreference/LauncherPreference'; -var mPreferences = storage.getStorageSync(PREFERENCES_PATH); +let mPreferences = Storage.getStorageSync(PREFERENCES_PATH); + +/** + * A class that stores layout information. + * @extends ILayoutConfig + */ export default class StorageLayoutConfig extends ILayoutConfig { constructor() { super(); } + /** + * Load the launcher layout view type. + * + * @return {string} Layout view type , should one of 'Grid' or 'List' which is stored in LayoutConstants class. + */ loadAppPageStartConfig() { console.info('Launcher mPreferences get APP_PAGE_START_CONFIG'); - var data = mPreferences.getSync(APP_PAGE_START_CONFIG, DefaultLayoutConfig.DefaultAppPageStartConfig); + let data = mPreferences.getSync(APP_PAGE_START_CONFIG, DefaultLayoutConfig.DefaultAppPageStartConfig); console.info('Launcher mPreferences get' + data); return data; } + /** + * Save the launcher layout view type. + * + * @param {string} type - View type , should one of 'Grid' or 'List' which is stored in LayoutConstants class. + */ saveAppPageStartConfig(type) { console.info('Launcher mPreferences put type' + type); mPreferences.putSync(APP_PAGE_START_CONFIG, type); @@ -42,13 +58,23 @@ export default class StorageLayoutConfig extends ILayoutConfig { console.info('Launcher mPreferences put type flush'); } + /** + * Load the launcher grid view layout config id. + * + * @return {number} id - Config id. + */ loadGridConfig() { console.info('Launcher mPreferences get GRID_CONFIG'); - var data = mPreferences.getSync(GRID_CONFIG, DefaultLayoutConfig.DefaultGridConfig); + let data = mPreferences.getSync(GRID_CONFIG, DefaultLayoutConfig.DefaultGridConfig); console.info('Launcher mPreferences get' + data); return data; } + /** + * Save the launcher grid view layout config id. + * + * @param {string} id - View type , should one of 'Grid' or 'List' which is stored in LayoutConstants class. + */ saveGridConfig(id) { console.info('Launcher mPreferences put id' + id); mPreferences.putSync(GRID_CONFIG, id); @@ -56,17 +82,64 @@ export default class StorageLayoutConfig extends ILayoutConfig { console.info('Launcher mPreferences put id flush'); } + /** + * Load the recent process max limit. + * + * @return {number} Recent process max limit. + */ loadRecentProcessLimit() { console.info('Launcher mPreferences get'); - var data = mPreferences.getSync(RECENT_PROCESS_LIMIT, DefaultLayoutConfig.DefaultRecentProcessLimit); + let data = mPreferences.getSync(RECENT_PROCESS_LIMIT, DefaultLayoutConfig.DefaultRecentProcessLimit); console.info('Launcher mPreferences get' + data); return data; } + /** + * Save the recent process max limit. + * + * @param {number} num - Recent process max limit. + */ saveRecentProcessLimit(num) { console.info('Launcher mPreferences put num' + num); mPreferences.putSync(RECENT_PROCESS_LIMIT, num); mPreferences.flushSync(); console.info('Launcher mPreferences put num flush'); } + + /** + * Load the layout information of grid view. + * + * @return {object} The layout information data. + */ + loadGridLayoutInfo() { + console.info('Launcher StorageLayoutConfig loadGridLayoutInfo start'); + let data = mPreferences.getSync(GRID_LAYOUT_INFO, ''); + console.info('Launcher StorageLayoutConfig loadGridLayoutInfo ' + data); + if(data == ''){ + return []; + }else{ + return JSON.parse(data); + } + } + + /** + * Load the layout information of grid view. + * + * @return {object} The layout information data. + */ + saveGridLayoutInfo(layoutInfo) { + console.info('Launcher StorageLayoutConfig saveGridLayoutInfo start'); + mPreferences.putSync(GRID_LAYOUT_INFO, JSON.stringify(layoutInfo)); + mPreferences.flushSync(); + console.info('Launcher StorageLayoutConfig saveGridLayoutInfo end'); + } + + /** + * Remove layout information of grid view in preferences. + */ + removeGridLayoutInfo() { + console.info('Launcher StorageLayoutConfig removeGridLayoutInfo start'); + mPreferences.deleteSync(GRID_LAYOUT_INFO); + console.info('Launcher StorageLayoutConfig removeGridLayoutInfo start'); + } } \ No newline at end of file diff --git a/launcher/src/main/js/default/common/pics/img_return.png b/launcher/src/main/js/default/common/pics/img_return.png new file mode 100644 index 0000000000000000000000000000000000000000..2b4ef6f83f1017a5710747548d00ac9f0843d338 GIT binary patch literal 255 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawj(NH`hGg7(d&`iI(NU!RBY%6u zL!oN<-lnMKg`D3nJ!aBgxHPgg(Bs6U9FaG6pZ+eNx%S!glc&`_ryY>^%q2323}V%d5|}e{fAkgiWx3*|2lh`;@tlM} yM^#yOu+*tN73dUsqIhs^ukfptt%l3=!e?)vd|R&i-D04R7(8A5T-G@yGywoZMQ%m_ literal 0 HcmV?d00001 diff --git a/launcher/src/main/js/default/common/pics/img_to_detail.png b/launcher/src/main/js/default/common/pics/img_to_detail.png new file mode 100644 index 0000000000000000000000000000000000000000..cdbb19a5b6ddb74d7f34446d6f74bdd855eb934d GIT binary patch literal 391 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%&M7!06}c;uunK>+S8+SxkWfEe~fo z_H;{}xO{?TzJ2q)o(0;j7hGqQI_&b2`gc$JYvHq)D!s$bd$UD=24Dc*?9i|7hq?Dx z8ZfmgD|p`Wwt97~oUiBCwI!wT2OPy~Q#rRbtbS&)uuAAS=hxK%Gaf{^EoM1yC!n&! zY?H*n?ZWLG=N7xPJh0_v<#=~^&fEv~y|XwwA8(mD;U#-dONeu_@)Ii~Va1z4Q5-kt z-Ei_u08ty(f@1r%VJy~ z{eN*;*uIc6^6_uRXFu{9Z1 -
- -
-
-
- - - - -
+
+ +
+
+ + + +
-
-
-
- -
- - {{ $item.AppName }} - +
+ + + +
+
+ + +
+ +
+
+ + +
+
+
- {{ $t('strings.do_you_want_to_uninstall_start') }}{{ uninstallAppName }}{{ - $t('strings.do_you_want_to_uninstall_end') }} + {{$t('strings.do_you_want_to_uninstall_start')}}{{$t('strings.do_you_want_to_uninstall_end')}}
- -
diff --git a/launcher/src/main/js/default/pages/AppGridView/AppGridView.js b/launcher/src/main/js/default/pages/AppGridView/AppGridView.js index ca2b970a..0cffba12 100644 --- a/launcher/src/main/js/default/pages/AppGridView/AppGridView.js +++ b/launcher/src/main/js/default/pages/AppGridView/AppGridView.js @@ -14,124 +14,607 @@ */ import AppGridPresenter from '../../presenter/app/AppGridPresenter.js'; -import prompt from '@system.prompt'; +import LayoutConstants from '../../common/constants/LayoutConstants.js'; +import CheckArray from '../../common/utils/CheckArray.js'; +import Prompt from '@system.prompt'; -var mAppGridPresenter; const APP_INFO_REFRESH_DELAY = 500; +const UNINSTALL_SUCCESS = "UNINSTALL_SUCCESS"; +const UNINSTALL_FAILED = "UNINSTALL_FAILED"; +const UNINSTALL_PROHIBITED = "UNINSTALL_PROHIBITED"; +const CELL_WIDTH_RATIO = 0.65; +const COLUMN_SPACING_RATIO = 0.35; +const PROPORTION = 0.85; +const KEY_ICON = "icon"; +const KEY_NAME = "name"; +const BOTTOM_BAR = 1; +const NO_FOCUS_INDEX = [-1, -1]; +const FOCUSED_ITEM_SCALE = 1.05; +const UNFOCUSED_ITEM_SCALE = 1; +const BOTTOM_BAR_FOCUS_PAGE = -1; +const KEY_CODE_CONFIRM_ON_TV_REMOTE = 23; +const KEY_CODE_CONFIRM_ON_KEYBOARD_ENTER = 66; +const KEY_CODE_CONFIRM_ON_NUMERIC_KEYBOARD_ENTER = 160; +const APP_NAME_HEIGHT = 40; +const POSITION_WIDTH_RATIO = 0.85; + +let mAppGridPresenter; +let mAppListInfo = []; +let mGridConfig; +let mPageCoordinateData = { + numberOfRows: 0, + numberOfColumns: 0, + columnSpacing: 0, + rowSpacing: 0, + cellHeight: 0, + cellWidth: 0, + x_axis: [], + y_axis: [], + grid_x_axis: [], + grid_y_axis: [], + bottom_x_axis: [], + bottom_y_axis: [] +}; +let mTouchPointCoordinate = { + startX: 0, + startY: 0, + endX: 0, + endY: 0 +}; + +let mPageCount; +let mScreenBottomBarTop = 0; +let mScreenHeight = 0; +let mScreenWidth = 0; +let mSelectedAppItem; +let mSelectedAppIndex = 0; +let mLongPress = false; +let mResourceManager; +let mDefaultAppIcon; export default { data: { index: 0, - uninstallAppName: "", - uninstallAppId: "", - uninstallSystem: "", - appArray: [[[]]], + disabled: false, + isSwappingPage: false, bottomBar: [], + pageCoordinateData: {}, + gridAppsInfos: [], + chooseDialogRightBtnStr: "", + movingAppInfo: { + appIcon: mDefaultAppIcon, + appName: "APP", + display: "none", + top: 0, + left: 0 + }, + selectedAppItem: {}, + focusItemIndex: NO_FOCUS_INDEX, + BOTTOM_BAR_FOCUS_PAGE: BOTTOM_BAR_FOCUS_PAGE }, onInit() { console.info("Launcher AppGridView onInit"); - mAppGridPresenter = new AppGridPresenter(this.$app.$def.data.appModel, this.$app.$def.data.settingsModel); - mAppGridPresenter.registerAppUninstallListener(this.onAppUninstallCallback.bind(this)); - mAppGridPresenter.registerAppInstallListener(this.onAppInstallCallback.bind(this)); + globalThis.$globalR = this.$r.bind(this); + mResourceManager = this.$app.$def.data.resourceManager; + mAppGridPresenter = new AppGridPresenter(this.$app.$def.data.appModel, this.$app.$def.data.mmiModel, + this.$app.$def.data.settingsModel, this.$app.$def.data.appListInfoCacheManager); + mAppGridPresenter.registerAppListChangeCallback(this.getGridListCallback.bind(this)); + mScreenHeight = this.$app.$def.data.screenHeight * PROPORTION; + mScreenWidth = this.$app.$def.data.screenWidth; + mScreenBottomBarTop = this.$app.$def.data.screenHeight * PROPORTION; + mDefaultAppIcon = globalThis.$globalR('image.icon_default'); }, onShow() { console.info("Launcher AppGridView onShow"); - mAppGridPresenter.clearRouter(); - this.index = mAppGridPresenter.getGridIndex(); - mAppGridPresenter.getGridList(this.getGridListCallback.bind(this)); - this.bottomBar = mAppGridPresenter.getBootAppList(); - }, - - onDestory() { - mAppGridPresenter.unregisterAppInstallListener(this.onAppInstallCallback.bind(this)); - }, - - openApplication(bundleName) { - mAppGridPresenter.jumpTo(bundleName); - }, - - longPress(appId, appName, system) { - this.uninstallAppName = appName; - this.uninstallAppId = appId; - this.uninstallSystem = system; - if (system == 0) { - this.$element('simpleDialog').show() - } else{ - prompt.showToast({ - message: this.$t('strings.prohibited') - }) + let isLayoutMigrate = mAppGridPresenter.layoutMigrate(LayoutConstants.Grid); + if (isLayoutMigrate) { + return; + } + let isLayoutConfigUpdated = mAppGridPresenter.updateLayoutConfig(); + if (isLayoutConfigUpdated) { + this.loadData(); } }, - intoSetting() { - mAppGridPresenter.jumpToSetting(); + /** + * Load application data for grid layout. + */ + loadData() { + console.info("Launcher AppGridView loadData"); + mGridConfig = mAppGridPresenter.getGridConfig(); + this.pageCoordinateData = getPageCoordinateData(); + mAppGridPresenter.getGridList(this.getGridListCallback.bind(this)); }, + onDestroy() { + console.info("Launcher AppGridView onDestroy"); + mAppGridPresenter.unregisterAppListChangeCallback(); + }, + + /** + * Open the choosen application. + * + * @param {string} abilityName - Abilityname of the application. + * @param {string} bundleName - Bundlename of the application. + */ + openApplication(abilityName, bundleName) { + console.info("Launcher openApplication " + bundleName + " + " + abilityName); + mAppGridPresenter.jumpTo(abilityName, bundleName); + }, + + /** + * Jump to setting. + */ + intoSetting() { + console.info("Launcher AppGridView intoSetting"); + this.$element('chooseDialog').close(); + mAppGridPresenter.jumpToSetting(); + }, + + /** + * Open uninstall dialog. + * + * @param {object} e - Event. + */ cancelDialog(e) { - prompt.showToast({ + Prompt.showToast({ message: 'Dialog cancelled' }) }, + /** + * Close uninstall dialog. + * + * @param {object} e - Event. + */ cancelSchedule(e) { this.$element('simpleDialog').close(); - prompt.showToast({ + Prompt.showToast({ message: this.$t('strings.cancelled') }) }, + /** + * Uninstall the choosen application and close the dialog. + * + * @param {object} e - Event. + */ uninstallApplication(e) { - this.$element('simpleDialog').close() - mAppGridPresenter.uninstallApp(this.uninstallAppId); - prompt.showToast({ - message: this.$t('strings.uninstall_succeeded') - }) + this.$element('simpleDialog').close(); + if (this.selectedAppItem.bundleName != null) { + mAppGridPresenter.uninstallApp(this.selectedAppItem.bundleName, this.selectedAppItem.System, this.getUninstallApp.bind(this)); + } }, + /** + * Get the result after uninstall application. + * + * @param {object} callback - Uninstall result. + */ + getUninstallApp(callback) { + console.info("Launcher AppGridView getUninstallApp"); + let success = callback; + if (success == UNINSTALL_PROHIBITED) { + Prompt.showToast({ + message: this.$t('strings.prohibited') + }); + } else if (success == UNINSTALL_SUCCESS) { + Prompt.showToast({ + message: this.$t('strings.uninstall_succeeded') + }); + mAppListInfo = []; + this.gridAppsInfos = []; + mAppGridPresenter.getGridList(this.getGridListCallback.bind(this)); + } else if (success == UNINSTALL_FAILED) { + Prompt.showToast({ + message: this.$t('strings.uninstall_failed') + }); + } + }, + + /** + * Change index after swipe page. + * + * @param {object} e - Event. + */ pageChange(e) { this.index = e.index; - mAppGridPresenter.setGridIndex(e.index); }, - getGridListCallback(callbackDate) { - this.appArray = callbackDate; - console.info("Launcher AppGridView getGridListCallback this.appList.length = " + this.appArray.length); - }, - - onAppUninstallCallback(appId) { - mAppGridPresenter.getGridList(this.getGridListCallback.bind(this)); - }, - - onAppInstallCallback(appId) { - console.info("Launcher AppGridView onAppInstallCallback start"); - mAppGridPresenter.getGridList(this.applicationInstallCallback.bind(this)); + /** + * Get grid applications' information and show them. + * + * @param {object} callbackData - Grid applications' information. + */ + getGridListCallback(callbackData) { + console.info("Launcher AppGridView getGridListCallback"); + mAppListInfo = callbackData; + console.info("Launcher AppGridView getGridListCallback this.appList.length = " + mAppListInfo.length); + this.integrateData(); + this.initFocus(); + this.updateAppInfos(); }, + /** + * Update applications' icon and name. + */ updateAppInfos() { setTimeout(() => { - console.info("Launcher AppGridView getGridListCallback setTimeout this.appList.length = " + this.appArray.length); - for (let i = 0; i < this.appArray.length; i++) { - let page = this.appArray[i]; + console.info("Launcher AppGridView getGridListCallback setTimeout this.appList.length = " + this.gridAppsInfos.length); + for (let i = 0; i < this.gridAppsInfos.length; i++) { + let page = this.gridAppsInfos[i]; console.info("Launcher AppGridView getGridListCallback setTimeout page = " + i); for (let j = 0; j < page.length; j++) { - let row = page[j]; - console.info("Launcher AppGridView getGridListCallback setTimeout row = " + j); - for (let k = 0; k < row.length; k++) { - let element = row[k]; - console.info("Launcher AppGridView getGridListCallback setTimeout in page = " + i + " row = " + j + " column = " + k); - this.$child('icon-' + element.bundleName).updateIcon(); - this.$child('name-' + element.bundleName).updateName(); - } + let element = page[j]; + this.$child('icon-' + element.bundleName).updateIcon(); + this.$child('name-' + element.bundleName).updateName(); } } + console.info("Launcher AppGridView updateAppInfos bottomBar.length = " + this.bottomBar.length); + for (let i = 0; i < this.bottomBar.length; i++) { + let element = this.bottomBar[i]; + this.$child('icon-' + element.bundleName).updateIcon(); + this.$child('name-' + element.bundleName).updateName(); + } }, APP_INFO_REFRESH_DELAY); }, - applicationInstallCallback(callbackData) { - this.appArray = callbackData; - console.info("Launcher AppGridView applicationIntallCallback this.appList.length = " + this.appArray.length); - this.updateAppInfos(); + /** + * LongPress event for application. + * + * @param {object} appItem - The pressed application. + * @param {number} index - The application's index in the page. + */ + longPress(appItem, index) { + console.info("Launcher AppGridView longPress index: " + index); + mSelectedAppItem = appItem; + this.selectedAppItem = appItem; + this.movingAppInfo.appIcon = mResourceManager.getAppResourceCache(this.selectedAppItem.bundleName, KEY_ICON); + this.movingAppInfo.appName = mResourceManager.getAppResourceCache(this.selectedAppItem.bundleName, KEY_NAME); + mSelectedAppIndex = index; + mLongPress = true; + this.disabled = true; + this.$element('simpleDialog').show(); + }, + + /** + * Touchstart event for launcher. + * + * @param {object} e - Event. + */ + touchStart(e) { + console.info("Launcher AppGridView touchStart globalX = " + e.touches[0].globalX + " globalY = " + e.touches[0].globalY); + mTouchPointCoordinate.startX = e.touches[0].globalX, + mTouchPointCoordinate.startY = e.touches[0].globalY, + this.movingAppInfo.top = e.touches[0].globalY; + this.movingAppInfo.left = e.touches[0].globalX; + }, + + /** + * Touchmove event for launcher. + * + * @param {object} e - Event. + */ + touchMove(e) { + if(!mLongPress) { + return; + } + this.$element('simpleDialog').close(); + this.movingAppInfo.display = 'flex'; + if (this.selectedAppItem.bottomBarFlag == BOTTOM_BAR) { + this.bottomBar[mSelectedAppIndex].opacity = 0; + } else { + this.gridAppsInfos[mSelectedAppItem.page][mSelectedAppIndex].opacity = 0; + } + this.movingAppInfo.top = e.touches[0].globalY - mPageCoordinateData.cellWidth / 2; + this.movingAppInfo.left = e.touches[0].globalX - mPageCoordinateData.cellWidth / 2; + if (this.movingAppInfo.left < 0 && !this.isSwappingPage && this.index > 0 && this.movingAppInfo.top < mScreenHeight) { + this.index -= 1; + this.movingIconSwapPageDelay(); + } else if (this.movingAppInfo.left + mPageCoordinateData.cellWidth > 720 && !this.isSwappingPage && this.movingAppInfo.top < mScreenHeight) { + if (this.index == mPageCount - 1) { + this.addBlankPage(); + } else { + this.index += 1; + } + this.movingIconSwapPageDelay(); + } + }, + + /** + * Touchend event for launcher. + * + * @param {object} e - Event. + */ + touchEnd(e) { + console.info("Launcher AppGridView touchEnd globalX = " + e.changedTouches[0].globalX + " globalY = " + e.changedTouches[0].globalY); + this.movingAppInfo.display = 'none'; + mTouchPointCoordinate.endX = e.changedTouches[0].globalX; + mTouchPointCoordinate.endY = e.changedTouches[0].globalY; + let startColumn = 0, startRow = 0, startPage = this.index; + let endColumn = 0, endRow = 0; + let appInfo = mAppListInfo.find(item => { + return item.bundleName == mSelectedAppItem.bundleName; + }); + if (appInfo != '' && appInfo != undefined && appInfo != null) { + startColumn = appInfo.column; + startRow = appInfo.row; + startPage = appInfo.page; + } + if (mTouchPointCoordinate.endY > mPageCoordinateData.bottom_y_axis[0]) { + endRow = -1; + } else { + for (let i = 0; i < mPageCoordinateData.numberOfRows; i++) { + if (mTouchPointCoordinate.endY < mPageCoordinateData.grid_y_axis[i]) { + endRow = i - 1; + break; + } else { + endRow = mPageCoordinateData.numberOfRows - 1; + } + } + } + for (let i = 0; i < mPageCoordinateData.numberOfColumns; i++) { + if (mTouchPointCoordinate.endX < mPageCoordinateData.grid_x_axis[i]) { + endColumn = i - 1; + break; + } else { + endColumn = mPageCoordinateData.numberOfColumns - 1; + } + } + if (mLongPress) { + let startInfo = { + page: startPage, + row: startRow, + column: startColumn + } + let endInfo = { + page: this.index, + row: endRow, + column: endColumn + } + mAppListInfo = mAppGridPresenter.layoutAdjustment(startInfo, endInfo); + this.integrateData(); + this.initFocus(); + this.updateAppInfos(); + } + mLongPress = false; + this.disabled = false; + }, + + /** + * Integrate applications' information. + */ + integrateData() { + console.info("Launcher AppGridView integrateData"); + mPageCount = mAppGridPresenter.getGridPageCount(); + let pageMax = 0; + for (let i = 0;i < mAppListInfo.length; i++) { + if (pageMax < mAppListInfo[i].page) { + pageMax = mAppListInfo[i].page; + } + } + if (mPageCount < pageMax + 1) { + mPageCount = pageMax + 1; + } + let maxColumn = mGridConfig.column; + this.bottomBar = []; + let page = []; + for (let i = 0;i < mPageCount; i++) { + page.push([]); + } + this.gridAppsInfos = page; + for (let i = 0;i < mAppListInfo.length; i++) { + let iconInfo = { + AppId: mAppListInfo[i].AppId, + labelId: mAppListInfo[i].labelId, + AppName: mAppListInfo[i].AppName, + AppIcon: mAppListInfo[i].AppIcon, + bundleName: mAppListInfo[i].bundleName, + System: mAppListInfo[i].System, + abilityName: mAppListInfo[i].abilityName, + type: 0, + page: mAppListInfo[i].page, + wPixel: mPageCoordinateData.cellWidth, + hPixel: mPageCoordinateData.cellHeight, + wPosition: mPageCoordinateData.positionWidth, + marginPosition: mPageCoordinateData.positionMargin, + x: mPageCoordinateData.x_axis[mAppListInfo[i].column], + y: mPageCoordinateData.y_axis[mAppListInfo[i].row], + opacity: 1, + scale: 1, + bottomBarFlag:0 + } + if (mAppListInfo[i].row == -1) { + if (this.bottomBar.length < maxColumn) { + iconInfo.y = mPageCoordinateData.bottom_y_axis[0]; + iconInfo.bottomBarFlag = 1; + this.bottomBar.push(iconInfo); + } + continue; + } + this.gridAppsInfos[mAppListInfo[i].page].push(iconInfo); + } + }, + + /** + * Longpress event for launcher. + */ + onPageLongPress() { + this.chooseDialogRightBtnStr = this.getBlankPageBtnStr(); + this.$element('chooseDialog').show(); + }, + + /** + * Get strings for addBlankPageButton. + * + * @return {string} AddBlankPageButton Strings. + */ + getBlankPageBtnStr() { + return this.isBlankPage() ? this.$t('strings.delete_blank_page') : this.$t('strings.add_blank_page'); + }, + + /** + * Detemine whether the page is empty. + * + * @return {boolean} Verify result. + */ + isBlankPage() { + return this.gridAppsInfos[this.index].length == 0; + }, + + /** + * Add or delete the choosen blank page. + */ + addOrDeleteBlankPage() { + this.$element('chooseDialog').close(); + if (this.isBlankPage()) { + this.deleteBlankPage(); + } else { + this.addBlankPage(); + } + }, + + /** + * Add a blank page. + */ + addBlankPage() { + console.info("Launcher AppGridView addBlankPage"); + mAppGridPresenter.setGridPageCount(mPageCount + 1); + this.integrateData(); + this.initFocus(); + this.index = mPageCount - 1; + }, + + /** + * Delete the choosen blank page. + */ + deleteBlankPage() { + console.info("Launcher AppGridView deleteBlankPage"); + mAppGridPresenter.deleteGridPage(this.index); + if (this.index == this.gridAppsInfos.length - 1) { + this.index = this.index - 1; + } + mAppGridPresenter.setGridPageCount(mPageCount - 1); + mAppListInfo = mAppGridPresenter.getAppListInfo(); + this.integrateData(); + this.initFocus(); + }, + + /** + * Delay when swap page with icon. + */ + movingIconSwapPageDelay() { + this.isSwappingPage = true; + setTimeout(() => { + this.isSwappingPage = false; + }, 1000); + }, + + /** + * Focus event for application icon. + * + * @param {number} page - The index of the page where the focused application is in. + * @param {number} idx - The index of the application in the page. + */ + focus(page, idx) { + if (!(CheckArray.arrayEqual(this.focusItemIndex, NO_FOCUS_INDEX))) { + this.gridAppsInfos[this.focusItemIndex[0]][this.focusItemIndex[1]].scale = UNFOCUSED_ITEM_SCALE; + } + this.focusItemIndex = [page, idx]; + if (page == BOTTOM_BAR_FOCUS_PAGE) { + this.bottomBar[idx].scale = FOCUSED_ITEM_SCALE; + } else { + this.gridAppsInfos[page][idx].scale = FOCUSED_ITEM_SCALE; + } + }, + + /** + * Init the focus status. + */ + initFocus() { + if (!(CheckArray.arrayEqual(this.focusItemIndex, NO_FOCUS_INDEX))) { + if (this.focusItemIndex[0] != BOTTOM_BAR_FOCUS_PAGE) { + if (this.gridAppsInfos[this.focusItemIndex[0]][this.focusItemIndex[1]] != undefined) { + this.gridAppsInfos[this.focusItemIndex[0]][this.focusItemIndex[1]].scale = FOCUSED_ITEM_SCALE; + } + } else { + if (this.bottomBar[this.focusItemIndex[1]] != undefined) { + this.bottomBar[this.focusItemIndex[1]].scale = FOCUSED_ITEM_SCALE; + } + } + } + }, + + /** + * Key event of the application icon. + * + * @param {object} KeyEvent - Event. + */ + onAppGridKeyEvent(KeyEvent) { + console.info("Launcher AppGridView onAppGridKeyEvent KeyEvent: " + KeyEvent); + switch (KeyEvent.code) { + case KEY_CODE_CONFIRM_ON_TV_REMOTE: + case KEY_CODE_CONFIRM_ON_KEYBOARD_ENTER: + case KEY_CODE_CONFIRM_ON_NUMERIC_KEYBOARD_ENTER: + this.openApplication(mAppListInfo[this.focusItemIndex[0][this.focusItemIndex[1]]].bundleName); + break; + default: + break; + } + }, +} + +/** + * Calculate the coordinate. + * + * @return {object} Coordinate information. + */ +function getPageCoordinateData() { + let column = mGridConfig.column; + let row = mGridConfig.row; + mPageCoordinateData.numberOfColumns = column; + mPageCoordinateData.numberOfRows = row; + if ((mScreenWidth / column) < (mScreenHeight / row)) { + mPageCoordinateData.cellWidth = (mScreenWidth / column) * CELL_WIDTH_RATIO; + mPageCoordinateData.columnSpacing = ((mScreenWidth / column) * COLUMN_SPACING_RATIO) / 2; + mPageCoordinateData.cellHeight = mPageCoordinateData.cellWidth + APP_NAME_HEIGHT; + mPageCoordinateData.rowSpacing = (mScreenHeight - mPageCoordinateData.cellHeight * row) / (row * 2); + mPageCoordinateData.positionWidth = (mScreenWidth / column) * POSITION_WIDTH_RATIO; + mPageCoordinateData.positionMargin = (mPageCoordinateData.positionWidth - mPageCoordinateData.cellWidth) / 2; + } else { + mPageCoordinateData.cellWidth = (mScreenHeight / row) - APP_NAME_HEIGHT; + mPageCoordinateData.columnSpacing = (mScreenWidth - (mPageCoordinateData.cellWidth * column)) / (column * 2); + mPageCoordinateData.cellHeight = mScreenHeight / row; + mPageCoordinateData.rowSpacing = (mScreenHeight - (mPageCoordinateData.cellHeight * row)) / (row * 2); + mPageCoordinateData.positionWidth = (mScreenWidth / column) * POSITION_WIDTH_RATIO > mPageCoordinateData.cellWidth ? (mScreenWidth / column) * POSITION_WIDTH_RATIO : mPageCoordinateData.cellWidth; + mPageCoordinateData.positionMargin = (mPageCoordinateData.positionWidth - mPageCoordinateData.cellWidth) / 2; } -} \ No newline at end of file + mPageCoordinateData.x_axis = [], + mPageCoordinateData.y_axis = [], + mPageCoordinateData.grid_x_axis = [], + mPageCoordinateData.grid_y_axis = [], + mPageCoordinateData.bottom_x_axis = [], + mPageCoordinateData.bottom_y_axis = [] + for (let i = 0; i < row; i++) { + let iconPositioningY = (i * 2 + 1) * mPageCoordinateData.rowSpacing + i * mPageCoordinateData.cellHeight; + let touchPositioningY = i * (mPageCoordinateData.rowSpacing * 2 + mPageCoordinateData.cellHeight); + mPageCoordinateData.y_axis.push(iconPositioningY); + mPageCoordinateData.grid_y_axis.push(touchPositioningY); + } + + for (let i = 0; i < column; i++) { + let iconPositioningX = (i * 2 + 1) * mPageCoordinateData.columnSpacing + i * mPageCoordinateData.cellWidth - mPageCoordinateData.positionMargin; + let touchPositioningX = i * (mPageCoordinateData.columnSpacing * 2 + mPageCoordinateData.cellWidth); + mPageCoordinateData.x_axis.push(iconPositioningX); + mPageCoordinateData.grid_x_axis.push(touchPositioningX); + mPageCoordinateData.bottom_x_axis.push(iconPositioningX); + } + + for (let i = 0; i < column; i++) { + mPageCoordinateData.bottom_y_axis.push(mScreenBottomBarTop); + } + + return mPageCoordinateData; +} diff --git a/launcher/src/main/js/default/pages/AppListView/AppListView.css b/launcher/src/main/js/default/pages/AppListView/AppListView.css index b380aa6e..38cc4a08 100644 --- a/launcher/src/main/js/default/pages/AppListView/AppListView.css +++ b/launcher/src/main/js/default/pages/AppListView/AppListView.css @@ -16,7 +16,6 @@ @import '../../common/css/CommonPageStyle.css'; .container { - background-image: url("common/pics/img_wallpaper_default.jpg"); background-size: cover; } @@ -34,6 +33,8 @@ } .appitem { + background-color: #66123456; + border-radius: 20px; height: 110px; width: 90%; display: flex; diff --git a/launcher/src/main/js/default/pages/AppListView/AppListView.hml b/launcher/src/main/js/default/pages/AppListView/AppListView.hml index fe7dc17e..9a8563ce 100644 --- a/launcher/src/main/js/default/pages/AppListView/AppListView.hml +++ b/launcher/src/main/js/default/pages/AppListView/AppListView.hml @@ -18,12 +18,13 @@ -
+
- -
+
diff --git a/launcher/src/main/js/default/pages/AppListView/AppListView.js b/launcher/src/main/js/default/pages/AppListView/AppListView.js index 9afeaa9b..523defde 100644 --- a/launcher/src/main/js/default/pages/AppListView/AppListView.js +++ b/launcher/src/main/js/default/pages/AppListView/AppListView.js @@ -14,112 +14,226 @@ */ import AppListPresenter from '../../presenter/app/AppListPresenter.js'; -import prompt from '@system.prompt'; - -var mAppListPresenter; +import LayoutConstants from '../../common/constants/LayoutConstants.js'; +import Prompt from '@system.prompt'; +const NO_FOCUS_INDEX = -1; +const FOCUSED_ITEM_SCALE = 1.05; +const UNFOCUSED_ITEM_SCALE = 1; +const KEY_CODE_CONFIRM_ON_TV_REMOTE = 23; +const KEY_CODE_CONFIRM_ON_KEYBOARD_ENTER = 66; +const KEY_CODE_CONFIRM_ON_NUMERIC_KEYBOARD_ENTER = 160; +const UNINSTALL_SUCCESS = "UNINSTALL_SUCCESS"; +const UNINSTALL_FAILED = "UNINSTALL_FAILED"; +const UNINSTALL_PROHIBITED = "UNINSTALL_PROHIBITED"; const APP_INFO_REFRESH_DELAY = 500; +let mAppListPresenter; + export default { data: { appList: [], uninstallAppId: null, - uninstallAppName: null, + uninstallBundleName: null, ifSystem: true, + listItemScales: [], + focusItemIndex: NO_FOCUS_INDEX }, onInit() { - mAppListPresenter = new AppListPresenter(this.$app.$def.data.appModel); - mAppListPresenter.registerAppUninstallListener(this.onAppUninstallCallback); - mAppListPresenter.registerAppInstallListener(this.onAppInstallCallback); + console.info("Launcher AppListView onInit"); + globalThis.$globalR = this.$r.bind(this); + mAppListPresenter = new AppListPresenter(this.$app.$def.data.appModel, this.$app.$def.data.mmiModel, + this.$app.$def.data.settingsModel, this.$app.$def.data.appListInfoCacheManager); + mAppListPresenter.registerAppListChangeCallback(this.getListCallback.bind(this)); }, onShow() { - mAppListPresenter.clearRouter(); + console.info("Launcher AppListView onShow"); + let isLayoutMigrate = mAppListPresenter.layoutMigrate(LayoutConstants.List); + if (isLayoutMigrate) { + return; + } mAppListPresenter.getAppList(this.getListCallback.bind(this)); }, - onDestory() { - mAppListPresenter.unregisterAppInstallListener(this.onAppInstallCallback.bind(this)); + onDestroy() { + console.info("Launcher AppListView onDestroy"); + mAppListPresenter.unregisterAppListChangeCallback(); }, + /** + * Callback function of get application list. + * + * @param {object} list - list of applications. + */ getListCallback(list) { if (list == undefined || list == null) { this.appList = []; return; } this.appList = list; + this.initListFocus(); + this.updateAppInfos(); }, - openApplication(bundleName) { - mAppListPresenter.jumpTo(bundleName); + /** + * Open application function. + * + * @param {string} abilityName - ability name of the application to be jump to. + * @param {string} bundleName - bundle name of the application to be jump to. + */ + openApplication(abilityName, bundleName) { + console.info("Launcher AppListView openApplication abilityName:" + abilityName); + mAppListPresenter.jumpTo(abilityName, bundleName); }, + /** + * Application list item long press function. + * + * @param {string} appId - appId of long pressed item. + * @param {string} bundleName - bundle name of long pressed item. + * @param {string} System - whether long pressed item is system app or not. + */ longPress(appId, bundleName, System) { + console.info("Launcher AppListView longPress appId:" + appId); this.uninstallAppId = appId; - this.uninstallAppName = bundleName; + this.uninstallBundleName = bundleName; this.ifSystem = System; this.$element('chooseDialog').show(); }, + /** + * Migrate to launcher settings. + */ toSetting() { mAppListPresenter.jumpToSetting(); }, + /** + * Choose uninstall button when long pressed dialog showed. + */ chooseUninstall() { this.$element('simpleDialog').show(); }, + /** + * Choose launcher settings button when long pressed dialog showed. + */ chooseSettings() { this.$element('chooseDialog').close(); mAppListPresenter.jumpToSetting(); }, + /** + * Cancel dialog when long pressed dialog showed. + * + * @param {object} e + */ cancelDialog(e) { this.$element('chooseDialog').close(); - prompt.showToast({ + Prompt.showToast({ message: 'Dialog cancelled' }) }, + /** + * Called when uninstall dialog canceled. + * + * @param {object} e + */ cancelSchedule(e) { this.$element('chooseDialog').close(); this.$element('simpleDialog').close(); - prompt.showToast({ + Prompt.showToast({ message: this.$t('strings.cancelled') }) }, + /** + * Called when uninstall dialog's uninstall dialog button clicked. + * + * @param {object} e + */ uninstallApplication(e) { this.$element('chooseDialog').close(); this.$element('simpleDialog').close(); - if (this.uninstallAppName != null) { - mAppListPresenter.uninstallApp(this.uninstallAppName,this.ifSystem,this.getUninstallApp.bind(this)); + if (this.uninstallBundleName != null) { + mAppListPresenter.uninstallApp(this.uninstallBundleName, this.ifSystem, this.getUninstallApp.bind(this)); } }, - getUninstallApp(callback) { - var success = callback; - if (!success) { - prompt.showToast({ + /** + * Callback function of uninstall application. + * + * @param {string} uninstallationResult - the result of uninstallation. + */ + getUninstallApp(uninstallationResult) { + console.info("Launcher AppListView getUninstallApp uninstallationResult:" + uninstallationResult); + if (uninstallationResult == UNINSTALL_PROHIBITED) { + Prompt.showToast({ message: this.$t('strings.prohibited') }) - } else if (success) { - prompt.showToast({ + } else if (uninstallationResult == UNINSTALL_SUCCESS) { + Prompt.showToast({ message: this.$t('strings.uninstall_succeeded') - }) + }); + this.appList = []; + mAppListPresenter.getAppList(this.getListCallback.bind(this)); + } else if (uninstallationResult == UNINSTALL_FAILED) { + Prompt.showToast({ + message: this.$t('strings.uninstall_failed') + }); } }, - onAppUninstallCallback(appId) { + /** + * Function called when list item focus changed. + * + * @param {string} idx - the index of list item to be focused. + */ + focus(idx) { + if (this.focusItemIndex != NO_FOCUS_INDEX) { + this.listItemScales.splice(this.focusItemIndex, 1, UNFOCUSED_ITEM_SCALE); + } + this.focusItemIndex = idx; + this.listItemScales.splice(idx, 1, FOCUSED_ITEM_SCALE); }, - onAppInstallCallback(appId) { - console.info("Launcher AppListView onAppInstallCallback start"); - mAppListPresenter.getAppList(this.applicationInstallCallback.bind(this)); - console.info("Launcher AppListView onAppInstallCallback end"); + /** + * Function called when key event on list item changed. + * + * @param {object} KeyEvent - key event object. + */ + onAppListKeyEvent(KeyEvent) { + console.info("Launcher AppListView onAppListKeyEvent KeyEvent:" + KeyEvent); + switch (KeyEvent.code) { + case KEY_CODE_CONFIRM_ON_TV_REMOTE: + case KEY_CODE_CONFIRM_ON_KEYBOARD_ENTER: + case KEY_CODE_CONFIRM_ON_NUMERIC_KEYBOARD_ENTER: + this.openApplication(this.appList[this.focusItemIndex].bundleName, + this.appList[this.focusItemIndex].abilityName); + break; + default: + break; + } }, + /** + * Initial list focus status. + */ + initListFocus() { + for (let i = 0; i < this.appList.length; i++) { + this.listItemScales.push(UNFOCUSED_ITEM_SCALE); + } + if (this.focusItemIndex != NO_FOCUS_INDEX) { + this.listItemScales[this.focusItemIndex] = FOCUSED_ITEM_SCALE; + } + }, + + /** + * Update application icon and name when application data changed. + */ updateAppInfos() { console.info("Launcher AppListView getListCallback setTimeout this.appList.length = " + this.appList.length); setTimeout(() => { @@ -130,15 +244,4 @@ export default { } }, APP_INFO_REFRESH_DELAY); }, - - applicationInstallCallback(list) { - console.info("Launcher AppListView applicationInstallCallback in "); - if (list == undefined || list == null) { - this.appList = []; - return; - } - this.appList = list; - this.initListFocus(); - this.updateAppInfos(); - } } \ No newline at end of file diff --git a/launcher/src/main/js/default/pages/EntryView/EntryView.css b/launcher/src/main/js/default/pages/EntryView/EntryView.css index 624f3dd7..97708f81 100644 --- a/launcher/src/main/js/default/pages/EntryView/EntryView.css +++ b/launcher/src/main/js/default/pages/EntryView/EntryView.css @@ -14,7 +14,6 @@ */ .container { - background-image: url("common/pics/img_wallpaper_default.jpg"); background-size: cover; display: flex; flex-direction: column; diff --git a/launcher/src/main/js/default/pages/EntryView/EntryView.hml b/launcher/src/main/js/default/pages/EntryView/EntryView.hml index 3e887d82..e5054f1f 100644 --- a/launcher/src/main/js/default/pages/EntryView/EntryView.hml +++ b/launcher/src/main/js/default/pages/EntryView/EntryView.hml @@ -15,6 +15,6 @@ */ --> -
+
{{$t('strings.loading')}}
diff --git a/launcher/src/main/js/default/pages/EntryView/EntryView.js b/launcher/src/main/js/default/pages/EntryView/EntryView.js index ac5937cd..cf164b84 100644 --- a/launcher/src/main/js/default/pages/EntryView/EntryView.js +++ b/launcher/src/main/js/default/pages/EntryView/EntryView.js @@ -14,10 +14,12 @@ */ import EntryPresenter from '../../presenter/entry/EntryPresenter.js' +import Device from '@system.device'; -var mEntryPresenter; const timeout = 1000; +let mEntryPresenter; + export default { onInit() { console.info("Launcher EntryView onInit start"); @@ -26,13 +28,27 @@ export default { }, onShow() { - setTimeout(() => { - console.info("Launcher EntryView onShow start"); - mEntryPresenter.startAppListView(); - console.info("Launcher EntryView onShow end"); - }, timeout); - + Device.getInfo({ + success: (data) => { + this.$app.$def.data.screenHeight = data.windowHeight; + this.$app.$def.data.screenWidth = data.windowWidth; + setTimeout(() => { + console.info("Launcher EntryView onShow start"); + mEntryPresenter.startAppListView(); + console.info("Launcher EntryView onShow end"); + }, timeout); + }, + fail: (data, code) => { + console.info('Launcher Failed to obtain Device information. Error code:'+ code + '; Error information: ' + data); + //Fake data + this.$app.$def.data.screenHeight = 1240; + this.$app.$def.data.screenWidth = 720; + setTimeout(() => { + console.info("Launcher EntryView onShow start"); + mEntryPresenter.startAppListView(); + console.info("Launcher EntryView onShow end"); + }, timeout); + } + }) }, - - fun(){} } diff --git a/launcher/src/main/js/default/pages/SettingsView/SettingsView.css b/launcher/src/main/js/default/pages/SettingsView/SettingsView.css deleted file mode 100755 index 553f9421..00000000 --- a/launcher/src/main/js/default/pages/SettingsView/SettingsView.css +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2021 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. - */ - -.container { - display: flex; - flex-direction: column; - align-items: center; - width: 100%; - height: 100%; - background-color: white; -} - -.top-bar { - top:0; - height: 100px; - width: 100%; - display: flex; - justify-content: center; - align-items: center; - background-color: #F0EEEE; -} - -.settings-box { - height: 100%; - width: 90%; -} - -text { - font-size: 40px; -} - -list { - height: 100%; - width: 100%; - background-color: white; -} - -.list-bar { - background-color: white; - border-bottom-width: 3px; - border-color: black; -} - -list-item { - height: 100px; - width: 100%; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; -} - -.item-box { - width: 95%; - height: 100%; - border-bottom-width: 3px; - border-color: #ACABAB; - display: flex; - flex-direction: row; - align-items: center; - justify-content:space-around; -} - -.layout, .recentProcessLimit { - width: 70%; - height: 100%; - display: flex; - flex-direction: row; - align-items: center; -} - -.switch, .select { - width: 30%; - height: 100%; - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; -} - -.over { - height: 100px; - width: 70%; - background-color: #BE008000; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - border-radius: 20px; -} - -.over:active { - background-color: green; -} - -.layoutButton { - background-color: green; - height: 50%; - width: 15%; - border-radius: 30px; - border-color: #A0A0A0; - border-width: 2px; - margin:3px ; - display: flex; - align-items: center; - justify-content: center; -} diff --git a/launcher/src/main/js/default/pages/SettingsView/SettingsView.hml b/launcher/src/main/js/default/pages/SettingsView/SettingsView.hml deleted file mode 100644 index 7285adcb..00000000 --- a/launcher/src/main/js/default/pages/SettingsView/SettingsView.hml +++ /dev/null @@ -1,88 +0,0 @@ - - -
-
- - {{$t('strings.settings')}} - -
-
- - - - - {{$t('strings.layout')}} - - - -
-
- - {{layout}} - -
-
- -
-
-
- -
-
- {{$item.layout}} -
-
-
-
- - - - {{$t('strings.recent_tasks_settings')}} - - - -
-
- - {{recentProcessLimit}} - -
-
- -
-
-
-
-
-
-
- - {{$t('strings.carry_out')}} - -
-
diff --git a/launcher/src/main/js/default/pages/SettingsView/SettingsView.js b/launcher/src/main/js/default/pages/SettingsView/SettingsView.js deleted file mode 100644 index 47fe4dc2..00000000 --- a/launcher/src/main/js/default/pages/SettingsView/SettingsView.js +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2021 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 SettingsPresenter from '../../presenter/settings/SettingsPresenter.js'; -import Colors from '../../common/colors/Colors.js' -import LayoutConstants from '../../common/constants/LayoutConstants.js' - -var mSettingsPresenter; -var mGridConfig; - -export default { - data: { - layout: "", - checked: false, - layoutButtonStyle: [], - gridLayoutTable: [], - recentProcessLimit: '' - }, - - onInit() { - mSettingsPresenter = new SettingsPresenter(this.$app.$def.data.settingsModel); - mGridConfig = mSettingsPresenter.getGridConfig(); - this.gridLayoutTable = mSettingsPresenter.getGridLayoutTable() - this.recentProcessLimit = mSettingsPresenter.getRecentProcessLimit(); - for (let i = 0; i < this.gridLayoutTable.length; i++) { - this.layoutButtonStyle.push({ - color: "", - fontColor: "" - }); - } - }, - - onShow() { - this.layout = mSettingsPresenter.getAppPageStartConfig(); - if (this.layout == LayoutConstants.Grid) { - this.checked = false; - this.layout = LayoutConstants.Grid; - } else { - this.checked = true; - this.layout = LayoutConstants.List; - } - for (let i = 0; i < this.gridLayoutTable.length; i++) { - if (i == mGridConfig.id) { - this.layoutButtonStyle[i].color = Colors.bgSelectedColor; - this.layoutButtonStyle[i].fontColor = Colors.fontSelectedColor; - } else { - this.layoutButtonStyle[i].color = Colors.bgUnselectedColor; - this.layoutButtonStyle[i].fontColor = Colors.fontUnselectedColor; - } - } - }, - - changeSwitch() { - if (this.checked) { - this.checked = false; - this.layout = LayoutConstants.Grid; - } else { - this.checked = true; - this.layout = LayoutConstants.List; - } - }, - - changeSelect(selected) { - this.recentProcessLimit = Number(selected.newValue) - mSettingsPresenter.setRecentProcessLimit(this.recentProcessLimit); - }, - - submit() { - mSettingsPresenter.setAppPageStartConfig(this.layout); - mSettingsPresenter.settingUpdate(); - mSettingsPresenter.setRecentProcessLimit(this.recentProcessLimit); - }, - - changeLayout(id) { - for (let i = 0; i < this.gridLayoutTable.length; i++) { - if (i == id) { - this.layoutButtonStyle[i].color = Colors.bgSelectedColor; - this.layoutButtonStyle[i].fontColor = Colors.fontSelectedColor; - } else { - this.layoutButtonStyle[i].color = Colors.bgUnselectedColor; - this.layoutButtonStyle[i].fontColor = Colors.fontUnselectedColor; - } - } - mSettingsPresenter.setGridConfig(id); - } -} diff --git a/launcher/src/main/js/default/presenter/app/AppGridPresenter.js b/launcher/src/main/js/default/presenter/app/AppGridPresenter.js index ca3c8b9c..90e8ac2c 100644 --- a/launcher/src/main/js/default/presenter/app/AppGridPresenter.js +++ b/launcher/src/main/js/default/presenter/app/AppGridPresenter.js @@ -15,82 +15,721 @@ import BaseAppPresenter from './base/BaseAppPresenter.js'; -var mSettingsModel; -var mGridConfig; -var mAppGridList = []; -var viewCallback; -var mIndex = 0; +const KEY_APP_LIST = "appListInfo"; +let mGridConfig; +let mViewCallback; +let mBundleInfoList; +let mSettingsModel; + +/** + * Presenter of launcher grid view + */ export default class AppGridPresenter extends BaseAppPresenter { - constructor(AppModel, SettingsModel) { - super(AppModel); - this.appModel = AppModel; + + constructor(AppModel, MMIModel, SettingsModel, AppListInfoCacheManager) { + super(AppModel, MMIModel, SettingsModel, AppListInfoCacheManager); mSettingsModel = SettingsModel; - mGridConfig = mSettingsModel.getGridConfig(); } - pagingFiltering(mblist) { - mAppGridList = []; - var listLength = mblist.length; - var column = mGridConfig.column; - var row = mGridConfig.row; - var page = Math.ceil(listLength / column / row); - for (var k = 0; k < page; k++) { - var appPageList = []; - for (var i = 0; i < row; i++) { - var appRowList = []; - for (var j = 0; j < column; j++) { - if ((i * column) + j + k * column * row >= listLength) { - var appInfo = { - System: false, - AppName: '', - AppId: '', - AppIcon: '', - bundleName: '', - labelId: '', - visibility: 'hidden' - }; - appRowList.push(appInfo); - } else { - var tmp ={ - System: mblist[(i * column) + j + k * column * row].System, - AppName: mblist[(i * column) + j + k * column * row].AppName, - AppId: mblist[(i * column) + j + k * column * row].AppId, - AppIcon: mblist[(i * column) + j + k * column * row].AppIcon, - bundleName: mblist[(i * column) + j + k * column * row].bundleName, - labelId: mblist[(i * column) + j + k * column * row].labelId, - visibility:'visible' - }; - appRowList.push(tmp); + /** + * Get application info list. + * + * @return {object} Application layout information. + */ + getAppListInfo() { + mBundleInfoList = this.appListInfoCacheManager.getCache(KEY_APP_LIST); + return this.#pagingFiltering(); + } + + /** + * Change the application position after move it. + * + * @param {object} startInfo - Starting position. + * @param {object} endInfo - Ending posiition. + * @return {object} Application layout information. + */ + layoutAdjustment(startInfo, endInfo) { + let info = mSettingsModel.getLayoutInfo(); + let layoutInfo = info.layoutInfo; + mBundleInfoList = this.appListInfoCacheManager.getCache(KEY_APP_LIST); + if (endInfo.row == -1) { + this.#moveBottomLayout(startInfo, endInfo, layoutInfo); + info.layoutInfo = layoutInfo; + mSettingsModel.setLayoutInfo(info); + return this.#pagingFiltering(); + } + this.#moveLayout(startInfo, endInfo, layoutInfo, startInfo); + info.layoutInfo = layoutInfo; + mSettingsModel.setLayoutInfo(info); + return this.#pagingFiltering(); + } + + /** + * Get application list for grid layout. + * + * @param {array} callback - Application list. + */ + getGridList(callback) { + mViewCallback = callback; + this.appModel.getAppList(this.getGridListCallback.bind(this)); + } + + /** + * Get application info list and intergrate them. + * + * @param {array} list - Callback data(application info list). + */ + getGridListCallback(list) { + mBundleInfoList = list; + this.appListInfoCacheManager.setCache(KEY_APP_LIST, mBundleInfoList); + let callbackList = this.#pagingFiltering(); + mViewCallback(callbackList); + } + + /** + * Judge whether the current layout config and the setting layout config is consistent,and change the current layout config. + * + * @return {boolean} Verify result. + */ + updateLayoutConfig() { + let result = this.settingModel.getGridConfig(); + if(mGridConfig == result) { + return false; + } else { + mGridConfig = result; + return true; + } + } + + /** + * Get the current layout config. + * + * @return {object} Layout config information. + */ + getGridConfig() { + return mSettingsModel.getGridConfig(); + } + + /** + * Get pageCount. + * + * @return {number} PageCount. + */ + getGridPageCount() { + let layoutInfo = []; + layoutInfo = mSettingsModel.getLayoutInfo(); + return layoutInfo.layoutDescription.pageCount; + } + + /** + * Set pageCount. + * + * @param {number} pageCount - PageCount. + */ + setGridPageCount(pageCount) { + let layoutInfo = []; + layoutInfo = mSettingsModel.getLayoutInfo(); + layoutInfo.layoutDescription.pageCount = pageCount; + mSettingsModel.setLayoutInfo(layoutInfo); + } + + /** + * Delete blank page. + * + * @param {number} pageIndex - Index of the page which is to be deleted. + */ + deleteGridPage(pageIndex) { + let info = mSettingsModel.getLayoutInfo(); + let layoutInfo = info.layoutInfo; + for (let element of layoutInfo) { + if (element.page > pageIndex) { + element.page = element.page - 1; + } + } + info.layoutInfo = layoutInfo; + mSettingsModel.setLayoutInfo(info); + } + + /** + * Intergrate application list. + * + * @return {object} Application information list. + */ + #pagingFiltering = () => { + let appListInfo = []; + let info = this.#getLayoutInfo(); + let layoutInfo = info.layoutInfo; + for (let i = 0;i < layoutInfo.length; i++) { + for (let j = 0; j < mBundleInfoList.length; j++) { + if (layoutInfo[i].bundleName == mBundleInfoList[j].bundleName) { + appListInfo.push( + { + System: mBundleInfoList[j].System, + AppName: mBundleInfoList[j].AppName, + AppId: mBundleInfoList[j].AppId, + AppIcon: mBundleInfoList[j].AppIcon, + bundleName: mBundleInfoList[j].bundleName, + labelId: mBundleInfoList[j].labelId, + abilityName: mBundleInfoList[j].abilityName, + type: 0, + area: layoutInfo[i].area, + page: layoutInfo[i].page, + row: layoutInfo[i].row, + column: layoutInfo[i].column + } + ); + } + } + } + return appListInfo; + } + + /** + * Verify whether the info is legal. + * + * @param {object} info - The info which is needed to be verify. + * @return {boolean} Verify result. + */ + #ifRationality = (info) => { + let column = mGridConfig.column; + let row = mGridConfig.row; + //verify whether the info is null. + if(this.#ifInfoIsNull(info)) { + return false; + } + let layoutDescription = info.layoutDescription; + //verify whether the layoutDescription is diffrent. + if(this.#ifDescriptionIsDiffrent(layoutDescription, row, column)) { + return false; + } + let layoutInfo = info.layoutInfo; + //verify whether the layoutInfo's row and column is more than standard. + if(this.#ifColumnOrRowAreBigger(layoutInfo, row, column)) { + return false; + } + //verify whether the bottomBar's position is duplicated. + if(this.#ifDuplicateBottomBarPosition(layoutInfo)) { + return false; + } + //verify whether the layoutInfo's position is duplicated. + if(this.#ifDuplicatePosition(layoutInfo)) { + return false; + } + //verify whether the layoutInfo's bundleName is duplicated. + if(this.#ifDuplicateBundleName(layoutInfo)) { + return false; + } + return true; + } + + /** + * Verify whether the info is null. + * + * @param {object} info - The info which is needed to be verify. + * @return {boolean} Verify result. + */ + #ifInfoIsNull = (info) => { + if(info == undefined || info == '' || info == {} || info == null) { + return true; + } + return false; + } + + /** + * Verify whether the layoutDescription is diffrent. + * + * @param {object} layoutDescription - The layoutDescription which is needed to be verify. + * @param {number} row - Standard row number. + * @param {number} column - Standard column number. + * @return {boolean} Verify result. + */ + #ifDescriptionIsDiffrent = (layoutDescription,row,column) => { + if(row != layoutDescription.row || column != layoutDescription.column) { + return true; + } + return false; + } + + /** + * Verify whether the layoutInfo's row and column is more than standard. + * + * @param {object} layoutInfo - The layoutInfo which is needed to be verify. + * @param {number} row - Standard row number. + * @param {number} column - Standard column number. + * @return {boolean} Verify result. + */ + #ifColumnOrRowAreBigger = (layoutInfo, row, column) => { + for (let i = 0; i < layoutInfo.length; i++) { + //column or row are bigger than legal num + if (layoutInfo[i].column >= column || layoutInfo[i].row >= row) { + return true; + } + } + return false; + } + + /** + * Verify whether the bottomBar's position is duplicated. + * + * @param {object} layoutInfo - The layoutInfo which is needed to be verify. + * @return {boolean} Verify result. + */ + #ifDuplicateBottomBarPosition = (layoutInfo) => { + for (let i = 0; i < layoutInfo.length; i++) { + if (layoutInfo[i].row < 0) { + for (let j = layoutInfo.length - 1; j > 0 && j > i; j--) { + if (i != j && layoutInfo[j].row < 0) { + if (layoutInfo[i].column == layoutInfo[j].column) { + return true; + } } } - appPageList.push(appRowList); } - mAppGridList.push(appPageList); } - return mAppGridList; + return false; } - getGridList(callback) { - viewCallback = callback; - this.appModel.getGridPagesAppList(this.getGridListCallback.bind(this)); + /** + * Verify whether the layoutInfo's position is duplicated. + * + * @param {object} layoutInfo - The layoutInfo which is needed to be verify. + * @return {boolean} Verify result. + */ + #ifDuplicatePosition = (layoutInfo) => { + for (let i = 0; i < layoutInfo.length; i++) { + for (let j = layoutInfo.length - 1; j > 0 && j > i; j--) { + if (layoutInfo[i].row == layoutInfo[j].row && layoutInfo[i].column == layoutInfo[j].column) { + return true; + } + + } + } + return false; } - getGridListCallback(list) { - let callbackList = this.pagingFiltering(list); - viewCallback(callbackList); + /** + * Verify whether the layoutInfo's bundleName is duplicated. + * + * @param {object} layoutInfo - The layoutInfo which is needed to be verify. + * @return {boolean} Verify result. + */ + #ifDuplicateBundleName = (layoutInfo) => { + let count = {}; + for(let i = 0; i < layoutInfo.length; i++) { + if(count[layoutInfo[i].bundleName] == undefined || count[layoutInfo[i].bundleName] == null || count[layoutInfo[i].bundleName] == '') { + count[layoutInfo[i].bundleName] = 0; + }else{ + if(++ count[layoutInfo[i].bundleName] > 1) { + return true; + } + } + } + return false; } - getGridIndex() { - return mIndex; + + /** + * Get the latest info position in the page. + * + * @param {object} layoutInfo - Layout information. + * @return {number} The latest information position number. + */ + #getExistNumber = (layoutInfo) => { + let column = mGridConfig.column; + let row = mGridConfig.row; + let existNumber = 0; + for(let i = 0; i < layoutInfo.length ;i++) { + let Page = layoutInfo[i].page; + let Row = layoutInfo[i].row; + let Column = layoutInfo[i].column; + let result = (Page * column * row) + (Row * column) + (Column + 1); + if(result > existNumber) { + existNumber = result; + } + } + return existNumber; } - setGridIndex(index) { - mIndex = index + /** + * Update layout information. + * + * @param {object} info - The current layout information. + * @return {object} New layout information. + */ + #updateLayoutInfo = (info) => { + let layoutDescription = info.layoutDescription; + let layoutInfo = info.layoutInfo; + let column = mGridConfig.column; + let row = mGridConfig.row; + let newApp = []; + layoutDescription.row = row; + layoutDescription.column = column; + //Detect newly installed apps + for (let i in mBundleInfoList) { + let sign = false; + for (let j in layoutInfo) { + if (mBundleInfoList[i].bundleName == layoutInfo[j].bundleName) { + sign = true; + break; + } + } + if (!sign) { + newApp.push(mBundleInfoList[i]); + } + } + //Detect uninstalled apps + for (let i in layoutInfo) { + let sign = false; + for (let j in mBundleInfoList) { + if (layoutInfo[i].bundleName == mBundleInfoList[j].bundleName) { + sign = true; + break; + } + } + if (!sign) { + layoutInfo.splice(i, 1); + } + } + //The latest info position in the page + let existNumber = this.#getExistNumber(layoutInfo); + //Add new app + for (let i = 0; i < newApp.length; i++) { + layoutInfo.push({ + bundleName: newApp[i].bundleName, + type: 0, + area: [1,1], + page: Math.floor((i + existNumber) / (column * row)), + row: Math.floor((i + existNumber) % (column * row) / column), + column: Math.floor((i + existNumber) % (column * row) % column), + }); + } + info.layoutDescription = layoutDescription; + info.layoutInfo = layoutInfo; + return info; } - getBootAppList() { - return this.appModel.getGridBootAppList(); + /** + * Get the current layout information. + * + * @return {object} Layout information. + */ + #getLayoutInfo = () => { + let layoutInfo = []; + layoutInfo = mSettingsModel.getLayoutInfo(); + let isLegal = this.#ifRationality(layoutInfo); + if (isLegal) { + layoutInfo = this.#updateLayoutInfo(layoutInfo); + } else if (this.#ifRationality(mSettingsModel.getDefaultLayoutInfo())) { + layoutInfo = this.#updateLayoutInfo(mSettingsModel.getDefaultLayoutInfo()); + } else { + layoutInfo = this.#updateLayoutInfo(this.#createNewLayoutInfo()); + } + mSettingsModel.setLayoutInfo(layoutInfo); + return layoutInfo; } -} \ No newline at end of file + /** + * Create a new layout information. + * + * @return {object} New layout information. + */ + #createNewLayoutInfo = () => { + let layoutInfo = mSettingsModel.getLayoutInfo(); + let column = mGridConfig.column; + let row = mGridConfig.row; + let layoutNum = layoutInfo.layoutInfo.length; + let maxPerPage = column * row; + let pageNum = Math.ceil(layoutNum/maxPerPage); + let newLayoutInfo = {}; + newLayoutInfo.layoutDescription = { + "pageCount" : pageNum, + "row" : row, + "column" : column, + } + newLayoutInfo.layoutInfo = []; + return newLayoutInfo; + } + + /** + * Move application to bottomBar. + */ + #moveBottomLayout = (startInfo, endInfo, layoutInfo) => { + let column = mGridConfig.column; + let bottomBarLayoutInfo = []; + let moveItem = { + bundleName: "", + type: 0, + page: 0, + row: 0, + column: 0, + }; + for (let i = layoutInfo.length - 1; i >= 0; i--) { + if (layoutInfo[i].page == startInfo.page && layoutInfo[i].row == startInfo.row && layoutInfo[i].column == startInfo.column) { + moveItem.bundleName = layoutInfo[i].bundleName; + moveItem.type = layoutInfo[i].type; + moveItem.page = layoutInfo[i].page; + moveItem.row = layoutInfo[i].row; + moveItem.column = layoutInfo[i].column; + layoutInfo.splice(i, 1); + } + } + for (let i = layoutInfo.length - 1; i >= 0; i--) { + if (layoutInfo[i].row == -1) { + bottomBarLayoutInfo.push(layoutInfo[i]); + layoutInfo.splice(i, 1); + } + } + + if (bottomBarLayoutInfo.length >= column) { + this.#swapAppIcon(moveItem, endInfo, bottomBarLayoutInfo); + } else { + if (this.#isBottomEndPositionEmpty(endInfo, bottomBarLayoutInfo)) { + moveItem.page = endInfo.page; + moveItem.row = endInfo.row; + moveItem.column = endInfo.column; + } else { + if (this.#isBottomEmptyPositionAtForward(endInfo, bottomBarLayoutInfo)) { + this.#moveBottomLayoutForward(moveItem, endInfo, bottomBarLayoutInfo); + } else { + this.#moveBottomLayoutBackward(moveItem, endInfo, bottomBarLayoutInfo); + } + } + } + + bottomBarLayoutInfo.push(moveItem); + + for (let i = 0;i < bottomBarLayoutInfo.length; i++) { + layoutInfo.push(bottomBarLayoutInfo[i]); + } + } + + /** + * Change position of the two application information. + * + * @param {object} moveItem - Started application information. + * @param {object} endInfo - Ended application information. + * @param {object} bottomBarLayoutInfo - BottomBar layout information. + */ + #swapAppIcon = (moveItem, endInfo, bottomBarLayoutInfo) => { + let tmp = { + page: 0, + row: 0, + column: 0 + }; + for (let i = 0;i < bottomBarLayoutInfo.length; i++) { + if (bottomBarLayoutInfo[i].row == endInfo.row && bottomBarLayoutInfo[i].column == endInfo.column) { + tmp.page = bottomBarLayoutInfo[i].page; + tmp.row = bottomBarLayoutInfo[i].row; + tmp.column = bottomBarLayoutInfo[i].column; + bottomBarLayoutInfo[i].page = moveItem.page; + bottomBarLayoutInfo[i].row = moveItem.row; + bottomBarLayoutInfo[i].column = moveItem.column; + moveItem.page = tmp.page; + moveItem.row = tmp.row; + moveItem.column = tmp.column; + } + } + } + + /** + * Verify whether the moveEnd position is null while the moveEnd position is in bottomBar. + * + * @param {object} endInfo - MoveEnd position information. + * @param {object} bottomBarLayoutInfo - BottomBar layout information. + * @return {boolean} Verify result. + */ + #isBottomEndPositionEmpty = (endInfo, bottomBarLayoutInfo) => { + let isEndPositionEmpty = true; + for (let i = 0;i < bottomBarLayoutInfo.length; i++) { + if (bottomBarLayoutInfo[i].row == endInfo.row && bottomBarLayoutInfo[i].column == endInfo.column) { + isEndPositionEmpty = false; + break; + } + } + return isEndPositionEmpty; + } + + /** + * Verify whether there is an empty position in front of the moveEnd position. + * + * @param {object} endInfo - MoveEnd position information. + * @param {object} bottomBarLayoutInfo - BottomBar layout information. + * @return {boolean} Verify result. + */ + #isBottomEmptyPositionAtForward = (endInfo, bottomBarLayoutInfo) => { + let isEmptyPositionAtForward = true; + for (let i = endInfo.column;i < mGridConfig.column; i++) { + isEmptyPositionAtForward = true; + for (let j = 0;j < bottomBarLayoutInfo.length; j++) { + if (bottomBarLayoutInfo[j].column == i) { + isEmptyPositionAtForward = false; + } + } + if (isEmptyPositionAtForward) { + break; + } + } + return isEmptyPositionAtForward; + } + + /** + * The icons go forwards. + * + * @param {object} moveItem - The moving item. + * @param {object} endInfo - MoveEnd position information. + * @param {object} bottomBarLayoutInfo - BottomBar layout information. + */ + #moveBottomLayoutForward = (moveItem, endInfo, bottomBarLayoutInfo) => { + moveItem.page = endInfo.page; + moveItem.row = endInfo.row; + moveItem.column = endInfo.column; + let cTmp = []; + for (let j = 0;j < bottomBarLayoutInfo.length; j++) { + cTmp.push(bottomBarLayoutInfo[j].column); + } + for (let i = endInfo.column;i < mGridConfig.column; i++) { + let isColumnEmpty = true; + for (let j = 0;j < bottomBarLayoutInfo.length; j++) { + if (cTmp[j] == i) { + isColumnEmpty = false; + bottomBarLayoutInfo[j].column = cTmp[j] + 1; + } + } + if (isColumnEmpty) { + break; + } + } + } + + /** + * The icons go backwards. + * + * @param {object} moveItem - Moving item information. + * @param {object} endInfo - MoveEnd position information. + * @param {object} bottomBarLayoutInfo - BottomBar layout information. + */ + #moveBottomLayoutBackward = (moveItem, endInfo, bottomBarLayoutInfo) => { + moveItem.page = endInfo.page; + moveItem.row = endInfo.row; + moveItem.column = endInfo.column; + let cTmp = []; + for (let j = 0;j < bottomBarLayoutInfo.length; j++) { + cTmp.push(bottomBarLayoutInfo[j].column); + } + for (let i = endInfo.column;i >= 0; i--) { + let isColumnEmpty = true; + for (let j = 0;j < bottomBarLayoutInfo.length; j++) { + if (cTmp[j] == i) { + isColumnEmpty = false; + bottomBarLayoutInfo[j].column = cTmp[j] - 1; + } + } + if (isColumnEmpty) { + break; + } + } + } + + /** + * Move icon. + * + * @param {object} source - Start position information. + * @param {object} destination - End position information. + * @param {object} layoutInfo - Current layout information. + * @param {object} startInfo - Recursion start position information. + */ + #moveLayout = (source, destination, layoutInfo, startInfo) => { + let couldMoveForward = this.#moveLayoutForward(source, destination, layoutInfo, startInfo); + if (couldMoveForward) return; + this.#moveLayoutBackward(source, destination, layoutInfo, startInfo); + } + + /** + * Icons go forwards. + * + * @param {object} source - Start position information. + * @param {object} destination - End position information. + * @param {object} layoutInfo - Current layout information. + * @param {object} startInfo - Recursion start position information. + * @return {boolean} Move result. + */ + #moveLayoutForward = (source, destination, layoutInfo, startInfo) => { + + let startLayoutInfo = layoutInfo.find(item => { + return item.page == source.page && item.row == source.row && item.column == source.column; + }); + let endLayoutInfo = layoutInfo.find(item => { + return item.page == destination.page && item.row == destination.row && item.column == destination.column; + }); + + if (endLayoutInfo != undefined && !(endLayoutInfo.page == startInfo.page && endLayoutInfo.row == startInfo.row && endLayoutInfo.column == startInfo.column)) { + + if (endLayoutInfo.row == mGridConfig.row - 1 && endLayoutInfo.column == mGridConfig.column - 1) { + return false; + } + + let nextPosition = { + page: destination.page, + row: destination.column == mGridConfig.column - 1 ? destination.row + 1 : destination.row, + column: destination.column == mGridConfig.column - 1 ? 0 : destination.column + 1 + } + let couldMoveForward = this.#moveLayoutForward(destination, nextPosition, layoutInfo, startInfo); + if (!couldMoveForward) return false; + } + startLayoutInfo.page = destination.page; + startLayoutInfo.row = destination.row; + startLayoutInfo.column = destination.column; + return true; + } + + /** + * Icons go backwards. + * + * @param {object} source - Start position information. + * @param {object} destination - End position information. + * @param {object} layoutInfo - Current layout information. + * @param {object} startInfo - Recursion start position information. + * @return {boolean} Move result. + */ + #moveLayoutBackward = (source, destination, layoutInfo, startInfo) => { + + let startLayoutInfo = layoutInfo.find(item => { + return item.page == source.page && item.row == source.row && item.column == source.column; + }); + let endLayoutInfo = layoutInfo.find(item => { + return item.page == destination.page && item.row == destination.row && item.column == destination.column; + }); + + if (endLayoutInfo != undefined && !(endLayoutInfo.page == startInfo.page && endLayoutInfo.row == startInfo.row && endLayoutInfo.column == startInfo.column)) { + + if (endLayoutInfo.row == 0 && endLayoutInfo.column == 0) { + return false; + } + + let nextPosition = { + page: destination.page, + row: (destination.column == 0 && destination.row > 0) ? destination.row - 1 : destination.row, + column: destination.column == 0 ? mGridConfig.column - 1 : destination.column - 1 + } + + let couldMoveBackward = this.#moveLayoutBackward(destination, nextPosition, layoutInfo, startInfo); + if (!couldMoveBackward) return false; + } + startLayoutInfo.page = destination.page; + startLayoutInfo.row = destination.row; + startLayoutInfo.column = destination.column; + return true; + } + + /** + * Integrate layout information after install application. + * + * @return {object} Layout information. + */ + regroupDataAfterInstall(callbackList) { + mBundleInfoList = callbackList; + return this.#pagingFiltering(); + } +} + diff --git a/launcher/src/main/js/default/presenter/app/AppListPresenter.js b/launcher/src/main/js/default/presenter/app/AppListPresenter.js index a9c2e277..8204803a 100644 --- a/launcher/src/main/js/default/presenter/app/AppListPresenter.js +++ b/launcher/src/main/js/default/presenter/app/AppListPresenter.js @@ -15,8 +15,27 @@ import BaseAppPresenter from './base/BaseAppPresenter.js'; +/** + * Presenter of launcher list view. + * + * @extends BaseAppPresenter. + */ export default class AppListPresenter extends BaseAppPresenter { - constructor(AppModel) { - super(AppModel); + constructor(AppModel, MMIModel, SettingsModel, AppListInfoCacheManager) { + super(AppModel, MMIModel, SettingsModel, AppListInfoCacheManager); + } + + /** + * Adapt bundleInfo data to in list view. + * + * @param {object} callbackList - BundleInfo list get from cache. + * @return {object} The regrouped list. + */ + regroupDataAfterInstall(callbackList) { + return callbackList.sort( + function compareFunction(param1, param2) { + return param1.AppName.localeCompare(param2.AppName, "zh"); + } + ); } } \ No newline at end of file diff --git a/launcher/src/main/js/default/presenter/app/base/BaseAppPresenter.js b/launcher/src/main/js/default/presenter/app/base/BaseAppPresenter.js index 96b455a3..cce97ce4 100644 --- a/launcher/src/main/js/default/presenter/app/base/BaseAppPresenter.js +++ b/launcher/src/main/js/default/presenter/app/base/BaseAppPresenter.js @@ -14,70 +14,285 @@ */ import RouterUtil from '../../../common/utils/RouterUtil.js'; +import LayoutConstants from '../../../common/constants/LayoutConstants.js'; +import PageData from '../../../common/constants/PageData.js'; -const JUMPSETTING='pages/SettingsView/SettingsView'; -var viewCallback; -var uninstallCallback; +const UNINSTALL_SUCCESS = true; +const UNINSTALL_PROHIBITED = "UNINSTALL_PROHIBITED"; +const SETTING_BUNDLE = 'com.ohos.launcher'; +const SETTING_ABILITY = 'com.ohos.launcher.settings.MainAbility'; +const KEY_APP_LIST = "appListInfo"; +let mViewCallback; +let mUninstallCallback; +let mAppListChangeCallback; +let mAppListInstallListener; +let mAppListUninstallListener; +let mAppListChangeListener; + +/** + * Base class of list view presenter and grid view presenter. + */ export default class BaseAppPresenter { - constructor(AppModel) { + constructor(AppModel, MMIModel, SettingsModel, AppListInfoCacheManager) { this.appModel = AppModel; + this.mmiModel = MMIModel; + this.settingModel = SettingsModel; + this.appListInfoCacheManager =AppListInfoCacheManager; + mAppListInstallListener = this.appListInstallListener.bind(this); + mAppListUninstallListener = this.appListUninstallListener.bind(this); + mAppListChangeListener = this.appListChangeListener.bind(this); } + /** + * Get app data function. + * + * @param {object} callback - callback function. + */ getAppList(callback) { - viewCallback = callback; + mViewCallback = callback; this.appModel.getAppList(this.getListCallback.bind(this)); } + /** + * Get app data callback function in BaseAppPresenter. + * + * @param {object} list - app data. + */ getListCallback(list) { let callbacklist = list.sort( function compareFunction(param1, param2) { return param1.AppName.localeCompare(param2.AppName, "zh"); } ); - - viewCallback(callbacklist); + this.appListInfoCacheManager.setCache(KEY_APP_LIST, list); + mViewCallback(callbacklist); } - uninstallApp(uninstallAppName, ifSystem, callback) { - uninstallCallback = callback; - if (ifSystem == true) { - callback(false); + /** + * Uninstall app. + * + * @param {string} uninstallBundleName - bundleName of the app to be uninstall. + * @param {boolean} ifSystem - whether the app is a system app or not. + * @param {object} callback - callback function of uninstall app. + */ + uninstallApp(uninstallBundleName, ifSystem, callback) { + mUninstallCallback = callback; + if (ifSystem == UNINSTALL_SUCCESS) { + callback(UNINSTALL_PROHIBITED); } else { - this.appModel.uninstallApp(uninstallAppName, this.uninstallAppCallback.bind(this)); + this.appModel.uninstallApp(uninstallBundleName, this.uninstallAppCallback.bind(this)); } } + /** + * Uninstall app callback function in BaseAppPresenter. + * + * @param {object} callback - callback function of uninstall app. + */ uninstallAppCallback(callback) { - uninstallCallback(callback); + mUninstallCallback(callback); } - jumpTo(bundleName) { - this.appModel.openApplication(bundleName); + /** + * Jump to another application. + * + * @param {string} abilityName - ability name of the application to be jump to. + * @param {string} bundleName - bundle name of the application to be jump to. + */ + jumpTo(abilityName, bundleName) { + this.appModel.startApplication(abilityName, bundleName); } + /** + * Jump to launcher settings module. + */ jumpToSetting() { - RouterUtil.push(JUMPSETTING); + this.appModel.startApplication(SETTING_ABILITY, SETTING_BUNDLE); } + /** + * Back to front page. + */ back() { RouterUtil.back(); } - clearRouter() { - RouterUtil.clear(); + /** + * Register multi mode input event listener. + * + * @param {object} listener - the listener to be registered to handle the multi mode input event. + */ + registerMMIEventListener(listener) { + this.mmiModel.registerEventCallback(listener); } - registerAppUninstallListener(listener) { - this.appModel.registerAppUninstallListener(listener); + /** + * Unregister multi mode input event listener. + * + * @param {object} listener - The listener to be unregistered. + */ + unregisterMMIEventListener(listener) { + this.mmiModel.unregisterEventCallback(listener); } - registerAppInstallListener(listener) { - console.info("Launcher BaseAppPresenter registerAppInstallListener start"); - this.appModel.registerAppInstallListener(listener); + /** + * Get the layout view type. + * + * @return {string} Layout view type, should one of 'Grid' or 'List' which is stored in LayoutConstants class. + */ + getAppPageStartConfig() { + return this.settingModel.getAppPageStartConfig(); } - unregisterAppInstallListener(listener) { - this.appModel.unregisterAppInstallListener(listener); + /** + * Layout migrate function. + * + * @param {string} currentLayout - Current layout type. + * @return {string} Whether the layout should be migrate or not. + */ + layoutMigrate(currentLayout) { + + console.info("Launcher layoutMigrate in currentLayout = " + currentLayout); + + let isNeedLayoutMigrate = false; + let destinationLayout = this.getAppPageStartConfig(); + if (currentLayout === destinationLayout) { + return isNeedLayoutMigrate; + } + + if (destinationLayout === LayoutConstants.Grid) { + RouterUtil.replace(PageData.GRID_APP_PAGE); + isNeedLayoutMigrate = true; + } else if (destinationLayout === LayoutConstants.List) { + RouterUtil.replace(PageData.LIST_APP_PAGE); + isNeedLayoutMigrate = true; + } else { + console.error("Launcher layoutMigrate error"); + } + + console.info("Launcher layoutMigrate in isNeedLayoutMigrate = " + isNeedLayoutMigrate); + return isNeedLayoutMigrate; + } + + /** + * Called in onInit method from view to register listeners. + * + * @param {object} listener - View update listener. + */ + registerAppListChangeCallback(listener) { + mAppListChangeCallback = listener; + this.appModel.registerAppListInstallListener(mAppListInstallListener); + this.appModel.registerAppListUninstallListener(mAppListUninstallListener); + this.appModel.registerAppListChangeListener(mAppListChangeListener); + } + + /** + * Called in onDestroy method from view to unregister listeners. + */ + unregisterAppListChangeCallback() { + console.info("Launcher appPresenter unregisterAppListChangeCallback"); + this.appModel.unregisterAppListInstallListener(mAppListInstallListener); + this.appModel.unregisterAppListUninstallListener(mAppListUninstallListener); + this.appModel.unregisterAppListChangeListener(mAppListChangeListener); + } + + /** + * Call back function of app installation. + * + * @param {object} bundleInfo - BundleInfo of installed application. + */ + appListInstallListener(bundleInfo) { + this.modifyItemList(this.appendItem, bundleInfo); + } + + /** + * Append item to list. + * + * @param {object} list - List to be operated. + * @param {object} item - Item to be appended. + * @return {object} The list with appended item. + */ + appendItem(list, item) { + list.push(item); + return list; + } + + /** + * Call back function of app uninstallation. + * + * @param {object} bundleInfo - BundleInfo of uninstalled application. + */ + appListUninstallListener(bundleInfo) { + this.modifyItemList(this.removeItem, bundleInfo); + } + + /** + * Remove item from list. + * + * @param {object} list - List to be operated. + * @param {object} item - Item to be removed. + * @return {object} The list with removed item. + */ + removeItem(list, item) { + for (let listItem of list) { + if (listItem.bundleName == item.bundleName) { + let index = list.indexOf(listItem); + list.splice(index, 1); + } + } + return list; + } + + /** + * Call back function of app package change event. + * + * @param {object} bundleInfo - BundleInfo of changed application. + */ + appListChangeListener(bundleInfo) { + this.modifyItemList(this.replaceItem, bundleInfo); + } + + /** + * Replace item from list. + * + * @param {object} list - List to be operated. + * @param {object} item - Item to be replaced. + * @return {object} The list with replaced item. + */ + replaceItem(list, item) { + for (let listItem of list) { + console.info("Launcher replaceCache + " + listItem.bundleName + " + " + item.bundleName); + if (listItem.bundleName == item.bundleName) { + let index = list.indexOf(listItem); + list.splice(index, 1, item); + } + } + return list; + } + + /** + * To operate cache and call callback method from view. + * + * @param {object} method - Method that add/modify/remove item in cache. + * @param {object} item - The item that will be operated. + */ + modifyItemList(method, item) { + console.info("Launcher AppListPresenter appListChangeListener + " + JSON.stringify(item)); + let currentCacheList = this.appListInfoCacheManager.getCache(KEY_APP_LIST); + method(currentCacheList, item); + this.appListInfoCacheManager.setCache(KEY_APP_LIST, currentCacheList); + let callbackList = this.regroupDataAfterInstall(currentCacheList); + mAppListChangeCallback(callbackList); + } + + /** + * To adapt bundleInfo data to different views. + * Will be overridden by sub-classes. + * + * @param {object} callbackList - BundleInfo list get from cache. + */ + regroupDataAfterInstall(callbackList) { + } } \ No newline at end of file diff --git a/launcher/src/main/js/default/presenter/entry/EntryPresenter.js b/launcher/src/main/js/default/presenter/entry/EntryPresenter.js index f0ceb61a..63783bfa 100644 --- a/launcher/src/main/js/default/presenter/entry/EntryPresenter.js +++ b/launcher/src/main/js/default/presenter/entry/EntryPresenter.js @@ -20,13 +20,20 @@ import PageData from '../../common/constants/PageData.js'; const GRID = LayoutConstants.Grid; const GRID_APP_VIEW = PageData.GRID_APP_PAGE; const LIST_APP_VIEW = PageData.LIST_APP_PAGE; -var mSettingsModel; +let mSettingsModel; + +/** + * Presenter of entry view. + */ export default class EntryPresenter { constructor(settingsModel) { mSettingsModel = settingsModel; } + /** + * Entry the launcher grid view or list view. + */ startAppListView() { console.info("Launcher EntryPresenter startAppListView start"); let data = mSettingsModel.getAppPageStartConfig(); diff --git a/launcher/src/main/js/default/resources/res-hdpi.json b/launcher/src/main/js/default/resources/res-hdpi.json new file mode 100644 index 00000000..62ae1689 --- /dev/null +++ b/launcher/src/main/js/default/resources/res-hdpi.json @@ -0,0 +1,8 @@ +{ + "image": { + "icon_default": "common/pics/icon_default.png", + "img_return": "common/pics/img_return.png", + "img_to_detail": "common/pics/img_to_detail.png", + "img_wallpaper_default": "common/pics/img_wallpaper_default.jpg" + } +} \ No newline at end of file diff --git a/launcher/src/main/js/default/resources/res-ldpi.json b/launcher/src/main/js/default/resources/res-ldpi.json new file mode 100644 index 00000000..62ae1689 --- /dev/null +++ b/launcher/src/main/js/default/resources/res-ldpi.json @@ -0,0 +1,8 @@ +{ + "image": { + "icon_default": "common/pics/icon_default.png", + "img_return": "common/pics/img_return.png", + "img_to_detail": "common/pics/img_to_detail.png", + "img_wallpaper_default": "common/pics/img_wallpaper_default.jpg" + } +} \ No newline at end of file diff --git a/launcher/src/main/js/default/resources/res-mdpi.json b/launcher/src/main/js/default/resources/res-mdpi.json new file mode 100644 index 00000000..62ae1689 --- /dev/null +++ b/launcher/src/main/js/default/resources/res-mdpi.json @@ -0,0 +1,8 @@ +{ + "image": { + "icon_default": "common/pics/icon_default.png", + "img_return": "common/pics/img_return.png", + "img_to_detail": "common/pics/img_to_detail.png", + "img_wallpaper_default": "common/pics/img_wallpaper_default.jpg" + } +} \ No newline at end of file diff --git a/launcher/src/main/js/default/resources/res-xhdpi.json b/launcher/src/main/js/default/resources/res-xhdpi.json new file mode 100644 index 00000000..62ae1689 --- /dev/null +++ b/launcher/src/main/js/default/resources/res-xhdpi.json @@ -0,0 +1,8 @@ +{ + "image": { + "icon_default": "common/pics/icon_default.png", + "img_return": "common/pics/img_return.png", + "img_to_detail": "common/pics/img_to_detail.png", + "img_wallpaper_default": "common/pics/img_wallpaper_default.jpg" + } +} \ No newline at end of file diff --git a/launcher/src/main/js/default/resources/res-xxhdpi.json b/launcher/src/main/js/default/resources/res-xxhdpi.json new file mode 100644 index 00000000..480270e2 --- /dev/null +++ b/launcher/src/main/js/default/resources/res-xxhdpi.json @@ -0,0 +1,8 @@ +{ + "image": { + "icon_default": "common/pics/icon_default.png", + "img_return": "common/pics/img_return.png", + "img_to_detail": "common/pics/img_to_detail.png", + "img_wallpaper_default": "common/pics/img_wallpaper_default.jpg" + } +} diff --git a/launcher/src/main/js/default/resources/res-xxxhdpi.json b/launcher/src/main/js/default/resources/res-xxxhdpi.json new file mode 100644 index 00000000..62ae1689 --- /dev/null +++ b/launcher/src/main/js/default/resources/res-xxxhdpi.json @@ -0,0 +1,8 @@ +{ + "image": { + "icon_default": "common/pics/icon_default.png", + "img_return": "common/pics/img_return.png", + "img_to_detail": "common/pics/img_to_detail.png", + "img_wallpaper_default": "common/pics/img_wallpaper_default.jpg" + } +} \ No newline at end of file diff --git a/launcher/src/main/resources/rawfile/layoutInfo.json b/launcher/src/main/resources/rawfile/layoutInfo.json new file mode 100644 index 00000000..4905de12 --- /dev/null +++ b/launcher/src/main/resources/rawfile/layoutInfo.json @@ -0,0 +1,9 @@ +{ + "layoutDescription" : { + "pageCount" : 0, + "row" : 5, + "column" : 4 + }, + "layoutInfo" : [ + ] +} \ No newline at end of file diff --git a/recents/src/main/config.json b/recents/src/main/config.json index 8f7c2571..0203ac7a 100644 --- a/recents/src/main/config.json +++ b/recents/src/main/config.json @@ -3,8 +3,8 @@ "bundleName": "com.ohos.launcher", "vendor": "ohos", "version": { - "code": 1, - "name": "1.0" + "code": 1000000, + "name": "1.0.0" }, "apiVersion": { "compatible": 5, diff --git a/recents/src/main/js/default/app.js b/recents/src/main/js/default/app.js index dfb8ca10..16b10fd6 100644 --- a/recents/src/main/js/default/app.js +++ b/recents/src/main/js/default/app.js @@ -14,14 +14,18 @@ */ import RecentsModel from './common/model/RecentsModel.js' +import ResourceManager from './common/model/ResourceManager.js' export default { data: { recentsModel: new RecentsModel(), + resourceManager: new ResourceManager() }, + onCreate() { console.info('Launcher recents AceApplication onCreate'); }, + onDestroy() { console.info('Launcher recents AceApplication onDestroy'); } diff --git a/recents/src/main/js/default/common/component/AppIcon/AppIcon.js b/recents/src/main/js/default/common/component/AppIcon/AppIcon.js index cbb56de8..6dc0c1d8 100644 --- a/recents/src/main/js/default/common/component/AppIcon/AppIcon.js +++ b/recents/src/main/js/default/common/component/AppIcon/AppIcon.js @@ -13,9 +13,8 @@ * limitations under the License. */ -import ResourceManager from '../../model/ResourceManager.js'; - -var mResourceManager; +let mResourceManager; +let mDefaultAppIcon; export default { props: ['itemAppId', 'itemAppIcon', 'itemBundleName'], @@ -27,21 +26,26 @@ export default { }; }, onInit() { - console.info("Launcher recents AppIcon onInit start") - this.$watch('itemAppIcon', 'appIconWatcher'); - mResourceManager = new ResourceManager(); - mResourceManager.getAppIcon(this.itemAppIcon, this.itemBundleName, this.iconLoadCallback); + console.info("Launcher recents AppIcon onInit start"); + mDefaultAppIcon = globalThis.$globalR('image.icon_default'); + mResourceManager = this.$app.$def.data.resourceManager; console.info("Launcher recents AppIcon onInit end") }, - onShow() { - }, - appIconWatcher(newV, oldV) { - if (newV != null && newV != undefined) { - mResourceManager.getAppIcon(this.itemAppIcon, this.itemBundleName, this.iconLoadCallback); - } - }, + /** + * Set image. + * + * @param {object} image - the image. + */ iconLoadCallback(image) { this.appIcon = image; + }, + + /** + * Update icon. + */ + updateIcon() { + console.info("Launcher AppIcon updateIcon in bundleName = " + this.itemBundleName); + mResourceManager.getAppIcon(this.itemAppIcon,this.itemBundleName,this.iconLoadCallback, mDefaultAppIcon); } } \ No newline at end of file diff --git a/recents/src/main/js/default/common/component/AppName/AppName.js b/recents/src/main/js/default/common/component/AppName/AppName.js index 64c103c2..8ae52a89 100644 --- a/recents/src/main/js/default/common/component/AppName/AppName.js +++ b/recents/src/main/js/default/common/component/AppName/AppName.js @@ -13,9 +13,7 @@ * limitations under the License. */ -import ResourceManager from '../../model/ResourceManager.js'; - -var mResourceManager; +let mResourceManager; export default { props: ['itemAppId', 'itemLabelId', 'itemBundleName', 'itemAppName'], @@ -28,19 +26,25 @@ export default { }; }, onInit() { - this.$watch('itemLabelId', 'appIconWatcher'); - mResourceManager = new ResourceManager(); - mResourceManager.getAppName(this.itemLabelId, this.itemBundleName, this.itemAppName, this.iconLoadCallback); + console.info("Launcher recents AppName onInit start"); + mResourceManager = this.$app.$def.data.resourceManager; + console.info("Launcher recents AppName onInit end"); }, - onShow() { - }, - appIconWatcher(newV, oldV) { - if (newV != null && newV != undefined) { - mResourceManager.getAppName(this.itemLabelId, this.itemBundleName, this.itemAppName, this.iconLoadCallback); - } - }, + /** + * Set app name. + * + * @param {string} name - the name of app. + */ iconLoadCallback(name) { this.appName = name; + }, + + /** + * Update name. + */ + updateName() { + console.info("Launcher AppName updateName in bundleName = " + this.itemBundleName); + mResourceManager.getAppName(this.itemLabelId,this.itemBundleName,this.itemAppName,this.iconLoadCallback); } } \ No newline at end of file diff --git a/recents/src/main/js/default/common/model/RecentsModel.js b/recents/src/main/js/default/common/model/RecentsModel.js index 9eac335b..23c680d8 100644 --- a/recents/src/main/js/default/common/model/RecentsModel.js +++ b/recents/src/main/js/default/common/model/RecentsModel.js @@ -13,32 +13,47 @@ * limitations under the License. */ -import napiAbilityManager from '@ohos.napi_ability_manager'; -import featureAbility from '@ohos.feature_ability'; -import storage from '@ohos.data.storage'; -import bundle_mgr from '@ohos.bundle_mgr'; -import feature_ability from '@ohos.feature_ability'; +import NapiAbilityManager from '@ohos.app.abilitymanager'; +import Storage from '@ohos.data.storage'; +import BundleMgr from '@ohos.bundle'; +import FeatureAbility from '@ohos.ability.featureability'; -var RECENT_PROCESS_LIMIT_KEY = 'RecentProcessLimit'; const PREFERENCES_PATH = '/data/accounts/account_0/appdata/com.ohos.launcher/sharedPreference/LauncherPreference'; -var mRecentList = []; -var DEFAULT_RECENT_PROCESS_LIMIT = 10; -var INCLUDE_SYSTEM_APP = 0; -var EXCLUDE_SYSTEM_APP = 1; -var mIconResultCount = 0; -var mPreferences = storage.getStorageSync(PREFERENCES_PATH); +const MAX_NUM = 20; +const PERMISSION_NUM = 8; +const NON = 0; +const RECENT_PROCESS_LIMIT_KEY = 'RecentProcessLimit'; +const DEFAULT_RECENT_PROCESS_LIMIT = 10; +let mRecentList = []; +let mIconResultCount = 0; +let mPreferences = Storage.getStorageSync(PREFERENCES_PATH); + +/** + * Class RecentsModel. + */ export default class RecentsModel { + + /** + * Get recent process list. + * + * @param {object} callback - the callback from presenter. + */ getRecentProcessList(callback) { - console.info("Launcher recents RecentsModel getRecentProcessList start") + console.info("Launcher recents RecentsModel getRecentProcessList start"); mRecentList = []; mIconResultCount = 0; - console.info("Launcher recents RecentsModel napiAbilityManager.queryRecentAbilityMissionInfos start") - napiAbilityManager.queryRecentAbilityMissionInfos().then((data) => { - console.info("Launcher recents RecentsModel napiAbilityManager.queryRecentAbilityMissionInfos() callback") - console.info('Launcher recents queryRecentAbilityMissionInfos data length [' + data.length + ']'); - console.info('Launcher recents queryRecentAbilityMissionInfos data = ' + JSON.stringify(data)); - for (var i = 0; i < data.length; i++) { + console.info("Launcher recents RecentsModel NapiAbilityManager.queryRecentAbilityMissionInfos start") + NapiAbilityManager.queryRunningAbilityMissionInfos(MAX_NUM).then((data) => { + console.info("Launcher recents RecentsModel NapiAbilityManager.queryRecentAbilityMissionInfos() callback") + console.info('Launcher recents queryRecentAbilityMissionInfos data length [' + data.length + ']'); + console.info('Launcher recents queryRecentAbilityMissionInfos data = ' + JSON.stringify(data)); + if(data.length == 0) { + console.info('Launcher recents data empty'); + callback(mRecentList); + return; + } + for (let i = 0; i < data.length; i++) { let recentTaskInfo = { AppName: data[i].missionDescription.label, AppId: data[i].topAbility.bundleName, @@ -50,72 +65,89 @@ export default class RecentsModel { } mRecentList.push(recentTaskInfo); } - console.info('Launcher recents RecentsModel queryRecentAbilityMissionInfos mRecentList = ' + JSON.stringify(mRecentList)); + console.info('Launcher recents RecentsModel queryRecentAbilityMissionInfos mRecentList = ' + JSON.stringify(mRecentList)); for (let element of mRecentList) { - console.info('Launcher recents RecentsModel bundle_mgr.getApplicationInfo element of mRecentList = ' + JSON.stringify(element)); - bundle_mgr.getApplicationInfo(element.AppId).then(data => { - console.info('Launcher recents bundle_mgr.getApplicationInfo data = ' + JSON.stringify(data)); + console.info('Launcher recents RecentsModel bundle_mgr.getApplicationInfo element of mRecentList = ' + JSON.stringify(element)); + BundleMgr.getApplicationInfo(element.AppId, PERMISSION_NUM, NON).then(data => { + console.info('Launcher recents bundle_mgr.getApplicationInfo data = ' + JSON.stringify(data)); let recentTaskInfo = mRecentList.find((recentItem) => { - if (recentItem.AppId == data.bundleName) return recentItem; + if (recentItem.AppId == data.name) return recentItem; }); recentTaskInfo.iconId = data.iconId; recentTaskInfo.labelId = data.labelId; mIconResultCount++; - console.info('Launcher recents getApplicationInfo mIconResultCount = ' + mIconResultCount); - console.info('Launcher recents getApplicationInfo mRecentList.length = ' + mRecentList.length); + console.info('Launcher recents getApplicationInfo mIconResultCount = ' + mIconResultCount); + console.info('Launcher recents getApplicationInfo mRecentList.length = ' + mRecentList.length); if (mIconResultCount == mRecentList.length) { callback(mRecentList); } - }); + }).catch(error => + console.error("Launcher recents RecentsModel getRecentProcessList promise::catch : " + JSON.stringify(error)) + ); } - }); - console.info("Launcher recents RecentsModel getRecentProcessList end") + }).catch(error => + console.error("Launcher recents RecentsModel getRecentProcessList promise::catch : " + JSON.stringify(error)) + ); + console.info("Launcher recents RecentsModel getRecentProcessList end") } + /** + * Clear recent process list. + * + */ clearRecentProcess() { - console.info("Launcher recents RecentsModel clearRecentProcess start") + console.info("Launcher recents RecentsModel clearRecentProcess start") while (mRecentList.length > 0) { mRecentList.pop(); } - console.info("Launcher recents RecentsModel napiAbilityManager.removeStack start") - napiAbilityManager.removeStack(EXCLUDE_SYSTEM_APP).then((data) => { - console.info('Launcher recents removeStack data [' + data + ']'); + console.info("Launcher recents RecentsModel NapiAbilityManager.removeStack start") + NapiAbilityManager.clearMissions().then((data) => { }); setTimeout(() => { - console.info("Launcher recents RecentsModel feature_ability.terminateAbility start") - feature_ability.terminateAbility() - .then(data => console.info("Launcher recents terminateAbility promise::then : " + data)) - .catch(error => console.info("Launcher recents terminateAbility promise::catch : " + error)); + console.info("Launcher recents RecentsModel feature_ability.terminateAbility start") + FeatureAbility.terminateAbility() + .then(data => console.info("Launcher recents terminateAbility promise::then : " + data)) + .catch(error => console.info("Launcher recents terminateAbility promise::catch : " + error)); }, 1000); - console.info("Launcher recents RecentsModel clearRecentProcess end") + console.info("Launcher recents RecentsModel clearRecentProcess end") } + /** + * Remove recent process list. + * + * @param {string} missionId - the missionId of recent process. + */ removeRecentProcess(missionId) { - console.info("Launcher recents RecentsModel removeRecentProcess start") - for (var idx = 0; idx < mRecentList.length; idx++) { + console.info("Launcher recents RecentsModel removeRecentProcess start") + for (let idx = 0; idx < mRecentList.length; idx++) { if (mRecentList[idx].missionId == missionId) { mRecentList.splice(idx, 1); break; } } - console.info("Launcher recents RecentsModel napiAbilityManager.removeMission start") - napiAbilityManager.removeMission(missionId).then((data) => { + console.info("Launcher recents RecentsModel NapiAbilityManager.removeMission start") + NapiAbilityManager.removeMission(missionId).then((data) => { console.info('removeMission data [' + data + ']'); }); if (mRecentList.length == 0) { setTimeout(() => { - console.info("Launcher recents RecentsModel feature_ability.terminateAbility start") - feature_ability.terminateAbility() - .then(data => console.info("Launcher recents terminateAbility promise::then : " + data)) - .catch(error => console.info("Launcher recents terminateAbility promise::catch : " + error)); + console.info("Launcher recents RecentsModel feature_ability.terminateAbility start") + FeatureAbility.terminateAbility() + .then(data => console.info("Launcher recents terminateAbility promise::then : " + data)) + .catch(error => console.info("Launcher recents terminateAbility promise::catch : " + error)); }, 1000); } - console.info("Launcher recents RecentsModel removeRecentProcess end") + console.info("Launcher recents RecentsModel removeRecentProcess end") } + /** + * Get recent process list. + * + * @return {number} - the number of recent process. + */ getRecentProcessLimit() { console.info("Launcher recents RecentsModel getRecentProcessLimit start"); let limit = DEFAULT_RECENT_PROCESS_LIMIT; @@ -126,35 +158,35 @@ export default class RecentsModel { return limit; } + /** + * Hot start app. + * + * @param {object} appInfo - the app info. + */ hotStartUpApp(appInfo) { - console.info('Launcher recents hotStartUpApp start'); + console.info('Launcher recents hotStartUpApp start'); this.startAbility(appInfo); - console.info('Launcher recents hotStartUpApp end'); + console.info('Launcher recents hotStartUpApp end'); } + /** + * Start ability. + * + * @param {object} appInfo - the app info. + */ startAbility(appInfo) { - console.info("Launcher recents startAbility start"); - console.info("Launcher recents featureAbility.startAbility appId = " + JSON.stringify(appInfo)); - featureAbility.startAbility({ - bundleName: appInfo.AppId, - abilityName: appInfo.abilityName, - requestCode: 1, - abilityType: "PageAbility", + // promise + console.info('Launcher startApplication abilityname'); + let result = FeatureAbility.startAbility({ want: { - action: "action1", - entities: ["entity1"], - type: "PageAbility", - flags: 2, - elementName: { - deviceId: "deviceId", - bundleName: appInfo.AppId, - abilityName: appInfo.abilityName, - }, - }, - syncOption: 1 + bundleName: appInfo.AppId, + abilityName: appInfo.abilityName + } }).then(data => - console.info("Launcher recents promise::then : " + data)).catch(error => - console.info("Launcher recents promise::catch : " + error)); - console.info("Launcher recents startAbility end"); + console.info("Launcher promise::then : " + JSON.stringify(data)) + ).catch(error => + console.info("Launcher promise::catch : " + JSON.stringify(error)) + ); + console.info("Launcher AceApplication : startAbility : " + result); } } \ No newline at end of file diff --git a/recents/src/main/js/default/common/model/ResourceManager.js b/recents/src/main/js/default/common/model/ResourceManager.js index 518d90f6..49262acb 100644 --- a/recents/src/main/js/default/common/model/ResourceManager.js +++ b/recents/src/main/js/default/common/model/ResourceManager.js @@ -13,22 +13,30 @@ * limitations under the License. */ -import resmgr from '@ohos.resmgr'; - -const DEFAULT_ICON_URL = 'common/pics/icon_default.png'; +import Resmgr from '@ohos.resmgr'; +/** + * A manager class provide app icon and name from cache or system API. + */ export default class ResourceManager { - ResourceManager() { + constructor() { } - getAppIcon(path, bundleName, callback) { + /** + * Get icon image of specific app. + * + * @param {string} path - path of target file + * @param {string} bundleName - bundle name of the app + * @param {object} callback - callback method + */ + getAppIcon(path, bundleName, callback, defaultIconUrl) { console.info("Launcher recents ResourceManager getAppIcon start path = " + path + " bundleName = " + bundleName); if (path == null || path == undefined || path == "") { console.info("Launcher recents ResourceManager defaultIcon callback "); - callback(DEFAULT_ICON_URL) + callback(defaultIconUrl) } else { - console.info("Launcher recents ResourceManager resmgr.getResourceManager called"); - resmgr.getResourceManager(bundleName).then(item => { + console.info("Launcher recents ResourceManager Resmgr.getResourceManager called"); + Resmgr.getResourceManager(bundleName).then(item => { console.info("Launcher recents ResourceManager item.getMediaBase64 called"); item.getMediaBase64(path, (error, value) => { console.info("Launcher recents ResourceManager item.getMediaBase64 callback value = " + value); @@ -36,27 +44,39 @@ export default class ResourceManager { callback(value); } }); - }); + }).catch(error => + console.error("Launcher recents ResourceManager getAppIcon promise::catch : " + JSON.stringify(error)) + ); } console.info("Launcher recents ResourceManager getAppIcon end"); } + /** + * Get app name of specific app. + * + * @param {string} labelId - label id of target app + * @param {string} bundleName - bundle name of the app + * @param {string} appName - app name + * @param {object} callback - callback method + */ getAppName(labelId, bundleName, appName, callback) { - console.info("Launcher recents ResourceManager getAppName start labelId = " + labelId + console.info("Launcher recents ResourceManager getAppName start labelId = " + labelId + " bundleName = " + bundleName + " appName = " + appName); if (labelId <= 0) { callback(appName); } else { - console.info("Launcher recents ResourceManager resmgr.getResourceManager "); - resmgr.getResourceManager(bundleName).then(item => { + console.info("Launcher recents ResourceManager Resmgr.getResourceManager "); + Resmgr.getResourceManager(bundleName).then(item => { console.info("Launcher recents ResourceManager item.getString " + JSON.stringify(item)); item.getString(labelId, (error, value) => { if (value != null) { - console.info("Launcher recents ResourceManager item.getString callback value = " + value); + console.info("Launcher recents ResourceManager item.getString callback value = " + value); callback(value); } }); - }); + }).catch(error => + console.error("Launcher recents ResourceManager getAppName promise::catch : " + JSON.stringify(error)) + ); } } } \ No newline at end of file diff --git a/recents/src/main/js/default/common/pics/icon_default.png b/recents/src/main/js/default/common/pics/icon_default.png new file mode 100644 index 0000000000000000000000000000000000000000..f72f0a34194021bc42141e07ca8c284f88527ea6 GIT binary patch literal 5979 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 literal 0 HcmV?d00001 diff --git a/recents/src/main/js/default/i18n/en-US.json b/recents/src/main/js/default/i18n/en-US.json index 9e520910..cbad6c4f 100644 --- a/recents/src/main/js/default/i18n/en-US.json +++ b/recents/src/main/js/default/i18n/en-US.json @@ -1,4 +1,5 @@ { "strings": { + "no_recent": "No recent apps" } } \ No newline at end of file diff --git a/recents/src/main/js/default/i18n/zh-CN.json b/recents/src/main/js/default/i18n/zh-CN.json index 9e520910..7c4aa4e0 100644 --- a/recents/src/main/js/default/i18n/zh-CN.json +++ b/recents/src/main/js/default/i18n/zh-CN.json @@ -1,4 +1,5 @@ { "strings": { + "no_recent": "最近无运行应用" } } \ No newline at end of file diff --git a/recents/src/main/js/default/pages/recent/recent.css b/recents/src/main/js/default/pages/recent/recent.css index d9a54f25..4a5918c1 100644 --- a/recents/src/main/js/default/pages/recent/recent.css +++ b/recents/src/main/js/default/pages/recent/recent.css @@ -16,7 +16,6 @@ @import '../../common/css/CommonPageStyle.css'; .container { - background-image: url("common/pics/ic_wallpaper_recent.jpg"); background-size: cover; } @@ -65,11 +64,25 @@ .piece { height: 20%; width: 100%; - display: flex; align-items: center; justify-content: center; } +.no-recent { + height: 100%; + width: 100%; + align-items: center; + justify-content: center; +} + +.no-recent-text { + color: white; + font-size: 30px; + height: 60px; + line-height: 60px; + align-items: center; +} + .clear { background-color: black; opacity: 0.4; diff --git a/recents/src/main/js/default/pages/recent/recent.hml b/recents/src/main/js/default/pages/recent/recent.hml index 6161ce99..428e510b 100644 --- a/recents/src/main/js/default/pages/recent/recent.hml +++ b/recents/src/main/js/default/pages/recent/recent.hml @@ -17,31 +17,34 @@ -
-
+
+
- -
-
-
+
- +
+
+ {{$t('strings.no_recent')}} +
\ No newline at end of file diff --git a/recents/src/main/js/default/pages/recent/recent.js b/recents/src/main/js/default/pages/recent/recent.js index 950c65e8..93f75bb5 100644 --- a/recents/src/main/js/default/pages/recent/recent.js +++ b/recents/src/main/js/default/pages/recent/recent.js @@ -15,14 +15,21 @@ import RecentsPresenter from '../../presenter/recent/RecentsPresenter.js'; -var mRecentsPresenter; +const APP_INFO_REFRESH_DELAY = 500; +const DISPLAY_NONE = 'none'; +const DISPLAY_FLEX = 'flex'; + +let mRecentsPresenter; export default { data: { - recentProcessList: [] + recentProcessList: [], + recentProcessListDisplay: DISPLAY_NONE, + emptyMsgDisplay: DISPLAY_FLEX }, onInit() { console.info("Launcher recents onInit start"); + globalThis.$globalR = this.$r.bind(this); console.info("Launcher recents onInit end"); }, @@ -31,13 +38,23 @@ export default { mRecentsPresenter = new RecentsPresenter(this.$app.$def.data.recentsModel); mRecentsPresenter.getRecentProcessList((data) => { this.recentProcessList = data; + if (this.recentProcessList.length == 0) { + this.recentProcessListDisplay = DISPLAY_NONE; + this.emptyMsgDisplay = DISPLAY_FLEX; + return; + } + this.recentProcessListDisplay = DISPLAY_FLEX; + this.emptyMsgDisplay = DISPLAY_NONE; console.info("Launcher recents onShow getRecentProcessList this.recentProcessList = " + JSON.stringify(this.recentProcessList)); + this.updateAppInfos(); }); console.info("Launcher recents onShow end"); }, onHide() { console.info("Launcher recents onHide start"); + this.recentProcessListDisplay = DISPLAY_NONE; + this.emptyMsgDisplay = DISPLAY_NONE; this.recentProcessList = []; console.info("Launcher recents onHide end"); }, @@ -52,6 +69,12 @@ export default { console.info("Launcher recents clearAll end"); }, + /** + * Remove recent process. + * + * @param {string} missionId - the missionId of recent process. + * @param {object} e - the event form pre page. + */ clearApp(missionId, e) { console.info("Launcher recents clearApp start missionId = " + missionId + " e.direction = " + e.direction); if (e.direction == "up") { @@ -61,9 +84,28 @@ export default { console.info("Launcher recents clearApp end"); }, + /** + * Hot start app. + * + * @param {object} appInfo - the app info. + */ startUp(appInfo) { console.info("Launcher recents startUp start appInfo = " + JSON.stringify(appInfo)); mRecentsPresenter.startUpApp(appInfo); console.info("Launcher recents startUp end"); + }, + + /** + * Update app information. + */ + updateAppInfos() { + console.info("Launcher recents updateAppInfos setTimeout this.recentProcessList.length = " + this.recentProcessList.length); + setTimeout(() => { + for(let i = 0; i < this.recentProcessList.length; i++) { + console.info("Launcher recents updateAppInfos setTimeout in i = " + i); + this.$child('icon' + i).updateIcon(); + this.$child('name' + i).updateName(); + } + }, APP_INFO_REFRESH_DELAY); } } \ No newline at end of file diff --git a/recents/src/main/js/default/presenter/recent/RecentsPresenter.js b/recents/src/main/js/default/presenter/recent/RecentsPresenter.js index dcd2b9c4..a30d3a78 100644 --- a/recents/src/main/js/default/presenter/recent/RecentsPresenter.js +++ b/recents/src/main/js/default/presenter/recent/RecentsPresenter.js @@ -13,12 +13,20 @@ * limitations under the License. */ -import router from '@system.router'; +import Router from '@system.router'; -var mRecentsModel; -var mRecentsLimit; +let mRecentsModel; +let mRecentsLimit; +/** + * Class RecentsPresenter. + */ export default class RecentsPresenter { + /** + * Constructor of RecentsPresenter. + * + * @param {object} recentsModel - the model of recentPresenter. + */ constructor(recentsModel) { console.info("Launcher recents RecentsPresenter constructor start"); mRecentsModel = recentsModel; @@ -26,6 +34,11 @@ export default class RecentsPresenter { console.info("Launcher recents RecentsPresenter constructor end"); } + /** + * Callback function of getRecentProcessList. + * + * @param {object} callback - the callback from view. + */ getRecentProcessList(callback) { console.info("Launcher recents RecentsPresenter getRecentProcessList start") mRecentsModel.getRecentProcessList((data) => { @@ -46,6 +59,11 @@ export default class RecentsPresenter { console.info("Launcher recents RecentsPresenter clearRecentProcess end"); } + /** + * Remove recent process. + * + * @param {string} missionId - the missionId of recent process. + */ removeRecentProcess(missionId) { console.info("Launcher recents RecentsPresenter removeRecentProcess start missionId = " + missionId); mRecentsModel.removeRecentProcess(missionId); @@ -54,13 +72,18 @@ export default class RecentsPresenter { back() { console.info("Launcher recents RecentsPresenter back start"); - router.back(); + Router.back(); console.info("Launcher recents RecentsPresenter back end"); } + /** + * Hot start app. + * + * @param {object} appInfo - the app info . + */ startUpApp(appInfo) { console.info("Launcher recents RecentsPresenter startUpApp start appInfo = " + JSON.stringify(appInfo)); mRecentsModel.hotStartUpApp(appInfo); console.info("Launcher recents RecentsPresenter startUpApp end "); } -} \ No newline at end of file +} diff --git a/recents/src/main/js/default/resources/res-hdpi.json b/recents/src/main/js/default/resources/res-hdpi.json new file mode 100644 index 00000000..a3f78819 --- /dev/null +++ b/recents/src/main/js/default/resources/res-hdpi.json @@ -0,0 +1,8 @@ +{ + "image": { + "ic_recent_delete": "common/pics/ic_recent_delete.png", + "ic_wallpaper_recent": "common/pics/ic_wallpaper_recent.jpg", + "img_app_default": "common/pics/img_app_default.png", + "icon_default": "common/pics/icon_default.png" + } +} \ No newline at end of file diff --git a/recents/src/main/js/default/resources/res-ldpi.json b/recents/src/main/js/default/resources/res-ldpi.json new file mode 100644 index 00000000..a3f78819 --- /dev/null +++ b/recents/src/main/js/default/resources/res-ldpi.json @@ -0,0 +1,8 @@ +{ + "image": { + "ic_recent_delete": "common/pics/ic_recent_delete.png", + "ic_wallpaper_recent": "common/pics/ic_wallpaper_recent.jpg", + "img_app_default": "common/pics/img_app_default.png", + "icon_default": "common/pics/icon_default.png" + } +} \ No newline at end of file diff --git a/recents/src/main/js/default/resources/res-mdpi.json b/recents/src/main/js/default/resources/res-mdpi.json new file mode 100644 index 00000000..a3f78819 --- /dev/null +++ b/recents/src/main/js/default/resources/res-mdpi.json @@ -0,0 +1,8 @@ +{ + "image": { + "ic_recent_delete": "common/pics/ic_recent_delete.png", + "ic_wallpaper_recent": "common/pics/ic_wallpaper_recent.jpg", + "img_app_default": "common/pics/img_app_default.png", + "icon_default": "common/pics/icon_default.png" + } +} \ No newline at end of file diff --git a/recents/src/main/js/default/resources/res-xhdpi.json b/recents/src/main/js/default/resources/res-xhdpi.json new file mode 100644 index 00000000..a3f78819 --- /dev/null +++ b/recents/src/main/js/default/resources/res-xhdpi.json @@ -0,0 +1,8 @@ +{ + "image": { + "ic_recent_delete": "common/pics/ic_recent_delete.png", + "ic_wallpaper_recent": "common/pics/ic_wallpaper_recent.jpg", + "img_app_default": "common/pics/img_app_default.png", + "icon_default": "common/pics/icon_default.png" + } +} \ No newline at end of file diff --git a/recents/src/main/js/default/resources/res-xxhdpi.json b/recents/src/main/js/default/resources/res-xxhdpi.json new file mode 100644 index 00000000..a3f78819 --- /dev/null +++ b/recents/src/main/js/default/resources/res-xxhdpi.json @@ -0,0 +1,8 @@ +{ + "image": { + "ic_recent_delete": "common/pics/ic_recent_delete.png", + "ic_wallpaper_recent": "common/pics/ic_wallpaper_recent.jpg", + "img_app_default": "common/pics/img_app_default.png", + "icon_default": "common/pics/icon_default.png" + } +} \ No newline at end of file diff --git a/recents/src/main/js/default/resources/res-xxxhdpi.json b/recents/src/main/js/default/resources/res-xxxhdpi.json new file mode 100644 index 00000000..a3f78819 --- /dev/null +++ b/recents/src/main/js/default/resources/res-xxxhdpi.json @@ -0,0 +1,8 @@ +{ + "image": { + "ic_recent_delete": "common/pics/ic_recent_delete.png", + "ic_wallpaper_recent": "common/pics/ic_wallpaper_recent.jpg", + "img_app_default": "common/pics/img_app_default.png", + "icon_default": "common/pics/icon_default.png" + } +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index b28c933e..e5e91779 100755 --- a/settings.gradle +++ b/settings.gradle @@ -13,5 +13,5 @@ * limitations under the License. */ -include ':launcher', ':recents' +include ':launcher', ':recents', ':settings' diff --git a/settings/build.gradle b/settings/build.gradle new file mode 100644 index 00000000..5c6256e9 --- /dev/null +++ b/settings/build.gradle @@ -0,0 +1,22 @@ +apply plugin: 'com.huawei.ohos.hap' +ohos { + compileSdkVersion 6 + defaultConfig { + compatibleSdkVersion 6 + } + supportSystem "standard" + buildTypes { + release { + proguardOpt { + proguardEnabled false + rulesFiles 'proguard-rules.pro' + } + } + } + entryModules "launcher" +} + +dependencies { + entryImplementation project(':launcher') +} + diff --git a/settings/package.json b/settings/package.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/settings/package.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/settings/src/main/config.json b/settings/src/main/config.json new file mode 100644 index 00000000..3ca79747 --- /dev/null +++ b/settings/src/main/config.json @@ -0,0 +1,53 @@ +{ + "app": { + "bundleName": "com.ohos.launcher", + "vendor": "ohos", + "version": { + "code": 1000000, + "name": "1.0.0" + }, + "apiVersion": { + "compatible": 5, + "target": 5, + "releaseType": "Beta1" + } + }, + "deviceConfig": {}, + "module": { + "package": "com.ohos.launcher.settings", + "name": ".MyApplication", + "mainAbility": "com.ohos.launcher.settings.MainAbility", + "deviceType": [ + "phone" + ], + "distro": { + "deliveryWithInstall": true, + "moduleName": "settings", + "moduleType": "feature", + "installationFree": true + }, + "abilities": [ + { + "visible": true, + "name": "com.ohos.launcher.settings.MainAbility", + "icon": "$media:icon", + "description": "$string:mainability_description", + "label": "$string:app_name", + "type": "page", + "launchType": "singleton" + } + ], + "js": [ + { + "name": "default", + "window": { + "designWidth": 720, + "autoDesignWidth": true + }, + "pages": [ + "pages/settings/settings" + ] + } + ] + } +} \ No newline at end of file diff --git a/settings/src/main/js/default/app.js b/settings/src/main/js/default/app.js new file mode 100644 index 00000000..210ce5cc --- /dev/null +++ b/settings/src/main/js/default/app.js @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2021 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 SettingsModel from './common/model/SettingsModel.js' + +export default { + data: { + settingsModel: new SettingsModel() + }, + + onCreate() { + console.info('Launcher settings AceApplication onCreate'); + }, + + onDestroy() { + console.info('Launcher settings AceApplication onDestroy'); + } +}; diff --git a/settings/src/main/js/default/common/configs/DefaultLayoutConfig.js b/settings/src/main/js/default/common/configs/DefaultLayoutConfig.js new file mode 100644 index 00000000..9d8b007a --- /dev/null +++ b/settings/src/main/js/default/common/configs/DefaultLayoutConfig.js @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021 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. + */ + +const DefaultLayoutConfig = { + DefaultAppPageStartConfig: 'Grid', + DefaultGridConfig: 1, + DefaultRecentProcessLimit: 20, + DefaultRecentProcessLimitArray: [5,10,15,20], +} + +export default DefaultLayoutConfig; \ No newline at end of file diff --git a/settings/src/main/js/default/common/configs/GridLayoutConfigs.js b/settings/src/main/js/default/common/configs/GridLayoutConfigs.js new file mode 100644 index 00000000..c5019064 --- /dev/null +++ b/settings/src/main/js/default/common/configs/GridLayoutConfigs.js @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021 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. + */ + +const GridLayoutConfigs = { + GridLayoutTable: [ + { + id: 0, + layout: '4X4', + row: 4, + column: 4 + }, + + { + id: 1, + layout: '5X4', + row: 5, + column: 4 + }, + + { + id: 2, + layout: '6X4', + row: 6, + column: 4 + }, + ] +} + +export default GridLayoutConfigs; \ No newline at end of file diff --git a/settings/src/main/js/default/common/constants/LayoutConstants.js b/settings/src/main/js/default/common/constants/LayoutConstants.js new file mode 100644 index 00000000..32d10147 --- /dev/null +++ b/settings/src/main/js/default/common/constants/LayoutConstants.js @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2021 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. + */ + +const LayoutContants = { + Grid: "Grid", + List: "List" +} + +export default LayoutContants; \ No newline at end of file diff --git a/settings/src/main/js/default/common/constants/PageData.js b/settings/src/main/js/default/common/constants/PageData.js new file mode 100644 index 00000000..a96472cc --- /dev/null +++ b/settings/src/main/js/default/common/constants/PageData.js @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2021 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. + */ + +const PageData = { + GRID_APP_PAGE: 'pages/AppGridView/AppGridView', + LIST_APP_PAGE: 'pages/AppListView/AppListView' +} + +export default PageData; \ No newline at end of file diff --git a/settings/src/main/js/default/common/model/ILayoutConfig.js b/settings/src/main/js/default/common/model/ILayoutConfig.js new file mode 100644 index 00000000..8b91db79 --- /dev/null +++ b/settings/src/main/js/default/common/model/ILayoutConfig.js @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2021 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 ILayoutConfig. + */ +export default class ILayoutConfig { + /** + * constructor. + * + */ + constructor() { + } + + /** + * Get the layout view type. + * + * @return {string} Layout view type, should one of 'Grid' or 'List' which is stored in LayoutConstants class. + */ + getAppPageStartConfig() { + return this.loadAppPageStartConfig(); + } + + /** + * Set the layout view type. + * + * @param {String} type - Layout view type, should one of 'Grid' or 'List' which is stored in LayoutConstants class. + */ + setAppPageStartConfig(type) { + this.saveAppPageStartConfig(type); + } + + /** + * Get grid layout config id. + * + * @return {object} grid layout config id. + */ + getGridConfig() { + return this.loadGridConfig(); + } + + /** + * Set grid layout config id. + * + * @param {number} id - layout config id. + */ + setGridConfig(id) { + this.saveGridConfig(id); + } + + /** + * Get recent process max limit. + * + * @return {number} recent process max limit. + */ + getRecentProcessLimit() { + return this.loadRecentProcessLimit(); + } + + /** + * Set recent process max limit. + * + * @param {number} num - Recent process max limit. + */ + setRecentProcessLimit(num) { + this.saveRecentProcessLimit(num); + } + + /** + * Should overridden by sub-classes , load the launcher layout view type. + */ + loadAppPageStartConfig() { + } + + /** + * Should overridden by sub-classes , save the launcher layout view type. + */ + saveAppPageStartConfig(type) { + } + + /** + * Should overridden by sub-classes , save the launcher layout view type. + */ + loadGridConfig() { + } + + /** + * Should overridden by sub-classes , save the launcher grid view layout config id. + */ + saveGridConfig(id) { + } + + /** + * Should overridden by sub-classes , load the recent process max limit. + */ + loadRecentProcessLimit() { + } + + /** + * Should overridden by sub-classes , save the recent process max limit. + */ + saveRecentProcessLimit(num) { + } +} \ No newline at end of file diff --git a/settings/src/main/js/default/common/model/LayoutConfigManager.js b/settings/src/main/js/default/common/model/LayoutConfigManager.js new file mode 100644 index 00000000..7988feec --- /dev/null +++ b/settings/src/main/js/default/common/model/LayoutConfigManager.js @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2021 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 StorageLayoutConfig from './StorageLayoutConfig.js' +/** + * The factory function of producing the class to operate layout config. + * + * @return {object} The class to operate layout config. + */ +export function getLayoutConfig() { + return new StorageLayoutConfig(); +} diff --git a/settings/src/main/js/default/common/model/SettingsModel.js b/settings/src/main/js/default/common/model/SettingsModel.js new file mode 100644 index 00000000..4ef82e42 --- /dev/null +++ b/settings/src/main/js/default/common/model/SettingsModel.js @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2021 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 GridLayoutConfigs from '../../common/configs/GridLayoutConfigs.js'; +import {getLayoutConfig} from './LayoutConfigManager.js'; +import FeatureAbility from '@ohos.ability.featureability'; + +let mLayoutConfig = getLayoutConfig(); +let mGridConfig = 0; +let mGridLayoutTable = GridLayoutConfigs.GridLayoutTable; + +/** + * Class settingsModel. + */ +export default class SettingsModel { + /** + * Get the grid view presetting collection of layout config information table. + * + * @return {object} Grid view presetting collection object. + */ + getGridLayoutTable() { + return mGridLayoutTable; + } + + /** + * Get layout config of grid view. + * + * @return {object} Layout config of grid view. + */ + getGridConfig() { + mGridConfig = mLayoutConfig.getGridConfig(); + return mGridLayoutTable[mGridConfig]; + } + + /** + * Set layout config id of grid view. + * + * @param {string} id - Layout config id of grid view. + */ + setGridConfig(id) { + mLayoutConfig.setGridConfig(id); + } + + /** + * Get recent process max limit. + * + * @return {number} recent process max limit. + */ + getRecentProcessLimit() { + return mLayoutConfig.getRecentProcessLimit(); + } + + /** + * Set recent process max limit. + * + * @param {number} num - Recent process max limit. + */ + setRecentProcessLimit(num) { + mLayoutConfig.setRecentProcessLimit(num); + } + + /** + * Get the layout view type. + * + * @return {string} Layout view type, should one of 'Grid' or 'List' which is stored in LayoutConstants class. + */ + getAppPageStartConfig() { + return mLayoutConfig.getAppPageStartConfig(); + } + + /** + * Set the layout view type. + * + * @param {string} type - Layout view type, should one of 'Grid' or 'List' which is stored in LayoutConstants class. + */ + setAppPageStartConfig(type) { + mLayoutConfig.setAppPageStartConfig(type); + } + + /** + * Close settings. + */ + closeSettings() { + console.info("Launcher settings SettingsModel closeSettings start") + FeatureAbility.terminateAbility() + .then(data => console.info("Launcher settings SettingsModel closeSettings promise::then : " + data)) + .catch(error => console.info("Launcher settings SettingsModel closeSettings promise::catch : " + error)); + console.info("Launcher settings SettingsModel closeSettings end "); + } +} \ No newline at end of file diff --git a/settings/src/main/js/default/common/model/StorageLayoutConfig.js b/settings/src/main/js/default/common/model/StorageLayoutConfig.js new file mode 100644 index 00000000..95707e9d --- /dev/null +++ b/settings/src/main/js/default/common/model/StorageLayoutConfig.js @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2021 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 ILayoutConfig from './ILayoutConfig.js'; +import DefaultLayoutConfig from '../../common/configs/DefaultLayoutConfig.js'; +import Storage from '@ohos.data.storage'; + +const APP_PAGE_START_CONFIG = 'AppStartPageType'; +const GRID_CONFIG = "GridConfig"; +const RECENT_PROCESS_LIMIT = "RecentProcessLimit"; +const PREFERENCES_PATH = '/data/accounts/account_0/appdata/com.ohos.launcher/sharedPreference/LauncherPreference'; + +let mPreferences = Storage.getStorageSync(PREFERENCES_PATH); + +/** + * A class that stores layout information. + * @extends ILayoutConfig + */ +export default class StorageLayoutConfig extends ILayoutConfig { + + constructor() { + super(); + } + + /** + * Load the launcher layout view type. + * + * @return {string} Layout view type , should one of 'Grid' or 'List' which is stored in LayoutConstants class. + */ + loadAppPageStartConfig() { + console.info('Launcher setttings StorageLayoutConfig loadAppPageStartConfig start'); + let data = mPreferences.getSync(APP_PAGE_START_CONFIG, DefaultLayoutConfig.DefaultAppPageStartConfig); + console.info('Launcher setttings StorageLayoutConfig loadAppPageStartConfig mPreferences end' + data); + return data; + } + + /** + * Save the launcher layout view type. + * + * @param {string} type - View type , should one of 'Grid' or 'List' which is stored in LayoutConstants class. + */ + saveAppPageStartConfig(type) { + console.info('Launcher settings StorageLayoutConfig saveAppPageStartConfig mPreferences put type ' + type); + mPreferences.putSync(APP_PAGE_START_CONFIG, type); + mPreferences.flushSync(); + console.info('Launcher settings StorageLayoutConfig saveAppPageStartConfig mPreferences put type flush'); + } + + /** + * Load the launcher grid view layout config id. + * + * @return {number} id - Config id. + */ + loadGridConfig() { + console.info('Launcher settings StorageLayoutConfig loadGridConfig mPreferences get GRID_CONFIG'); + let data = mPreferences.getSync(GRID_CONFIG, DefaultLayoutConfig.DefaultGridConfig); + console.info('Launcher settings StorageLayoutConfig loadGridConfig mPreferences get' + data); + return data; + } + + /** + * Save the launcher grid view layout config id. + * + * @param {string} id - View type , should one of 'Grid' or 'List' which is stored in LayoutConstants class. + */ + saveGridConfig(id) { + console.info('Launcher settings StorageLayoutConfig saveGridConfig mPreferences put id' + id); + mPreferences.putSync(GRID_CONFIG, id); + mPreferences.flushSync(); + console.info('Launcher settings StorageLayoutConfig saveGridConfig mPreferences put id flush'); + } + + /** + * Load the recent process max limit. + * + * @return {number} Recent process max limit. + */ + loadRecentProcessLimit() { + console.info('Launcher settings StorageLayoutConfig loadRecentProcessLimit mPreferences get'); + let data = mPreferences.getSync(RECENT_PROCESS_LIMIT, DefaultLayoutConfig.DefaultRecentProcessLimit); + console.info('Launcher settings StorageLayoutConfig loadRecentProcessLimit mPreferences get' + data); + return data; + } + + /** + * Save the recent process max limit. + * + * @param {number} num - Recent process max limit. + */ + saveRecentProcessLimit(num) { + console.info('Launcher settings StorageLayoutConfig saveRecentProcessLimit mPreferences put num' + num); + mPreferences.putSync(RECENT_PROCESS_LIMIT, num); + mPreferences.flushSync(); + console.info('Launcher settings StorageLayoutConfig saveRecentProcessLimit mPreferences put num flush'); + } +} \ No newline at end of file diff --git a/settings/src/main/js/default/common/pics/img_return.png b/settings/src/main/js/default/common/pics/img_return.png new file mode 100644 index 0000000000000000000000000000000000000000..2b4ef6f83f1017a5710747548d00ac9f0843d338 GIT binary patch literal 255 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawj(NH`hGg7(d&`iI(NU!RBY%6u zL!oN<-lnMKg`D3nJ!aBgxHPgg(Bs6U9FaG6pZ+eNx%S!glc&`_ryY>^%q2323}V%d5|}e{fAkgiWx3*|2lh`;@tlM} yM^#yOu+*tN73dUsqIhs^ukfptt%l3=!e?)vd|R&i-D04R7(8A5T-G@yGywoZMQ%m_ literal 0 HcmV?d00001 diff --git a/settings/src/main/js/default/common/pics/img_to_detail.png b/settings/src/main/js/default/common/pics/img_to_detail.png new file mode 100644 index 0000000000000000000000000000000000000000..cdbb19a5b6ddb74d7f34446d6f74bdd855eb934d GIT binary patch literal 391 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%&M7!06}c;uunK>+S8+SxkWfEe~fo z_H;{}xO{?TzJ2q)o(0;j7hGqQI_&b2`gc$JYvHq)D!s$bd$UD=24Dc*?9i|7hq?Dx z8ZfmgD|p`Wwt97~oUiBCwI!wT2OPy~Q#rRbtbS&)uuAAS=hxK%Gaf{^EoM1yC!n&! zY?H*n?ZWLG=N7xPJh0_v<#=~^&fEv~y|XwwA8(mD;U#-dONeu_@)Ii~Va1z4Q5-kt z-Ei_u08ty(f@1r%VJy~ z{eN*;*uIc6^6_uRXFu{9Z1 + +
+
+
+ + {{$t('strings.launcher_settings')}} + +
+
+
+ + {{$t('strings.layout')}} + +
+
+
+
+ + {{$t('strings.layout_style')}} + +
+
+ + {{layoutStyle}} + +
+
+
+
+
+ + {{$t('strings.launcher_layout')}} + +
+
+ + {{launcherLayout}} + +
+
+
+
+
+ + {{$t('strings.recent_tasks_settings')}} + +
+
+ + {{recentProcessLimit}} + +
+
+
+
+
+ +
+
+ + {{$t('strings.layout_style')}} + +
+
+ + {{$item.layoutChinese}} + + +
+
+ + {{$t('strings.cancel')}} + +
+
+
+ +
+
+ + {{$t('strings.launcher_layout')}} + +
+
+ + {{$item.layout}} + + +
+
+ + {{$t('strings.cancel')}} + +
+
+
+ +
+
+ + {{$t('strings.recent_tasks_settings')}} + +
+
+ + {{$item.limit}} + + +
+
+ + {{$t('strings.cancel')}} + +
+
+
+
diff --git a/settings/src/main/js/default/pages/settings/settings.js b/settings/src/main/js/default/pages/settings/settings.js new file mode 100644 index 00000000..829a8bb8 --- /dev/null +++ b/settings/src/main/js/default/pages/settings/settings.js @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2021 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 SettingsPresenter from '../../presenter/settings/SettingsPresenter.js'; +import LayoutConstants from '../../common/constants/LayoutConstants.js' + +let mSettingsPresenter; +let mGridConfig; + +export default { + data: { + layout: "", + layoutStyle: "", + layoutStyleTable: [], + checked: false, + launcherLayout: "", + layoutButtonStyle: [], + gridLayoutTable: [], + recentProcessLimit: '', + recentProcessLimitArray: [], + }, + + onInit() { + console.info("Launcher settings onInit start"); + mSettingsPresenter = new SettingsPresenter(this.$app.$def.data.settingsModel); + mGridConfig = mSettingsPresenter.getGridConfig(); + console.info("Launcher settings onInit end"+mGridConfig); + }, + + onShow() { + console.info("Launcher settings onShow start"); + mGridConfig = mSettingsPresenter.getGridConfig(); + this.gridLayoutTable = mSettingsPresenter.getGridLayoutTable(); + this.recentProcessLimit = mSettingsPresenter.getRecentProcessLimit(); + for (let i = 0; i < this.gridLayoutTable.length; i++) { + this.layoutButtonStyle.push({ + color: "", + fontColor: "", + checked: false, + }); + } + this.layout = mSettingsPresenter.getAppPageStartConfig(); + if (this.layout == LayoutConstants.Grid) { + this.checked = false; + this.layoutStyle = this.$t('strings.layout_grid'); + } else { + this.checked = true; + this.layout = LayoutConstants.List; + this.layoutStyle = this.$t('strings.layout_list'); + } + this.setLayoutStyleSettings(); + this.setLauncherLayoutSettings(); + this.setRecentTasksSettings(); + console.info("Launcher settings onShow end"); + }, + /** + * Set layout style. + * + */ + setLayoutStyleSettings() { + console.info("Launcher settings setLayoutStyleSettings start"); + this.layoutStyleTable = []; + if (this.layout == LayoutConstants.Grid) { + this.layoutStyleTable.push( + {'layout': LayoutConstants.Grid, 'layoutChinese': this.$t('strings.layout_grid'), 'checked':true}, + {'layout': LayoutConstants.List, 'layoutChinese': this.$t('strings.layout_list'), 'checked':false} + ); + } else { + this.layoutStyleTable.push( + {'layout': LayoutConstants.Grid, 'layoutChinese': this.$t('strings.layout_grid'), 'checked':false}, + {'layout': LayoutConstants.List, 'layoutChinese': this.$t('strings.layout_list'), 'checked':true} + ); + } + console.info("Launcher settings setLayoutStyleSettings end"); + }, + + /** + * Set layout setting. + * + */ + setLauncherLayoutSettings() { + console.info("Launcher settings setLauncherLayoutSettings start"); + for (let i = 0; i < this.gridLayoutTable.length; i++) { + if (i == mGridConfig.id) { + this.layoutButtonStyle[i].checked = true; + this.launcherLayout = mGridConfig.layout; + } else { + this.layoutButtonStyle[i].checked = false; + } + } + console.info("Launcher settings setLauncherLayoutSettings end"); + }, + + /** + * Set recent task settings. + * + */ + setRecentTasksSettings() { + console.info("Launcher settings setRecentTasksSettings start"); + let defaultRecentProcessArray = mSettingsPresenter.getDefaultRecentProcessLimitArray(); + this.recentProcessLimitArray = []; + for (let i = 0; i < defaultRecentProcessArray.length; i++){ + if (defaultRecentProcessArray[i] == this.recentProcessLimit) { + this.recentProcessLimitArray.push({'limit' : defaultRecentProcessArray[i] , 'checked' : true}); + } else { + this.recentProcessLimitArray.push({'limit' : defaultRecentProcessArray[i] , 'checked' : false}); + } + } + console.info("Launcher settings setRecentTasksSettings end"); + }, + + /** + * Show dialog. + * + * @param {object} e - the event from front page. + */ + showLayoutStyleDialog(e) { + this.$element('dialog-layout-style-setting').show(); + }, + + /** + * Hide dialog. + * + * @param {object} e - the event from front page. + */ + hideLayoutStyleDialog(e) { + this.$element('dialog-layout-style-setting').close(); + }, + + /** + * Show dialog. + * + * @param {object} e - the event from front page. + */ + showLauncherLayoutDialog(e) { + this.$element('dialog-launcher-layout-setting').show(); + }, + + /** + * Hide dialog. + * + * @param {object} e - the event from front page. + */ + hideLauncherLayoutDialog(e) { + this.$element('dialog-launcher-layout-setting').close(); + }, + + /** + * Show recent task dialog. + * + * @param {object} e - the event from front page. + */ + showRecentTasksDialog(e) { + this.$element('dialog-recent-tasks-setting').show(); + }, + + /** + * Hide recent task dialog. + * + * @param {object} e - the event from front page. + */ + hideRecentTasksDialog(e) { + this.$element('dialog-recent-tasks-setting').close(); + }, + + /** + * Change style. + * + * @param {string} layout - the layout of app page. + */ + changeLayoutStyle(layout) { + mSettingsPresenter.setAppPageStartConfig(layout); + this.hideLayoutStyleDialog(); + mSettingsPresenter.settingUpdate(); + }, + + /** + * Show dialog. + * + * @param {string} launcherLayoutId - the id of launcher. + */ + changeLauncherLayout(launcherLayoutId) { + mSettingsPresenter.setGridConfig(launcherLayoutId); + this.hideLauncherLayoutDialog(); + mSettingsPresenter.settingUpdate(); + }, + + /** + * Change recent process. + * + * @param {object} recentProcessLimit - the recent process. + */ + changeRecentProcessLimit(recentProcessLimit) { + console.info("Launcher settings changeRecentProcessLimit start"); + mSettingsPresenter.setRecentProcessLimit(recentProcessLimit); + this.recentProcessLimit = mSettingsPresenter.getRecentProcessLimit(); + for (let i = 0; i < this.recentProcessLimitArray.length; i++){ + if (this.recentProcessLimitArray[i].limit == this.recentProcessLimit) { + this.recentProcessLimitArray[i].checked = true; + } else { + this.recentProcessLimitArray[i].checked = false; + } + } + this.hideRecentTasksDialog(); + console.info("Launcher settings changeRecentProcessLimit end"); + }, + + /** + * Return to desktop. + * + */ + returnToDesktop() { + mSettingsPresenter.backToTheDesktop(); + } +} diff --git a/launcher/src/main/js/default/presenter/settings/SettingsPresenter.js b/settings/src/main/js/default/presenter/settings/SettingsPresenter.js similarity index 58% rename from launcher/src/main/js/default/presenter/settings/SettingsPresenter.js rename to settings/src/main/js/default/presenter/settings/SettingsPresenter.js index f57819a8..a21e23e0 100644 --- a/launcher/src/main/js/default/presenter/settings/SettingsPresenter.js +++ b/settings/src/main/js/default/presenter/settings/SettingsPresenter.js @@ -13,60 +13,114 @@ * limitations under the License. */ -import RouterUtil from '../../common/utils/RouterUtil.js'; import LayoutConstants from '../../common/constants/LayoutConstants.js' import PageData from '../../common/constants/PageData.js'; +import DefaultLayoutConfig from '../../common/configs/DefaultLayoutConfig.js'; const GRID = LayoutConstants.Grid; const GRID_APP_VIEW = PageData.GRID_APP_PAGE; const LIST_APP_VIEW = PageData.LIST_APP_PAGE; -var mSettingsModel; +let mSettingsModel; + +/** + * Class SettingsPresenter. + */ export default class SettingsPresenter { + /** + * Constructor. + * + * @param {object} settingsModel - model of setting. + */ constructor(settingsModel) { mSettingsModel = settingsModel; } + /** + * Get app config. + * + * @return {object} - app config. + */ getAppPageStartConfig() { return mSettingsModel.getAppPageStartConfig(); } + /** + * Set app config. + * + * @param {string} type - the type of config. + */ setAppPageStartConfig(type) { mSettingsModel.setAppPageStartConfig(type); } + /** + * Update setting. + * + */ settingUpdate() { - if (mSettingsModel.getAppPageStartConfig() == GRID) { - RouterUtil.replace(GRID_APP_VIEW); - } else { - RouterUtil.replace(LIST_APP_VIEW); - } + mSettingsModel.closeSettings(); } + /** + * Get grid config. + * + * @return {object} - grid config. + */ getGridConfig() { return mSettingsModel.getGridConfig(); } + /** + * Set grid config. + * + * @param {string} id - the id of grid config. + */ setGridConfig(id) { mSettingsModel.setGridConfig(id); } + /** + * Get grid layout table. + * + * @return {object} - the grid table. + */ getGridLayoutTable() { return mSettingsModel.getGridLayoutTable(); } + /** + * Get recent process. + * + * @return {object} - the recent process. + */ getRecentProcessLimit() { return mSettingsModel.getRecentProcessLimit(); } + /** + * Set recent process. + * + * @param {number} num - the num of recent process. + */ setRecentProcessLimit(num) { mSettingsModel.setRecentProcessLimit(num) } /** - * Back to the desktop interface + * Back to the desktop interface. + * */ backToTheDesktop() { this.settingUpdate(); } + + /** + * Get default recent process. + * + * @return {Array} + */ + getDefaultRecentProcessLimitArray(){ + return DefaultLayoutConfig.DefaultRecentProcessLimitArray; + } } \ No newline at end of file diff --git a/settings/src/main/js/default/resources/res-hdpi.json b/settings/src/main/js/default/resources/res-hdpi.json new file mode 100644 index 00000000..e2850c91 --- /dev/null +++ b/settings/src/main/js/default/resources/res-hdpi.json @@ -0,0 +1,6 @@ +{ + "image": { + "img_return": "common/pics/img_return.png", + "img_to_detail": "common/pics/img_to_detail.png" + } +} \ No newline at end of file diff --git a/settings/src/main/js/default/resources/res-ldpi.json b/settings/src/main/js/default/resources/res-ldpi.json new file mode 100644 index 00000000..e2850c91 --- /dev/null +++ b/settings/src/main/js/default/resources/res-ldpi.json @@ -0,0 +1,6 @@ +{ + "image": { + "img_return": "common/pics/img_return.png", + "img_to_detail": "common/pics/img_to_detail.png" + } +} \ No newline at end of file diff --git a/settings/src/main/js/default/resources/res-mdpi.json b/settings/src/main/js/default/resources/res-mdpi.json new file mode 100644 index 00000000..e2850c91 --- /dev/null +++ b/settings/src/main/js/default/resources/res-mdpi.json @@ -0,0 +1,6 @@ +{ + "image": { + "img_return": "common/pics/img_return.png", + "img_to_detail": "common/pics/img_to_detail.png" + } +} \ No newline at end of file diff --git a/settings/src/main/js/default/resources/res-xhdpi.json b/settings/src/main/js/default/resources/res-xhdpi.json new file mode 100644 index 00000000..e2850c91 --- /dev/null +++ b/settings/src/main/js/default/resources/res-xhdpi.json @@ -0,0 +1,6 @@ +{ + "image": { + "img_return": "common/pics/img_return.png", + "img_to_detail": "common/pics/img_to_detail.png" + } +} \ No newline at end of file diff --git a/settings/src/main/js/default/resources/res-xxhdpi.json b/settings/src/main/js/default/resources/res-xxhdpi.json new file mode 100644 index 00000000..e2850c91 --- /dev/null +++ b/settings/src/main/js/default/resources/res-xxhdpi.json @@ -0,0 +1,6 @@ +{ + "image": { + "img_return": "common/pics/img_return.png", + "img_to_detail": "common/pics/img_to_detail.png" + } +} \ No newline at end of file diff --git a/settings/src/main/js/default/resources/res-xxxhdpi.json b/settings/src/main/js/default/resources/res-xxxhdpi.json new file mode 100644 index 00000000..e2850c91 --- /dev/null +++ b/settings/src/main/js/default/resources/res-xxxhdpi.json @@ -0,0 +1,6 @@ +{ + "image": { + "img_return": "common/pics/img_return.png", + "img_to_detail": "common/pics/img_to_detail.png" + } +} \ No newline at end of file diff --git a/settings/src/main/resources/base/element/string.json b/settings/src/main/resources/base/element/string.json new file mode 100644 index 00000000..2df7b8ab --- /dev/null +++ b/settings/src/main/resources/base/element/string.json @@ -0,0 +1,12 @@ +{ + "string": [ + { + "name": "app_name", + "value": "Settings" + }, + { + "name": "mainability_description", + "value": "JS_Phone_Empty Feature Ability" + } + ] +} \ No newline at end of file diff --git a/settings/src/main/resources/base/media/icon.png b/settings/src/main/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c GIT binary patch literal 6790 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