├── .gitignore ├── AppScope ├── app.json5 └── resources │ └── base │ ├── element │ └── string.json │ └── media │ └── app_icon.svg ├── LICENSE ├── README.md ├── build-profile.json5 ├── code-linter.json5 ├── entry ├── .gitignore ├── build-profile.json5 ├── hvigorfile.ts ├── obfuscation-rules.txt ├── oh-package-lock.json5 ├── oh-package.json5 └── src │ ├── main │ ├── ets │ │ ├── component │ │ │ └── CategoryNavigation.ets │ │ ├── data │ │ │ ├── CategoryData.ets │ │ │ └── CategoryItem.ets │ │ ├── entryability │ │ │ └── EntryAbility.ets │ │ ├── entrybackupability │ │ │ └── EntryBackupAbility.ets │ │ ├── pages │ │ │ ├── Index.ets │ │ │ ├── anchor │ │ │ │ ├── AnchorMockData.ts │ │ │ │ └── OmniAnchorExamplePage.ets │ │ │ ├── autolinegrid │ │ │ │ └── OmniAutoLineGridEntryPage.ets │ │ │ ├── bottombar │ │ │ │ └── OmniBottomBarExamplePage.ets │ │ │ ├── calendar │ │ │ │ └── OmniCalendarExamplePage.ets │ │ │ ├── charts │ │ │ │ ├── OmniFunnelChartExamplePage.ets │ │ │ │ ├── OmniLineChartExamplePage.ets │ │ │ │ ├── OmniPieChartExamplePage.ets │ │ │ │ ├── OmniProgressBarChartExamplePage.ets │ │ │ │ └── OmniRadarChartExamplePage.ets │ │ │ ├── dialog │ │ │ │ └── OmniDialogEntryPage.ets │ │ │ ├── expandabletext │ │ │ │ └── OmniExpandableTextEntryPage.ets │ │ │ ├── filterbar │ │ │ │ ├── OmniFilterBarCustomExamplePage.ets │ │ │ │ ├── OmniFilterBarExampleEntryPage.ets │ │ │ │ ├── OmniFilterBarMenuCustomExamplePage.ets │ │ │ │ ├── OmniFilterBarMoreExamplePage.ets │ │ │ │ ├── OmniFilterBarMultiGridExamplePage.ets │ │ │ │ ├── OmniFilterBarMultiListExamplePage.ets │ │ │ │ ├── OmniFilterBarStyleCustomExamplePage.ets │ │ │ │ └── component │ │ │ │ │ └── OmniCustomValueRange.ets │ │ │ ├── gallery │ │ │ │ ├── OmniGalleryExamplePage.ets │ │ │ │ └── OmniSummaryExamplePage.ets │ │ │ ├── guide │ │ │ │ ├── OmniGuideExampleIndex.ets │ │ │ │ └── OmniGuideMultiPageExample.ets │ │ │ ├── imagepicker │ │ │ │ ├── OmniImageAlbumPickerPage.ets │ │ │ │ ├── OmniImagePickerExamplePage.ets │ │ │ │ └── OmniImagePickerSelectExamplePage.ets │ │ │ ├── loading │ │ │ │ └── OmniLoadingEntryPage.ets │ │ │ ├── navigationbar │ │ │ │ └── OmniNavigationBarExamplePage.ets │ │ │ ├── picker │ │ │ │ └── OmniDataPickerEntryPage.ets │ │ │ ├── pullable │ │ │ │ └── OmniPullableExamplePage.ets │ │ │ ├── richtext │ │ │ │ └── OmniRichTextExamplePage.ets │ │ │ ├── search │ │ │ │ └── OmniSearchExamplePage.ets │ │ │ ├── step │ │ │ │ └── OmniStepLineExample.ets │ │ │ ├── tabs │ │ │ │ └── OmniTabExamplePage.ets │ │ │ ├── tags │ │ │ │ └── OmniTagEntryPage.ets │ │ │ ├── theme │ │ │ │ └── OmniThemeDemoPage.ets │ │ │ └── toast │ │ │ │ └── OmniToastEntryPage.ets │ │ └── utils │ │ │ └── utils.ts │ ├── module.json5 │ └── resources │ │ ├── base │ │ ├── element │ │ │ ├── color.json │ │ │ └── string.json │ │ ├── media │ │ │ ├── app_icon_startwindow.png │ │ │ ├── background.png │ │ │ ├── bottombar_car.png │ │ │ ├── bottombar_car_selected.png │ │ │ ├── bottombar_home.png │ │ │ ├── bottombar_home_selecte.png │ │ │ ├── bottombar_mine.png │ │ │ ├── bottombar_mine_selected.png │ │ │ ├── bottombar_read.png │ │ │ ├── bottombar_read_selected.png │ │ │ ├── foreground.png │ │ │ ├── ic_back_white.png │ │ │ ├── ic_down_arrow.png │ │ │ ├── ic_right_arrow.png │ │ │ ├── icon_category_chart.svg │ │ │ ├── icon_category_form.svg │ │ │ ├── icon_category_navigation.svg │ │ │ ├── icon_category_operatefeedback.svg │ │ │ ├── icon_category_page.svg │ │ │ ├── icon_category_theme_style.png │ │ │ ├── icon_category_view.svg │ │ │ ├── icon_filter_reset_custom.png │ │ │ ├── layered_image.json │ │ │ ├── startIcon.png │ │ │ ├── tag_heart.png │ │ │ └── tag_heart_fill.png │ │ └── profile │ │ │ ├── backup_config.json │ │ │ ├── main_pages.json │ │ │ └── route_map.json │ │ ├── en_US │ │ └── element │ │ │ └── string.json │ │ ├── rawfile │ │ ├── custom_filter.json │ │ ├── more_filter.json │ │ ├── multi_grid_filter.json │ │ └── multi_list_filter.json │ │ └── zh_CN │ │ └── element │ │ └── string.json │ ├── mock │ └── mock-config.json5 │ ├── ohosTest │ ├── ets │ │ └── test │ │ │ ├── Ability.test.ets │ │ │ └── List.test.ets │ └── module.json5 │ └── test │ ├── List.test.ets │ └── LocalUnit.test.ets ├── hvigor └── hvigor-config.json5 ├── hvigorfile.ts ├── oh-package-lock.json5 ├── oh-package.json5 └── omni_component ├── .gitignore ├── CHANGELOG.md ├── Index.ets ├── LICENSE ├── README.md ├── build-profile.json5 ├── consumer-rules.txt ├── hvigorfile.ts ├── obfuscation-rules.txt ├── oh-package-lock.json5 ├── oh-package.json5 └── src ├── main ├── ets │ ├── OmniComponent.ets │ ├── components │ │ ├── MainPage.ets │ │ ├── anchor │ │ │ └── OmniAnchor.ets │ │ ├── autolinegrid │ │ │ ├── AutoLineWrapLayout.ets │ │ │ ├── LineWrapLayout.ets │ │ │ └── OmniAutoLineGrid.ets │ │ ├── bottomtabbar │ │ │ └── OmniBottomTabBar.ets │ │ ├── calendar │ │ │ └── OmniCalendar.ets │ │ ├── chart │ │ │ ├── OmniChart.ets │ │ │ ├── OmniFunnelChart.ets │ │ │ ├── OmniLineChart.ets │ │ │ ├── OmniPieChart.ets │ │ │ ├── OmniProgressBarChart.ets │ │ │ ├── OmniRadarChart.ets │ │ │ ├── Options.ets │ │ │ ├── Tooltip.ets │ │ │ └── utils │ │ │ │ ├── DrawAxisViewModel.ets │ │ │ │ ├── DrawBaseViewModel.ets │ │ │ │ ├── DrawHorViewModel.ets │ │ │ │ ├── DrawLineViewModel.ets │ │ │ │ ├── DrawPieViewModel.ets │ │ │ │ ├── DrawRadarViewModel.ets │ │ │ │ ├── DrawVerBarViewModel.ets │ │ │ │ ├── chartInterface.ts │ │ │ │ ├── defaultOption.ts │ │ │ │ └── index.ts │ │ ├── dialog │ │ │ ├── OmniDialog.ets │ │ │ ├── OmniDialogBuilder.ets │ │ │ └── OmniDialogConstant.ets │ │ ├── expandabletext │ │ │ └── OmniExpandableText.ets │ │ ├── filterbar │ │ │ ├── OmniFilterBar.ets │ │ │ ├── OmniFilterComponentRegistry.ets │ │ │ ├── OmniFilterConstants.ets │ │ │ ├── OmniFilterThemeConfig.ets │ │ │ ├── bean │ │ │ │ ├── OmniFilterItemBean.ets │ │ │ │ └── OmniFilterMenuItemBean.ets │ │ │ ├── component │ │ │ │ ├── OmniFilterBottomPanel.ets │ │ │ │ ├── OmniFilterGridGroup.ets │ │ │ │ ├── OmniFilterGridItem.ets │ │ │ │ ├── OmniFilterListGroup.ets │ │ │ │ ├── OmniFilterListItem.ets │ │ │ │ ├── OmniFilterMenuItem.ets │ │ │ │ ├── OmniFilterSingleGrid.ets │ │ │ │ └── OmniFilterSingleList.ets │ │ │ ├── converter │ │ │ │ └── OmniFilterConverter.ets │ │ │ └── util │ │ │ │ └── OmniFilterUtil.ets │ │ ├── gallery │ │ │ ├── OmniGallery.ets │ │ │ ├── OmniSummary.ets │ │ │ └── OmniVideoView.ets │ │ ├── guide │ │ │ ├── OmniGuide.ets │ │ │ ├── core │ │ │ │ ├── Controller.ets │ │ │ │ └── OmniGuideBuilder.ets │ │ │ ├── interface │ │ │ │ ├── HighLight.ets │ │ │ │ ├── OnClickListener.ets │ │ │ │ ├── OnGuideChangedListener.ets │ │ │ │ ├── OnGuideLifeCycleListener.ets │ │ │ │ ├── OnHighLightDrewListener.ets │ │ │ │ └── OnPageChangedListener.ets │ │ │ ├── model │ │ │ │ ├── BubbleIndicator.ets │ │ │ │ ├── GuidePage.ets │ │ │ │ ├── HighLightInfoOfComponent.ets │ │ │ │ ├── HighLightInfoOfRectF.ets │ │ │ │ ├── HighLightOptions.ets │ │ │ │ ├── HighLightOptionsBuilder.ets │ │ │ │ ├── HighLightShape.ets │ │ │ │ ├── ObservedMaskVisibleState.ets │ │ │ │ ├── ObservedPageIndex.ets │ │ │ │ └── RectF.ets │ │ │ └── util │ │ │ │ ├── ComponentRectFUtil.ets │ │ │ │ └── GlobalContext.ts │ │ ├── imagepicker │ │ │ ├── OmniImagePicker.ets │ │ │ └── OmniImagePickerTrigger.ets │ │ ├── loading │ │ │ ├── OmniDotLoadingView.ets │ │ │ └── OmniPageLoading.ets │ │ ├── navigationbar │ │ │ └── OmniNavigationBar.ets │ │ ├── picker │ │ │ └── OmniDataPicker.ets │ │ ├── popup │ │ │ ├── ArrowLocation.ets │ │ │ ├── BaseAttachPopup.ets │ │ │ ├── BasePopup.ets │ │ │ ├── BubbleComponent.ets │ │ │ ├── BubblePopup.ets │ │ │ ├── Builder.ets │ │ │ ├── Config.ets │ │ │ ├── CustomBubbleComponent.ets │ │ │ ├── CustomBuilder.ets │ │ │ ├── CustomNodeController.ets │ │ │ ├── OmniPopup.ets │ │ │ ├── PopupAction.ets │ │ │ ├── PopupCallback.ets │ │ │ ├── PopupConfig.ets │ │ │ ├── PopupManager.ets │ │ │ ├── PopupPosition.ets │ │ │ ├── PopupType.ets │ │ │ └── entity │ │ │ │ ├── ButtonOptions.ets │ │ │ │ ├── PopupBean.ets │ │ │ │ └── PopupInfo.ets │ │ ├── pullable │ │ │ ├── OmniPullToRefreshLayout.ets │ │ │ ├── OmniPullable.ets │ │ │ ├── OmniPullableController.ets │ │ │ ├── OmniRefreshLayoutConfig.ets │ │ │ ├── core │ │ │ │ ├── RefreshLayout.ets │ │ │ │ └── RefreshLayoutHelper.ets │ │ │ └── interface.ets │ │ ├── richtext │ │ │ ├── OmniRichText.ets │ │ │ └── utils │ │ │ │ ├── ExposeData.ts │ │ │ │ ├── HtmlParseUtil.ts │ │ │ │ ├── MetadataStorage.ts │ │ │ │ ├── StyleStringUtil.ets │ │ │ │ ├── Util.ts │ │ │ │ └── index.ts │ │ ├── search │ │ │ └── OmniSearchV2.ets │ │ ├── step │ │ │ ├── OmniLine.ets │ │ │ └── OmniSteps.ets │ │ ├── tabs │ │ │ └── OmniTabs.ets │ │ ├── tags │ │ │ ├── OmniTag.ets │ │ │ └── TagItemInfo.ets │ │ └── toast │ │ │ ├── OmniToast.ets │ │ │ ├── OmniToastBuilders.ets │ │ │ └── OmniToastTheme.ets │ ├── constants │ │ └── CommonConstants.ets │ ├── theme │ │ ├── OmniColorStyle.ets │ │ ├── OmniFontStyle.ets │ │ ├── OmniStyleModifier.ets │ │ ├── OmniTheme.ets │ │ └── OmniThemeUtil.ets │ └── utils │ │ ├── ImmersionBar.ets │ │ ├── ScreenUtils.ets │ │ ├── TextUtils.ts │ │ └── Utils.ets ├── module.json5 └── resources │ ├── base │ ├── element │ │ ├── color.json │ │ └── string.json │ └── media │ │ ├── back.webp │ │ ├── comm_page_icon_jt_s.png │ │ ├── comm_page_icon_jt_x.png │ │ ├── error.svg │ │ ├── ic_arrow_right.svg │ │ ├── ic_clear.png │ │ ├── ic_highlight.svg │ │ ├── ic_search.png │ │ ├── icon_arrow_down.svg │ │ ├── icon_arrow_down_selected.png │ │ ├── icon_arrow_down_unselected.png │ │ ├── icon_arrow_up.svg │ │ ├── icon_arrow_up_selected.png │ │ ├── icon_calendar_next_month.png │ │ ├── icon_calendar_pre_month.png │ │ ├── icon_filter_reset.png │ │ ├── icon_filter_select.svg │ │ ├── icon_filter_unselect.png │ │ ├── icon_selection_reset.png │ │ ├── icon_step_2.png │ │ ├── icon_step_3.png │ │ ├── icon_step_4.png │ │ ├── icon_step_5.png │ │ ├── icon_step_completed.svg │ │ ├── icon_step_doing.svg │ │ ├── image_trigger_add.png │ │ ├── playIcon.png │ │ ├── search.webp │ │ ├── startIcon.png │ │ ├── success.svg │ │ ├── voice_off.webp │ │ ├── voice_on.webp │ │ ├── warning.svg │ │ └── zr_refresh_arrow.svg │ ├── en_US │ └── element │ │ └── string.json │ └── zh_CN │ └── element │ └── string.json ├── ohosTest ├── ets │ └── test │ │ ├── Ability.test.ets │ │ └── List.test.ets └── module.json5 └── test ├── List.test.ets └── LocalUnit.test.ets /.gitignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | /oh_modules 3 | /local.properties 4 | /.idea 5 | **/build 6 | /.hvigor 7 | .cxx 8 | /.clangd 9 | /.clang-format 10 | /.clang-tidy 11 | **/.test 12 | /.appanalyzer 13 | **/BuildProfile.ets -------------------------------------------------------------------------------- /AppScope/app.json5: -------------------------------------------------------------------------------- 1 | { 2 | "app": { 3 | "bundleName": "com.omni.ui.component", 4 | "vendor": "example", 5 | "versionCode": 1000000, 6 | "versionName": "1.0.1", 7 | "icon": "$media:app_icon", 8 | "label": "$string:app_name" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /AppScope/resources/base/element/string.json: -------------------------------------------------------------------------------- 1 | { 2 | "string": [ 3 | { 4 | "name": "app_name", 5 | "value": "omni-ui" 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /AppScope/resources/base/media/app_icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /build-profile.json5: -------------------------------------------------------------------------------- 1 | { 2 | "app": { 3 | "signingConfigs": [ 4 | ], 5 | "products": [ 6 | { 7 | "name": "default", 8 | "signingConfig": "default", 9 | "compatibleSdkVersion": "5.0.0(12)", 10 | "runtimeOS": "HarmonyOS", 11 | "buildOption": { 12 | "strictMode": { 13 | "useNormalizedOHMUrl": false 14 | } 15 | } 16 | }, 17 | ], 18 | "buildModeSet": [ 19 | { 20 | "name": "debug", 21 | }, 22 | { 23 | "name": "release" 24 | } 25 | ] 26 | }, 27 | "modules": [ 28 | { 29 | "name": "entry", 30 | "srcPath": "./entry", 31 | "targets": [ 32 | { 33 | "name": "default", 34 | "applyToProducts": [ 35 | "default" 36 | ] 37 | } 38 | ] 39 | }, 40 | { 41 | "name": "omni_component", 42 | "srcPath": "./omni_component" 43 | } 44 | ] 45 | } -------------------------------------------------------------------------------- /code-linter.json5: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "**/*.ets" 4 | ], 5 | "ignore": [ 6 | "**/src/ohosTest/**/*", 7 | "**/src/test/**/*", 8 | "**/src/mock/**/*", 9 | "**/node_modules/**/*", 10 | "**/oh_modules/**/*", 11 | "**/build/**/*", 12 | "**/.preview/**/*" 13 | ], 14 | "ruleSet": [ 15 | "plugin:@performance/recommended", 16 | "plugin:@typescript-eslint/recommended" 17 | ], 18 | "rules": { 19 | } 20 | } -------------------------------------------------------------------------------- /entry/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /oh_modules 3 | /.preview 4 | /build 5 | /.cxx 6 | /.test -------------------------------------------------------------------------------- /entry/build-profile.json5: -------------------------------------------------------------------------------- 1 | { 2 | "apiType": "stageMode", 3 | "buildOption": { 4 | }, 5 | "buildOptionSet": [ 6 | { 7 | "name": "release", 8 | "arkOptions": { 9 | "obfuscation": { 10 | "ruleOptions": { 11 | "enable": false, 12 | "files": [ 13 | "./obfuscation-rules.txt" 14 | ] 15 | } 16 | } 17 | } 18 | }, 19 | ], 20 | "targets": [ 21 | { 22 | "name": "default" 23 | }, 24 | { 25 | "name": "ohosTest", 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /entry/hvigorfile.ts: -------------------------------------------------------------------------------- 1 | import { hapTasks } from '@ohos/hvigor-ohos-plugin'; 2 | 3 | export default { 4 | system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ 5 | plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ 6 | } 7 | -------------------------------------------------------------------------------- /entry/obfuscation-rules.txt: -------------------------------------------------------------------------------- 1 | # Define project specific obfuscation rules here. 2 | # You can include the obfuscation configuration files in the current module's build-profile.json5. 3 | # 4 | # For more details, see 5 | # https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5 6 | 7 | # Obfuscation options: 8 | # -disable-obfuscation: disable all obfuscations 9 | # -enable-property-obfuscation: obfuscate the property names 10 | # -enable-toplevel-obfuscation: obfuscate the names in the global scope 11 | # -compact: remove unnecessary blank spaces and all line feeds 12 | # -remove-log: remove all console.* statements 13 | # -print-namecache: print the name cache that contains the mapping from the old names to new names 14 | # -apply-namecache: reuse the given cache file 15 | 16 | # Keep options: 17 | # -keep-property-name: specifies property names that you want to keep 18 | # -keep-global-name: specifies names that you want to keep in the global scope 19 | 20 | -enable-property-obfuscation 21 | -enable-toplevel-obfuscation 22 | -enable-filename-obfuscation 23 | -enable-export-obfuscation -------------------------------------------------------------------------------- /entry/oh-package.json5: -------------------------------------------------------------------------------- 1 | { 2 | "name": "entry", 3 | "version": "1.0.0", 4 | "description": "Please describe the basic information.", 5 | "main": "", 6 | "author": "", 7 | "license": "", 8 | "dependencies": { 9 | "@omni-ui/omni_component": "file:../omni_component" 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /entry/src/main/ets/component/CategoryNavigation.ets: -------------------------------------------------------------------------------- 1 | import { CategoryItem, ComponentItem } from '../data/CategoryItem' 2 | import { promptAction, router } from '@kit.ArkUI' 3 | 4 | @Component 5 | export struct CategoryItemCard { 6 | @BuilderParam 7 | categoryItem: CategoryItem 8 | @Provide("expand") expand: boolean = false 9 | private onFlagChange = () => { 10 | animateTo({ 11 | duration: 200, 12 | curve: Curve.Smooth 13 | }, () => { 14 | this.expand = !this.expand; 15 | }) 16 | } 17 | 18 | build() { 19 | Column() { 20 | Row() { 21 | Image(this.categoryItem.icon) 22 | .width(24) 23 | .height(24) 24 | .objectFit(ImageFit.Fill) 25 | 26 | Text(this.categoryItem.title) 27 | .fontSize(16) 28 | .margin({ left: 16 }) 29 | .fontColor(Color.Black) 30 | 31 | Blank() 32 | 33 | if (this.categoryItem.components) { 34 | Image(this.expand ? $r('app.media.ic_down_arrow') : $r('app.media.ic_right_arrow')) 35 | .width(this.expand ? 24 : 12) 36 | .height(this.expand ? 12 : 24) 37 | .margin({ right: this.expand ? 0 : 6 }) 38 | } 39 | } 40 | .height(56) 41 | .width('100%') 42 | .onClick(() => { 43 | // this.expand = !this.expand; 44 | this.onFlagChange() 45 | }) 46 | 47 | // Click to expand the fourth-level category 48 | if (this.expand) { 49 | ForEach(this.categoryItem.components, (componentItem: ComponentItem) => { 50 | Column() { 51 | Divider() 52 | .height(1) 53 | .opacity(0.2) 54 | .margin({ left: 42, right: 8 }) 55 | .color(Color.Black) 56 | 57 | FourthLevelNavigation({ componentItem: componentItem }) 58 | } 59 | }) 60 | } 61 | } 62 | } 63 | } 64 | 65 | @Component 66 | struct FourthLevelNavigation { 67 | @BuilderParam 68 | private componentItem: ComponentItem 69 | 70 | @Consume('pathStack') pathStack: NavPathStack; 71 | 72 | build() { 73 | Row() { 74 | Text(this.componentItem.title) 75 | .fontSize(16) 76 | .layoutWeight(1) 77 | .margin({ left: 42 }) 78 | .align(Alignment.Start) 79 | .fontFamily('HarmonyHeiTi-Medium') 80 | .fontColor(Color.Black) 81 | Blank() 82 | } 83 | .height(48) 84 | .width('100%') 85 | .onClick(() => { 86 | if (this.componentItem.url) { 87 | this.pathStack.pushPath({ name: this.componentItem.url }) 88 | } else { 89 | promptAction.showToast({ 90 | message: '开发中' 91 | }) 92 | } 93 | }) 94 | } 95 | } -------------------------------------------------------------------------------- /entry/src/main/ets/data/CategoryItem.ets: -------------------------------------------------------------------------------- 1 | export interface CategoryItem { 2 | icon: Resource 3 | title: string 4 | components: ComponentItem[] 5 | } 6 | 7 | export interface ComponentItem { 8 | title: string, 9 | url: string | undefined 10 | } -------------------------------------------------------------------------------- /entry/src/main/ets/entryability/EntryAbility.ets: -------------------------------------------------------------------------------- 1 | import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; 2 | import { hilog } from '@kit.PerformanceAnalysisKit'; 3 | import { window } from '@kit.ArkUI'; 4 | import { BusinessError } from '@kit.BasicServicesKit'; 5 | import { OmniComponent } from '@omni-ui/omni_component'; 6 | 7 | export default class EntryAbility extends UIAbility { 8 | onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { 9 | hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); 10 | } 11 | 12 | onDestroy(): void { 13 | hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); 14 | } 15 | 16 | onWindowStageCreate(windowStage: window.WindowStage): void { 17 | // Main window is created, set main page for this ability 18 | hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); 19 | windowStage.getMainWindow((err: BusinessError, data) => { 20 | const errCode: number = err.code 21 | if (errCode) { 22 | hilog.error(0x0000, 'testTag',`Failed to obtain the main window. Cause:${JSON.stringify(err)}`) 23 | return 24 | } 25 | //初始化框架 26 | OmniComponent.init(data) 27 | console.info('Succeeded in obtaining the main window. Data: ' + JSON.stringify(data)); 28 | }) 29 | windowStage.loadContent('pages/Index', (err) => { 30 | if (err.code) { 31 | hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); 32 | return; 33 | } 34 | hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.'); 35 | }); 36 | } 37 | 38 | onWindowStageDestroy(): void { 39 | // Main window is destroyed, release UI related resources 40 | hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); 41 | } 42 | 43 | onForeground(): void { 44 | // Ability has brought to foreground 45 | hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); 46 | } 47 | 48 | onBackground(): void { 49 | // Ability has back to background 50 | hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /entry/src/main/ets/entrybackupability/EntryBackupAbility.ets: -------------------------------------------------------------------------------- 1 | import { hilog } from '@kit.PerformanceAnalysisKit'; 2 | import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; 3 | 4 | export default class EntryBackupAbility extends BackupExtensionAbility { 5 | async onBackup() { 6 | hilog.info(0x0000, 'testTag', 'onBackup ok'); 7 | } 8 | 9 | async onRestore(bundleVersion: BundleVersion) { 10 | hilog.info(0x0000, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); 11 | } 12 | } -------------------------------------------------------------------------------- /entry/src/main/ets/pages/Index.ets: -------------------------------------------------------------------------------- 1 | import { CATEGORY_DATA } from '../data/CategoryData'; 2 | import { CategoryItem } from '../data/CategoryItem'; 3 | import { CategoryItemCard } from '../component/CategoryNavigation'; 4 | import { OmniToast } from '@omni-ui/omni_component'; 5 | 6 | @Entry 7 | @Component 8 | struct Index { 9 | @Provide('pathStack') pathStack: NavPathStack = new NavPathStack() 10 | private categoryItems: CategoryItem[] = CATEGORY_DATA 11 | 12 | aboutToAppear(): void { 13 | OmniToast.initToast(this.getUIContext()) 14 | } 15 | 16 | build() { 17 | Navigation(this.pathStack) { 18 | Column() { 19 | List() { 20 | ForEach(this.categoryItems, (categoryItem: CategoryItem) => { 21 | ListItem() { 22 | Column() { 23 | CategoryItemCard({ categoryItem: categoryItem }) 24 | } 25 | .ColumnStyle() 26 | } 27 | .margin({ top: 6, bottom: 6 }) 28 | }) 29 | } 30 | .width("100%") 31 | .height("100%") 32 | .padding({ left: 16, right: 16, top: 16 }) 33 | } 34 | .width("100%") 35 | .height("100%") 36 | .backgroundColor(0xfff1f3f5) 37 | } 38 | .title('OmniUI') 39 | .titleMode(NavigationTitleMode.Mini) 40 | .mode(NavigationMode.Auto) 41 | } 42 | } 43 | 44 | @Extend(Column) 45 | function ColumnStyle() { 46 | .width('100%') 47 | .borderRadius(24) 48 | .backgroundColor(Color.White) 49 | .padding({ 50 | left: 12, 51 | right: 12, 52 | bottom: 4, 53 | top: 4 54 | }) 55 | } -------------------------------------------------------------------------------- /entry/src/main/ets/pages/autolinegrid/OmniAutoLineGridEntryPage.ets: -------------------------------------------------------------------------------- 1 | import { OmniAutoLineGrid, PairItemInfo, OmniToast } from "@omni-ui/omni_component" 2 | 3 | @Builder 4 | export function OmniAutoLineGridEntryPageBuilder() { 5 | OmniAutoLineGridEntryPage() 6 | } 7 | 8 | @Entry 9 | @Component 10 | struct OmniAutoLineGridEntryPage { 11 | @State items: PairItemInfo[] = [ 12 | { 13 | singleLine: false, 14 | title: '姓名', 15 | content: '王二狗' 16 | }, 17 | { 18 | singleLine: false, 19 | title: '性别', 20 | content: '男' 21 | }, 22 | { 23 | singleLine: false, 24 | title: '出生年月', 25 | content: '1992/01' 26 | }, 27 | { 28 | singleLine: false, 29 | title: '婚姻状态', 30 | content: '未婚' 31 | }, 32 | { 33 | singleLine: true, 34 | title: '身份证号', 35 | content: '110101199201101234' 36 | }, 37 | { 38 | singleLine: false, 39 | title: '身高', 40 | content: '172cm' 41 | }, 42 | { 43 | singleLine: false, 44 | title: '体重', 45 | content: '70kg' 46 | }, 47 | { 48 | singleLine: true, 49 | title: '联系方式', 50 | content: '13012345678', 51 | rightText: '立即联系', 52 | rightIcon: $r('app.media.ic_arrow_right'), 53 | hasRightPart: true 54 | }, 55 | { 56 | singleLine: true, 57 | title: '家庭地址', 58 | content: '北京市北京市东城区xx街道xx小区xx楼xx单元101', 59 | rightText: '查看详情', 60 | rightIcon: $r('app.media.ic_arrow_right'), 61 | hasRightPart: true 62 | } 63 | ] 64 | 65 | @Builder 66 | buildRightArea() { 67 | Row() { 68 | Text('r1') 69 | .fontSize(10) 70 | .fontColor('#979B9E') 71 | .margin({ right: 5 }) 72 | 73 | Text('r2') 74 | .fontSize(10) 75 | .fontColor('#0B0F12') 76 | }.onClick(() => { 77 | OmniToast.showText({ msg: 'Right Area Clicked' }) 78 | }) 79 | } 80 | 81 | build() { 82 | NavDestination() { 83 | Column({ space: 20 }) { 84 | OmniAutoLineGrid({ 85 | items: this.items, onRightAreaClick: () => { 86 | OmniToast.showText({ msg: 'Right Area Clicked' }) 87 | } 88 | }).padding({ 89 | left: 20, 90 | right: 20, 91 | top: 16, 92 | bottom: 16 93 | }) 94 | OmniAutoLineGrid({ 95 | items: this.items, 96 | rightPartBuilder: this.buildRightArea, 97 | }).padding({ 98 | left: 20, 99 | right: 20, 100 | top: 16, 101 | bottom: 16 102 | }) 103 | } 104 | }.title('OmniAutoLineGrid示例') 105 | } 106 | } -------------------------------------------------------------------------------- /entry/src/main/ets/pages/charts/OmniLineChartExamplePage.ets: -------------------------------------------------------------------------------- 1 | import { OmniLineChart } from "@omni-ui/omni_component" 2 | import { Options } from "@omni-ui/omni_component/src/main/ets/components/chart/Options" 3 | import { LineDataType } from "@omni-ui/omni_component/src/main/ets/components/chart/utils/DrawLineViewModel" 4 | 5 | @Builder 6 | export function OmniLineChartExamplePageBuilder() { 7 | OmniLineChartExamplePage() 8 | } 9 | 10 | @Component 11 | export struct OmniLineChartExamplePage { 12 | @State defOption: Options = new Options({ 13 | xAxis: { 14 | type: 'value', 15 | data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'], 16 | // axisLabel: { 17 | // interval: 0 18 | // }, 19 | }, 20 | yAxis: { 21 | type: 'category', 22 | name: '温度' 23 | }, 24 | series: [ 25 | { 26 | name: '最高气温', 27 | lineStyle: { 28 | width: 1.5 29 | }, 30 | areaStyle: { 31 | color: { 32 | direction: [0, 0, 0, 1], 33 | colors: ['#00f39c12', '#fff39c12'] 34 | } 35 | }, 36 | color: '#fff39c12', 37 | data: [9, 13, 10, 15, 12, 12, 10] 38 | }, 39 | { 40 | name: '最低气温', 41 | lineStyle: { 42 | width: 2.5 43 | }, 44 | color: '#ff3498db', 45 | data: [0, -1, 2, 0, 3, -2, 1] 46 | }, 47 | 48 | ] 49 | }) 50 | build() { 51 | NavDestination() { 52 | Column() { 53 | OmniLineChart({ 54 | options: this.defOption 55 | }) 56 | } 57 | .height('50%') 58 | } 59 | .title('折线图示例') 60 | } 61 | } -------------------------------------------------------------------------------- /entry/src/main/ets/pages/charts/OmniPieChartExamplePage.ets: -------------------------------------------------------------------------------- 1 | import { OmniPieChart, Options } from "@omni-ui/omni_component" 2 | import { PieDataType } from "@omni-ui/omni_component/src/main/ets/components/chart/utils/DrawPieViewModel" 3 | 4 | @Builder 5 | export function OmniPieChartExamplePageBuilder() { 6 | OmniPieChartExamplePage() 7 | } 8 | 9 | @Component 10 | export struct OmniPieChartExamplePage { 11 | @State defOption: Options = new Options({ 12 | series:[ 13 | { 14 | name:'最高气温', 15 | data: [ 16 | {value:435, name:'直接访问'}, 17 | {value:310, name:'邮件营销'}, 18 | {value:234, name:'联盟广告'}, 19 | {value:135, name:'视频广告'}, 20 | {value:1548, name:'搜索引擎'} 21 | ] 22 | } 23 | ] 24 | }) 25 | build() { 26 | NavDestination() { 27 | Column(){ 28 | OmniPieChart({ 29 | options: this.defOption 30 | }) 31 | } 32 | .height('50%') 33 | } 34 | .title("环状图示例") 35 | } 36 | } -------------------------------------------------------------------------------- /entry/src/main/ets/pages/charts/OmniProgressBarChartExamplePage.ets: -------------------------------------------------------------------------------- 1 | import { BarChartStyle, OmniProgressBarChart, Options } from '@omni-ui/omni_component' 2 | 3 | @Builder 4 | export function OmniProgressBarChartExamplePageBuilder() { 5 | OmniProgressBarChartExamplePage() 6 | } 7 | 8 | @Component 9 | export struct OmniProgressBarChartExamplePage { 10 | @State defOption: Options = new Options({ 11 | xAxis: { 12 | type: 'value', 13 | data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'], 14 | }, 15 | yAxis: { 16 | type: 'category', 17 | name: '温度' 18 | }, 19 | series: [ 20 | { 21 | name: '最高气温', 22 | barStyle: { 23 | width: 15, 24 | }, 25 | color: '#296DFF', 26 | data: [30, 11, 25, 28, 33, 25, 20] 27 | }, 28 | { 29 | name: '最低气温', 30 | barStyle: { 31 | width: 15, 32 | }, 33 | color: '#61cdf8', 34 | data: [8, 9, 5, 7, 10, 6, 9] 35 | }, 36 | ], 37 | }) 38 | 39 | build() { 40 | NavDestination() { 41 | Column() { 42 | Column() { 43 | OmniProgressBarChart({ 44 | barChartStyle: BarChartStyle.horizontal, 45 | options: this.defOption 46 | }) 47 | } 48 | .height('50%') 49 | 50 | Column() { 51 | OmniProgressBarChart({ 52 | options: this.defOption 53 | }) 54 | } 55 | .height('50%') 56 | } 57 | } 58 | .title("柱状图示例") 59 | .height('100%') 60 | } 61 | } -------------------------------------------------------------------------------- /entry/src/main/ets/pages/charts/OmniRadarChartExamplePage.ets: -------------------------------------------------------------------------------- 1 | import { OmniRadarChart, Options } from "@omni-ui/omni_component" 2 | 3 | @Builder 4 | export function OmniRadarChartExamplePageBuilder() { 5 | OmniRadarChartExamplePage() 6 | } 7 | 8 | @Component 9 | export struct OmniRadarChartExamplePage { 10 | @State defOption: Options = new Options({ 11 | radar: { 12 | indicator: [ 13 | { name: 'Sales' }, 14 | { name: 'Administration' }, 15 | { name: 'Information Technology' }, 16 | { name: 'Customer Support' }, 17 | { name: 'Development' } 18 | ] 19 | }, 20 | series: [ 21 | { 22 | name: '最高气温', 23 | lineStyle: { 24 | width: 1.5, 25 | color: "#ff52be80" 26 | }, 27 | areaStyle: { 28 | color: { 29 | direction: [0, 1, 0, 0], 30 | colors: [ 31 | '#9952be80' 32 | ] 33 | } 34 | }, 35 | data: [11, 12, 15, 13, 12], 36 | }, 37 | { 38 | name: '最高气温2', 39 | areaStyle: { 40 | color: { 41 | direction: [0, 1, 0, 0], 42 | colors: [ 43 | '#99265fe5' 44 | ] 45 | } 46 | }, 47 | data: [10, 12, 10.5, 13, 10] 48 | }, 49 | ] 50 | }) 51 | build() { 52 | NavDestination() { 53 | Column(){ 54 | OmniRadarChart({ 55 | options: this.defOption 56 | }) 57 | } 58 | .height('50%') 59 | } 60 | .title("雷达图示例") 61 | } 62 | } -------------------------------------------------------------------------------- /entry/src/main/ets/pages/expandabletext/OmniExpandableTextEntryPage.ets: -------------------------------------------------------------------------------- 1 | import { OmniExpandableText } from '@omni-ui/omni_component' 2 | 3 | @Builder 4 | export function OmniExpandableTextEntryPageBuilder() { 5 | OmniExpandableTextEntryPage() 6 | } 7 | 8 | @Preview 9 | @Entry 10 | @Component 11 | struct OmniExpandableTextEntryPage { 12 | @State content: string = 13 | '这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容' + 14 | '这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容' + 15 | '这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容' + 16 | '这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容这是正文内容' 17 | 18 | build() { 19 | NavDestination() { 20 | Scroll() { 21 | Column() { 22 | Text('示例一:默认样式') 23 | .fontSize(20) 24 | .fontWeight(FontWeight.Bold) 25 | .fontColor(0x333333) 26 | .padding({ 27 | top: 20, 28 | bottom: 20, 29 | right: 20, 30 | left: 20 31 | }) 32 | .width('100%') 33 | OmniExpandableText({ 34 | content: this.content, 35 | maxLine: 5, 36 | }).margin( 37 | { 38 | left: 20, 39 | right: 20, 40 | bottom: 20 41 | } 42 | ) 43 | Text('示例二:自定义样式') 44 | .fontSize(20) 45 | .fontWeight(FontWeight.Bold) 46 | .fontColor(0x333333) 47 | .padding({ 48 | top: 20, 49 | bottom: 20, 50 | right: 20, 51 | left: 20 52 | }) 53 | .width('100%') 54 | OmniExpandableText({ 55 | content: this.content, 56 | maxLine: 6, 57 | contentFontColor: 0x333333, 58 | expandFontColor: 0xec623e 59 | }) 60 | .margin({ 61 | top: 20, 62 | bottom: 20, 63 | right: 20, 64 | left: 20 65 | }) 66 | } 67 | } 68 | }.title('OmniExpandableText示例') 69 | } 70 | } -------------------------------------------------------------------------------- /entry/src/main/ets/pages/filterbar/OmniFilterBarExampleEntryPage.ets: -------------------------------------------------------------------------------- 1 | @Builder 2 | export function OmniFilterBarExampleEntryPageBuilder() { 3 | OmniFilterBarExampleEntryPage() 4 | } 5 | 6 | @Entry 7 | @Component 8 | struct OmniFilterBarExampleEntryPage { 9 | @Consume('pathStack') pathStack: NavPathStack; 10 | 11 | aboutToAppear(): void { 12 | 13 | } 14 | 15 | build() { 16 | NavDestination() { 17 | Column() { 18 | Button(`多列示例`) 19 | .onClick(() => { 20 | this.pathStack.pushPath({ name: 'OmniFilterBarMultiListExamplePage' }) 21 | }) 22 | Button(`网格示例`) 23 | .onClick(() => { 24 | this.pathStack.pushPath({ name: 'OmniFilterBarMultiGridExamplePage' }) 25 | }) 26 | .margin({ top: 10 }) 27 | Button(`更多示例`) 28 | .onClick(() => { 29 | this.pathStack.pushPath({ name: 'OmniFilterBarMoreExamplePage' }) 30 | }) 31 | .margin({ top: 10 }) 32 | Button(`自定义类型示例`) 33 | .onClick(() => { 34 | this.pathStack.pushPath({ name: 'OmniFilterBarCustomExamplePage' }) 35 | }) 36 | .margin({ top: 10 }) 37 | Button(`自定义Menu示例`) 38 | .onClick(() => { 39 | this.pathStack.pushPath({ name: 'OmniFilterBarMenuCustomExamplePage' }) 40 | }) 41 | .margin({ top: 10 }) 42 | Button(`自定义样式`) 43 | .onClick(() => { 44 | this.pathStack.pushPath({ name: 'OmniFilterBarStyleCustomExamplePage' }) 45 | }) 46 | .margin({ top: 10 }) 47 | } 48 | .height('100%') 49 | .width('100%') 50 | } 51 | .title('筛选示例入口') 52 | 53 | } 54 | 55 | @Builder 56 | Title() { 57 | Text('筛选示例') 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /entry/src/main/ets/pages/filterbar/OmniFilterBarMoreExamplePage.ets: -------------------------------------------------------------------------------- 1 | import { OmniFilterItemBean, 2 | OmniFilterBar 3 | } from '@omni-ui/omni_component' 4 | import { 5 | OmniFilterDataRoot} from '@omni-ui/omni_component/src/main/ets/components/filterbar/bean/OmniFilterItemBean' 6 | import util from '@ohos.util' 7 | import { OmniFilterController 8 | } from '@omni-ui/omni_component/src/main/ets/components/filterbar/OmniFilterBar' 9 | import { JSON } from '@kit.ArkTS' 10 | import ObjectUtil from '../../utils/utils' 11 | 12 | @Builder 13 | export function OmniFilterBarMoreExamplePageBuilder() { 14 | OmniFilterBarMoreExamplePage() 15 | } 16 | 17 | @Entry 18 | @Component 19 | struct OmniFilterBarMoreExamplePage { 20 | @State filterDataRoot?: OmniFilterDataRoot = undefined 21 | @State selectedParams?: Map = undefined 22 | private filterController: OmniFilterController = new OmniFilterController() 23 | 24 | aboutToAppear(): void { 25 | getContext(this).resourceManager.getRawFileContent('more_filter.json', (_err, value) => { 26 | let textDecoder = util.TextDecoder.create('utf-8', { ignoreBOM: true }); 27 | const result = textDecoder.decodeWithStream(value, { stream: false }) 28 | this.filterDataRoot = new OmniFilterDataRoot(OmniFilterItemBean.convertJsonToObj(result)!) 29 | }); 30 | } 31 | 32 | build() { 33 | NavDestination() { 34 | Column() { 35 | if (this.filterDataRoot) { 36 | OmniFilterBar( 37 | { 38 | filterDataRoot: this.filterDataRoot, 39 | onFilterParamsChanged: (selectedParams: Map) => { 40 | this.selectedParams = selectedParams 41 | }, 42 | filterController: this.filterController, 43 | } 44 | ) 45 | } 46 | if (this.selectedParams) { 47 | Flex() { 48 | Column() { 49 | Text(`${JSON.stringify(ObjectUtil.ObjectFromEntries(this.selectedParams))}`) 50 | } 51 | .width(`100%`) 52 | .height(`100%`) 53 | .justifyContent(FlexAlign.Center) 54 | .alignItems(HorizontalAlign.Center) 55 | } 56 | } 57 | } 58 | .height('100%') 59 | .width('100%') 60 | } 61 | .title('筛选示例') 62 | .onWillDisappear(() => { 63 | console.log(``) 64 | this.filterController.close() 65 | }) 66 | } 67 | 68 | @Builder 69 | Title() { 70 | Text('筛选示例') 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /entry/src/main/ets/pages/filterbar/OmniFilterBarMultiGridExamplePage.ets: -------------------------------------------------------------------------------- 1 | import { OmniFilterItemBean, 2 | OmniFilterBar 3 | } from '@omni-ui/omni_component' 4 | import { 5 | OmniFilterDataRoot} from '@omni-ui/omni_component/src/main/ets/components/filterbar/bean/OmniFilterItemBean' 6 | import util from '@ohos.util' 7 | import { OmniFilterController 8 | } from '@omni-ui/omni_component/src/main/ets/components/filterbar/OmniFilterBar' 9 | import { JSON } from '@kit.ArkTS' 10 | import ObjectUtil from '../../utils/utils' 11 | 12 | @Builder 13 | export function OmniFilterBarMultiGridExamplePageBuilder() { 14 | OmniFilterBarMultiGridExamplePage() 15 | } 16 | 17 | @Entry 18 | @Component 19 | struct OmniFilterBarMultiGridExamplePage { 20 | @State filterDataRoot?: OmniFilterDataRoot = undefined 21 | @State selectedParams?: Map = undefined 22 | private filterController: OmniFilterController = new OmniFilterController() 23 | 24 | aboutToAppear(): void { 25 | getContext(this).resourceManager.getRawFileContent('multi_grid_filter.json', (_err, value) => { 26 | let textDecoder = util.TextDecoder.create('utf-8', { ignoreBOM: true }); 27 | const result = textDecoder.decodeWithStream(value, { stream: false }) 28 | this.filterDataRoot = new OmniFilterDataRoot(OmniFilterItemBean.convertJsonToObj(result)!) 29 | }); 30 | } 31 | 32 | build() { 33 | NavDestination() { 34 | Column() { 35 | if (this.filterDataRoot) { 36 | OmniFilterBar( 37 | { 38 | filterDataRoot: this.filterDataRoot, 39 | onFilterParamsChanged: (selectedParams: Map) => { 40 | this.selectedParams = selectedParams 41 | }, 42 | filterController: this.filterController, 43 | } 44 | ) 45 | } 46 | if (this.selectedParams) { 47 | Flex() { 48 | Column() { 49 | Text(`${JSON.stringify(ObjectUtil.ObjectFromEntries(this.selectedParams))}`) 50 | } 51 | .width(`100%`) 52 | .height(`100%`) 53 | .justifyContent(FlexAlign.Center) 54 | .alignItems(HorizontalAlign.Center) 55 | } 56 | } 57 | } 58 | .height('100%') 59 | .width('100%') 60 | } 61 | .title('筛选示例') 62 | .onWillDisappear(() => { 63 | console.log(``) 64 | this.filterController.close() 65 | }) 66 | } 67 | 68 | @Builder 69 | Title() { 70 | Text('筛选示例') 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /entry/src/main/ets/pages/filterbar/OmniFilterBarMultiListExamplePage.ets: -------------------------------------------------------------------------------- 1 | import { OmniFilterItemBean, 2 | OmniFilterBar 3 | } from '@omni-ui/omni_component' 4 | import { 5 | OmniFilterDataRoot} from '@omni-ui/omni_component/src/main/ets/components/filterbar/bean/OmniFilterItemBean' 6 | import util from '@ohos.util' 7 | import { OmniFilterController 8 | } from '@omni-ui/omni_component/src/main/ets/components/filterbar/OmniFilterBar' 9 | import { JSON } from '@kit.ArkTS' 10 | import ObjectUtil from '../../utils/utils' 11 | 12 | @Builder 13 | export function OmniFilterBarMultiListExamplePageBuilder() { 14 | OmniFilterBarMultiListExamplePage() 15 | } 16 | 17 | @Entry 18 | @Component 19 | struct OmniFilterBarMultiListExamplePage { 20 | @State filterDataRoot?: OmniFilterDataRoot = undefined 21 | @State selectedParams?: Map = undefined 22 | private filterController: OmniFilterController = new OmniFilterController() 23 | 24 | aboutToAppear(): void { 25 | getContext(this).resourceManager.getRawFileContent('multi_list_filter.json', (_err, value) => { 26 | let textDecoder = util.TextDecoder.create('utf-8', { ignoreBOM: true }); 27 | const result = textDecoder.decodeWithStream(value, { stream: false }) 28 | this.filterDataRoot = new OmniFilterDataRoot(OmniFilterItemBean.convertJsonToObj(result)!) 29 | }); 30 | } 31 | 32 | build() { 33 | NavDestination() { 34 | Column() { 35 | if (this.filterDataRoot) { 36 | OmniFilterBar( 37 | { 38 | filterDataRoot: this.filterDataRoot, 39 | onFilterParamsChanged: (selectedParams: Map) => { 40 | this.selectedParams = selectedParams 41 | }, 42 | filterController: this.filterController, 43 | } 44 | ) 45 | } 46 | if (this.selectedParams) { 47 | Flex() { 48 | Column() { 49 | Text(`${JSON.stringify(ObjectUtil.ObjectFromEntries(this.selectedParams))}`) 50 | } 51 | .width(`100%`) 52 | .height(`100%`) 53 | .justifyContent(FlexAlign.Center) 54 | .alignItems(HorizontalAlign.Center) 55 | } 56 | } 57 | } 58 | .height('100%') 59 | .width('100%') 60 | } 61 | .title('筛选示例') 62 | .onWillDisappear(() => { 63 | console.log(``) 64 | this.filterController.close() 65 | }) 66 | } 67 | 68 | @Builder 69 | Title() { 70 | Text('筛选示例') 71 | } 72 | } -------------------------------------------------------------------------------- /entry/src/main/ets/pages/filterbar/component/OmniCustomValueRange.ets: -------------------------------------------------------------------------------- 1 | import { OmniFilterItemBean } from "@omni-ui/omni_component/src/main/ets/components/filterbar/bean/OmniFilterItemBean" 2 | import { OmniFilterUtil } from "@omni-ui/omni_component/src/main/ets/components/filterbar/util/OmniFilterUtil" 3 | 4 | @Component 5 | export struct OmniFilterCustomValueRange { 6 | @ObjectLink item: OmniFilterItemBean 7 | onConfirmAction?: () => void 8 | 9 | build() { 10 | List() { 11 | ForEach(this.item.children, (item: OmniFilterItemBean, index: number) => { 12 | ListItem() { 13 | if (item.customMap) { 14 | Row() { 15 | Slider({ 16 | style: SliderStyle.OutSet, 17 | value: 4000, 18 | min: item.customMap[`leftValue`], 19 | max: item.customMap[`rightValue`], 20 | }) 21 | .selectedColor(0xFF552E) 22 | .trackColor(0xFF552E) 23 | .blockStyle({ type: SliderBlockType.DEFAULT }) 24 | .layoutWeight(1) 25 | } 26 | .margin({ left: 20, right: 20 }) 27 | } else { 28 | Column() { 29 | Text(`${item.title}`) 30 | .fontColor(this.tagTextColor(item)) 31 | } 32 | .width("100%") 33 | .height(30) 34 | .onClick(() => { 35 | //内置工具类处理兄弟节点的选中状态(通用情况下),如有特殊逻辑需要自定义 36 | OmniFilterUtil.processBrotherItemSelectStatus(item) 37 | this.onConfirmAction?.() 38 | }) 39 | } 40 | } 41 | .margin({ top: 10 }) 42 | }, (item: OmniFilterItemBean, index: number) => item.generateListKey() + index) 43 | } 44 | .backgroundColor(Color.White) 45 | } 46 | 47 | private tagTextColor(item: OmniFilterItemBean): ResourceColor { 48 | if (item.isSelected) { 49 | return 0xFF552E 50 | } else { 51 | return Color.Black 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /entry/src/main/ets/pages/guide/OmniGuideExampleIndex.ets: -------------------------------------------------------------------------------- 1 | import { 2 | BubbleBean, 3 | BubbleIndicator, 4 | BubblePosition, 5 | Controller, 6 | GuidePage, 7 | OmniGuide, 8 | OmniGuideBuilder 9 | } from '@omni-ui/omni_component'; 10 | 11 | @Builder 12 | export function OmniGuideExamplePageBuilder() { 13 | OmniGuideExampleIndex() 14 | } 15 | 16 | @Entry 17 | @Component 18 | export struct OmniGuideExampleIndex { 19 | @Consume('pathStack') pathStack: NavPathStack; 20 | private builder: OmniGuideBuilder | null = null; 21 | private controller: Controller | null = null; 22 | 23 | aboutToAppear() { 24 | this.builder = new OmniGuideBuilder() 25 | .setLabel('OmniGuideExampleIndex') 26 | .alwaysShow(true) 27 | .addGuidePage(GuidePage.newInstance() 28 | .addHighLight('Simple') 29 | .setBubbleIndicator( 30 | new BubbleIndicator( 31 | 'Simple', 32 | new BubbleBean('标题栏', '这里是副标题栏,这是一个简单的演示'), 33 | BubblePosition.BOTTOM 34 | ) 35 | ) 36 | ) 37 | } 38 | 39 | build() { 40 | NavDestination() { 41 | Column() { 42 | Stack() { 43 | OmniGuide({ 44 | content: this.content, 45 | builder: this.builder, 46 | onReady: (controller: Controller) => { 47 | this.controller = controller; 48 | } 49 | }) 50 | } 51 | } 52 | .width('100%') 53 | }.title('OmniGuide 示例') 54 | } 55 | 56 | @Builder 57 | private content() { 58 | Column() { 59 | Button($r('app.string.just_use_it_simply')) 60 | .onClick(() => { 61 | if (this.controller) { 62 | this.controller.show(); 63 | } 64 | }).id('Simple') 65 | .margin(10) 66 | .width('50%') 67 | 68 | Button($r('app.string.multi_guide_page')) 69 | .onClick(() => { 70 | this.pathStack.pushPath({ name: 'OmniGuideMultiPageExample' }) 71 | }) 72 | .margin(10) 73 | .width('50%') 74 | }.alignItems(HorizontalAlign.Center) 75 | .width('100%') 76 | .height('100%'); 77 | } 78 | } -------------------------------------------------------------------------------- /entry/src/main/ets/pages/imagepicker/OmniImageAlbumPickerPage.ets: -------------------------------------------------------------------------------- 1 | import { AlbumInfo, AlbumPickerComponent, AlbumPickerOptions, PickerColorMode } from "@kit.MediaLibraryKit" 2 | 3 | @Builder 4 | export function OmniImageAlbumPickerPageBuilder() { 5 | OmniImageAlbumPickerPage() 6 | } 7 | 8 | @Component 9 | export struct OmniImageAlbumPickerPage { 10 | @Consume('pathStack') pageStack: NavPathStack; 11 | 12 | albumOptions: AlbumPickerOptions = new AlbumPickerOptions(); 13 | 14 | onAlbumInfoClick(albumInfo: AlbumInfo): boolean { 15 | this.pageStack.pop(albumInfo) 16 | return true 17 | } 18 | build() { 19 | NavDestination() { 20 | AlbumPickerComponent({ 21 | albumPickerOptions: this.albumOptions, 22 | onAlbumClick: (albumInfo: AlbumInfo): boolean => this.onAlbumInfoClick?.(albumInfo) ?? false 23 | }) 24 | } 25 | .title("相册选择") 26 | } 27 | 28 | aboutToAppear(): void { 29 | this.albumOptions.themeColorMode = PickerColorMode.AUTO 30 | 31 | } 32 | } -------------------------------------------------------------------------------- /entry/src/main/ets/pages/imagepicker/OmniImagePickerExamplePage.ets: -------------------------------------------------------------------------------- 1 | import { 2 | OmniImagePickerTrigger 3 | } from "@omni-ui/omni_component/src/main/ets/components/imagepicker/OmniImagePickerTrigger"; 4 | 5 | @Builder 6 | export function OmniImagePickerExamplePageBuilder() { 7 | OmniImagePickerExamplePage() 8 | } 9 | 10 | @Component 11 | export struct OmniImagePickerExamplePage { 12 | @Consume('pathStack') pageStack: NavPathStack; 13 | @State selectUris: Array = new Array(); 14 | 15 | build() { 16 | NavDestination() { 17 | OmniImagePickerTrigger({ 18 | selectUris: $selectUris, 19 | goImagePicker: () => { 20 | this.pageStack.pushPathByName("OmniImagePickerSelectExamplePage", null, (data: PopInfo) => { 21 | if (data.result instanceof Array) { 22 | data.result.forEach((url: string) => { 23 | this.selectUris.push(url) 24 | }) 25 | } 26 | }, true) 27 | } 28 | }) 29 | } 30 | .title("图片选择器示例") 31 | } 32 | } -------------------------------------------------------------------------------- /entry/src/main/ets/pages/imagepicker/OmniImagePickerSelectExamplePage.ets: -------------------------------------------------------------------------------- 1 | import { OmniImagePicker } from '@omni-ui/omni_component' 2 | import { AlbumInfo } from '@kit.MediaLibraryKit'; 3 | 4 | @Builder 5 | export function OmniImagePickerSelectExamplePageBuilder() { 6 | OmniImagePickerSelectExamplePage() 7 | } 8 | @Component 9 | export struct OmniImagePickerSelectExamplePage { 10 | @Consume('pathStack') pageStack: NavPathStack; 11 | 12 | @State currentAlbumUrl?: string = "" 13 | @State currentAlbumName?: string = "照片和视频" 14 | build() { 15 | NavDestination() { 16 | OmniImagePicker({ 17 | currentAlbumUrl: this.currentAlbumUrl, 18 | onFinished: (result: Object) => { 19 | this.pageStack.pop(result) 20 | }, 21 | goAlbumPicker: () => { 22 | this.pageStack.pushPathByName("OmniImageAlbumPickerPage", null, (popInfo: PopInfo) => { 23 | if (popInfo.result instanceof AlbumInfo) { 24 | this.currentAlbumUrl = popInfo.result.uri 25 | this.currentAlbumName = popInfo.result.albumName 26 | } 27 | }, true) 28 | } 29 | }) 30 | } 31 | .title(this.currentAlbumName) 32 | } 33 | } -------------------------------------------------------------------------------- /entry/src/main/ets/pages/loading/OmniLoadingEntryPage.ets: -------------------------------------------------------------------------------- 1 | import { OmniDotLoadingView, OmniLoading, OmniPageLoading } from '@omni-ui/omni_component'; 2 | 3 | @Builder 4 | export function OmniLoadingEntryPageBuilder() { 5 | OmniLoadingEntryPage() 6 | } 7 | 8 | @Entry 9 | @Component 10 | struct OmniLoadingEntryPage { 11 | @State loading: boolean = true; 12 | 13 | build() { 14 | NavDestination() { 15 | Column({ space: 10 }) { 16 | Text('正常Loading展示') 17 | OmniPageLoading() 18 | Text('短文案Loading展示') 19 | OmniPageLoading({ options: { content: '我是较短的的Loading' } }) 20 | Text('长文案Loading展示') 21 | OmniPageLoading({ options: {content: '我是较长的我是较长的我是较长的...' }}) 22 | Text('四色圆点Loading展示') 23 | OmniDotLoadingView({ loading: $loading }) 24 | Button('点击开始/暂停loading') 25 | .onClick(() => { 26 | this.loading = !this.loading 27 | }) 28 | Button('点击打开loading弹窗,持续2s') 29 | .onClick(() => { 30 | let loading = new OmniLoading(this.getUIContext()); 31 | loading.show() 32 | setTimeout(() => { 33 | loading.dismiss() 34 | }, 2000) 35 | }) 36 | } 37 | .alignItems(HorizontalAlign.Center) 38 | .width('100%') 39 | } 40 | .title('Loading示例') 41 | } 42 | } -------------------------------------------------------------------------------- /entry/src/main/ets/pages/search/OmniSearchExamplePage.ets: -------------------------------------------------------------------------------- 1 | import { 2 | OmniSearchV2, 3 | SearchContainerModifier, 4 | SearchTextInputModifier, 5 | OmniToast 6 | } from "@omni-ui/omni_component" 7 | import { inputMethod } from "@kit.IMEKit" 8 | 9 | @Builder 10 | export function OmniSearchExamplePageBuilder() { 11 | OmniSearchExamplePage() 12 | } 13 | 14 | @Component 15 | struct OmniSearchExamplePage { 16 | build() { 17 | NavDestination() { 18 | 19 | Column() { 20 | Text('默认样式').margin({ bottom: 15 }) 21 | OmniSearchV2() 22 | 23 | Text('自定义样式').margin({ bottom: 15, top: 15 }) 24 | OmniSearchV2({ 25 | config: { 26 | defaultText: '关键字', 27 | placeHolderText: '请输入想要搜索的内容', 28 | hasCancelBtn: false, 29 | hasClearBtn: true, 30 | hasSearchBtn: true 31 | }, 32 | textInputModifier: new SearchTextInputModifier() 33 | .withCaretColor('#FF552E') 34 | .withBackgroundColor(0xffffff), 35 | foregroundContainerModifier: new SearchContainerModifier() 36 | .withHeight(44) 37 | .withBackgroundColor(0xffffff) 38 | .withBorderRadius(6) 39 | .withBorderWidth(1) 40 | .withBorderColor('#F7F7F7') 41 | .withShadow({ 42 | radius: 5, 43 | type: ShadowType.BLUR, 44 | color: '#F7F7F7' 45 | }) 46 | .withMargin({ 47 | left: '5%', 48 | right: '5%', 49 | top: 10, 50 | bottom: 10 51 | }), 52 | backgroundContainerModifier: new SearchContainerModifier() 53 | .withWidth('100%') 54 | .withPadding({ 55 | right: 10 56 | }) 57 | .withBackgroundColor(0xffffff), 58 | submitCallback: (searchText) => { 59 | OmniToast.showText({ msg: `搜索:${searchText}` }) 60 | }, 61 | onCancel: () => { 62 | OmniToast.showText({ msg: `点击取消按钮` }) 63 | }, 64 | onFocusCallback: () => { 65 | // OmniToast.showText({ msg: `获取到焦点` }) 66 | }, 67 | onTextChange: (text) => { 68 | OmniToast.showText({ msg: `输入框内容变化:${text}` }) 69 | } 70 | }) 71 | } 72 | .height('100%') 73 | .onClick(() => { 74 | // 退出文本编辑状态 75 | inputMethod.getController().stopInputSession(); 76 | }) 77 | 78 | }.title('Search示例') 79 | } 80 | } -------------------------------------------------------------------------------- /entry/src/main/ets/pages/tabs/OmniTabExamplePage.ets: -------------------------------------------------------------------------------- 1 | import { OmniTabConfig, OmniTabController, OmniTabItemConfig, OmniTabMode, OmniTabs } from "@omni-ui/omni_component" 2 | import { OmniToast } from "@omni-ui/omni_component/src/main/ets/components/toast/OmniToast" 3 | 4 | @Builder 5 | export function OmniTabExamplePageBuilder() { 6 | OmniTabExamplePage() 7 | } 8 | 9 | @Component 10 | export struct OmniTabExamplePage { 11 | private tabCtrl = new OmniTabController() 12 | private tabConfig: OmniTabConfig = { 13 | mode: OmniTabMode.Scrollable, 14 | labelColor: '#0090ff' 15 | } 16 | private tabConfig1: OmniTabConfig = { 17 | mode: OmniTabMode.Fix, 18 | labelColor: '#ff552e', 19 | indicatorColor: '#ff552e' 20 | } 21 | @State 22 | tabs: OmniTabItemConfig[] = [ 23 | new OmniTabItemConfig("tab0"), 24 | new OmniTabItemConfig("tab1", "", $r('app.media.tag_heart_fill'), ""), 25 | new OmniTabItemConfig("tab2", "", "", "", true), 26 | new OmniTabItemConfig("tab3", "", "", $r('app.media.tag_heart')), 27 | new OmniTabItemConfig("tab4"), 28 | new OmniTabItemConfig("tab5"), 29 | new OmniTabItemConfig("tab6"), 30 | new OmniTabItemConfig("tab7"), 31 | ] 32 | 33 | 34 | build() { 35 | NavDestination() { 36 | Column() { 37 | OmniTabs({ 38 | tabs: this.tabs, 39 | tabConfig: this.tabConfig, 40 | onTabClick: (index: number) => { 41 | OmniToast.showText({ 42 | msg: `click tab ${index}` 43 | }) 44 | } 45 | }) 46 | 47 | OmniTabs({ 48 | tabs: this.tabs, 49 | tabConfig: this.tabConfig1, 50 | tabController: this.tabCtrl 51 | }) 52 | .margin({ 53 | top: 20 54 | }) 55 | 56 | Button('Tab改变index') 57 | .margin({ 58 | top: 30 59 | }) 60 | .onClick(() => { 61 | this.tabCtrl.changeIndex(3) 62 | }) 63 | 64 | Button('添加小红点') 65 | .margin({ 66 | top: 20 67 | }) 68 | .onClick(() => { 69 | this.tabs[0].badgeText = "New" 70 | }) 71 | Button('取消小红点') 72 | .margin({ 73 | top: 20 74 | }) 75 | .onClick(() => { 76 | this.tabs[0].badgeText = "" 77 | }) 78 | 79 | } 80 | .height('100%') 81 | .width('100%') 82 | } 83 | .title('Tabs示例') 84 | 85 | } 86 | 87 | onDidBuild(): void { 88 | 89 | } 90 | 91 | } -------------------------------------------------------------------------------- /entry/src/main/ets/utils/utils.ts: -------------------------------------------------------------------------------- 1 | export default class ObjectUtil { 2 | static ObjectFromEntries(source: Iterable): Object { 3 | return Object.fromEntries(source) 4 | } 5 | } -------------------------------------------------------------------------------- /entry/src/main/module.json5: -------------------------------------------------------------------------------- 1 | { 2 | "module": { 3 | "name": "entry", 4 | "type": "entry", 5 | "description": "$string:module_desc", 6 | "mainElement": "EntryAbility", 7 | "deviceTypes": [ 8 | "phone" 9 | ], 10 | "deliveryWithInstall": true, 11 | "installationFree": false, 12 | "pages": "$profile:main_pages", 13 | "routerMap": "$profile:route_map", 14 | "abilities": [ 15 | { 16 | "name": "EntryAbility", 17 | "srcEntry": "./ets/entryability/EntryAbility.ets", 18 | "description": "$string:EntryAbility_desc", 19 | "icon": "$media:app_icon_startwindow", 20 | "label": "$string:EntryAbility_label", 21 | "startWindowIcon": "$media:app_icon_startwindow", 22 | "startWindowBackground": "$color:start_window_background", 23 | "exported": true, 24 | "skills": [ 25 | { 26 | "entities": [ 27 | "entity.system.home" 28 | ], 29 | "actions": [ 30 | "action.system.home" 31 | ] 32 | } 33 | ] 34 | } 35 | ], 36 | "extensionAbilities": [ 37 | { 38 | "name": "EntryBackupAbility", 39 | "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets", 40 | "type": "backup", 41 | "exported": false, 42 | "metadata": [ 43 | { 44 | "name": "ohos.extension.backup", 45 | "resource": "$profile:backup_config" 46 | } 47 | ] 48 | } 49 | ], 50 | "requestPermissions": [ 51 | { 52 | "name": "ohos.permission.INTERNET", 53 | "usedScene": { 54 | "abilities": [ 55 | "EntryAbility" 56 | ], 57 | "when": "always" 58 | } 59 | } 60 | ] 61 | } 62 | } -------------------------------------------------------------------------------- /entry/src/main/resources/base/element/color.json: -------------------------------------------------------------------------------- 1 | { 2 | "color": [ 3 | { 4 | "name": "start_window_background", 5 | "value": "#FFFFFF" 6 | } 7 | ] 8 | } -------------------------------------------------------------------------------- /entry/src/main/resources/base/element/string.json: -------------------------------------------------------------------------------- 1 | { 2 | "string": [ 3 | { 4 | "name": "module_desc", 5 | "value": "module description" 6 | }, 7 | { 8 | "name": "EntryAbility_desc", 9 | "value": "description" 10 | }, 11 | { 12 | "name": "EntryAbility_label", 13 | "value": "OmniUI" 14 | }, 15 | { 16 | "name": "multi_guide_page", 17 | "value": "Multi page guide page" 18 | }, 19 | { 20 | "name": "just_use_it_simply", 21 | "value": "just use it simply" 22 | }, 23 | { 24 | "name": "current_index", 25 | "value": "当前引导页index: " 26 | }, 27 | { 28 | "name": "guide_page_switching", 29 | "value": "Guide page switching" 30 | } 31 | ] 32 | } -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/app_icon_startwindow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/entry/src/main/resources/base/media/app_icon_startwindow.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/entry/src/main/resources/base/media/background.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/bottombar_car.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/entry/src/main/resources/base/media/bottombar_car.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/bottombar_car_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/entry/src/main/resources/base/media/bottombar_car_selected.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/bottombar_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/entry/src/main/resources/base/media/bottombar_home.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/bottombar_home_selecte.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/entry/src/main/resources/base/media/bottombar_home_selecte.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/bottombar_mine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/entry/src/main/resources/base/media/bottombar_mine.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/bottombar_mine_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/entry/src/main/resources/base/media/bottombar_mine_selected.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/bottombar_read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/entry/src/main/resources/base/media/bottombar_read.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/bottombar_read_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/entry/src/main/resources/base/media/bottombar_read_selected.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/entry/src/main/resources/base/media/foreground.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/ic_back_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/entry/src/main/resources/base/media/ic_back_white.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/ic_down_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/entry/src/main/resources/base/media/ic_down_arrow.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/ic_right_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/entry/src/main/resources/base/media/ic_right_arrow.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_category_chart.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_category_form.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_category_navigation.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_category_operatefeedback.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_category_page.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_category_theme_style.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/entry/src/main/resources/base/media/icon_category_theme_style.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_category_view.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_filter_reset_custom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/entry/src/main/resources/base/media/icon_filter_reset_custom.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/layered_image.json: -------------------------------------------------------------------------------- 1 | { 2 | "layered-image": 3 | { 4 | "background" : "$media:background", 5 | "foreground" : "$media:foreground" 6 | } 7 | } -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/startIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/entry/src/main/resources/base/media/startIcon.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/tag_heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/entry/src/main/resources/base/media/tag_heart.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/tag_heart_fill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/entry/src/main/resources/base/media/tag_heart_fill.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/profile/backup_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "allowToBackupRestore": true 3 | } -------------------------------------------------------------------------------- /entry/src/main/resources/base/profile/main_pages.json: -------------------------------------------------------------------------------- 1 | { 2 | "src": [ 3 | "pages/Index", 4 | "pages/loading/OmniLoadingEntryPage" 5 | ] 6 | } -------------------------------------------------------------------------------- /entry/src/main/resources/en_US/element/string.json: -------------------------------------------------------------------------------- 1 | { 2 | "string": [ 3 | { 4 | "name": "module_desc", 5 | "value": "module description" 6 | }, 7 | { 8 | "name": "EntryAbility_desc", 9 | "value": "description" 10 | }, 11 | { 12 | "name": "EntryAbility_label", 13 | "value": "label" 14 | }, 15 | { 16 | "name": "multi_guide_page", 17 | "value": "Multi page guide page" 18 | }, 19 | { 20 | "name": "just_use_it_simply", 21 | "value": "just use it simply" 22 | }, 23 | { 24 | "name": "current_index", 25 | "value": "Current guide page index: " 26 | }, 27 | { 28 | "name": "guide_page_switching", 29 | "value": "Guide page switching: " 30 | } 31 | ] 32 | } -------------------------------------------------------------------------------- /entry/src/main/resources/zh_CN/element/string.json: -------------------------------------------------------------------------------- 1 | { 2 | "string": [ 3 | { 4 | "name": "module_desc", 5 | "value": "模块描述" 6 | }, 7 | { 8 | "name": "EntryAbility_desc", 9 | "value": "description" 10 | }, 11 | { 12 | "name": "EntryAbility_label", 13 | "value": "OmniUI" 14 | }, 15 | { 16 | "name": "multi_guide_page", 17 | "value": "多页引导页" 18 | }, 19 | { 20 | "name": "just_use_it_simply", 21 | "value": "简单使用" 22 | }, 23 | { 24 | "name": "current_index", 25 | "value": "当前引导页index: " 26 | }, 27 | { 28 | "name": "guide_page_switching", 29 | "value": "引导页切换: " 30 | } 31 | ] 32 | } -------------------------------------------------------------------------------- /entry/src/mock/mock-config.json5: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /entry/src/ohosTest/ets/test/Ability.test.ets: -------------------------------------------------------------------------------- 1 | import { hilog } from '@kit.PerformanceAnalysisKit'; 2 | import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; 3 | 4 | export default function abilityTest() { 5 | describe('ActsAbilityTest', () => { 6 | // Defines a test suite. Two parameters are supported: test suite name and test suite function. 7 | beforeAll(() => { 8 | // Presets an action, which is performed only once before all test cases of the test suite start. 9 | // This API supports only one parameter: preset action function. 10 | }) 11 | beforeEach(() => { 12 | // Presets an action, which is performed before each unit test case starts. 13 | // The number of execution times is the same as the number of test cases defined by **it**. 14 | // This API supports only one parameter: preset action function. 15 | }) 16 | afterEach(() => { 17 | // Presets a clear action, which is performed after each unit test case ends. 18 | // The number of execution times is the same as the number of test cases defined by **it**. 19 | // This API supports only one parameter: clear action function. 20 | }) 21 | afterAll(() => { 22 | // Presets a clear action, which is performed after all test cases of the test suite end. 23 | // This API supports only one parameter: clear action function. 24 | }) 25 | it('assertContain', 0, () => { 26 | // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. 27 | hilog.info(0x0000, 'testTag', '%{public}s', 'it begin'); 28 | let a = 'abc'; 29 | let b = 'b'; 30 | // Defines a variety of assertion methods, which are used to declare expected boolean conditions. 31 | expect(a).assertContain(b); 32 | expect(a).assertEqual(a); 33 | }) 34 | }) 35 | } -------------------------------------------------------------------------------- /entry/src/ohosTest/ets/test/List.test.ets: -------------------------------------------------------------------------------- 1 | import abilityTest from './Ability.test'; 2 | 3 | export default function testsuite() { 4 | abilityTest(); 5 | } -------------------------------------------------------------------------------- /entry/src/ohosTest/module.json5: -------------------------------------------------------------------------------- 1 | { 2 | "module": { 3 | "name": "entry_test", 4 | "type": "feature", 5 | "deviceTypes": [ 6 | "phone" 7 | ], 8 | "deliveryWithInstall": true, 9 | "installationFree": false 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /entry/src/test/List.test.ets: -------------------------------------------------------------------------------- 1 | import localUnitTest from './LocalUnit.test'; 2 | 3 | export default function testsuite() { 4 | localUnitTest(); 5 | } -------------------------------------------------------------------------------- /entry/src/test/LocalUnit.test.ets: -------------------------------------------------------------------------------- 1 | import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; 2 | 3 | export default function localUnitTest() { 4 | describe('localUnitTest', () => { 5 | // Defines a test suite. Two parameters are supported: test suite name and test suite function. 6 | beforeAll(() => { 7 | // Presets an action, which is performed only once before all test cases of the test suite start. 8 | // This API supports only one parameter: preset action function. 9 | }); 10 | beforeEach(() => { 11 | // Presets an action, which is performed before each unit test case starts. 12 | // The number of execution times is the same as the number of test cases defined by **it**. 13 | // This API supports only one parameter: preset action function. 14 | }); 15 | afterEach(() => { 16 | // Presets a clear action, which is performed after each unit test case ends. 17 | // The number of execution times is the same as the number of test cases defined by **it**. 18 | // This API supports only one parameter: clear action function. 19 | }); 20 | afterAll(() => { 21 | // Presets a clear action, which is performed after all test cases of the test suite end. 22 | // This API supports only one parameter: clear action function. 23 | }); 24 | it('assertContain', 0, () => { 25 | // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. 26 | let a = 'abc'; 27 | let b = 'b'; 28 | // Defines a variety of assertion methods, which are used to declare expected boolean conditions. 29 | expect(a).assertContain(b); 30 | expect(a).assertEqual(a); 31 | }); 32 | }); 33 | } -------------------------------------------------------------------------------- /hvigor/hvigor-config.json5: -------------------------------------------------------------------------------- 1 | { 2 | "modelVersion": "5.0.0", 3 | "dependencies": { 4 | }, 5 | "execution": { 6 | // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | false ]. Default: "normal" */ 7 | // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */ 8 | // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */ 9 | // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */ 10 | // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */ 11 | }, 12 | "logging": { 13 | // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */ 14 | }, 15 | "debugging": { 16 | // "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */ 17 | }, 18 | "nodeOptions": { 19 | // "maxOldSpaceSize": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/ 20 | // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/ 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /hvigorfile.ts: -------------------------------------------------------------------------------- 1 | import { appTasks } from '@ohos/hvigor-ohos-plugin'; 2 | 3 | export default { 4 | system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ 5 | plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ 6 | } 7 | -------------------------------------------------------------------------------- /oh-package-lock.json5: -------------------------------------------------------------------------------- 1 | { 2 | "meta": { 3 | "stableOrder": true 4 | }, 5 | "lockfileVersion": 3, 6 | "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", 7 | "specifiers": { 8 | "@ohos/hamock@1.0.0": "@ohos/hamock@1.0.0", 9 | "@ohos/hypium@1.0.19": "@ohos/hypium@1.0.19" 10 | }, 11 | "packages": { 12 | "@ohos/hamock@1.0.0": { 13 | "name": "@ohos/hamock", 14 | "version": "1.0.0", 15 | "integrity": "sha512-K6lDPYc6VkKe6ZBNQa9aoG+ZZMiwqfcR/7yAVFSUGIuOAhPvCJAo9+t1fZnpe0dBRBPxj2bxPPbKh69VuyAtDg==", 16 | "resolved": "https://repo.harmonyos.com/ohpm/@ohos/hamock/-/hamock-1.0.0.har", 17 | "registryType": "ohpm" 18 | }, 19 | "@ohos/hypium@1.0.19": { 20 | "name": "@ohos/hypium", 21 | "version": "1.0.19", 22 | "integrity": "sha512-cEjDgLFCm3cWZDeRXk7agBUkPqjWxUo6AQeiu0gEkb3J8ESqlduQLSIXeo3cCsm8U/asL7iKjF85ZyOuufAGSQ==", 23 | "resolved": "https://repo.harmonyos.com/ohpm/@ohos/hypium/-/hypium-1.0.19.har", 24 | "registryType": "ohpm" 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /oh-package.json5: -------------------------------------------------------------------------------- 1 | { 2 | "modelVersion": "5.0.0", 3 | "name": "Omni-UI", 4 | "version": "1.0.1", 5 | "description": "开箱即用、高扩展性、丰富高效的鸿蒙开源组件库。", 6 | "main": "", 7 | "author": "", 8 | "license": "", 9 | "dependencies": { 10 | }, 11 | "devDependencies": { 12 | "@ohos/hypium": "1.0.19", 13 | "@ohos/hamock": "1.0.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /omni_component/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /oh_modules 3 | /.preview 4 | /build 5 | /.cxx 6 | /.test -------------------------------------------------------------------------------- /omni_component/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 版本记录 2 | 3 | ## 1.0.1 4 | * 修复若干已知问题。 5 | 6 | ## 1.0.0 7 | * 发布1.0.0初版。 -------------------------------------------------------------------------------- /omni_component/build-profile.json5: -------------------------------------------------------------------------------- 1 | { 2 | "apiType": "stageMode", 3 | "buildOption": { 4 | }, 5 | "buildOptionSet": [ 6 | { 7 | "name": "release", 8 | "arkOptions": { 9 | "obfuscation": { 10 | "ruleOptions": { 11 | "enable": false, 12 | "files": [ 13 | "./obfuscation-rules.txt" 14 | ] 15 | }, 16 | "consumerFiles": [ 17 | "./consumer-rules.txt" 18 | ] 19 | } 20 | }, 21 | }, 22 | ], 23 | "targets": [ 24 | { 25 | "name": "default" 26 | }, 27 | { 28 | "name": "ohosTest" 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /omni_component/consumer-rules.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/omni_component/consumer-rules.txt -------------------------------------------------------------------------------- /omni_component/hvigorfile.ts: -------------------------------------------------------------------------------- 1 | import { harTasks } from '@ohos/hvigor-ohos-plugin'; 2 | 3 | export default { 4 | system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ 5 | plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ 6 | } 7 | -------------------------------------------------------------------------------- /omni_component/obfuscation-rules.txt: -------------------------------------------------------------------------------- 1 | # Define project specific obfuscation rules here. 2 | # You can include the obfuscation configuration files in the current module's build-profile.json5. 3 | # 4 | # For more details, see 5 | # https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5 6 | 7 | # Obfuscation options: 8 | # -disable-obfuscation: disable all obfuscations 9 | # -enable-property-obfuscation: obfuscate the property names 10 | # -enable-toplevel-obfuscation: obfuscate the names in the global scope 11 | # -compact: remove unnecessary blank spaces and all line feeds 12 | # -remove-log: remove all console.* statements 13 | # -print-namecache: print the name cache that contains the mapping from the old names to new names 14 | # -apply-namecache: reuse the given cache file 15 | 16 | # Keep options: 17 | # -keep-property-name: specifies property names that you want to keep 18 | # -keep-global-name: specifies names that you want to keep in the global scope 19 | 20 | -enable-property-obfuscation 21 | -enable-toplevel-obfuscation 22 | -enable-filename-obfuscation 23 | -enable-export-obfuscation -------------------------------------------------------------------------------- /omni_component/oh-package.json5: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wuba58/omni-ui", 3 | "version": "1.0.1", 4 | "description": "开箱即用、高扩展性、丰富高效的鸿蒙开源组件库。", 5 | "keywords": [ 6 | "鸿蒙UI库", 7 | "组件库", 8 | "UI组件库", 9 | "HarmonyUI", 10 | "富文本", 11 | "引导", 12 | "图表" 13 | ], 14 | "main": "Index.ets", 15 | "author": "wuba58", 16 | "license": "Apache-2.0", 17 | "dependencies": { 18 | "class-transformer": "^0.5.1", 19 | "@ohos/htmlparser2": "^1.0.2" 20 | }, 21 | "type": "module", 22 | "repository": "https://github.com/wuba/omni-ui", 23 | "homepage": "https://wuba.github.io/omni-ui" 24 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/OmniComponent.ets: -------------------------------------------------------------------------------- 1 | import { window } from "@kit.ArkUI"; 2 | import immersionBar from "./utils/ImmersionBar"; 3 | 4 | export class OmniComponent{ 5 | static init(window:window.Window){ 6 | immersionBar.init(window) 7 | } 8 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/MainPage.ets: -------------------------------------------------------------------------------- 1 | @Component 2 | export struct MainPage { 3 | @State message: string = 'Hello World'; 4 | 5 | build() { 6 | Row() { 7 | Column() { 8 | Text(this.message) 9 | .fontSize(50) 10 | .fontWeight(FontWeight.Bold) 11 | } 12 | .width('100%') 13 | } 14 | .height('100%') 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/autolinegrid/OmniAutoLineGrid.ets: -------------------------------------------------------------------------------- 1 | import { OmniTheme, OmniThemeStyle } from "../../theme/OmniTheme" 2 | import { AutoLineWrapLayout } from "./AutoLineWrapLayout" 3 | import { LineWrapLayout } from "./LineWrapLayout" 4 | 5 | @Component 6 | export struct OmniAutoLineGrid { 7 | @StorageLink(OmniTheme.KEY) 8 | private baseStyle: OmniThemeStyle = OmniTheme.getDefaultStyle() 9 | @Prop items: PairItemInfo[] 10 | @Prop titleStyle: TextStyle = { fontSize: this.baseStyle.fontSizeLg, fontColor: '#979B9E' } 11 | @Prop contentStyle: TextStyle = { fontSize: this.baseStyle.fontSizeLg, fontColor: '#0B0F12' } 12 | @Prop rightTextStyle: TextStyle = { fontSize: this.baseStyle.fontSizeLg, fontColor: '#517a99' } 13 | @BuilderParam rightPartBuilder?: VoidCallback | undefined | null 14 | onRightAreaClick?: (event: ClickEvent) => void 15 | 16 | build() { 17 | Stack({ alignContent: Alignment.Top }) { 18 | //内容布局 19 | Column() { 20 | AutoLineWrapLayout({ lineGap: 10, lineMaxNum: 2 }) { 21 | ForEach(this.items, (item: PairItemInfo) => { 22 | LineWrapLayout({ gap: 10, singleLine: item.singleLine, hasRightPart: item.hasRightPart ?? false }) { 23 | // left part 24 | Text(item.title) 25 | .fontSize(this.titleStyle.fontSize) 26 | .fontColor(this.titleStyle.fontColor) 27 | Text(item.content) 28 | .fontSize(this.contentStyle.fontSize) 29 | .fontColor(this.contentStyle.fontColor) 30 | .maxLines(1) 31 | .textOverflow({ overflow: TextOverflow.Ellipsis }) 32 | 33 | // right part 34 | if (item.singleLine && (item.hasRightPart ?? false)) { 35 | if (this.rightPartBuilder) { 36 | this.rightPartBuilder() 37 | } else { 38 | Row() { 39 | Text(item.rightText) 40 | .fontSize(this.rightTextStyle.fontSize) 41 | .fontColor(this.rightTextStyle.fontColor) 42 | 43 | if (item.rightIcon) { 44 | Image(item.rightIcon) 45 | .size(item.rightIconSize ?? { width: 12, height: 12 }) 46 | } 47 | }.onClick((event) => { 48 | if (this.onRightAreaClick) { 49 | this.onRightAreaClick(event) 50 | } 51 | }) 52 | } 53 | } 54 | } 55 | }) 56 | } 57 | }.width('100%') 58 | } 59 | } 60 | } 61 | 62 | export interface PairItemInfo { 63 | title: string 64 | content: string 65 | rightText?: string 66 | rightIcon?: PixelMap | ResourceStr | DrawableDescriptor 67 | rightIconSize?: SizeOptions 68 | singleLine: boolean 69 | hasRightPart?: boolean 70 | } 71 | 72 | export interface TextStyle { 73 | fontSize?: string | number | Resource 74 | fontColor?: ResourceColor 75 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/chart/OmniChart.ets: -------------------------------------------------------------------------------- 1 | import { InterfaceObj, OptionInterface } from './utils/chartInterface' 2 | import { Tooltip, globalBuilder } from './Tooltip' 3 | import { Options } from './Options' 4 | import { DrawBaseViewModel } from './utils/DrawBaseViewModel' 5 | 6 | type ChartUnionData = object | number | string 7 | 8 | @Component 9 | export struct OmniChart { 10 | private settings: RenderingContextSettings = new RenderingContextSettings(true) 11 | private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings) 12 | drawViewModel: DrawBaseViewModel | null = null; 13 | click: Function = (event: ClickEvent, args: InterfaceObj) => {}; 14 | tooltipClick: Function = () => {}; 15 | @Link @Watch('onCountUpdated') options: OptionInterface; 16 | @Link renderType: string 17 | @State isTooltipShow: boolean = false 18 | @State tooltipInfo: InterfaceObj = {} 19 | @BuilderParam customTooltip: (tooltipInfo: InterfaceObj) => void = globalBuilder; // 自定义组件 20 | 21 | onCountUpdated(options: Options): void { 22 | this.isTooltipShow = false 23 | this.drawViewModel && this.drawViewModel.draw(this.context, this.options, this.renderType) 24 | } 25 | 26 | updateTooltipInfo (flag: boolean, event: ClickEvent, pos?: InterfaceObj, title?: string, arr?: [], tooltipInfo: InterfaceObj = {}) { 27 | if (!tooltipInfo.show) { 28 | this.isTooltipShow = false 29 | return; 30 | } 31 | this.isTooltipShow = flag 32 | if (tooltipInfo.type !== 'default') { 33 | this.tooltipClick && this.tooltipClick(event, flag ? { title, pos, data: arr } : {}) 34 | } 35 | if (tooltipInfo.type !== 'default') return; 36 | if (this.isTooltipShow) { 37 | this.tooltipInfo = { 38 | pos, 39 | title, 40 | data: arr 41 | } 42 | const keys = Object.keys(tooltipInfo) 43 | keys.forEach(item => { 44 | this.tooltipInfo[item] = tooltipInfo[item] 45 | }) 46 | } 47 | } 48 | 49 | build() { 50 | Column () { 51 | Canvas(this.context) 52 | .width('100%') 53 | .height('100%') 54 | .onReady(() => { 55 | this.drawViewModel && this.drawViewModel.draw(this.context, this.options, this.renderType) 56 | }) 57 | .onClick((event) => { 58 | if (this.drawViewModel) { 59 | this.drawViewModel.bindEvent(event, (flag: boolean, event: ClickEvent, pos: InterfaceObj = {}, title: string = '', arr: [] = [], tooltipInfo: InterfaceObj = {}) => { 60 | this.click && this.click(event, flag ? { 61 | title, 62 | data: arr 63 | } : {}) 64 | this.updateTooltipInfo(flag, event, pos, title, arr, tooltipInfo) 65 | }) 66 | } 67 | }) 68 | 69 | if (this.isTooltipShow) { 70 | Tooltip({ 71 | tooltipInfo: $tooltipInfo, 72 | customTooltip: this.customTooltip 73 | }) 74 | } 75 | } 76 | .width('100%') 77 | .height('100%') 78 | .onDisAppear(() => { 79 | this.drawViewModel && this.drawViewModel.clear() 80 | }) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/chart/OmniLineChart.ets: -------------------------------------------------------------------------------- 1 | import { OmniChart } from './OmniChart' 2 | import { Options } from './Options' 3 | import { globalBuilder } from './Tooltip' 4 | import { InterfaceObj, OptionInterface } from './utils/chartInterface' 5 | import { DrawBaseViewModel } from './utils/DrawBaseViewModel' 6 | import { DrawLineViewModel, LineDataType } from './utils/DrawLineViewModel' 7 | 8 | @Component 9 | export struct OmniLineChart { 10 | private drawViewModel?: DrawBaseViewModel 11 | @Prop @Watch('onCountUpdated') options: Options; 12 | @State chartOption: OptionInterface = {}; 13 | @State renderType: string = 'init' 14 | private click: Function = (event: InterfaceObj, params: InterfaceObj) => { 15 | } 16 | private tooltipClick: Function = (event: InterfaceObj, params: InterfaceObj) => { 17 | } 18 | @BuilderParam customTooltip: (tooltipInfo: InterfaceObj) => void = globalBuilder 19 | 20 | onCountUpdated(): void { 21 | this.renderType = 'update' 22 | this.chartOption = this.options.options 23 | } 24 | 25 | aboutToAppear() { 26 | this.chartOption = this.options.options 27 | this.drawViewModel = new DrawLineViewModel() 28 | } 29 | 30 | build() { 31 | OmniChart({ 32 | options: $chartOption, 33 | drawViewModel: this.drawViewModel, 34 | renderType: this.renderType, 35 | customTooltip: this.customTooltip, 36 | click: (event: InterfaceObj, params: InterfaceObj) => { 37 | this.click(event, params) 38 | }, 39 | tooltipClick: (event: InterfaceObj, params: InterfaceObj) => { 40 | this.tooltipClick(event, params) 41 | } 42 | }) 43 | } 44 | } 45 | 46 | -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/chart/OmniProgressBarChart.ets: -------------------------------------------------------------------------------- 1 | import { OmniChart } from './OmniChart' 2 | import { Options } from './Options' 3 | import { globalBuilder } from './Tooltip' 4 | import { InterfaceObj, OptionInterface } from '../chart/utils/chartInterface' 5 | import { DrawBaseViewModel } from '../chart/utils/DrawBaseViewModel' 6 | import { DrawVerBarViewModel } from './utils/DrawVerBarViewModel' 7 | import { DrawHorViewModel } from './utils/DrawHorViewModel' 8 | 9 | // 柱状图样式 10 | export enum BarChartStyle { 11 | //纵向 12 | vertical, 13 | 14 | //横向 15 | horizontal, 16 | } 17 | 18 | @Component 19 | export struct OmniProgressBarChart { 20 | private drawViewModel?: DrawBaseViewModel 21 | @Prop @Watch('onCountUpdated') options: Options; 22 | @State chartOption: OptionInterface = {}; 23 | @State renderType: string = 'init' 24 | // 柱状图的样式 25 | @State barChartStyle: BarChartStyle = BarChartStyle.vertical; 26 | private click: Function = (event: InterfaceObj, params: InterfaceObj) => { 27 | } 28 | private tooltipClick: Function = (event: InterfaceObj, params: InterfaceObj) => { 29 | } 30 | @BuilderParam customTooltip: (tooltipInfo: InterfaceObj) => void = globalBuilder 31 | 32 | onCountUpdated(options: Options): void { 33 | this.renderType = 'update' 34 | this.chartOption = this.options.options 35 | } 36 | 37 | aboutToAppear() { 38 | this.chartOption = this.options.options 39 | if (this.barChartStyle === BarChartStyle.vertical) { 40 | this.drawViewModel = new DrawVerBarViewModel() 41 | } else { 42 | this.drawViewModel = new DrawHorViewModel() 43 | } 44 | } 45 | 46 | build() { 47 | OmniChart({ 48 | options: $chartOption, 49 | drawViewModel: this.drawViewModel, 50 | customTooltip: this.customTooltip, 51 | renderType: this.renderType, 52 | click: (event: InterfaceObj, params: InterfaceObj) => { 53 | this.click(event, params) 54 | }, 55 | tooltipClick: (event: InterfaceObj, params: InterfaceObj) => { 56 | this.tooltipClick(event, params) 57 | } 58 | }) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/chart/OmniRadarChart.ets: -------------------------------------------------------------------------------- 1 | import { OmniChart } from './OmniChart' 2 | import { Options } from './Options' 3 | import { InterfaceObj, OptionInterface } from './utils/chartInterface' 4 | import { globalBuilder } from './Tooltip' 5 | import { DrawBaseViewModel } from './utils/DrawBaseViewModel' 6 | import { DrawRadarViewModel, RadarDataType } from './utils/DrawRadarViewModel' 7 | 8 | @Component 9 | export struct OmniRadarChart { 10 | private drawViewModel?: DrawBaseViewModel 11 | @Prop @Watch('onCountUpdated') options: Options; 12 | @State chartOption: OptionInterface = {}; 13 | @State renderType: string = 'init' 14 | private click: Function = (event: InterfaceObj, params: InterfaceObj) => { 15 | } 16 | private tooltipClick: Function = (event: InterfaceObj, params: InterfaceObj) => { 17 | } 18 | @BuilderParam customTooltip: (tooltipInfo: InterfaceObj) => void = globalBuilder 19 | 20 | onCountUpdated(): void { 21 | this.chartOption = this.options.options 22 | } 23 | 24 | aboutToAppear() { 25 | this.onCountUpdated() 26 | this.drawViewModel = new DrawRadarViewModel() 27 | } 28 | 29 | build() { 30 | OmniChart({ 31 | options: $chartOption, 32 | drawViewModel: this.drawViewModel, 33 | renderType: this.renderType, 34 | customTooltip: this.customTooltip, 35 | click: (event: InterfaceObj, params: InterfaceObj) => { 36 | this.click(event, params) 37 | }, 38 | tooltipClick: (event: InterfaceObj, params: InterfaceObj) => { 39 | this.tooltipClick(event, params) 40 | } 41 | }) 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/chart/Options.ets: -------------------------------------------------------------------------------- 1 | import { InterfaceObj, LegendInterface, TooltipInterface, SeriesInterface, AxisInterface, RadarInterface, OptionInterface } from './utils/chartInterface' 2 | import { xAxisOpt, yAxisOpt, tooltip, legend, legendTextStyle, radar } from './utils/defaultOption' 3 | import { deepCopy, assign } from './utils/index' 4 | 5 | export class Options { 6 | options: OptionInterface = { 7 | color: ['#296DFF', '#ff5495fd', '#ff1acffd', '#ff72e4fd', '#7B72F7', '#F85758', '#FFBF29', '#D1E9F9', '#F5FAFC', '#5A657A'], 8 | title: {}, 9 | legend: deepCopy(legend), 10 | tooltip: deepCopy(tooltip), 11 | radar: deepCopy(radar), 12 | xAxis: deepCopy(xAxisOpt), 13 | yAxis: deepCopy(yAxisOpt), 14 | series: [] 15 | } 16 | cPaddingT: number = 30; 17 | cPaddingB: number = 30; 18 | cPaddingL: number = 30; 19 | cPaddingR: number = 20; 20 | color: Array = []; 21 | title: InterfaceObj = {}; 22 | legend: LegendInterface = {}; 23 | tooltip: TooltipInterface = {}; 24 | radar: RadarInterface = {}; 25 | xAxis: AxisInterface = {}; 26 | yAxis: AxisInterface | AxisInterface[] = {}; 27 | series: Array> = []; 28 | 29 | constructor(options: OptionInterface) { 30 | this.setVal(options) 31 | } 32 | 33 | setVal (options: OptionInterface) { 34 | const oldOptions: OptionInterface = deepCopy(this.options) 35 | const keys = ['cPaddingT', 'cPaddingB', 'cPaddingL', 'cPaddingR', 'color', 'title', 'legend', 'xAxis', 'yAxis', 'tooltip', 'radar', 'dataZoom', 'series'] 36 | for (let i = 0; i < keys.length; i++) { 37 | const item = keys[i] 38 | if (options[item] === undefined) continue 39 | switch (item) { 40 | case 'tooltip': 41 | oldOptions.tooltip = options[item] 42 | break 43 | case 'title': 44 | oldOptions.title = assign(oldOptions.title, options[item]) 45 | break 46 | case 'color': 47 | oldOptions.color = options[item] 48 | break 49 | case 'legend': 50 | oldOptions.legend = assign(oldOptions.legend, options[item]) 51 | break 52 | case 'xAxis': 53 | oldOptions.xAxis = assign(oldOptions.xAxis, options[item]) 54 | break 55 | case 'yAxis': 56 | oldOptions.yAxis = assign(oldOptions.yAxis, options[item]) 57 | break 58 | case 'radar': 59 | oldOptions.radar = assign(oldOptions.radar, options[item]) 60 | break 61 | case 'series': 62 | const seriesData: SeriesInterface[] | undefined = options[item] 63 | if (oldOptions.series && seriesData) { 64 | if (oldOptions.series.length === seriesData.length) { 65 | oldOptions.series = oldOptions.series.map((item: SeriesInterface, index): SeriesInterface => { 66 | item = assign(item, seriesData[index]) 67 | return item 68 | }) 69 | } else { 70 | oldOptions.series = options[item] 71 | } 72 | } else { 73 | oldOptions.series = options[item] 74 | } 75 | break 76 | } 77 | } 78 | this.options = oldOptions 79 | } 80 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/chart/Tooltip.ets: -------------------------------------------------------------------------------- 1 | import { InterfaceObj } from './utils/chartInterface' 2 | @Builder 3 | function globalBuilder($$: InterfaceObj) { 4 | Column() { 5 | if($$.tooltipInfo.title) { 6 | Text($$.tooltipInfo.title) 7 | .fancy($$.tooltipInfo) 8 | .margin({ 9 | bottom: 8 10 | }) 11 | } 12 | ForEach($$.tooltipInfo.data, (item: InterfaceObj, index) => { 13 | Text(item.name + ':' + item.num) 14 | .fancy($$.tooltipInfo) 15 | }) 16 | } 17 | .alignItems(HorizontalAlign.Start) 18 | .padding($$.tooltipInfo.padding) 19 | .backgroundColor($$.tooltipInfo.backgroundColor) 20 | .borderColor($$.tooltipInfo.borderColor) 21 | .borderWidth($$.tooltipInfo.borderWidth) 22 | .borderRadius(10) 23 | } 24 | 25 | @Extend(Text) function fancy (tooltipInfo: InterfaceObj) { 26 | .fontSize(tooltipInfo.textStyle.fontSize || 14) 27 | .fontColor(tooltipInfo.textStyle.color || '#fff') 28 | .fontWeight(tooltipInfo.textStyle.fontWeight || 'normal') 29 | .fontFamily(tooltipInfo.textStyle.fontFamily ||'sans-serif') 30 | } 31 | 32 | export { 33 | globalBuilder 34 | } 35 | 36 | @Component 37 | export struct Tooltip { 38 | @Link @Watch('onTooltipInfoUpdated') tooltipInfo: InterfaceObj; 39 | @State x: number = -1000; 40 | @State y: number = -1000; 41 | // 自定义提示组件 42 | @BuilderParam customTooltip: (tooltipInfo: InterfaceObj) => void = globalBuilder; 43 | 44 | onTooltipInfoUpdated (): void { 45 | const pos: InterfaceObj = this.tooltipInfo.pos 46 | const x: number = pos.x 47 | if (x + 40 !== this.x) { 48 | this.x = -10000 49 | this.y = -10000 50 | } 51 | } 52 | getPos (rect: InterfaceObj) { 53 | const pos: InterfaceObj = this.tooltipInfo.pos 54 | const W: number = pos.W 55 | const H: number = pos.H 56 | const x: number = pos.x 57 | const y: number = pos.y 58 | const width: number = rect.width 59 | const height: number = rect.height 60 | if (x + 40 + width > W - 10) { 61 | this.x = Math.max(x - width + 20, 10) 62 | } else { 63 | this.x = x + 40 64 | } 65 | if (y !== undefined) { 66 | if (y + 40 + height > H - 10) { 67 | this.y = y - height + 20 68 | } else { 69 | this.y = y 70 | } 71 | } else { 72 | this.y = H / 2 - height / 2 73 | } 74 | } 75 | build() { 76 | Column () { 77 | this.customTooltip({ 78 | tooltipInfo: this.tooltipInfo 79 | }) 80 | } 81 | .alignItems(HorizontalAlign.Start) 82 | .position({ 83 | x: this.x, 84 | y: this.y 85 | }) 86 | .onAreaChange((oldValue: Area, newValue: Area) => { 87 | this.getPos(newValue) 88 | }) 89 | } 90 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/dialog/OmniDialog.ets: -------------------------------------------------------------------------------- 1 | import { ComponentContent, PromptAction } from "@kit.ArkUI" 2 | import { buildDialog } from "./OmniDialogBuilder" 3 | import { OmniDialogArgs, OmniDialogParams } from "./OmniDialogConstant" 4 | 5 | export function generateId() { 6 | return Math.random().toString(36) 7 | } 8 | 9 | export class OmniDialogManager { 10 | private static dialogMap: Map = new Map(); 11 | 12 | private constructor() { 13 | } 14 | 15 | public static put(dialog: OmniDialog): string { 16 | const key = generateId() 17 | OmniDialogManager.dialogMap.set(key, dialog); 18 | return key 19 | } 20 | 21 | public static dismiss(key: string) { 22 | OmniDialogManager.dialogMap.get(key)?.dismiss(); 23 | } 24 | } 25 | 26 | export class OmniDialogController { 27 | private key: string 28 | 29 | constructor(key: string) { 30 | this.key = key; 31 | } 32 | 33 | public dismiss() { 34 | OmniDialogManager.dismiss(this.key) 35 | } 36 | } 37 | 38 | export class OmniDialog { 39 | private uiContext: UIContext 40 | private promptAction: PromptAction 41 | private compContent?: ComponentContent 42 | 43 | constructor(uiContext: UIContext) { 44 | this.uiContext = uiContext 45 | this.promptAction = uiContext.getPromptAction() 46 | } 47 | 48 | public dismiss() { 49 | this.promptAction.closeCustomDialog(this.compContent).then(() => { 50 | this.compContent?.dispose() 51 | }) 52 | } 53 | 54 | public show(args: OmniDialogArgs) { 55 | let params = new OmniDialogParams(new OmniDialogController(OmniDialogManager.put(this)), args) 56 | this.compContent = new ComponentContent(this.uiContext, wrapBuilder(buildDialog), params) 57 | 58 | this.promptAction.openCustomDialog(this.compContent, { 59 | showInSubWindow: args.showInSubWindow ?? false, 60 | autoCancel: args.autoCancel ?? true, 61 | alignment: args.alignment ?? DialogAlignment.Center, 62 | isModal: args.isModal ?? true, 63 | offset: args.offset ?? { dx: 0, dy: 0 }, 64 | transition: args.transition, 65 | maskColor: args.maskColor, 66 | onDidAppear: args.onDidAppear, 67 | onDidDisappear: args.onDidDisappear 68 | }) 69 | } 70 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/dialog/OmniDialogConstant.ets: -------------------------------------------------------------------------------- 1 | import { OmniDialogController } from "./OmniDialog" 2 | 3 | export interface OmniDialogTextArgs { 4 | value: string 5 | style?: OmniDialogFontStyle 6 | padding?: Padding | Length | LocalizedPadding 7 | } 8 | 9 | export interface OmniDialogFontStyle { 10 | font?: Font 11 | color?: ResourceColor 12 | } 13 | 14 | export interface OmniDialogButtonArgs { 15 | value: string 16 | fontStyle?: OmniDialogFontStyle 17 | padding?: Padding | Length | LocalizedPadding 18 | backgroundColor?: ResourceColor 19 | border?: BorderOptions 20 | } 21 | 22 | export interface OmniDialogArgs { 23 | titleBuilder?: () => void 24 | contentBuilder?: () => void 25 | buttonBuilder?: (controller?: OmniDialogController) => void 26 | titleArgs?: OmniDialogTextArgs 27 | contentArgs?: OmniDialogTextArgs 28 | leftButtonArgs?: OmniDialogButtonArgs 29 | rightButtonArgs?: OmniDialogButtonArgs 30 | dialogBorder?: BorderOptions 31 | dialogBgColor?: ResourceColor 32 | dialogDivider?: OmniDialogDividerOptions 33 | isModal?: boolean 34 | showInSubWindow?: boolean 35 | autoCancel?: boolean 36 | alignment?: DialogAlignment 37 | offset?: Offset 38 | transition?: TransitionEffect 39 | maskColor?: ResourceColor 40 | onDidAppear?: VoidCallback 41 | onDidDisappear?: VoidCallback 42 | onLeftButtonClick?: (event: ClickEvent) => void 43 | onRightButtonClick?: (event: ClickEvent) => void 44 | } 45 | 46 | export class OmniDialogParams { 47 | controller: OmniDialogController 48 | titleBuilder?: () => void 49 | contentBuilder?: () => void 50 | buttonBuilder?: (controller?: OmniDialogController) => void 51 | titleArgs?: OmniDialogTextArgs 52 | contentArgs?: OmniDialogTextArgs 53 | leftButtonArgs?: OmniDialogButtonArgs 54 | rightButtonArgs?: OmniDialogButtonArgs 55 | dialogBorder?: BorderOptions 56 | dialogBgColor?: ResourceColor 57 | dialogDivider?: OmniDialogDividerOptions 58 | onLeftButtonClick?: (event: ClickEvent) => void 59 | onRightButtonClick?: (event: ClickEvent) => void 60 | 61 | constructor(controller: OmniDialogController, args: OmniDialogArgs) { 62 | this.controller = controller; 63 | this.titleBuilder = args.titleBuilder 64 | this.contentBuilder = args.contentBuilder 65 | this.buttonBuilder = args.buttonBuilder 66 | this.titleArgs = args.titleArgs 67 | this.contentArgs = args.contentArgs 68 | this.leftButtonArgs = args.leftButtonArgs 69 | this.rightButtonArgs = args.rightButtonArgs 70 | this.dialogBorder = args.dialogBorder 71 | this.dialogBgColor = args.dialogBgColor 72 | this.dialogDivider = args.dialogDivider 73 | this.onLeftButtonClick = args.onLeftButtonClick 74 | this.onRightButtonClick = args.onRightButtonClick 75 | } 76 | } 77 | 78 | export interface OmniDialogDividerOptions { 79 | strokeWidth?: number | string 80 | color?: ResourceColor 81 | margin?: Margin | Length | LocalizedMargin 82 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/filterbar/OmniFilterComponentRegistry.ets: -------------------------------------------------------------------------------- 1 | import { OmniFilterItemBean } from "./bean/OmniFilterItemBean"; 2 | 3 | //确认动作 4 | export declare type OnConfirmAction = () => void 5 | //关闭动作 6 | export declare type OnCloseAction = () => void 7 | 8 | export class OmniFilterComponentRegistry { 9 | // 下拉类型组件池 10 | private dropSlideTypeBuilderPool: Map> = new Map(); 11 | 12 | // 右滑类型组件池 13 | private rightSlideTypeBuilderPool: Map> = new Map(); 14 | 15 | // 初始化方法,用于注册默认的组件 16 | constructor() { 17 | } 18 | 19 | // 注册下拉类型的组件 20 | registerDropSlideComponent(type: string, builder: WrappedBuilder<[OmniFilterItemBean, OnConfirmAction, OnCloseAction]>) { 21 | this.dropSlideTypeBuilderPool.set(type, builder); 22 | } 23 | 24 | // 注册右滑类型的组件 25 | registerRightSlideComponent(type: string, builder: WrappedBuilder<[OmniFilterItemBean, OnConfirmAction, OnCloseAction]>) { 26 | this.rightSlideTypeBuilderPool.set(type, builder); 27 | } 28 | 29 | // 获取下拉类型的组件构建器 30 | getDropSlideComponentBuilder(type: string): WrappedBuilder<[OmniFilterItemBean, OnConfirmAction, OnCloseAction]> | undefined { 31 | return this.dropSlideTypeBuilderPool.get(type); 32 | } 33 | 34 | // 获取右滑类型的组件构建器 35 | getRightSlideComponentBuilder(type: string): WrappedBuilder<[OmniFilterItemBean, OnConfirmAction, OnCloseAction]> | undefined { 36 | return this.rightSlideTypeBuilderPool.get(type); 37 | } 38 | 39 | // 检查是否存在某个下拉类型的组件 40 | hasDropSlideType(type: string): boolean { 41 | return this.dropSlideTypeBuilderPool.has(type); 42 | } 43 | 44 | // 检查是否存在某个右滑类型的组件 45 | hasRightSlideType(type: string): boolean { 46 | return this.rightSlideTypeBuilderPool.has(type); 47 | } 48 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/filterbar/OmniFilterConstants.ets: -------------------------------------------------------------------------------- 1 | export namespace OmniFilterConstants{ 2 | export declare const OMNI_FILTER_LIST_DEEP_SELECT_BG = 0xFFF8F8F8 3 | export declare const OMNI_FILTER_LIST_MIDDLE_SELECT_BG = 0xFFFFFFFF 4 | export declare const OMNI_FILTER_LIST_LIGHT_SELECT_BG = 0xFFFFFFFF 5 | 6 | export declare const OMNI_FILTER_LIST_DEEP_NORMAL_BG = 0xFFF0F0F0 7 | export declare const OMNI_FILTER_LIST_MIDDLE_NORMAL_BG = 0xFFF8F8F8 8 | export declare const OMNI_FILTER_LIST_LIGHT_NORMAL_BG = 0xFFFFFFFF 9 | } 10 | -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/filterbar/OmniFilterThemeConfig.ets: -------------------------------------------------------------------------------- 1 | import { OmniResourceColor } from "../../theme/OmniTheme" 2 | 3 | export interface OmniFilterStyle { 4 | menuStyle?: OmniFilterMenuStyle 5 | gridStyle?: OmniFilterGridStyle 6 | listStyle?: OmniFilterListStyle 7 | bottomPanelStyle?: OmniFilterBottomPanelStyle 8 | } 9 | 10 | export interface OmniFilterMenuStyle { 11 | menuTextStyle?: OmniFilterTextStyle //菜单文字常规样式 12 | menuSelectedTextStyle?: OmniFilterTextStyle //菜单文字选中样式 13 | } 14 | 15 | export interface OmniFilterListStyle { 16 | maxHeight?:number 17 | itemTextStyle?: OmniFilterTextStyle; // 列表文字常规样式 18 | itemSelectedTextStyle?: OmniFilterTextStyle; // 列表文字选中样式 19 | itemMultiSelectIconUnselected?: OmniFilterIcon //多选icon 20 | itemMultiSelectIconSelected?: OmniFilterIcon //多选icon(选中) 21 | } 22 | 23 | export interface OmniFilterGridStyle { 24 | maxHeight?:number 25 | rowCount?:number//每行个数 26 | titleTextStyle?: OmniFilterTextStyle //网格标题样式 27 | itemTextStyle?: OmniFilterTextStyle //网格文字常规样式 28 | itemSelectedTextStyle?: OmniFilterTextStyle //网格文字选中样式 29 | itemBgColor?: OmniResourceColor //item背景色 30 | itemSelectedBgColor?: OmniResourceColor //item背景色(选中) 31 | } 32 | 33 | export interface OmniFilterBottomPanelStyle { 34 | resetText?:string 35 | resetTextStyle?: OmniFilterTextStyle //重置文字样式 36 | resetIcon?: OmniFilterIcon //重置图标 37 | confirmText?:string 38 | confirmTextStyle?: OmniFilterTextStyle //确定文字样式 39 | confirmButtonColor?: OmniResourceColor //确定按钮颜色 40 | } 41 | 42 | export declare type OmniFilterIcon = PixelMap | ResourceStr | DrawableDescriptor | ImageContent 43 | 44 | export interface OmniFilterTextStyle { 45 | fontColor?: OmniResourceColor //文字颜色 46 | fontSize?: number | string | Resource //文字大小 47 | fontWeight?: number | FontWeight | string //文字粗细 48 | } 49 | -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/filterbar/bean/OmniFilterMenuItemBean.ets: -------------------------------------------------------------------------------- 1 | import { OmniFilterItemBean } from "./OmniFilterItemBean" 2 | 3 | @Observed 4 | export class OmniFilterMenuItemBean { 5 | item: OmniFilterItemBean 6 | menuTitle: string | undefined 7 | isHighLight: boolean 8 | active: boolean 9 | 10 | customTitle?:string = undefined 11 | isCustomTitleHighLight:boolean = false 12 | 13 | constructor(item: OmniFilterItemBean, menuTitle: string, isHighLight: boolean, active: boolean) { 14 | this.item = item 15 | this.menuTitle = menuTitle 16 | this.isHighLight = isHighLight 17 | this.active = active 18 | } 19 | 20 | } 21 | 22 | /** 23 | * 自定义Menu标题数据结构 24 | */ 25 | export class OmniFilterCustomMenuTitle{ 26 | menuTitle: string 27 | isHighLight: boolean 28 | 29 | constructor(menuTitle: string, isHighLight: boolean) { 30 | this.menuTitle = menuTitle 31 | this.isHighLight = isHighLight 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/filterbar/component/OmniFilterBottomPanel.ets: -------------------------------------------------------------------------------- 1 | import { OmniTheme, OmniThemeStyle } from "../../../theme/OmniTheme" 2 | import { OmniFilterStyle } from "../OmniFilterThemeConfig" 3 | 4 | @Component 5 | export struct OmniFilterBottomPanel { 6 | private static DEFAULT_RESET_TEXT = `重置` 7 | private static DEFAULT_CONFIRM_TEXT = `确定` 8 | @StorageLink(OmniTheme.KEY) 9 | baseStyle: OmniThemeStyle = OmniTheme.getDefaultStyle() 10 | @Consume filterStyle: OmniFilterStyle 11 | onResetClick?: () => void 12 | onConfirmClick?: () => void 13 | 14 | build() { 15 | Column() { 16 | Divider() 17 | .color(0xFFCCCCCC) 18 | .height(1) 19 | .width(`100%`) 20 | Row() { 21 | Column() { 22 | Image(this.filterStyle.bottomPanelStyle?.resetIcon ?? $r('app.media.icon_filter_reset')) 23 | .width(24) 24 | .height(24) 25 | Text(this.filterStyle.bottomPanelStyle?.resetText ?? OmniFilterBottomPanel.DEFAULT_RESET_TEXT) 26 | .fontColor(this.filterStyle?.bottomPanelStyle?.resetTextStyle?.fontColor ?? Color.Black) 27 | .fontWeight(this.filterStyle?.bottomPanelStyle?.resetTextStyle?.fontWeight ?? FontWeight.Medium) 28 | .fontSize(this.filterStyle?.bottomPanelStyle?.resetTextStyle?.fontSize ?? this.baseStyle.fontSizeMd) 29 | } 30 | .padding({ left: 12, right: 20 }) 31 | .justifyContent(FlexAlign.Center) 32 | .alignItems(HorizontalAlign.Center) 33 | .onClick(() => { 34 | this.onResetClick?.() 35 | }) 36 | 37 | Button(this.filterStyle.bottomPanelStyle?.confirmText ?? OmniFilterBottomPanel.DEFAULT_CONFIRM_TEXT, 38 | { type: ButtonType.Normal, stateEffect: true }) 39 | .fontColor(this.filterStyle?.bottomPanelStyle?.confirmTextStyle?.fontColor ?? Color.White) 40 | .fontWeight(this.filterStyle?.bottomPanelStyle?.confirmTextStyle?.fontWeight ?? FontWeight.Medium) 41 | .fontSize(this.filterStyle?.bottomPanelStyle?.confirmTextStyle?.fontSize ?? this.baseStyle.fontSizeMd) 42 | .width('100%') 43 | .backgroundColor(this.filterStyle?.bottomPanelStyle?.confirmButtonColor ?? this.baseStyle.primary) 44 | .borderRadius(8) 45 | .layoutWeight(1) 46 | .onClick(() => { 47 | this.onConfirmClick?.() 48 | }) 49 | } 50 | .padding({ 51 | left: 10, 52 | top: 10, 53 | right: 10, 54 | bottom: 10 55 | }) 56 | .alignItems(VerticalAlign.Center) 57 | } 58 | .backgroundColor(Color.White) 59 | .width('100%') 60 | } 61 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/filterbar/component/OmniFilterGridItem.ets: -------------------------------------------------------------------------------- 1 | import { OmniFilterItemBean } from "../bean/OmniFilterItemBean" 2 | import { OmniTheme, OmniThemeStyle } from "../../../theme/OmniTheme" 3 | import { OmniFilterStyle } from "../OmniFilterThemeConfig" 4 | 5 | @Component 6 | @Preview 7 | export struct OmniFilterGridItem { 8 | private static DEFAULT_ROW_COUNT = 3//默认网格数 9 | @StorageLink(OmniTheme.KEY) 10 | baseStyle: OmniThemeStyle = OmniTheme.getDefaultStyle() 11 | @Consume filterStyle: OmniFilterStyle 12 | @Prop item: OmniFilterItemBean 13 | @Prop focusedIndex: number 14 | @Prop listIndex: number 15 | @Prop @Require componentWidth: number = 0 16 | gridItemSelect?: () => void 17 | 18 | build() { 19 | Column() { 20 | Text(`${this.item.title}`) 21 | .fontColor(this.itemFontColor()) 22 | .fontSize(this.itemFontSize()) 23 | .fontWeight(this.itemFontWeight()) 24 | } 25 | .borderRadius(2) 26 | .justifyContent(FlexAlign.Center) 27 | .alignItems(HorizontalAlign.Center) 28 | .width(this.tagWidth()) 29 | .height(34) 30 | .backgroundColor(this.tagBackgroundColor()) 31 | .onClick(() => { 32 | //TODO 最大选择数量 33 | this.gridItemSelect?.() 34 | }) 35 | } 36 | 37 | private tagWidth(): number { 38 | const baseWidth = this.componentWidth 39 | const rowCount = this.filterStyle.gridStyle?.rowCount ?? OmniFilterGridItem.DEFAULT_ROW_COUNT 40 | return Math.floor( 41 | (baseWidth - 40 - 12 * (rowCount - 1)) / rowCount 42 | ); 43 | } 44 | 45 | private itemFontSize(): number | string | Resource { 46 | if (this.isItemFocused()) { 47 | return this.filterStyle.gridStyle?.itemSelectedTextStyle?.fontSize ?? this.baseStyle.fontSizeMd 48 | } else { 49 | return this.filterStyle.gridStyle?.itemTextStyle?.fontSize ?? this.baseStyle.fontSizeMd 50 | } 51 | } 52 | 53 | private itemFontColor(): ResourceColor { 54 | if (this.isItemFocused()) { 55 | return this.filterStyle.gridStyle?.itemSelectedTextStyle?.fontColor ?? this.baseStyle.primary 56 | } else { 57 | return this.filterStyle.gridStyle?.itemTextStyle?.fontColor ?? Color.Black 58 | } 59 | } 60 | 61 | private itemFontWeight(): number | FontWeight | string { 62 | if (this.isItemFocused()) { 63 | return this.filterStyle.gridStyle?.itemSelectedTextStyle?.fontWeight ?? FontWeight.Regular 64 | } else { 65 | return this.filterStyle.gridStyle?.itemTextStyle?.fontWeight ?? FontWeight.Regular 66 | } 67 | } 68 | 69 | private tagBackgroundColor(): ResourceColor { 70 | if (this.isItemFocused()) { 71 | return this.filterStyle.gridStyle?.itemSelectedBgColor ?? this.baseStyle.primaryColorWithOpacity(0.12) 72 | } else { 73 | return this.filterStyle.gridStyle?.itemBgColor ?? 0xFFF8F8F8 74 | } 75 | } 76 | 77 | private isItemFocused(): boolean { 78 | let isFocused = this.focusedIndex == this.listIndex; 79 | if (!isFocused && this.item.isSelected && this.item.isInLastLevel()) { 80 | isFocused = true; 81 | } 82 | return isFocused; 83 | } 84 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/filterbar/component/OmniFilterMenuItem.ets: -------------------------------------------------------------------------------- 1 | import { OmniTheme, OmniThemeStyle } from "../../../theme/OmniTheme" 2 | import { OmniFilterMenuItemBean } from "../bean/OmniFilterMenuItemBean" 3 | import { OmniFilterStyle } from "../OmniFilterThemeConfig" 4 | 5 | @Component 6 | export struct OmniFilterMenuItemComponent { 7 | @ObjectLink menuItem: OmniFilterMenuItemBean 8 | @Consume filterStyle: OmniFilterStyle 9 | @StorageLink(OmniTheme.KEY) 10 | baseStyle: OmniThemeStyle = OmniTheme.getDefaultStyle() 11 | 12 | build() { 13 | Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { 14 | Text(this.menuItem.menuTitle) 15 | .fontSize(this.menuFontSize()) 16 | .fontColor(this.menuFontColor()) 17 | .fontWeight(this.menuFontWeight()) 18 | .maxLines(1) 19 | .textOverflow({ overflow: TextOverflow.Ellipsis }) 20 | .ellipsisMode(EllipsisMode.END) 21 | .flexBasis('auto') 22 | Image(this.menuItem.active ? $r('app.media.icon_arrow_up') : $r('app.media.icon_arrow_down')) 23 | .width(12) 24 | .height(6) 25 | .fillColor(this.menuFontColor()) 26 | .margin({ left: 4 }) 27 | } 28 | .width(`100%`) 29 | .padding({ left: 10, right: 10 }) 30 | } 31 | 32 | private menuFontSize(): number | string | Resource { 33 | if (this.menuItem.isHighLight || this.menuItem.active) { 34 | return this.filterStyle.menuStyle?.menuSelectedTextStyle?.fontSize ?? this.baseStyle.fontSizeLg 35 | } else { 36 | return this.filterStyle.menuStyle?.menuTextStyle?.fontSize ?? this.baseStyle.fontSizeLg 37 | } 38 | } 39 | 40 | private menuFontColor(): ResourceColor { 41 | if (this.menuItem.isHighLight || this.menuItem.active) { 42 | return this.filterStyle.menuStyle?.menuSelectedTextStyle?.fontColor ?? this.baseStyle.primary 43 | } else { 44 | return this.filterStyle.menuStyle?.menuTextStyle?.fontColor ?? Color.Black 45 | } 46 | } 47 | 48 | private menuFontWeight(): number | FontWeight | string { 49 | if (this.menuItem.isHighLight || this.menuItem.active) { 50 | return this.filterStyle.menuStyle?.menuSelectedTextStyle?.fontWeight ?? FontWeight.Regular 51 | } else { 52 | return this.filterStyle.menuStyle?.menuTextStyle?.fontWeight ?? FontWeight.Regular 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/filterbar/converter/OmniFilterConverter.ets: -------------------------------------------------------------------------------- 1 | import { OmniFilterItemBean, OmniFilterShowType, OmniFilterType } from '../bean/OmniFilterItemBean'; 2 | import HashMap from '@ohos.util.HashMap'; 3 | import { TextUtils } from '../../../utils/TextUtils'; 4 | import { OmniFilterUtil } from '../util/OmniFilterUtil'; 5 | 6 | // 筛选项数据转换器接口 7 | export interface OmniFilterConverterDelegate { 8 | convertSelectedData(selectedResults: OmniFilterItemBean[]): Map; 9 | } 10 | 11 | // 默认筛选项数据转换器 12 | export class DefaultFilterConverter implements OmniFilterConverterDelegate { 13 | constructor() { 14 | } 15 | 16 | // 将选中的数据转换为 Map 17 | convertSelectedData(selectedResults: OmniFilterItemBean[]): Map { 18 | return getFilterParams(selectedResults); 19 | } 20 | } 21 | 22 | function getFilterParams(selectedResults: OmniFilterItemBean[] | null): Map { 23 | const params = new Map(); 24 | 25 | if (!selectedResults) return params; 26 | 27 | for (const menuItemEntity of selectedResults) { 28 | if (menuItemEntity.showType === OmniFilterShowType.more) { 29 | //TODO 更多的结构是否区别 30 | const childParams = getFilterParams(menuItemEntity.children); 31 | childParams.forEach((value, key) => params.set(key, value)); 32 | } else { 33 | 34 | // 2. 查找层级为 1、2、3 的选中项的参数 35 | const levelCount = OmniFilterUtil.getTotalLevel(menuItemEntity); 36 | if (levelCount === 1) { 37 | mergeMap(params, getCurrentSelectedFilterParams(menuItemEntity)); 38 | } else if (levelCount === 2) { 39 | mergeMap(params, getCurrentSelectedFilterParams(menuItemEntity)); 40 | menuItemEntity.children.forEach(firstLevelItem => { 41 | mergeMap(params, getCurrentSelectedFilterParams(firstLevelItem)); 42 | }); 43 | } else if (levelCount === 3) { 44 | mergeMap(params, getCurrentSelectedFilterParams(menuItemEntity)); 45 | menuItemEntity.children.forEach(firstLevelItem => { 46 | mergeMap(params, getCurrentSelectedFilterParams(firstLevelItem)); 47 | firstLevelItem.children.forEach(secondLevelItem => { 48 | mergeMap(params, getCurrentSelectedFilterParams(secondLevelItem)); 49 | }); 50 | }); 51 | } 52 | } 53 | } 54 | 55 | return params; 56 | } 57 | 58 | // 获取当前选中项的筛选数据 59 | function getCurrentSelectedFilterParams(filterItem: OmniFilterItemBean): Map { 60 | const params = new Map(); 61 | const parentKey = filterItem.key; 62 | 63 | const selectedEntities = filterItem.children 64 | .filter(child => child.isSelected && !TextUtils.isBlank(child.value)) 65 | .map(child => child.value); 66 | 67 | const selectedParams = selectedEntities.length > 0 ? selectedEntities.join(",") : ""; 68 | 69 | if (!TextUtils.isBlank(selectedParams) && !TextUtils.isBlank(parentKey)) { 70 | params.set(parentKey!, selectedParams); 71 | } 72 | 73 | return params; 74 | } 75 | 76 | // 合并 Map 77 | function mergeMap(target: Map, source: Map) { 78 | source.forEach((value, key) => target.set(key, value)); 79 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/gallery/OmniSummary.ets: -------------------------------------------------------------------------------- 1 | import { OmniTheme, OmniThemeStyle } from "../../theme/OmniTheme" 2 | 3 | @Component 4 | export struct OmniSummary { 5 | /** 6 | * 组件入参,必填参数 7 | */ 8 | @Prop @Require config: OmniSummaryConfig 9 | /** 10 | * item的点击事件,如查看大图 11 | */ 12 | onItemClick?: (index: number, items: OmniSummaryItem[]) => void 13 | @State private columnsTemplate: string = '' 14 | 15 | @StorageLink(OmniTheme.KEY) 16 | baseStyle: OmniThemeStyle = OmniTheme.getDefaultStyle() 17 | 18 | aboutToAppear(): void { 19 | for (let i = 0; i < this.config.countPerRow; i++) { 20 | this.columnsTemplate += '1fr ' 21 | } 22 | this.columnsTemplate.trimEnd() 23 | } 24 | 25 | @Builder 26 | buildSummaryItem(item: OmniSummaryItem, pIndex: number) { 27 | Column() { 28 | Text(`${item.title}(${item.images.length})`) 29 | .fontSize(20) 30 | .fontColor('#1F2326') 31 | .margin({ bottom: 20 }) 32 | .fontWeight(FontWeight.Bold) 33 | 34 | Grid() { 35 | ForEach(item.images, (image: string) => { 36 | GridItem() { 37 | Image(image) 38 | .width('100%') 39 | .aspectRatio(1) 40 | .objectFit(ImageFit.Cover) 41 | .draggable(false) 42 | .animation({ curve: Curve.Sharp, duration: 300 }) 43 | .onClick(() => { 44 | this.onItemClick?.(pIndex, this.config.items) 45 | }) 46 | } 47 | }, (item: string, index: number) => item + index) 48 | } 49 | .width('100%') 50 | .editMode(false) 51 | .columnsGap(12) 52 | .rowsGap(12) 53 | .scrollBar(BarState.Off) 54 | .supportAnimation(true) 55 | .enableScrollInteraction(true) 56 | .columnsTemplate(this.columnsTemplate) 57 | } 58 | .alignItems(HorizontalAlign.Start) 59 | .margin({ bottom: 20 }) 60 | } 61 | 62 | build() { 63 | Scroll() { 64 | List() { 65 | ForEach(this.config.items, (item: OmniSummaryItem, index: number) => { 66 | ListItem() { 67 | this.buildSummaryItem(item, index) 68 | } 69 | }) 70 | }.divider({ 71 | strokeWidth: 15, 72 | color: '#ffffffff' 73 | }) 74 | }.nestedScroll({ 75 | scrollForward: NestedScrollMode.SELF_FIRST, 76 | scrollBackward: NestedScrollMode.SELF_FIRST 77 | }) 78 | } 79 | } 80 | 81 | interface OmniSummaryConfig { 82 | items: OmniSummaryItem[], 83 | countPerRow: number 84 | } 85 | 86 | export interface OmniSummaryItem { 87 | title: string 88 | images: string[] 89 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/guide/core/OmniGuideBuilder.ets: -------------------------------------------------------------------------------- 1 | import { GuidePage } from '../model/GuidePage'; 2 | import { OnGuideChangedListener } from '../interface/OnGuideChangedListener'; 3 | import { OnPageChangedListener } from '../interface/OnPageChangedListener'; 4 | 5 | export class OmniGuideBuilder { 6 | // 标签名称 7 | label: string = ''; 8 | // 是否总显示引导页 9 | alwaysShowGuide: boolean = false; 10 | // 设置引导页显示次数 11 | showCounts: number = 1; 12 | // 引导页页面集合 13 | guidePages: GuidePage[] = new Array(); 14 | // 页面显示状态变化监听 15 | visibleStateChangeListener: OnGuideChangedListener | null = null; 16 | // 页面页数切换监听 17 | pageChangedListener: OnPageChangedListener | null = null; 18 | 19 | /** 20 | * 设置引导页名称,必须设置,用于存储引导页显示次数 21 | * @param label 引导页标签名称 22 | * @returns 引导页组件的配置项 23 | */ 24 | public setLabel(label: string): OmniGuideBuilder { 25 | this.label = label; 26 | return this; 27 | } 28 | 29 | /** 30 | * 设置引导页的显示次数 31 | * @param count 显示次数 32 | * @returns 引导页组件的配置项 33 | */ 34 | public setShowCounts(count: number): OmniGuideBuilder { 35 | this.showCounts = count; 36 | return this; 37 | } 38 | 39 | /** 40 | * 是否总是显示引导页,即是否无限次的显示 41 | * 默认为false,如果设置为true,{@Link HighLightGuideBuilder#setShowCounts}将失效 42 | * @param isAlways 永久显示 43 | * @returns 引导页组件的配置项 44 | */ 45 | public alwaysShow(isAlways: boolean): OmniGuideBuilder { 46 | this.alwaysShowGuide = isAlways; 47 | return this; 48 | } 49 | 50 | /** 51 | * 添加引导页 52 | * @param page 引导页对象 53 | * @returns 引导页组件的配置项 54 | */ 55 | public addGuidePage(page: GuidePage): OmniGuideBuilder { 56 | this.guidePages.push(page); 57 | return this; 58 | } 59 | 60 | /** 61 | * 添加引导页组件的可见状态监听 62 | * @param listener 状态监听器 63 | * @returns 引导页组件的配置项 64 | */ 65 | public setOnGuideChangedListener(listener: OnGuideChangedListener | null): OmniGuideBuilder { 66 | this.visibleStateChangeListener = listener; 67 | return this; 68 | } 69 | 70 | /** 71 | * 添加页面切换监听器 72 | * @param listener 页面切换监听器 73 | * @returns 引导页组件的配置项 74 | */ 75 | public setOnPageChangedListener(listener: OnPageChangedListener | null): OmniGuideBuilder { 76 | this.pageChangedListener = listener; 77 | return this; 78 | } 79 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/guide/interface/HighLight.ets: -------------------------------------------------------------------------------- 1 | import { HighLightOptions } from '../model/HighLightOptions'; 2 | import { RectF } from '../model/RectF'; 3 | import { HighLightShape } from '../model/HighLightShape'; 4 | 5 | export default interface HighLight { 6 | 7 | /** 8 | * 获取高亮区域的类型 9 | * @returns 高亮区域的类型:组件id或指定区域 10 | */ 11 | isComponentHighLight(): boolean | string; 12 | 13 | /** 14 | * 获取图形shape类型 15 | * @returns shape类型 16 | */ 17 | getShape(): HighLightShape; 18 | 19 | /** 20 | * 获取高亮图形的区域坐标,组件要求必传id,rectF区域需要为相对于父组件的相对坐标,坐标值需要转换为vp,不能直接为px 21 | * @param parentId 高亮区域为组件时,必传,父组件id:__HighLightGuideComponentContainer__ + 组件创建时的时间戳,id需要整个应用内唯一 22 | * @param componentId 高亮区域为组件时,必传,组件id需要整个应用内唯一 23 | * @returns 返回高亮区域的坐标,单位为vp 24 | */ 25 | getRectF(parentId?: string, componentId?: string): RectF | null; 26 | 27 | /** 28 | * 当shape为为CIRCLE时调用此方法获取半径 29 | * @param parentId 高亮区域为组件时,必传,父组件id: __HighLightGuideComponentContainer__ + 组件创建时的时间戳,id需要整个应用内唯一 30 | * @returns 圆的半径 31 | */ 32 | getRadius(parentId?: string): number; 33 | 34 | /** 35 | * 获取圆角弧度,仅当shape = HighLightShape.ROUND_RECTANGLE才调用此方法 36 | * @returns 圆角矩形的圆角弧度 37 | */ 38 | getRound(): number; 39 | 40 | /** 41 | * 获取高亮区域的额外参数,可设置高亮区域的点击事件,重绘高亮区域的图形,是否强制更新组件坐标(该属性用于高亮区域为组件id时有效) 42 | * @returns 高亮区域的额外配置 43 | */ 44 | getOptions(): HighLightOptions | null; 45 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/guide/interface/OnClickListener.ets: -------------------------------------------------------------------------------- 1 | export interface OnClickListener { 2 | 3 | /** 4 | * 高亮区域的点击事件 5 | */ 6 | onClick: () => void; 7 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/guide/interface/OnGuideChangedListener.ets: -------------------------------------------------------------------------------- 1 | import { Controller } from '../core/Controller'; 2 | 3 | export interface OnGuideChangedListener { 4 | 5 | /** 6 | * 当前引导页组件显示时回调 7 | * @param controller 引导页组件控制器 8 | */ 9 | onShowed: (controller: Controller) => void; 10 | 11 | /** 12 | * 当前引导页组件消失时回调 13 | * @param controller 引导页组件控制器 14 | */ 15 | onRemoved: (controller: Controller) => void; 16 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/guide/interface/OnGuideLifeCycleListener.ets: -------------------------------------------------------------------------------- 1 | export default interface OnGuideLifeCycleListener { 2 | 3 | /** 4 | * 组件蒙版即将加载到页面上,对应onAppear回调(在创建自定义组件的新实例后,在执行build()函数之前执行) 5 | */ 6 | _onGuideAppear: () => void; 7 | 8 | /** 9 | * 组件蒙版即将从页面上移除,对应onDisAppear回调(在自定义组件析构销毁之前执行) 10 | */ 11 | _onGuideDisAppear: () => void; 12 | 13 | /** 14 | * 指示组件的动画是否正在运行 15 | * @param isAnimationRunning 是否有动画正在运行 16 | */ 17 | _onAnimationRunning: (isAnimationRunning: boolean) => void; 18 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/guide/interface/OnHighLightDrewListener.ets: -------------------------------------------------------------------------------- 1 | import { RectF } from '../model/RectF'; 2 | 3 | export interface OnHighLightDrewListener { 4 | 5 | /** 6 | * 自定义高亮区域的显示图形 7 | * @param canvasContext2d 画布控制上下文 8 | * @param rectF 高亮区域 9 | */ 10 | onHighLightDrew: (canvasContext2d: CanvasRenderingContext2D, rectF: RectF) => void; 11 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/guide/interface/OnPageChangedListener.ets: -------------------------------------------------------------------------------- 1 | export interface OnPageChangedListener { 2 | 3 | /** 4 | * 当前显示的引导页页面的index 5 | * @param pageIndex 页面索引 6 | */ 7 | onPageChanged: (pageIndex: number) => void; 8 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/guide/model/BubbleIndicator.ets: -------------------------------------------------------------------------------- 1 | import { PopupPosition } from '../../popup/PopupPosition'; 2 | 3 | export class BubbleIndicator { 4 | private _componentId: string = ""; 5 | 6 | public get componentId(): string { 7 | return this._componentId; 8 | } 9 | 10 | private _bubblePosition: BubblePosition = BubblePosition.BOTTOM; 11 | 12 | public get popupPosition(): PopupPosition { 13 | switch (this._bubblePosition) { 14 | case BubblePosition.TOP: 15 | return PopupPosition.TOP; 16 | case BubblePosition.BOTTOM: 17 | return PopupPosition.BOTTOM; 18 | case BubblePosition.LEFT: 19 | return PopupPosition.LEFT; 20 | case BubblePosition.RIGHT: 21 | return PopupPosition.RIGHT; 22 | } 23 | } 24 | 25 | private _bubbleBean?: BubbleBean | undefined; 26 | 27 | public get bubbleBean(): BubbleBean | undefined { 28 | return this._bubbleBean; 29 | } 30 | 31 | constructor(componentId: string, bubbleBean: BubbleBean, bubblePosition?: BubblePosition) { 32 | this._componentId = componentId; 33 | this._bubblePosition = bubblePosition ?? BubblePosition.BOTTOM; 34 | this._bubbleBean = bubbleBean; 35 | } 36 | } 37 | 38 | export class BubbleBean { 39 | private _title: string = ""; 40 | 41 | public get title(): string { 42 | return this._title; 43 | } 44 | 45 | private _content: string = ""; 46 | 47 | public get content(): string { 48 | return this._content; 49 | } 50 | 51 | constructor(title: string, content: string) { 52 | this._title = title; 53 | this._content = content; 54 | } 55 | } 56 | 57 | export enum BubblePosition { 58 | TOP, 59 | BOTTOM, 60 | LEFT, 61 | RIGHT 62 | } 63 | 64 | @Builder 65 | export function bubbleBuilder(data: BubbleBean) { 66 | Column() { 67 | Text(data.title) 68 | .fontSize(15) 69 | .fontColor(Color.Black) 70 | Text(data.content) 71 | .fontSize(14) 72 | .fontColor(Color.Gray) 73 | .margin({ top: 8 }) 74 | }.alignItems(HorizontalAlign.Start) 75 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/guide/model/HighLightInfoOfRectF.ets: -------------------------------------------------------------------------------- 1 | import HighLight from '../interface/HighLight'; 2 | import { HighLightOptions } from './HighLightOptions'; 3 | import { HighLightShape } from './HighLightShape'; 4 | import { RectF } from './RectF'; 5 | 6 | export default class HighLightInfoOfRectF implements HighLight { 7 | private rectF: RectF | null = null; 8 | private shape: HighLightShape = HighLightShape.ROUND_RECTANGLE; 9 | private round: number = 0; 10 | private options: HighLightOptions | null = null; 11 | 12 | constructor(rectF: RectF, shape: HighLightShape, round?: number) { 13 | this.rectF = rectF; 14 | this.shape = shape; 15 | this.round = round ? round : 0; 16 | } 17 | 18 | /** 19 | * 设置高亮区域的额外配置 20 | * @param options 额外配置 21 | */ 22 | public setOptions(options: HighLightOptions): void { 23 | this.options = options; 24 | } 25 | 26 | /** 27 | * 获取高亮区域的额外配置 28 | */ 29 | getOptions(): HighLightOptions | null { 30 | return this.options; 31 | } 32 | 33 | /** 34 | * 获取圆角矩形的圆角弧度,仅当shape = HighLightShape.ROUND_RECTANGLE 时调用此方法 35 | * @returns 圆角矩形的圆角弧度 36 | */ 37 | getRound(): number { 38 | return this.round; 39 | } 40 | 41 | /** 42 | * 获取圆形的半径,仅当shape = HighLightShape.CIRCLE时调用此方法获取半径 43 | * @param parentId 父布局id 44 | * @returns 返回圆的半径 45 | */ 46 | getRadius(parentId?: string): number { 47 | if (!this.rectF) { 48 | return 0; 49 | } 50 | return Math.min(this.rectF.getWidth() / 2, this.rectF.getHeight() / 2); 51 | } 52 | 53 | /** 54 | * 获取高亮图形的区域坐标,组件要求必传id,rectF区域需要为相对于父组件的相对坐标,坐标值需要转换为vp,不能直接为px 55 | * @param parentId 高亮区域为组件时,必传,父组件id:__HighLightGuideComponentContainer__ + 组件创建时的时间戳,id需要整个应用内唯一 56 | * @param componentId 高亮区域为组件时,必传,组件id需要整个应用内唯一 57 | * @returns 返回高亮区域的坐标,单位为vp 58 | */ 59 | getRectF(parentId?: string, componentId?: string): RectF | null { 60 | return this.rectF; 61 | } 62 | 63 | /** 64 | * 获取高亮区域的图形类型 65 | */ 66 | getShape() { 67 | return this.shape; 68 | } 69 | 70 | /** 71 | * 高亮区域的类型 72 | * @returns 返回组件id 即高亮区域为组件类型,否则为指定的高亮区域 73 | */ 74 | isComponentHighLight(): string | boolean { 75 | return false; 76 | } 77 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/guide/model/HighLightOptions.ets: -------------------------------------------------------------------------------- 1 | import { OnClickListener } from '../interface/OnClickListener'; 2 | import { OnHighLightDrewListener } from '../interface/OnHighLightDrewListener'; 3 | 4 | export class HighLightOptions { 5 | public onClickListener: OnClickListener | null = null; 6 | public onHighLightDrewListener: OnHighLightDrewListener | null = null; 7 | public fetchLocationEveryTime: boolean = false; 8 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/guide/model/HighLightOptionsBuilder.ets: -------------------------------------------------------------------------------- 1 | import { OnClickListener } from '../interface/OnClickListener'; 2 | import { OnHighLightDrewListener } from '../interface/OnHighLightDrewListener'; 3 | import { HighLightOptions } from './HighLightOptions'; 4 | 5 | export class HighLightOptionsBuilder { 6 | private options: HighLightOptions; 7 | 8 | constructor() { 9 | this.options = new HighLightOptions(); 10 | } 11 | 12 | /** 13 | * 高亮点击事件 14 | * @param listener 点击事件回调 15 | * @returns 额外配置构建类 16 | */ 17 | public setOnClickListener(listener: OnClickListener | null): HighLightOptionsBuilder { 18 | this.options.onClickListener = listener; 19 | return this; 20 | } 21 | 22 | /** 23 | * 为高亮区域添加重绘监听 24 | * @param listener 重绘高亮区域图形的监听 25 | * @returns 额外配置构建类 26 | */ 27 | public setOnHighLightDrewListener(listener: OnHighLightDrewListener | null): HighLightOptionsBuilder { 28 | this.options.onHighLightDrewListener = listener; 29 | return this; 30 | } 31 | 32 | /** 33 | * 是否每次显示引导页都重新获取组件坐标 34 | * @param isFetchLocation 是否每次显示引导页都重新获取组件坐标 35 | * @returns 额外配置构建类 36 | */ 37 | public isFetchLocationEveryTime(isFetchLocation: boolean): HighLightOptionsBuilder { 38 | this.options.fetchLocationEveryTime = isFetchLocation; 39 | return this; 40 | } 41 | 42 | /** 43 | * 获取高亮区域的额外配置项 44 | * @returns 45 | */ 46 | public build(): HighLightOptions { 47 | return this.options; 48 | } 49 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/guide/model/HighLightShape.ets: -------------------------------------------------------------------------------- 1 | export enum HighLightShape { 2 | CIRCLE, // 圆形 3 | RECTANGLE, // 矩形 4 | OVAL, // 椭圆 5 | ROUND_RECTANGLE // 圆角矩形 6 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/guide/model/ObservedMaskVisibleState.ets: -------------------------------------------------------------------------------- 1 | @Observed 2 | export default class ObservedMaskVisibleState { 3 | private globalShowGuideMask: boolean = false; 4 | 5 | /** 6 | * 设置引导页蒙版显示状态 7 | * @param show 是否显示引导页蒙版 8 | */ 9 | setShowGuideMask(show: boolean): void { 10 | this.globalShowGuideMask = show; 11 | } 12 | 13 | /** 14 | * 获取引导页蒙版显示状态 15 | * @returns 蒙版是否正在显示 16 | */ 17 | isShowGuideMask() { 18 | return this.globalShowGuideMask; 19 | } 20 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/guide/model/ObservedPageIndex.ets: -------------------------------------------------------------------------------- 1 | @Observed 2 | export default class ObservedPageIndex { 3 | private globalCurrentPageIndex: number = -1; 4 | 5 | /** 6 | * 设置引导页index 7 | * @param index 引导页索引 8 | */ 9 | setCurrentPageIndex(index: number): void { 10 | this.globalCurrentPageIndex = index; 11 | } 12 | 13 | /** 14 | * 获取引导页的索引 15 | * @returns 引导页索引 16 | */ 17 | getCurrentPageIndex() { 18 | return this.globalCurrentPageIndex; 19 | } 20 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/guide/model/RectF.ets: -------------------------------------------------------------------------------- 1 | export class RectF { 2 | public left: number = 0; 3 | public top: number = 0; 4 | public right: number = 0; 5 | public bottom: number = 0; 6 | 7 | constructor(rect: RectF); 8 | 9 | constructor(left: number, top: number, right: number, bottom: number); 10 | 11 | constructor(left: number | RectF, top?: number, right?: number, bottom?: number) { 12 | if (typeof left === 'number') { 13 | this.check(left, top, right, bottom); 14 | this.left = left ? left : 0; 15 | this.top = top ? top : 0; 16 | this.right = right ? right : 0; 17 | this.bottom = bottom ? bottom : 0; 18 | } else if (left instanceof RectF) { 19 | this.createByRectF(left); 20 | } 21 | } 22 | 23 | /** 24 | * 通过rectF对象创建rectF 25 | * @param rectF 对象 26 | * @returns 27 | */ 28 | private createByRectF(rectF: RectF): RectF { 29 | this.check(rectF.left, rectF.top, rectF.right, rectF.bottom); 30 | this.left = rectF.left; 31 | this.top = rectF.top; 32 | this.right = rectF.right; 33 | this.bottom = rectF.bottom; 34 | return this; 35 | } 36 | 37 | /** 38 | * 获取矩形中心点X轴坐标 39 | * @returns x坐标 40 | */ 41 | public getCenterX(): number { 42 | this.check(this.left, this.top, this.right, this.bottom); 43 | return this.left + (this.right - this.left) / 2; 44 | } 45 | 46 | /** 47 | * 获取矩形中心点Y轴坐标 48 | * @returns Y坐标 49 | */ 50 | public getCenterY(): number { 51 | this.check(this.left, this.top, this.right, this.bottom); 52 | return this.top + (this.bottom - this.top) / 2; 53 | } 54 | 55 | /** 56 | * 获取矩形的宽 57 | * @returns 矩形区域的宽 58 | */ 59 | public getWidth(): number { 60 | return this.right - this.left; 61 | } 62 | 63 | /** 64 | * 获取矩形的高 65 | * @returns 矩形区域的高 66 | */ 67 | public getHeight(): number { 68 | return this.bottom - this.top; 69 | } 70 | 71 | /** 72 | * 检测矩形区域坐标数据的有效性 73 | * @param left 左上角的X坐标 74 | * @param top 左上角的Y坐标 75 | * @param right 右下角的X坐标 76 | * @param bottom 右下角的Y坐标 77 | */ 78 | private check(left: number | null | undefined, top: number | null | undefined, right: number | null | undefined, 79 | bottom: number | null | undefined): void { 80 | if (left == null || left == undefined || 81 | top == null || top == undefined || 82 | right == null || right == undefined || 83 | bottom == null || bottom == undefined || 84 | right < left || bottom < top) { 85 | throw new Error('please check the rect params'); 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/guide/util/GlobalContext.ts: -------------------------------------------------------------------------------- 1 | export class GlobalContext { 2 | private constructor() { 3 | } 4 | 5 | private static instance: GlobalContext; 6 | public static HILOG_TAG: string = 'HighLightGuide'; 7 | 8 | private _objects = new Map(); 9 | 10 | public static getContext(): GlobalContext { 11 | if (!GlobalContext.instance) { 12 | GlobalContext.instance = new GlobalContext(); 13 | } 14 | return GlobalContext.instance; 15 | } 16 | 17 | getObject(value: string): Object | undefined { 18 | return this._objects.get(value); 19 | } 20 | 21 | setObject(key: string, objectClass: Object): void { 22 | this._objects.set(key, objectClass); 23 | } 24 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/imagepicker/OmniImagePickerTrigger.ets: -------------------------------------------------------------------------------- 1 | 2 | 3 | @Component 4 | export struct OmniImagePickerTrigger { 5 | 6 | @Prop triggerImageIcon: ResourceStr 7 | @Link selectUris: Array 8 | @Require goImagePicker?: () => void 9 | 10 | build() { 11 | Column() { 12 | Grid() { 13 | ForEach(this.selectUris, (url: ResourceStr, index: number) => { 14 | GridItem() { 15 | Image(url) 16 | .width('100%') 17 | .aspectRatio(1) 18 | .borderRadius(4) 19 | .onClick(() => { 20 | if (index == 0) { 21 | this.goImagePicker?.() 22 | } 23 | }) 24 | } 25 | .width('100%') 26 | }) 27 | } 28 | .columnsTemplate("1fr 1fr 1fr 1fr") 29 | .columnsGap(5) 30 | .rowsGap(5) 31 | .margin({ 32 | top: 10 33 | }) 34 | .onAppear(() => { 35 | this.selectUris.push(this.triggerImageIcon ?? $r('app.media.image_trigger_add')) 36 | 37 | }) 38 | } 39 | 40 | } 41 | 42 | aboutToAppear(): void { 43 | } 44 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/loading/OmniDotLoadingView.ets: -------------------------------------------------------------------------------- 1 | @Preview 2 | @Component 3 | export struct OmniDotLoadingView { 4 | @Prop noDataText: string = '到底啦~' 5 | @Link loading: boolean 6 | private WIDTH = 8 7 | private DURATION = 200 8 | private colorArray = [0xFFFF552E, 0xFF3E80F8, 0xFF53E7AE, 0xFFFFCE5A] 9 | private scalesArray = [ 10 | [1.0, 0.8, 0.6, 0.4, 0.6, 0.8, 1.0], 11 | [0.8, 1.0, 0.8, 0.6, 0.4, 0.6, 0.8], 12 | [0.6, 0.8, 1.0, 0.8, 0.6, 0.4, 0.6], 13 | [0.4, 0.6, 0.8, 1.0, 0.8, 0.6, 0.4], 14 | ] 15 | private currentIndex: number = 0 16 | @State private scales: number[] = [1.0, 0.8, 0.6, 0.4] 17 | 18 | aboutToAppear() { 19 | this._animateTo() 20 | } 21 | 22 | _animateTo() { 23 | this.getUIContext().animateTo({ 24 | curve: Curve.Linear, 25 | duration: this.DURATION, 26 | onFinish: () => { 27 | this._animateTo() 28 | } 29 | }, () => { 30 | this.currentIndex = (this.currentIndex + 1) % this.scalesArray[0].length 31 | this.scales = this.scalesArray.map(scaleGroup => scaleGroup[this.currentIndex]) 32 | }) 33 | } 34 | 35 | build() { 36 | if (this.loading) { 37 | Row({ space: 4 }) { 38 | ForEach(this.colorArray, (color: number, i) => { 39 | Circle({ width: this.WIDTH, height: this.WIDTH }) 40 | .foregroundColor(color) 41 | .opacity(this.scales[i]) 42 | .scale({ x: this.scales[i], y: this.scales[i] }) 43 | }) 44 | } 45 | } else { 46 | Text(this.noDataText) 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/loading/OmniPageLoading.ets: -------------------------------------------------------------------------------- 1 | import { ComponentContent, PromptAction } from "@kit.ArkUI" 2 | import { OmniTheme, OmniThemeStyle } from "../../theme/OmniTheme" 3 | 4 | @Component 5 | export struct OmniPageLoading { 6 | @StorageLink(OmniTheme.KEY) 7 | private baseStyle: OmniThemeStyle = OmniTheme.getDefaultStyle() 8 | @Prop options?: LoadingOptions = undefined 9 | 10 | build() { 11 | Row() { 12 | Progress({ value: 0, total: 100, type: ProgressType.Ring }) 13 | .width(20) 14 | .color(Color.White) 15 | .style({ strokeWidth: 2, status: ProgressStatus.LOADING }) 16 | Text(this.options?.content ?? '加载中...') 17 | .fontSize(this.options?.theme?.fontSize ?? this.baseStyle.fontSizeLg) 18 | .fontColor(this.options?.theme?.fontColor ?? Color.White) 19 | .fontWeight(this.options?.theme?.fontWeight ?? FontWeight.Medium) 20 | .margin({ left: 6 }) 21 | } 22 | .backgroundColor(this.options?.theme?.backgroundColor ?? this.baseStyle.primary) 23 | .padding(10) 24 | .borderRadius(this.options?.theme?.borderRadius ?? 6) 25 | } 26 | } 27 | 28 | @Builder 29 | function buildLoading(ops?: LoadingOptions) { 30 | OmniPageLoading({ 31 | options: ops 32 | }) 33 | } 34 | 35 | export class OmniLoading { 36 | private static DEFAULT_CONTENT = '加载中...' 37 | private uiContext: UIContext 38 | private promptAction: PromptAction 39 | private compContent?: ComponentContent 40 | 41 | constructor(uiContext: UIContext) { 42 | this.uiContext = uiContext 43 | this.promptAction = uiContext.getPromptAction() 44 | } 45 | 46 | public show(options?: LoadingOptions) { 47 | if (this.compContent === undefined) { 48 | this.compContent = 49 | new ComponentContent(this.uiContext, wrapBuilder(buildLoading), options ?? { content: OmniLoading.DEFAULT_CONTENT }) 50 | } else { 51 | this.compContent.update(options ?? { content: OmniLoading.DEFAULT_CONTENT }) 52 | } 53 | 54 | // 显示 dialog 55 | this.promptAction.openCustomDialog(this.compContent, { 56 | isModal: true, // 弹窗是否为模态窗口,模态窗口有蒙层,非模态窗口无蒙层。 57 | autoCancel: false, // 是否允许点击遮障层退出,true表示关闭弹窗。false表示不关闭弹窗。 58 | alignment: DialogAlignment.Center, 59 | }) 60 | } 61 | 62 | public dismiss() { 63 | this.promptAction.closeCustomDialog(this.compContent).then(() => { 64 | this.compContent?.dispose() 65 | }) 66 | } 67 | } 68 | 69 | export interface LoadingOptions { 70 | content?: string 71 | theme?: LoadingTheme 72 | } 73 | 74 | export interface LoadingTheme { 75 | fontSize?: number | string | Resource 76 | fontColor?: ResourceColor 77 | fontWeight?: FontWeight 78 | backgroundColor?: ResourceColor 79 | borderRadius?: Dimension | BorderRadiuses 80 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/popup/ArrowLocation.ets: -------------------------------------------------------------------------------- 1 | export enum ArrowLocation { 2 | LEFT, 3 | TOP, 4 | RIGHT, 5 | BOTTOM 6 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/popup/BaseAttachPopup.ets: -------------------------------------------------------------------------------- 1 | import { BasePopup } from './BasePopup'; 2 | import { componentUtils } from '@kit.ArkUI'; 3 | import { PopupPosition } from './PopupPosition'; 4 | 5 | /** 6 | * 依附弹窗窗口基类 7 | */ 8 | export abstract class BaseAttachPopup extends BasePopup { 9 | constructor(customWrappedBuilder: WrappedBuilder) { 10 | super(customWrappedBuilder); 11 | } 12 | 13 | /** 14 | * Popup显示之前,可做一些数据处理 15 | */ 16 | beforeShow(): void { 17 | if (this.attachViewId != null) { 18 | let componentInfo = componentUtils.getRectangleById(this.attachViewId) 19 | this.popupConfig.attachViewComponentInfo = componentInfo 20 | const y = componentInfo.screenOffset.y 21 | const x = componentInfo.screenOffset.x 22 | const h = componentInfo.size.height 23 | const w = componentInfo.size.width 24 | const yOffset = px2vp(y) 25 | const xOffset = px2vp(x) 26 | const height = px2vp(h) 27 | const width = px2vp(w) 28 | if (this.popupConfig.popupPosition == PopupPosition.TOP) { 29 | //向上弹窗 30 | this.dialogOptions.alignment = DialogAlignment.BottomStart 31 | this.dialogOptions.offset = { 32 | dx: 0, 33 | dy: -(px2vp(this.screenHeight) - yOffset) + this.getAttachMargin() 34 | } 35 | } else if (this.popupConfig.popupPosition == PopupPosition.LEFT) { 36 | //向左弹窗 37 | this.dialogOptions.alignment = DialogAlignment.TopEnd 38 | this.dialogOptions.offset = { 39 | dx: -(px2vp(this.screenWidth) - xOffset) + this.getAttachMargin(), 40 | dy: 0 41 | } 42 | } else if (this.popupConfig.popupPosition == PopupPosition.RIGHT) { 43 | //向右弹窗 44 | this.dialogOptions.alignment = DialogAlignment.TopStart 45 | this.dialogOptions.offset = { 46 | dx: xOffset + width + this.getAttachMargin(), 47 | dy: 0 48 | } 49 | } else { 50 | //向下 51 | this.dialogOptions.alignment = DialogAlignment.TopStart 52 | this.dialogOptions.offset = { 53 | dx: 0, 54 | dy: yOffset + height + this.getAttachMargin() 55 | } 56 | } 57 | } 58 | } 59 | 60 | getAttachMargin(): number { 61 | if (this.popupConfig.popupPosition == PopupPosition.TOP) { 62 | return -this.popupConfig.attachMargin 63 | } else if (this.popupConfig.popupPosition == PopupPosition.LEFT) { 64 | return -this.popupConfig.attachMargin 65 | } else if (this.popupConfig.popupPosition == PopupPosition.RIGHT) { 66 | return this.popupConfig.attachMargin 67 | } else { 68 | return this.popupConfig.attachMargin 69 | } 70 | 71 | } 72 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/popup/BubblePopup.ets: -------------------------------------------------------------------------------- 1 | import { ArrowLocation } from './ArrowLocation'; 2 | import { PopupPosition } from './PopupPosition'; 3 | import { PopupType } from './PopupType'; 4 | import { BaseAttachPopup } from './BaseAttachPopup'; 5 | 6 | /** 7 | * 气泡弹窗 8 | */ 9 | export class BubblePopup extends BaseAttachPopup { 10 | /** 11 | * 默认阴影半径 12 | */ 13 | private readonly defaultShadowRadius: number = 15 14 | 15 | constructor(customBuilder: WrappedBuilder) { 16 | super(customBuilder) 17 | this.popupType = PopupType.BUBBLE 18 | } 19 | 20 | /** 21 | * Popup显示之前,可做一些数据处理 22 | */ 23 | beforeShow(): void { 24 | if (this.popupConfig.shadowRadius == null) { 25 | this.popupConfig.shadowRadius = this.defaultShadowRadius 26 | } 27 | this.popupConfig.wrap = true 28 | super.beforeShow() 29 | //处理箭头方向 30 | if (this.popupConfig.popupPosition == PopupPosition.TOP) { 31 | this.popupConfig.arrowLocation = ArrowLocation.BOTTOM 32 | } else if (this.popupConfig.popupPosition == PopupPosition.LEFT) { 33 | this.popupConfig.arrowLocation = ArrowLocation.RIGHT 34 | } else if (this.popupConfig.popupPosition == PopupPosition.RIGHT) { 35 | this.popupConfig.arrowLocation = ArrowLocation.LEFT 36 | } else { 37 | this.popupConfig.arrowLocation = ArrowLocation.TOP 38 | } 39 | } 40 | 41 | getAttachMargin(): number { 42 | if (this.popupConfig.popupPosition == PopupPosition.TOP) { 43 | return -this.popupConfig.attachMargin + (this.popupConfig.shadowRadius ?? 0) 44 | } else if (this.popupConfig.popupPosition == PopupPosition.LEFT) { 45 | return -this.popupConfig.attachMargin + (this.popupConfig.shadowRadius ?? 0) 46 | } else if (this.popupConfig.popupPosition == PopupPosition.RIGHT) { 47 | return this.popupConfig.attachMargin - (this.popupConfig.shadowRadius ?? 0) 48 | } else { 49 | return this.popupConfig.attachMargin - (this.popupConfig.shadowRadius ?? 0) 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/popup/Config.ets: -------------------------------------------------------------------------------- 1 | import { PopupConfig } from './PopupConfig' 2 | import { promptAction } from '@kit.ArkUI' 3 | import { PopupInfo } from './entity/PopupInfo' 4 | 5 | export class Config { 6 | /** 7 | * 弹窗基础配置参数 8 | */ 9 | static dialogOptions: promptAction.BaseDialogOptions = {} 10 | /** 11 | * 弹窗设置 12 | */ 13 | static popupConfig: PopupConfig = new PopupConfig() 14 | /** 15 | * 侧滑关闭 16 | */ 17 | static dismissOnBackPressed: boolean = true 18 | /** 19 | * 自定义组件时,是否NodeContainer包裹,wrap=true:参数可统一设置,比如弹窗圆角、内边距等;wrap=false:所有内容都需要自己在使用地方配置,比如圆角,内边距等 20 | */ 21 | static wrap: boolean = true 22 | /** 23 | * 全局设置 24 | */ 25 | static popupOptions: PopupInfo = {} 26 | 27 | /** 28 | * 获取弹窗系统设置 29 | * @returns 30 | */ 31 | static getDialogOptions(): promptAction.BaseDialogOptions { 32 | return JSON.parse(JSON.stringify(Config.dialogOptions)) 33 | } 34 | 35 | /** 36 | * 获取窗口设置 37 | * @returns 38 | */ 39 | static getPopupConfig(): PopupConfig { 40 | return JSON.parse(JSON.stringify(Config.popupConfig)) 41 | } 42 | 43 | /** 44 | * 获取弹窗内默认设置 45 | * @returns 46 | */ 47 | static getPopupOptions(): PopupInfo { 48 | return JSON.parse(JSON.stringify(Config.popupOptions)) 49 | } 50 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/popup/CustomBuilder.ets: -------------------------------------------------------------------------------- 1 | import { PopupBean } from './entity/PopupBean' 2 | import { CustomBubbleComponent } from './CustomBubbleComponent' 3 | 4 | /** 5 | * 气泡弹窗 6 | * @param data 7 | */ 8 | @Builder 9 | export function bubblePopupBuilder(data: PopupBean) { 10 | CustomBubbleComponent({ data: data }) 11 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/popup/CustomNodeController.ets: -------------------------------------------------------------------------------- 1 | import { BuilderNode, FrameNode, NodeController, Size, UIContext } from '@kit.ArkUI'; 2 | 3 | export class CustomNodeController extends NodeController { 4 | private customNode: BuilderNode | null = null 5 | private builder: WrappedBuilder 6 | private params?: T 7 | 8 | constructor(builder: WrappedBuilder, params?: T) { 9 | super(); 10 | this.builder = builder; 11 | this.params = params; 12 | } 13 | 14 | makeNode(uiContext: UIContext): FrameNode | null { 15 | this.customNode = new BuilderNode(uiContext) 16 | this.customNode.build(this.builder, this.params) 17 | return this.customNode.getFrameNode() 18 | } 19 | 20 | /** 21 | * 释放节点 22 | */ 23 | dispose() { 24 | if (this.customNode != null) { 25 | this.customNode.dispose() 26 | } 27 | } 28 | 29 | aboutToResize(size: Size): void { 30 | console.log("节点大小width=" + size.width + ",height" + size.height) 31 | } 32 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/popup/PopupAction.ets: -------------------------------------------------------------------------------- 1 | export interface PopupAction { 2 | dismiss: Callback 3 | index?: number 4 | data?: ESObject 5 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/popup/PopupCallback.ets: -------------------------------------------------------------------------------- 1 | import { PopupAction } from './PopupAction' 2 | 3 | export interface PopupCallback { 4 | /** 5 | * 弹窗准备显示 6 | */ 7 | beforeShow?: () => void 8 | /** 9 | * 弹窗完全显示 10 | */ 11 | onShow?: () => void 12 | /** 13 | * 弹窗完全消失 14 | */ 15 | onDismiss?: () => void 16 | /** 17 | * 弹窗准备消失 18 | */ 19 | beforeDismiss?: () => void 20 | /** 21 | * 返回按钮 22 | */ 23 | onBackPressed?: (data: DismissDialogAction) => void 24 | /** 25 | * 确认等操作数据返回 26 | */ 27 | onAction?: (data?: PopupAction) => void 28 | 29 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/popup/PopupConfig.ets: -------------------------------------------------------------------------------- 1 | import { PopupPosition } from './PopupPosition' 2 | import { componentUtils } from '@kit.ArkUI' 3 | import { ArrowLocation } from './ArrowLocation' 4 | 5 | export class PopupConfig { 6 | /** 7 | * 弹窗宽度,仅限于wrap=true,底部和顶部弹窗默认 100% ,中间弹窗默认90% 8 | */ 9 | width?: Length 10 | /** 11 | * 弹窗高度,仅限于wrap = true,默认50% 12 | */ 13 | height?: Length 14 | /** 15 | * 弹窗最大宽度,仅限于wrap=true 16 | */ 17 | maxWidth?: Length 18 | /** 19 | * 弹窗最小宽度,仅限于wrap=true 20 | */ 21 | minWidth?: Length 22 | /** 23 | * 弹窗最大高度,仅限于wrap=true 24 | */ 25 | maxHeight?: Length 26 | /** 27 | * 弹窗最小高度,仅限于wrap=true 28 | */ 29 | minHeight?: Length 30 | /** 31 | * 背景颜色 32 | */ 33 | backgroundColor: ResourceColor = Color.White 34 | /** 35 | * 圆角 36 | */ 37 | borderRadius: Length | BorderRadiuses | LocalizedBorderRadiuses = 16 38 | /** 39 | * Popup弹窗内边距 40 | */ 41 | popupPadding: Padding | Length | LocalizedPadding = 20 42 | /** 43 | * 主要颜色 44 | */ 45 | primaryColor?: ResourceColor 46 | /** 47 | * 侧滑关闭 48 | */ 49 | dismissOnBackPressed: boolean = true 50 | /** 51 | * 自定义组件时,是否NodeContainer包裹,wrap=true:参数可统一设置,比如弹窗圆角、内边距等;wrap=false:所有内容都需要自己在使用地方配置,比如圆角,内边距等 52 | */ 53 | wrap: boolean = true 54 | /** 55 | * 操作完成后是否自动关闭弹窗,默认true,比如点击ConfirmPopup的确认按钮,默认自动关闭;如果为false,则不会关闭 56 | */ 57 | autoDismiss: boolean = true 58 | /** 59 | * 弹窗位置 60 | */ 61 | popupPosition?: PopupPosition 62 | /** 63 | * 依赖View型数据 64 | */ 65 | attachViewComponentInfo?: componentUtils.ComponentInfo 66 | /** 67 | * 依附弹窗是否对组件居中 68 | */ 69 | isAttachCenter:boolean = true 70 | /** 71 | * 依附组件距离指定组件的距离,默认为0 72 | */ 73 | attachMargin: number = 0 74 | /** 75 | * 气泡弹窗,箭头偏移,单位vp 76 | */ 77 | arrowOffset: number = 0 78 | /** 79 | * 气泡弹窗,箭头是否居中 80 | */ 81 | isArrowPositionCenter: boolean = true 82 | /** 83 | * 阴影颜色 84 | */ 85 | shadowColor: string = "#FF444444" 86 | /** 87 | * 阴影半径,单位:vp 88 | */ 89 | shadowRadius?: number 90 | /** 91 | * 阴影X轴,单位:vp 92 | */ 93 | shadowX: number = 0 94 | /** 95 | * 阴影Y轴,单位:vp 96 | */ 97 | shadowY: number = 0 98 | /** 99 | * 气泡弹窗,箭头尖左边弧度,单位:vp 100 | */ 101 | arrowTopLeftRadius: number = 2 102 | /** 103 | * 气泡弹窗,箭头尖右边弧度,单位:vp 104 | */ 105 | arrowTopRightRadius: number = 2 106 | /** 107 | * 气泡弹窗,箭头底部左边弧度,单位:vp 108 | */ 109 | arrowDownLeftRadius: number = 2 110 | /** 111 | * 气泡弹窗,箭头底部右边弧度,单位:vp 112 | */ 113 | arrowDownRightRadius: number = 2 114 | /** 115 | * 气泡弹窗,箭头宽度,单位:vp 116 | */ 117 | arrowWidth: number = 20 118 | /** 119 | * 气泡弹窗,箭头高度,单位:vp 120 | */ 121 | arrowHeight: number = 8 122 | /** 123 | * 气泡弹窗,箭头的位置,默认顶部 124 | */ 125 | arrowLocation: ArrowLocation = ArrowLocation.TOP 126 | /** 127 | * 边框颜色 128 | */ 129 | borderColor: number = Color.Transparent 130 | /** 131 | * 边框大小,单位:vp 132 | */ 133 | borderSize: number = 0 134 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/popup/PopupManager.ets: -------------------------------------------------------------------------------- 1 | import { ComponentContent, promptAction, PromptAction, window } from '@kit.ArkUI'; 2 | import { bubblePopupBuilder } from './CustomBuilder'; 3 | import { PopupBean } from './entity/PopupBean'; 4 | import { PopupConfig } from './PopupConfig'; 5 | import { CustomNodeController } from './CustomNodeController'; 6 | import { PopupType } from './PopupType'; 7 | 8 | /** 9 | * 弹窗管理 10 | */ 11 | export class PopupManager { 12 | private popup?: ComponentContent 13 | private promptAction?: PromptAction 14 | /** 15 | * 自定义节点控制器 16 | */ 17 | private customNodeController?: CustomNodeController 18 | /** 19 | * 自定义弹窗类型 20 | */ 21 | popupType: PopupType = PopupType.BUBBLE 22 | 23 | /** 24 | * 完全自定义显示,没有外层包裹 25 | * @param config 26 | * @param wrapBuilder 27 | * @param args 28 | */ 29 | async show(config: promptAction.BaseDialogOptions, builder: WrappedBuilder, args?: T) { 30 | try { 31 | const windowClass = await window.getLastWindow(getContext()) 32 | const uiContext = windowClass.getUIContext() 33 | if (args) { 34 | this.popup = new ComponentContent(uiContext, builder, args) 35 | } else { 36 | this.popup = new ComponentContent(uiContext, builder as WrappedBuilder<[]>) 37 | } 38 | this.promptAction = uiContext.getPromptAction() 39 | this.promptAction.openCustomDialog(this.popup, config) 40 | } catch (e) { 41 | console.error(JSON.stringify(e)) 42 | } 43 | } 44 | 45 | 46 | /** 47 | * 自定义显示,有外层包裹,可控制总体圆角等参数 48 | * @param config 49 | * @param popupConfig 50 | * @param builder 51 | * @param args 52 | */ 53 | async wrapShow(config: promptAction.BaseDialogOptions, popupConfig: PopupConfig, 54 | builder: WrappedBuilder, args?: T) { 55 | try { 56 | const windowClass = await window.getLastWindow(getContext()) 57 | const uiContext = windowClass.getUIContext() 58 | let bean = new PopupBean(new CustomNodeController(builder, args), popupConfig) 59 | this.customNodeController = bean.customNodeController 60 | bean.maskColor = config.maskColor 61 | bean.onDismiss = () => { 62 | this.dismiss() 63 | } 64 | 65 | bean.popupType = this.popupType 66 | if (this.popupType == PopupType.BUBBLE) { 67 | this.popup = new ComponentContent(uiContext, wrapBuilder(bubblePopupBuilder), bean) 68 | } 69 | this.promptAction = uiContext.getPromptAction() 70 | this.promptAction.openCustomDialog(this.popup, config) 71 | } catch (e) { 72 | console.error(JSON.stringify(e)) 73 | } 74 | } 75 | 76 | 77 | /** 78 | * 关闭弹窗 79 | */ 80 | async dismiss() { 81 | try { 82 | const windowClass = await window.getLastWindow(getContext()) 83 | this.promptAction?.closeCustomDialog(this.popup) 84 | if (this.customNodeController != null) { 85 | this.customNodeController.dispose() 86 | this.customNodeController = undefined 87 | } 88 | } catch (e) { 89 | console.error(JSON.stringify(e)) 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/popup/PopupPosition.ets: -------------------------------------------------------------------------------- 1 | export enum PopupPosition { 2 | TOP, 3 | BOTTOM, 4 | LEFT, 5 | RIGHT 6 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/popup/PopupType.ets: -------------------------------------------------------------------------------- 1 | export enum PopupType { 2 | /** 3 | * 气泡弹窗 4 | */ 5 | BUBBLE 6 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/popup/entity/ButtonOptions.ets: -------------------------------------------------------------------------------- 1 | import { PopupAction } from '../PopupAction' 2 | 3 | export interface ButtonOptions { 4 | text: string | Resource 5 | action?: (data?: PopupAction) => void 6 | fontColor?: ResourceColor 7 | fontSize?: Length 8 | backgroundColor?: ResourceColor, 9 | buttonType?: ButtonType 10 | border?: BorderOptions 11 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/popup/entity/PopupBean.ets: -------------------------------------------------------------------------------- 1 | import { PopupConfig } from '../PopupConfig' 2 | import { CustomNodeController } from '../CustomNodeController' 3 | import { PopupType } from '../PopupType' 4 | 5 | export class PopupBean { 6 | customNodeController: CustomNodeController 7 | popupConfig: PopupConfig 8 | /** 9 | * 蒙层颜色 10 | */ 11 | maskColor?: ResourceColor 12 | /** 13 | * 关闭 14 | */ 15 | onDismiss?: () => void 16 | /** 17 | * 弹窗类型 18 | */ 19 | popupType?: PopupType 20 | 21 | constructor(customNodeController: CustomNodeController, popupConfig: PopupConfig) { 22 | this.customNodeController = customNodeController 23 | this.popupConfig = popupConfig 24 | } 25 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/popup/entity/PopupInfo.ets: -------------------------------------------------------------------------------- 1 | import { ButtonOptions } from './ButtonOptions' 2 | export interface PopupInfo { 3 | /** 4 | * Loading提示 5 | */ 6 | hint?: string | Resource 7 | /** 8 | * Loading提示大小 9 | */ 10 | hintFontSize?: number | string | Resource 11 | /** 12 | * Loading提示颜色 13 | */ 14 | hintFontColor?: ResourceColor 15 | /** 16 | * Loading提示Weight 17 | */ 18 | hintFontWeight?: number | FontWeight | string 19 | /** 20 | * 进度加载框大小 21 | */ 22 | loadingProgressSize?: Length 23 | /** 24 | * Loading颜色 25 | */ 26 | loadingProgressColor?: ResourceColor 27 | /** 28 | * 标题 29 | */ 30 | title?: string | Resource 31 | /** 32 | * 标题大小 33 | */ 34 | titleFontSize?: number | string | Resource 35 | /** 36 | * 标题颜色 37 | */ 38 | titleFontColor?: ResourceColor 39 | /** 40 | * 标题Weight 41 | */ 42 | titleFontWeight?: number | FontWeight | string 43 | /** 44 | * 内容 45 | */ 46 | text?: string | Resource 47 | /** 48 | * 内容大小 49 | */ 50 | textFontSize?: number | string | Resource 51 | /** 52 | * 内容颜色 53 | */ 54 | textFontColor?: ResourceColor 55 | /** 56 | * 内容Weight 57 | */ 58 | textFontWeight?: number | FontWeight | string 59 | /** 60 | * 文本对齐方式 61 | */ 62 | textTextAlign?: TextAlign 63 | /** 64 | * 输入框提醒 65 | */ 66 | placeholder?: string | Resource 67 | /** 68 | * 输入框提醒样式 69 | */ 70 | placeholderFont?: Font 71 | /** 72 | * 输入框提醒颜色 73 | */ 74 | placeholderFontColor?: ResourceColor 75 | /** 76 | * 按钮间间距 77 | */ 78 | buttonSpace?: string | number | undefined 79 | /** 80 | * 按钮 81 | */ 82 | buttons?: ButtonOptions[] 83 | /** 84 | * 数据 85 | */ 86 | values?: string[] 87 | /** 88 | * 列表选择回调 89 | * @param value 90 | * @param index 91 | */ 92 | onSelect?: (value: string, index: number) => void 93 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/pullable/OmniPullable.ets: -------------------------------------------------------------------------------- 1 | export { OmniPullToRefreshLayout } from './OmniPullToRefreshLayout' 2 | 3 | export { OmniRefreshLayoutConfig } from './OmniRefreshLayoutConfig' 4 | 5 | export { OmniPullStatus, OmniPullDown } from './interface' 6 | 7 | export { OmniPullableController } from './OmniPullableController' -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/pullable/OmniPullableController.ets: -------------------------------------------------------------------------------- 1 | import { OmniPullStatus } from './interface' 2 | import { OmniRefreshLayoutConfig } from './OmniRefreshLayoutConfig' 3 | 4 | // 视图状态枚举 5 | export enum ViewState { 6 | success = 0, // 成功状态 7 | loading, // 加载中 8 | empty, // 空数据 9 | error, // 错误 10 | noNetwork // 无网络 11 | } 12 | 13 | export class OmniPullableController { 14 | private viewState: ViewState = ViewState.success // 当前视图状态 15 | 16 | // 刷新相关方法 17 | refreshSuccess: (ignoreViewTips?: boolean) => void = () => {} // 刷新成功 18 | refreshError: () => void = () => {} // 刷新失败 19 | refreshComplete: (isSuccess: boolean, ignoreViewTips?: boolean) => void = () => {} // 刷新完成 20 | refreshCancel: () => void = () => {} // 取消刷新 21 | 22 | // 加载相关方法 23 | loadSuccess: (hasMore?: boolean) => void = () => {} // 加载成功 24 | loadError: () => void = () => {} // 加载失败 25 | loadComplete: (isSuccess: boolean, hasMore?: boolean) => void = () => {} // 加载完成 26 | loadCancel: () => void = () => {} // 取消加载 27 | 28 | // 视图状态控制方法 29 | viewLoading: () => void = () => { this.viewState = ViewState.loading } // 显示加载中 30 | viewEmpty: () => void = () => { this.viewState = ViewState.empty } // 显示空布局 31 | viewError: () => void = () => { this.viewState = ViewState.error } // 显示错误布局 32 | viewNoNetwork: () => void = () => { this.viewState = ViewState.noNetwork }// 显示无网络布局 33 | 34 | // 状态查询与控制方法 35 | getStatus: () => OmniPullStatus = () => OmniPullStatus.DEF // 获取当前状态 36 | hasMore: (hasMore: boolean) => void = () => {} // 设置是否还有更多数据 37 | refresh: () => void = () => {} // 手动触发下拉刷新 38 | load: () => void = () => {} // 手动触发上拉加载 39 | 40 | // 开关状态查询 41 | refreshIsEnable: () => boolean = () => true // 下拉刷新是否启用 42 | loadIsEnable: () => boolean = () => false // 上拉加载是否启用 43 | 44 | // 配置相关方法 45 | setConfig: (config: OmniRefreshLayoutConfig) => void = () => {} // 设置配置 46 | getConfig: () => OmniRefreshLayoutConfig = () => new OmniRefreshLayoutConfig() // 获取配置 47 | 48 | // WebView 相关方法 49 | onWebviewScroll: (xOffset: number, yOffset: number) => void = () => {} // WebView 滚动处理 50 | 51 | // 获取当前视图状态 52 | public getViewState(): ViewState { 53 | return this.viewState 54 | } 55 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/pullable/OmniRefreshLayoutConfig.ets: -------------------------------------------------------------------------------- 1 | export class OmniRefreshLayoutConfig { 2 | public pullRefreshEnable: boolean = true 3 | public loadMoreEnable: boolean = false 4 | 5 | /*******************************刷新配置*******************************************/ 6 | /*true:释放刷新,false下拉到一定距离刷新*/ 7 | public releaseRefresh: boolean = true 8 | /*下拉最大距离*/ 9 | public pullMaxDistance: number = 500 10 | /*下拉阻力*/ 11 | public pullRefreshResistance: number = 0.5 12 | /*下拉距离超过多少时达到刷新条件*/ 13 | public pullHeaderHeightRefresh: number = 0 14 | 15 | /*释放刷新时,回弹至headerView高度的时间*/ 16 | public durationToHeader: number = 250 17 | /*头布局刷新结束时回弹的时间*/ 18 | public durationCloseHeader: number = 200 19 | /*刷新时是否显示头view*/ 20 | public refreshKeepHeader: boolean = true 21 | /*是否显示刷新成功状态的view*/ 22 | public refreshShowSuccess: boolean = true; 23 | /*是否显示刷新失败状态的view*/ 24 | public refreshShowError: boolean = true; 25 | /*刷新结果view显示持续时间*/ 26 | public refreshResultDurationTime: number = 600 27 | 28 | 29 | 30 | /*******************************加载更多配置*******************************************/ 31 | /*true:释放加载,false下拉到一定距离加载*/ 32 | public releaseLoad: boolean = true 33 | /*上拉最大距离*/ 34 | public pullLoadMaxDistance: number = 500 35 | /*上拉阻力*/ 36 | public pullLoadResistance: number = 0.5 37 | /*上拉距离超过多少时达到刷新条件*/ 38 | public pullFooterHeightLoad: number = 0 39 | /*释放刷新时,回弹至footerView高度的时间*/ 40 | public durationToFooter: number = 250 41 | /*footer布局刷新结束时回弹的时间*/ 42 | public durationCloseFooter: number = 200 43 | /*刷新时是否显示footerView*/ 44 | public loadKeepFooter: boolean = true 45 | /*是否显示刷新成功状态的view*/ 46 | public loadShowSuccess: boolean = true; 47 | /*是否显示刷新失败状态的view*/ 48 | public loadShowError: boolean = true; 49 | /*刷新结果view显示持续时间*/ 50 | public loadResultDurationTime: number = 600 51 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/pullable/core/RefreshLayoutHelper.ets: -------------------------------------------------------------------------------- 1 | 2 | import { AnimatorOptions } from '@kit.ArkUI'; 3 | 4 | // 默认动画配置 5 | const DEFAULT_ANIMATION_OPTIONS: AnimatorOptions = { 6 | duration: 250, 7 | easing: "fast-out-linear-in", 8 | delay: 0, 9 | fill: "forwards", 10 | direction: "normal", 11 | iterations: 1, 12 | begin: 0, 13 | end: 1 14 | } 15 | 16 | // 默认视图构建器 17 | @Builder 18 | export function _headerView() { 19 | Text("headerView:()=>{your @Builder View}") 20 | } 21 | 22 | @Builder 23 | export function _ContentView() { 24 | Text("contentView:()=>{your @Builder View}") 25 | } 26 | 27 | @Builder 28 | export function _loadMoreView() { 29 | Text("loadView:()=>{your @Builder View}") 30 | } 31 | 32 | @Builder 33 | export function _noMoreView() { 34 | Text("noMoreView:()=>{your @Builder View}") 35 | } 36 | 37 | export class RefreshLayoutHelper { 38 | // 滚动相关属性 39 | public scrollerOffset: number = 0 40 | public preOffset: number = 0 41 | public totalOffset: number = 0 42 | public totalOffsetLoad: number = 0 43 | 44 | // 尺寸相关属性 45 | public headerSize: number = 0 46 | public footerSize: number = 0 47 | 48 | // 状态相关属性 49 | public isPressDown: boolean = false 50 | public notReleaseRefresh: boolean = false 51 | public notReleaseLoad: boolean = false 52 | 53 | // 手势配置 54 | public options: PanGestureOptions = new PanGestureOptions({ 55 | direction: PanDirection.Down | PanDirection.Up 56 | }) 57 | 58 | // WebView偏移量 59 | public webViewXOffset: number = 0 60 | public webViewYOffset: number = 0 61 | 62 | // 动画配置 63 | public animOptions: AnimatorOptions = DEFAULT_ANIMATION_OPTIONS 64 | public animLoadOptions: AnimatorOptions = DEFAULT_ANIMATION_OPTIONS 65 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/pullable/interface.ets: -------------------------------------------------------------------------------- 1 | export interface OmniPullDown { 2 | isPullDown: boolean // 是否处于下拉状态 3 | isPullUp: boolean // 是否处于上拉状态 4 | isTouch: boolean // 是否正在触摸 5 | distance: number // 下拉距离 6 | distanceLoad: number // 上拉距离 7 | headerViewSize: number // 头部视图高度 8 | footerViewSize: number // 底部视图高度 9 | status: OmniPullStatus // 当前状态 10 | } 11 | 12 | export enum OmniPullStatus { 13 | DEF, // 默认状态(无下拉) 14 | PullDown, // 正在下拉 15 | PreRefresh, // 达到可刷新状态 16 | Refresh, // 刷新中 17 | RefreshSuccess, // 刷新成功 18 | RefreshError, // 刷新失败 19 | PullUp, // 正在上拉 20 | PreLoad, // 达到可加载状态 21 | Load, // 加载中 22 | LoadSuccess, // 加载成功 23 | LoadError // 加载失败 24 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/richtext/utils/ExposeData.ts: -------------------------------------------------------------------------------- 1 | 2 | export interface ExposeData { 3 | // 字段别名 4 | name?: string 5 | // 原始字段名 6 | propertyName?: string 7 | // 转换执行回调函数 8 | transform?: Function 9 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/richtext/utils/MetadataStorage.ts: -------------------------------------------------------------------------------- 1 | import { ClassConstructor } from '.' 2 | import { ExposeData } from './ExposeData' 3 | 4 | export class MetadataStorage { 5 | 6 | private _typeMetadatas = new Map>>() 7 | 8 | private _exposeDatas = new Map>() 9 | 10 | addMetadata(protoType: Function, propertyName: string, cls: ClassConstructor) { 11 | if (!this._typeMetadatas.has(protoType)) { 12 | this._typeMetadatas.set(protoType, new Map>()) 13 | } 14 | this._typeMetadatas.get(protoType).set(propertyName, cls) 15 | } 16 | 17 | findMetadata(protoType: Function, propertyName: string): ClassConstructor { 18 | if (this._typeMetadatas.has(protoType)) { 19 | const meta = this._typeMetadatas.get(protoType) 20 | if (meta) { 21 | return meta.get(propertyName) 22 | } 23 | } 24 | return undefined 25 | } 26 | 27 | addExposeData(protoType: Function, propertyName: string, expose: ExposeData) { 28 | if (!this._exposeDatas.has(protoType)) { 29 | this._exposeDatas.set(protoType, new Map()) 30 | } 31 | this._exposeDatas.get(protoType).set(propertyName, expose) 32 | } 33 | 34 | findExposeData(protoType: Function, propertyName: string): ExposeData { 35 | if (this._exposeDatas.has(protoType)) { 36 | const expose = this._exposeDatas.get(protoType) 37 | if (expose) { 38 | return expose.get(propertyName) 39 | } 40 | } 41 | return undefined 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/richtext/utils/Util.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 将 style:"k:v;k:v" 解析成 map 3 | * @param style 4 | * @returns map 5 | */ 6 | export function parseStyle(style: string) { 7 | const styleMap: Map = new Map(); 8 | const regex = /([\w-]+)\s*:\s*([^;]+)/g; 9 | let match: RegExpExecArray | null; 10 | while ((match = regex.exec(style)) !== null) { 11 | styleMap.set(match[1],match[2]); 12 | } 13 | return styleMap; 14 | } 15 | 16 | export function convertObjectToMap(obj: Object | undefined): Map { 17 | const map = new Map(); 18 | if (obj != undefined) { 19 | for (const [key, value] of Object.entries(obj)) { 20 | map.set(key, `${value}`) 21 | } 22 | } 23 | return map 24 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/richtext/utils/index.ts: -------------------------------------------------------------------------------- 1 | import { MetadataStorage } from './MetadataStorage'; 2 | 3 | export type ObjectLike = Record 4 | export const defaultMetadataStorage = new MetadataStorage(); 5 | export declare type ClassConstructor = { 6 | new (...args: any[]): T; 7 | }; -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/step/OmniLine.ets: -------------------------------------------------------------------------------- 1 | @Component 2 | export struct OmniLine { 3 | @Prop modifier: OmniDividerModifier 4 | 5 | build() { 6 | Divider().attributeModifier(this.modifier) 7 | } 8 | } 9 | 10 | export class OmniDividerModifier implements AttributeModifier { 11 | private width: Length = '100%' 12 | private height: Length = '100%' 13 | private color: ResourceColor = '#FF552E' 14 | private padding: Padding | Length | LocalizedPadding = { 15 | top: 5, 16 | bottom: 5 17 | } 18 | 19 | withWidth(value: Length) { 20 | this.width = value 21 | return this 22 | } 23 | 24 | withHeight(value: Length) { 25 | this.height = value 26 | return this 27 | } 28 | 29 | withColor(value: ResourceColor) { 30 | this.color = value 31 | return this 32 | } 33 | 34 | withPadding(value: Padding | Length | LocalizedPadding) { 35 | this.padding = value 36 | return this 37 | } 38 | 39 | applyNormalAttribute(instance: DividerAttribute): void { 40 | instance.width(this.width) 41 | instance.height(this.height) 42 | instance.color(this.color) 43 | instance.padding(this.padding) 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/tags/TagItemInfo.ets: -------------------------------------------------------------------------------- 1 | export interface TagItemInfoParams { 2 | title?: string 3 | icons?: IconInfo 4 | tagStyle?: TagStyle 5 | isSelected?: boolean 6 | } 7 | 8 | @Observed 9 | export class TagItemInfo { 10 | title?: string 11 | icons?: IconInfo 12 | tagStyle?: TagStyle 13 | isSelected: boolean 14 | 15 | constructor(params: TagItemInfoParams) { 16 | this.title = params.title 17 | this.icons = params.icons 18 | this.tagStyle = params.tagStyle 19 | this.isSelected = params.isSelected ?? false 20 | } 21 | } 22 | 23 | export interface IconInfo { 24 | top?: IconItemInfo, 25 | bottom?: IconItemInfo, 26 | left?: IconItemInfo, 27 | right?: IconItemInfo 28 | } 29 | 30 | export interface IconItemInfo { 31 | icon?: PixelMap | ResourceStr | DrawableDescriptor 32 | iconSize?: SizeOptions 33 | } 34 | 35 | export interface TagStyle { 36 | textMargin?: Margin | Length | LocalizedMargin 37 | fontSize?: string | number | Resource 38 | fontColor?: ResourceColor 39 | backgroundColor?: ResourceColor 40 | selectedFontSize?: string | number | Resource 41 | selectedBackgroundColor?: ResourceColor 42 | selectedFontColor?: ResourceColor 43 | itemBorder?: BorderOptions 44 | selectedItemBorder?: BorderOptions 45 | itemPadding?: Padding | Length | LocalizedPadding 46 | itemSize?: SizeOptions 47 | } 48 | 49 | export enum TagMode { 50 | HORIZONTAL_SCROLL, 51 | FLEX 52 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/toast/OmniToastBuilders.ets: -------------------------------------------------------------------------------- 1 | import { OmniTheme, OmniThemeStyle } from '../../theme/OmniTheme' 2 | import { TextUtils } from '../../utils/TextUtils' 3 | import { ToastWrapBuilderArgs } from './OmniToastTheme' 4 | 5 | @Builder 6 | export function imageTextContentBuilder(args: ToastWrapBuilderArgs) { 7 | OmniToastComponent({ args }) 8 | } 9 | 10 | @Component 11 | struct OmniToastComponent { 12 | @StorageLink(OmniTheme.KEY) 13 | private baseStyle: OmniThemeStyle = OmniTheme.getDefaultStyle() 14 | @Prop args: ToastWrapBuilderArgs 15 | 16 | build() { 17 | Row() { 18 | if (this.args.icon) { 19 | Image(this.args.icon) 20 | .width(this.args.theme?.iconWidth ?? 25) 21 | .height(this.args.theme?.iconWidth ?? 25) 22 | .margin((this.args.icon && !TextUtils.isBlank(this.args.msg ?? '')) ? { right: 5 } : { right: 0 }) 23 | } 24 | if (!TextUtils.isBlank(this.args.msg ?? '')) { 25 | Text(this.args.msg) 26 | .fontSize(this.args.theme?.fontSize ?? this.baseStyle.fontSizeLg) 27 | .fontColor(this.args.theme?.textColor ?? Color.White) 28 | } 29 | } 30 | .height(this.args.theme?.height) 31 | .width(this.args.theme?.width) 32 | .margin({ left: 12, right: 12 }) 33 | .padding(12) 34 | .backgroundColor(this.args.theme?.backgroundColor ?? 0xDD000000) 35 | .backgroundBlurStyle(this.args.theme?.backgroundBlurStyle) 36 | .shadow(this.args.theme?.shadow) 37 | .borderRadius(this.args.theme?.borderRadius ?? 10) 38 | .borderWidth(this.args.theme?.borderWidth) 39 | .borderStyle(this.args.theme?.borderStyle) 40 | .borderColor(this.args.theme?.borderColor) 41 | } 42 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/components/toast/OmniToastTheme.ets: -------------------------------------------------------------------------------- 1 | /* 2 | * 主题设置 3 | * */ 4 | class ToastTheme { 5 | // 文本颜色 默认白色 6 | textColor?: ResourceColor 7 | // 文本大小 8 | fontSize?: number | string | Resource 9 | // 背景颜色 10 | backgroundColor?: ResourceColor 11 | // 边框圆角 12 | borderRadius?: Dimension | BorderRadiuses 13 | // 边框宽度 14 | borderWidth?: Dimension | EdgeWidths 15 | // 边框颜色 16 | borderColor?: ResourceColor | EdgeColors 17 | // 边框样式 18 | borderStyle?: BorderStyle | EdgeStyles 19 | // 背板模糊材质。 20 | backgroundBlurStyle?: BlurStyle 21 | // 设置背板的阴影。 22 | shadow?: ShadowOptions | ShadowStyle 23 | // toast的宽度 24 | width?: Dimension 25 | // toast的高度 26 | height?: Dimension 27 | // 图标的宽度,未设置图标不生效 28 | iconWidth?: Dimension 29 | // 图标的高度,未设置图标不生效 30 | iconHeight?: Dimension 31 | } 32 | 33 | /* 34 | * wrap builder args 35 | * */ 36 | interface ToastWrapBuilderArgs { 37 | msg?: string 38 | duration: number 39 | icon?: PixelMap | ResourceStr | DrawableDescriptor | ImageContent 40 | theme?: ToastTheme 41 | } 42 | 43 | export { ToastTheme, ToastWrapBuilderArgs, } -------------------------------------------------------------------------------- /omni_component/src/main/ets/constants/CommonConstants.ets: -------------------------------------------------------------------------------- 1 | export class CommonConstants { 2 | /** RelativeContainer 组件默认的ID */ 3 | static readonly RELATIVE_CONTAINER_ID: string = '__container__'; 4 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/theme/OmniColorStyle.ets: -------------------------------------------------------------------------------- 1 | import { OmniResourceColor } from "./OmniTheme"; 2 | 3 | export interface OmniColorStyle { 4 | primary: OmniResourceColor 5 | primaryColorWithOpacity: (opacity: number) => OmniResourceColor; 6 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/theme/OmniFontStyle.ets: -------------------------------------------------------------------------------- 1 | export interface OmniFontStyle { 2 | //Extra Small 3 | fontSizeXs: number | string | Resource 4 | //Small 5 | fontSizeSm: number | string | Resource 6 | //Medium 7 | fontSizeMd: number | string | Resource 8 | //Large 9 | fontSizeLg: number | string | Resource 10 | //Extra Large 11 | fontSizeXl: number | string | Resource 12 | } 13 | 14 | export enum FONT_SIZE { 15 | XS = 10, 16 | SM = 12, 17 | MD = 14, 18 | LG = 16, 19 | XL = 20 20 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/theme/OmniStyleModifier.ets: -------------------------------------------------------------------------------- 1 | import { OmniThemeStyle } from "./OmniTheme" 2 | 3 | export class PrimaryColorModifier implements AttributeModifier { 4 | baseStyle: OmniThemeStyle 5 | 6 | constructor(baseStyle: OmniThemeStyle) { 7 | this.baseStyle = baseStyle 8 | } 9 | 10 | applyNormalAttribute(instance: ButtonAttribute): void { 11 | instance.backgroundColor(this.baseStyle.primary) 12 | } 13 | } 14 | 15 | export class TitleTextModifier implements AttributeModifier { 16 | baseStyle: OmniThemeStyle 17 | 18 | constructor(baseStyle: OmniThemeStyle) { 19 | this.baseStyle = baseStyle 20 | } 21 | 22 | applyNormalAttribute(instance: ButtonAttribute): void { 23 | instance.fontWeight(FontWeight.Bolder) 24 | instance.fontSize(this.baseStyle.fontSizeXl) 25 | } 26 | } 27 | 28 | export class SubTitleTextModifier implements AttributeModifier { 29 | baseStyle: OmniThemeStyle 30 | 31 | constructor(baseStyle: OmniThemeStyle) { 32 | this.baseStyle = baseStyle 33 | } 34 | 35 | applyNormalAttribute(instance: ButtonAttribute): void { 36 | instance.fontWeight(FontWeight.Bold) 37 | instance.fontSize(this.baseStyle.fontSizeLg) 38 | } 39 | } 40 | 41 | export class ContentTextModifier implements AttributeModifier { 42 | baseStyle: OmniThemeStyle 43 | 44 | constructor(baseStyle: OmniThemeStyle) { 45 | this.baseStyle = baseStyle 46 | } 47 | 48 | applyNormalAttribute(instance: ButtonAttribute): void { 49 | instance.fontWeight(FontWeight.Medium) 50 | instance.fontSize(this.baseStyle.fontSizeMd) 51 | } 52 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/theme/OmniTheme.ets: -------------------------------------------------------------------------------- 1 | import { OmniColorStyle } from "./OmniColorStyle"; 2 | import { FONT_SIZE, OmniFontStyle } from "./OmniFontStyle"; 3 | import { OmniThemeUtil } from "./OmniThemeUtil"; 4 | 5 | export enum OmniColor{ 6 | PRIMARY_COLOR = -1 7 | }; 8 | 9 | export type OmniResourceColor = number | string ; 10 | 11 | export interface OmniThemeStyle extends OmniColorStyle, OmniFontStyle {} 12 | 13 | export class OmniTheme { 14 | static KEY = 'OMNI_THEME_KEY' 15 | static DEFAULT_PRIMARY_COLOR = "#296DFF" 16 | 17 | static init() { 18 | AppStorage.setOrCreate(OmniTheme.KEY, OmniTheme.getDefaultStyle()) 19 | } 20 | 21 | static getDefaultStyle(): OmniThemeStyle { 22 | const data: OmniThemeStyle = { 23 | primary: OmniTheme.DEFAULT_PRIMARY_COLOR, 24 | primaryColorWithOpacity: (opacity: number) => OmniThemeUtil.colorWithOpacity(data.primary, opacity), 25 | fontSizeXs: FONT_SIZE.XS, 26 | fontSizeSm: FONT_SIZE.SM, 27 | fontSizeMd: FONT_SIZE.MD, 28 | fontSizeLg: FONT_SIZE.LG, 29 | fontSizeXl: FONT_SIZE.XL, 30 | } 31 | return data; 32 | } 33 | 34 | static setThemeStyle(styleData?: Partial) { 35 | const newStyleData = OmniTheme.getDefaultStyle(); 36 | if (typeof styleData === 'object' && styleData !== null) { 37 | Object.keys(styleData).forEach(item => { 38 | if ((newStyleData as object)[item]) { 39 | (newStyleData as object)[item] = (styleData as object)[item] ?? (newStyleData as object)[item] 40 | } 41 | }) 42 | } 43 | AppStorage.setOrCreate(OmniTheme.KEY, newStyleData) 44 | } 45 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/theme/OmniThemeUtil.ets: -------------------------------------------------------------------------------- 1 | import { OmniResourceColor } from "./OmniTheme"; 2 | 3 | export class OmniThemeUtil { 4 | /** 5 | * Adjusts the opacity of a given color. 6 | * @param color - The color value (number or string). 7 | * @param opacity - The opacity level (0 to 1). 8 | * @returns A color with the specified opacity applied. 9 | */ 10 | static colorWithOpacity(color: OmniResourceColor, opacity: number): OmniResourceColor { 11 | if (typeof color === "number") { 12 | // Handle numeric color (ARGB format) 13 | const alpha = Math.round(opacity * 255); // Convert opacity to 0-255 range 14 | const rgb = color & 0x00ffffff; // Extract the RGB part 15 | return (alpha << 24) | rgb; // Combine alpha and RGB 16 | } else if (typeof color === "string") { 17 | // Handle string color 18 | if (color.startsWith("#")) { 19 | // Check if the string has 9 characters (#AARRGGBB) 20 | if (color.length === 9) { 21 | color = `#${color.slice(3)}`; // Strip the `AA` part 22 | } 23 | // Convert #RRGGBB to rgba 24 | const r = parseInt(color.slice(1, 3), 16); 25 | const g = parseInt(color.slice(3, 5), 16); 26 | const b = parseInt(color.slice(5, 7), 16); 27 | return `rgba(${r}, ${g}, ${b}, ${opacity})`; 28 | } else if (color.startsWith("rgba")) { 29 | // Update opacity in existing rgba 30 | return color.replace(/rgba\(([^,]+),([^,]+),([^,]+),[^)]+\)/, (_, r: string, g: string, b: string) => { 31 | return `rgba(${r}, ${g}, ${b}, ${opacity})`; 32 | }); 33 | } 34 | } 35 | throw new Error("Unsupported color format"); 36 | } 37 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/utils/ImmersionBar.ets: -------------------------------------------------------------------------------- 1 | import { window } from '@kit.ArkUI' 2 | 3 | export class ImmersionBarUtils { 4 | windowClass: window.Window | null = null 5 | private statusBarHeight: number = 0 6 | private navigationBarHeight: number = 0 7 | private navigationIndicatorHeight: number = 0 8 | 9 | getStatusBarHeight(): number { 10 | return this.statusBarHeight 11 | } 12 | 13 | getNavigationBarHeight(): number { 14 | return this.navigationBarHeight 15 | } 16 | 17 | getNavigationIndicatorHeight(): number { 18 | return this.navigationIndicatorHeight 19 | } 20 | 21 | getNavigationHeight(): number { 22 | return this.navigationBarHeight > this.navigationIndicatorHeight ? this.navigationBarHeight : this.navigationIndicatorHeight 23 | } 24 | 25 | fullScreen(isFullScreen: boolean = true) { 26 | if (canIUse('SystemCapability.Window.SessionManager')) { 27 | this.windowClass?.setSpecificSystemBarEnabled('status', !isFullScreen) 28 | this.windowClass?.setSpecificSystemBarEnabled('navigation', !isFullScreen) 29 | } 30 | } 31 | 32 | hideNavigation(isHide: boolean = true) { 33 | if (canIUse('SystemCapability.Window.SessionManager')) { 34 | this.windowClass?.setSpecificSystemBarEnabled('navigation', !isHide) 35 | } 36 | } 37 | 38 | hideStatusBar(isHide: boolean = true) { 39 | if (canIUse('SystemCapability.Window.SessionManager')) { 40 | this.windowClass?.setSpecificSystemBarEnabled('status', !isHide) 41 | } 42 | } 43 | 44 | init(w: window.Window) { 45 | this.windowClass = w 46 | this.statusBarHeight = px2vp(w.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM).topRect.height) 47 | this.navigationIndicatorHeight = px2vp(w.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR).bottomRect.height) 48 | this.navigationBarHeight = px2vp(w.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM).bottomRect.height) 49 | } 50 | 51 | /** 52 | * 如果 transparentStatusBar 53 | * @param value 54 | */ 55 | immersion(value: ImmersionBarSettings) { 56 | let isLayoutFullScreen: boolean = value.transparentStatusBar ?? false 57 | this.windowClass?.setImmersiveModeEnabledState(isLayoutFullScreen) 58 | let statusBarColor = value.statusBarColor 59 | if (value.transparentStatusBar) { 60 | statusBarColor = Color.Transparent.toString() 61 | } 62 | if (value.statusBarColor) { 63 | statusBarColor = value.statusBarColor 64 | } 65 | let sysBarProps: window.SystemBarProperties = { 66 | statusBarColor: statusBarColor, 67 | statusBarContentColor: value.statusBarContentColor, 68 | navigationBarColor: value.navigationBarColor, 69 | navigationBarContentColor: value.navigationBarContentColor 70 | } 71 | this.windowClass?.setWindowSystemBarProperties(sysBarProps) 72 | } 73 | } 74 | 75 | export interface ImmersionBarSettings { 76 | transparentStatusBar?: boolean, 77 | statusBarColor?: string, 78 | statusBarContentColor?: string, 79 | navigationBarColor?: string, 80 | navigationBarContentColor?: string, 81 | fullScreen?: boolean, 82 | } 83 | 84 | let immersionBar = new ImmersionBarUtils() 85 | 86 | export default immersionBar -------------------------------------------------------------------------------- /omni_component/src/main/ets/utils/ScreenUtils.ets: -------------------------------------------------------------------------------- 1 | import { display, window } from '@kit.ArkUI'; 2 | 3 | let screenWidth = -1 4 | 5 | export class ScreenUtils { 6 | static getScreenWidthSync(): number { 7 | if (screenWidth == -1) { 8 | screenWidth = ScreenUtils._getScreenWidthSync() 9 | } 10 | return screenWidth; 11 | } 12 | 13 | private static _getScreenWidthSync(): number { 14 | try { 15 | let displayClass = display.getDefaultDisplaySync(); 16 | return px2vp(displayClass.width); 17 | } catch (exception) { 18 | console.error('Failed to obtain the default display object. Code: ' + JSON.stringify(exception)); 19 | } 20 | return 0; 21 | } 22 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/utils/TextUtils.ts: -------------------------------------------------------------------------------- 1 | export class TextUtils { 2 | /* 3 | * 判断字符串是否为空白符。true为空,否则false 4 | * @param str 字符串 5 | * */ 6 | static isBlank(str: string | undefined): boolean { 7 | if (!str) { 8 | return true 9 | } 10 | if (str.length == 0) { 11 | return true 12 | } 13 | 14 | let rsValue = str.replace(RegExp(' '), '') 15 | if (rsValue.length == 0) { 16 | return true 17 | } 18 | return false 19 | } 20 | 21 | static isNotBlank(str: string): boolean { 22 | return !TextUtils.isBlank(str) 23 | } 24 | } -------------------------------------------------------------------------------- /omni_component/src/main/ets/utils/Utils.ets: -------------------------------------------------------------------------------- 1 | export function isVideoFormat(url: string) { 2 | return url.endsWith(".mp4") || url.endsWith(".avi") || url.endsWith(".mov") || url.endsWith(".m4v") || 3 | url.endsWith(".wmv") 4 | } -------------------------------------------------------------------------------- /omni_component/src/main/module.json5: -------------------------------------------------------------------------------- 1 | { 2 | "module": { 3 | "name": "omni_component", 4 | "type": "har", 5 | "deviceTypes": [ 6 | "default" 7 | ], 8 | requestPermissions: [ 9 | { 10 | "name": "ohos.permission.INTERNET" 11 | } 12 | ] 13 | } 14 | } -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/element/color.json: -------------------------------------------------------------------------------- 1 | { 2 | "color": [ 3 | { 4 | "name": "fb_primary_color", 5 | "value": "#ff8700" 6 | }, 7 | { 8 | "name": "fb_normal_color", 9 | "value": "#333333" 10 | }, 11 | { 12 | "name": "fb_grid_select_border_color", 13 | "value": "#4cff4d13" 14 | }, 15 | { 16 | "name": "fb_grid_border_color", 17 | "value": "#cccccc" 18 | }, 19 | { 20 | "name": "fb_grid_bg_color", 21 | "value": "#0aff4d13" 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/element/string.json: -------------------------------------------------------------------------------- 1 | { 2 | "string": [ 3 | { 4 | "name": "page_show", 5 | "value": "page from package" 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/back.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/omni_component/src/main/resources/base/media/back.webp -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/comm_page_icon_jt_s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/omni_component/src/main/resources/base/media/comm_page_icon_jt_s.png -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/comm_page_icon_jt_x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/omni_component/src/main/resources/base/media/comm_page_icon_jt_x.png -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/error.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/ic_arrow_right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Public/ic_public_arrow_right_filled 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/ic_clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/omni_component/src/main/resources/base/media/ic_clear.png -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/ic_highlight.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Public/ic_public_highlight_filled 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/ic_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/omni_component/src/main/resources/base/media/ic_search.png -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/icon_arrow_down.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/icon_arrow_down_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/omni_component/src/main/resources/base/media/icon_arrow_down_selected.png -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/icon_arrow_down_unselected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/omni_component/src/main/resources/base/media/icon_arrow_down_unselected.png -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/icon_arrow_up.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/icon_arrow_up_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/omni_component/src/main/resources/base/media/icon_arrow_up_selected.png -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/icon_calendar_next_month.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/omni_component/src/main/resources/base/media/icon_calendar_next_month.png -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/icon_calendar_pre_month.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/omni_component/src/main/resources/base/media/icon_calendar_pre_month.png -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/icon_filter_reset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/omni_component/src/main/resources/base/media/icon_filter_reset.png -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/icon_filter_select.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/icon_filter_unselect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/omni_component/src/main/resources/base/media/icon_filter_unselect.png -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/icon_selection_reset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/omni_component/src/main/resources/base/media/icon_selection_reset.png -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/icon_step_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/omni_component/src/main/resources/base/media/icon_step_2.png -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/icon_step_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/omni_component/src/main/resources/base/media/icon_step_3.png -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/icon_step_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/omni_component/src/main/resources/base/media/icon_step_4.png -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/icon_step_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/omni_component/src/main/resources/base/media/icon_step_5.png -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/icon_step_completed.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/icon_step_doing.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/image_trigger_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/omni_component/src/main/resources/base/media/image_trigger_add.png -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/playIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/omni_component/src/main/resources/base/media/playIcon.png -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/search.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/omni_component/src/main/resources/base/media/search.webp -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/startIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/omni_component/src/main/resources/base/media/startIcon.png -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/success.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/voice_off.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/omni_component/src/main/resources/base/media/voice_off.webp -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/voice_on.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuba/omni-ui/35590dedca468fe76b1dd1eca21dc649daf35fad/omni_component/src/main/resources/base/media/voice_on.webp -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/warning.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /omni_component/src/main/resources/base/media/zr_refresh_arrow.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 7 | -------------------------------------------------------------------------------- /omni_component/src/main/resources/en_US/element/string.json: -------------------------------------------------------------------------------- 1 | { 2 | "string": [ 3 | { 4 | "name": "page_show", 5 | "value": "page from package" 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /omni_component/src/main/resources/zh_CN/element/string.json: -------------------------------------------------------------------------------- 1 | { 2 | "string": [ 3 | { 4 | "name": "page_show", 5 | "value": "page from package" 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /omni_component/src/ohosTest/ets/test/Ability.test.ets: -------------------------------------------------------------------------------- 1 | import { hilog } from '@kit.PerformanceAnalysisKit'; 2 | import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; 3 | 4 | export default function abilityTest() { 5 | describe('ActsAbilityTest', () => { 6 | // Defines a test suite. Two parameters are supported: test suite name and test suite function. 7 | beforeAll(() => { 8 | // Presets an action, which is performed only once before all test cases of the test suite start. 9 | // This API supports only one parameter: preset action function. 10 | }) 11 | beforeEach(() => { 12 | // Presets an action, which is performed before each unit test case starts. 13 | // The number of execution times is the same as the number of test cases defined by **it**. 14 | // This API supports only one parameter: preset action function. 15 | }) 16 | afterEach(() => { 17 | // Presets a clear action, which is performed after each unit test case ends. 18 | // The number of execution times is the same as the number of test cases defined by **it**. 19 | // This API supports only one parameter: clear action function. 20 | }) 21 | afterAll(() => { 22 | // Presets a clear action, which is performed after all test cases of the test suite end. 23 | // This API supports only one parameter: clear action function. 24 | }) 25 | it('assertContain', 0, () => { 26 | // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. 27 | hilog.info(0x0000, 'testTag', '%{public}s', 'it begin'); 28 | let a = 'abc'; 29 | let b = 'b'; 30 | // Defines a variety of assertion methods, which are used to declare expected boolean conditions. 31 | expect(a).assertContain(b); 32 | expect(a).assertEqual(a); 33 | }) 34 | }) 35 | } -------------------------------------------------------------------------------- /omni_component/src/ohosTest/ets/test/List.test.ets: -------------------------------------------------------------------------------- 1 | import abilityTest from './Ability.test'; 2 | 3 | export default function testsuite() { 4 | abilityTest(); 5 | } -------------------------------------------------------------------------------- /omni_component/src/ohosTest/module.json5: -------------------------------------------------------------------------------- 1 | { 2 | "module": { 3 | "name": "omni_component_test", 4 | "type": "feature", 5 | "deviceTypes": [ 6 | "default" 7 | ], 8 | "deliveryWithInstall": true, 9 | "installationFree": false 10 | } 11 | } -------------------------------------------------------------------------------- /omni_component/src/test/List.test.ets: -------------------------------------------------------------------------------- 1 | import localUnitTest from './LocalUnit.test'; 2 | 3 | export default function testsuite() { 4 | localUnitTest(); 5 | } -------------------------------------------------------------------------------- /omni_component/src/test/LocalUnit.test.ets: -------------------------------------------------------------------------------- 1 | import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; 2 | 3 | export default function localUnitTest() { 4 | describe('localUnitTest', () => { 5 | // Defines a test suite. Two parameters are supported: test suite name and test suite function. 6 | beforeAll(() => { 7 | // Presets an action, which is performed only once before all test cases of the test suite start. 8 | // This API supports only one parameter: preset action function. 9 | }); 10 | beforeEach(() => { 11 | // Presets an action, which is performed before each unit test case starts. 12 | // The number of execution times is the same as the number of test cases defined by **it**. 13 | // This API supports only one parameter: preset action function. 14 | }); 15 | afterEach(() => { 16 | // Presets a clear action, which is performed after each unit test case ends. 17 | // The number of execution times is the same as the number of test cases defined by **it**. 18 | // This API supports only one parameter: clear action function. 19 | }); 20 | afterAll(() => { 21 | // Presets a clear action, which is performed after all test cases of the test suite end. 22 | // This API supports only one parameter: clear action function. 23 | }); 24 | it('assertContain', 0, () => { 25 | // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. 26 | let a = 'abc'; 27 | let b = 'b'; 28 | // Defines a variety of assertion methods, which are used to declare expected boolean conditions. 29 | expect(a).assertContain(b); 30 | expect(a).assertEqual(a); 31 | }); 32 | }); 33 | } --------------------------------------------------------------------------------